Data Preparation / Data Preprocessing 📂 Data Collection · 4 of 13 305 min read

Matplotlib in Python

A hands-on guide to Python's most powerful plotting library — covering line charts, bar charts, scatter plots, histograms, heatmaps, subplots, violin plots, and publication-quality figure styling, with every chart rendered as a live output diagram.

🌐
SectionSection第 01 节

Introduction to Matplotlib 🎨Matplotlib का परिचय 🎨Matplotlib 简介 🎨

Matplotlib is Python's base plotting library. seaborn and pandas .plot() are built on top of it. When you learn matplotlib directly, you can control every part of a chart: each line, label, tick and colour.

Matplotlib, Python की आधार plotting library है। seaborn और pandas .plot() इसी के ऊपर बने हैं। Matplotlib सीधे सीखने पर आप chart के हर हिस्से को नियंत्रित कर सकते हैं: हर line, label, tick और रंग।

Matplotlib 是 Python 的基础绘图库,seaborn 和 pandas .plot() 都构建在它之上。直接学习 matplotlib,你就能控制图表的每个部分:每条线、每个标签、每个刻度和每种颜色。

💡
When to Use Matplotlib DirectlyMatplotlib सीधे कब इस्तेमाल करें何时直接使用 Matplotlib

For a quick look during EDA, seaborn or plotly are often faster. Use matplotlib directly when you need exact control: custom tick formats, two y-axes, shared axes, inset charts, exact font sizes for a journal, or a layout the higher-level tools cannot make. Even when you use seaborn, you will still use matplotlib to fine-tune the result.

EDA के दौरान जल्दी देखने के लिए seaborn या plotly अक्सर तेज़ हैं। Matplotlib सीधे तब इस्तेमाल करें जब सटीक नियंत्रण चाहिए: custom tick formats, दो y-axes, shared axes, inset charts, journal के लिए सटीक font sizes, या ऐसा layout जो ऊँचे स्तर के tools नहीं बना सकते। Seaborn इस्तेमाल करते समय भी नतीजे को सुधारने के लिए matplotlib काम आता है।

在 EDA 中快速查看时,seaborn 或 plotly 往往更快。需要精确控制时直接用 matplotlib:自定义刻度格式、双 y 轴、共享坐标轴、嵌入小图、期刊要求的精确字号,或高层工具做不出的布局。即使用 seaborn,你仍要用 matplotlib 来微调结果。

The Object Tree: Figure → Axes → ArtistsObject Tree: Figure → Axes → Artists对象树:Figure → Axes → Artists

Everything you see is an object you can change. The Figure is the canvas. Each Axes is one plot inside it. Lines, bars, text and ticks are artists that live inside an Axes.

जो कुछ दिखता है वह एक object है जिसे आप बदल सकते हैं। Figure canvas है। हर Axes उसके अंदर एक plot है। Lines, bars, text और ticks artists हैं जो Axes के अंदर रहते हैं।

你看到的一切都是可以修改的对象。Figure 是画布,每个 Axes 是其中的一个图。线、柱、文字和刻度都是位于 Axes 内部的 artist。

🗺️ PICTURE 1 — ONE FIGURE, TWO AXES, MANY ARTISTSतस्वीर 1 — एक FIGURE, दो AXES, कई ARTISTS图 1 — 一个 FIGURE、两个 AXES、许多 ARTIST
Figure, Axes and artists hierarchy Figure · fig Axes · axes[0] XAxis / YAxis ticks, tick labels, axis labelticks, tick labels, axis label刻度、刻度标签、轴标签 Line2D, PathCollection, Rectangle what plot / scatter / bar drawplot / scatter / bar जो बनाते हैंplot / scatter / bar 画出的对象 Text title, annotationstitle, annotations标题、注释 Spines, Legend border lines, keyकिनारी रेखाएँ, key边框线、图例 Axes · axes[1] XAxis / YAxis ticks, tick labels, axis labelticks, tick labels, axis label刻度、刻度标签、轴标签 Line2D, PathCollection, Rectangle what plot / scatter / bar drawplot / scatter / bar जो बनाते हैंplot / scatter / bar 画出的对象 Text title, annotationstitle, annotations标题、注释 Spines, Legend border lines, keyकिनारी रेखाएँ, key边框线、图例

Note the spelling: "Axes" is one plot area. It is different from an "Axis" (the x or y ruler inside it).

वर्तनी पर ध्यान दें: "Axes" एक plot area है। यह "Axis" (उसके अंदर का x या y पैमाना) से अलग है।

注意拼写:“Axes”是一个绘图区,与“Axis”(其中的 x 或 y 轴标尺)不同。

LIVELIVE互动Anatomy of a Figure — Click a PartFigure की बनावट — किसी हिस्से पर Click करेंFigure 的结构 —— 点击一个部分

Click a part name. It is highlighted on the chart and the code that controls it appears below. Or press Tour.

किसी हिस्से के नाम पर click करें। वह chart पर highlight होगा और उसे नियंत्रित करने वाला code नीचे दिखेगा। या Tour दबाएँ।

点击一个部分的名字,它会在图上高亮,下方显示控制它的代码。也可以点“导览”。

Setup and ImportsSetup और Imports准备与导入

The code blocks in this tutorial run one after another in the same notebook, so later blocks reuse variables from earlier ones. They use the two practice files customers.csv and daily_sales.csv — Section 10 shows how to make them.

इस tutorial के code blocks एक ही notebook में एक के बाद एक चलते हैं, इसलिए बाद वाले blocks पहले के variables दोबारा इस्तेमाल करते हैं। ये दो practice files customers.csv और daily_sales.csv इस्तेमाल करते हैं — Section 10 में इन्हें बनाने का तरीक़ा है।

本教程的代码块在同一个笔记本中依次运行,后面的代码块会复用前面的变量。它们使用两个练习文件 customers.csv 和 daily_sales.csv —— 第 10 节介绍如何生成。

# 1) Setup: imports, a style sheet and global defaults (rcParams)
import matplotlib.pyplot as plt
import matplotlib.ticker as mticker
import numpy as np, pandas as pd

plt.style.use("seaborn-v0_8-whitegrid")          # one line changes the whole look
plt.rcParams.update({
    "font.family": "DejaVu Sans",                    # has the ₹ glyph; Arial/Liberation do not
    "figure.figsize": (10, 5), "figure.dpi": 120,
    "axes.titlesize": 14, "axes.labelsize": 12,
    "xtick.labelsize": 10, "ytick.labelsize": 10,
    "legend.fontsize": 10, "lines.linewidth": 2,
    "axes.spines.top": False, "axes.spines.right": False,
})
df = pd.read_csv("customers.csv")
daily = pd.read_csv("daily_sales.csv", parse_dates=["date"])
print("matplotlib", plt.matplotlib.__version__, "| styles available:", len(plt.style.available))
print("customers:", df.shape, "| days:", len(daily))
OUTPUT
matplotlib 3.11.2 | styles available: 28 customers: (2000, 7) | days: 731
₹
Missing ₹ Sign? Change the Font₹ चिह्न ग़ायब? Font बदलें₹ 符号不显示?换字体

Many style sheets (including the seaborn ones) ask for Arial or Liberation Sans first. These fonts have no ₹ glyph, so matplotlib warns "Glyph 8377 missing from font(s)" and draws an empty box. Setting "font.family": "DejaVu Sans" fixes it — that is why it is in the setup above.

कई style sheets (seaborn वाली भी) पहले Arial या Liberation Sans माँगती हैं। इन fonts में ₹ glyph नहीं है, इसलिए matplotlib चेतावनी देता है "Glyph 8377 missing from font(s)" और ख़ाली box बनाता है। "font.family": "DejaVu Sans" रखने से यह ठीक हो जाता है — इसीलिए यह ऊपर के setup में है।

许多样式表(包括 seaborn 系列)会优先使用 Arial 或 Liberation Sans。这些字体没有 ₹ 字形,所以 matplotlib 会警告 “Glyph 8377 missing from font(s)” 并画出空方框。设置 "font.family": "DejaVu Sans" 即可解决 —— 这就是上面设置里有它的原因。

📐
Two Interfaces: pyplot and Object-Orientedदो Interfaces: pyplot और Object-Oriented两种接口:pyplot 与面向对象

plt.plot() draws on the "current" Axes that pyplot keeps track of. It is fine for a quick one-off chart. With fig, ax = plt.subplots() you hold the objects yourself and call ax.plot(), ax.set_title() and so on. This is clearer as soon as you have more than one panel, and it is what the matplotlib docs recommend for anything non-trivial.

plt.plot() उस "current" Axes पर बनाता है जिसका pyplot हिसाब रखता है। जल्दी के एक chart के लिए यह ठीक है। fig, ax = plt.subplots() से objects आपके हाथ में रहते हैं और आप ax.plot(), ax.set_title() आदि बुलाते हैं। एक से ज़्यादा panel होते ही यह ज़्यादा साफ़ है, और matplotlib docs भी ज़रा-से भी जटिल काम के लिए यही सुझाते हैं।

plt.plot() 会画在 pyplot 记录的“当前” Axes 上,适合快速画一张图。使用 fig, ax = plt.subplots() 时,对象握在你手里,你调用 ax.plot()、ax.set_title() 等。一旦有多个面板,这种方式更清晰,matplotlib 官方文档也推荐稍复杂的图都这样写。


SectionSection第 02 节

Line Chart — Trends Over Time 📈Line Chart — समय के साथ Trends 📈折线图 —— 随时间的趋势 📈

A line chart joins points in order. Use it for time series and anything where order matters. Colour, width, style and markers can each be set on their own.

Line chart points को क्रम में जोड़ता है। Time series और जहाँ भी क्रम मायने रखे, वहाँ इसे इस्तेमाल करें। रंग, चौड़ाई, style और markers हर एक अलग से तय किए जा सकते हैं।

折线图按顺序连接各点,适用于时间序列以及任何顺序重要的数据。颜色、线宽、线型和标记都可以分别设置。

# 2) Line chart: monthly revenue vs target, shaded where revenue beats target
r25 = daily[daily["date"].dt.year == 2025]
months = r25["date"].dt.strftime("%b").unique()
revenue = r25.groupby(r25["date"].dt.month)["revenue"].median().to_numpy()   # median day: robust to the bad record
target = np.linspace(52, 63, 12)                                            # the sales plan

fig, ax = plt.subplots(figsize=(10, 5), layout="constrained")
ax.plot(months, revenue, color="#3b82f6", marker="o", markersize=5, label="Revenue (median day)")
ax.plot(months, target, color="#f59e0b", linewidth=1.5, linestyle="--", label="Target")
ax.fill_between(months, revenue, target, where=revenue > target, interpolate=True,
                alpha=0.2, color="#16a34a", label="Above target")
ax.set_title("2025: Revenue vs Target", fontweight="bold")
ax.set_xlabel("Month"); ax.set_ylabel("Revenue per day (₹ thousand)")
ax.yaxis.set_major_formatter(mticker.FuncFormatter(lambda v, _: f"₹{v:.0f}k"))
ax.legend(framealpha=0.3)
fig.savefig("line.png")
print("revenue:", revenue.round(1))
print("months above target:", list(months[revenue > target]))
OUTPUT
revenue: [51.7 53.9 53.8 55.7 54.2 55.6 56. 57.2 58.2 76.1 79.6 67.1] months above target: ['Feb', 'Apr', 'Oct', 'Nov', 'Dec']
📊 PICTURE 2 — REAL OUTPUT: 2025 REVENUE VS TARGETतस्वीर 2 — असली OUTPUT: 2025 REVENUE बनाम TARGET图 2 — 真实输出:2025 年收入 vs 目标
Line chart revenue vs target with fill_between ₹50k ₹55k ₹60k ₹65k ₹70k ₹75k ₹80k Jan Feb Mar Apr May Jun Jul Aug Sep Oct Nov Dec ₹79.6k Revenue (median day)Revenue (median दिन)收入(中位数日) TargetTarget目标 Above target (fill_between)Target से ऊपर (fill_between)高于目标(fill_between)

The green area appears only where revenue is above target. interpolate=True makes the shading meet the exact crossing points instead of stopping at the nearest month.

हरा हिस्सा सिर्फ़ वहाँ है जहाँ revenue target से ऊपर है। interpolate=True से shading सटीक crossing points तक जाती है, नज़दीकी महीने पर नहीं रुकती।

绿色区域只出现在收入高于目标的地方。interpolate=True 让阴影延伸到精确的交叉点,而不是停在最近的月份。

🧮
Why the Median Day?Median दिन क्यों?为什么用中位数日?

The daily data has one bad record (₹269k on 1 Feb 2025). A monthly mean would make February look like a great month. The median day ignores that one value. Small choices like this change what a chart says.

Daily data में एक ग़लत record है (1 फ़रवरी 2025 को ₹269k)। महीने का mean फ़रवरी को बहुत अच्छा महीना दिखाएगा। Median दिन उस एक मान को नज़रअंदाज़ करता है। ऐसे छोटे फ़ैसले chart का संदेश बदल देते हैं।

日数据里有一条错误记录(2025 年 2 月 1 日 ₹269k)。按月取均值会让 2 月看起来业绩很好,而取中位数日会忽略这个值。这类小选择会改变图表传达的信息。

🧮 Key Line Chart ParametersLine Chart के मुख्य Parameters折线图的关键参数
color
A name ("steelblue"), a hex code ("#3b82f6"), an RGB tuple, or "C0"–"C9" for the style's colour cycle.
नाम ("steelblue"), hex code ("#3b82f6"), RGB tuple, या style के colour cycle के लिए "C0"–"C9"।
颜色名("steelblue")、十六进制("#3b82f6")、RGB 元组,或用 "C0"–"C9" 引用样式的颜色循环。
linestyle
"-" solid, "--" dashed, "-." dash-dot, ":" dotted, or a custom tuple like (0, (5, 2, 1, 2)).
"-" ठोस, "--" dashed, "-." dash-dot, ":" dotted, या custom tuple जैसे (0, (5, 2, 1, 2))।
"-" 实线,"--" 虚线,"-." 点划线,":" 点线,或自定义元组如 (0, (5, 2, 1, 2))。
marker
"o" circle, "s" square, "^" triangle, "D" diamond, "x", "+". Size with markersize=.
"o" वृत्त, "s" वर्ग, "^" त्रिभुज, "D" हीरा, "x", "+"। आकार markersize= से।
"o" 圆,"s" 方块,"^" 三角,"D" 菱形,"x","+"。大小用 markersize= 设置。
fill_between
ax.fill_between(x, y1, y2, where=mask, interpolate=True, alpha=0.2) shades the area between two curves.
ax.fill_between(x, y1, y2, where=mask, interpolate=True, alpha=0.2) दो curves के बीच का हिस्सा भरता है।
ax.fill_between(x, y1, y2, where=mask, interpolate=True, alpha=0.2) 填充两条曲线之间的区域。
LIVELIVE互动Line Styler — Change It, See the CodeLine Styler — बदलें और Code देखें线条样式器 —— 改一改,看代码

Pick a line style, marker and width. The chart redraws and the code below always matches it.

Line style, marker और width चुनें। Chart दोबारा बनता है और नीचे का code हमेशा उससे मेल खाता है।

选择线型、标记和线宽。图会重新绘制,下方代码始终与之对应。

linestyle
marker
fill
fmt


SectionSection第 03 节

Bar Charts — Comparing Categories 📊Bar Charts — Categories की तुलना 📊条形图 —— 比较类别 📊

Bar charts compare one number across categories. matplotlib can draw vertical, horizontal, grouped and stacked bars. For grouped bars, shift each group by half a bar width.

Bar charts एक संख्या की categories के बीच तुलना करते हैं। Matplotlib vertical, horizontal, grouped और stacked bars बना सकता है। Grouped bars के लिए हर group को आधी bar चौड़ाई से खिसकाएँ।

条形图用来比较不同类别的同一个数值。matplotlib 可以画竖直、水平、分组和堆叠条形图。画分组条形图时,把每组向左右移动半个柱宽。

# 3) Grouped bars (two age groups) and a sorted horizontal bar chart
df["age_group"] = np.where(df["age"] < 40, "Under 40", "40 and over")
avg = df.pivot_table(index="product_category", columns="age_group",
                     values="purchase_amount", aggfunc="mean") / 1000          # ₹ thousand
categories = avg.index.to_numpy()
total = df.groupby("product_category")["purchase_amount"].sum() / 1e6          # ₹ million

fig, axes = plt.subplots(1, 2, figsize=(12, 5), layout="constrained")
x = np.arange(len(categories)); width = 0.38
b1 = axes[0].bar(x - width / 2, avg["Under 40"], width, label="Under 40", color="#60a5fa")
b2 = axes[0].bar(x + width / 2, avg["40 and over"], width, label="40 and over", color="#f87171")
axes[0].bar_label(b1, fmt="%.1f", padding=3, fontsize=9)
axes[0].bar_label(b2, fmt="%.1f", padding=3, fontsize=9)
axes[0].set_xticks(x, categories, rotation=30, ha="right")                   # labels in one call (mpl ≥ 3.5)
axes[0].set_ylabel("Average spend (₹ thousand)"); axes[0].legend()

order = total.sort_values()
axes[1].barh(order.index, order.to_numpy(), color="#f59e0b")
axes[1].bar_label(axes[1].containers[0], fmt="₹%.1fM", padding=3)
axes[1].set_xlabel("Total revenue (₹ million)")
fig.savefig("bars.png")
print(avg.round(1)); print(order.round(2).to_string())
OUTPUT
age_group 40 and over Under 40 product_category Books 2.5 1.6 Clothing 5.8 3.7 Electronics 18.9 11.1 Furniture 13.6 8.6 Grocery 1.2 0.8 product_category Grocery 0.49 Books 0.87 Furniture 2.20 Clothing 3.07 Electronics 4.04
📊 PICTURE 3 — REAL OUTPUT: GROUPED BARS (LEFT) AND SORTED BARH (RIGHT)तस्वीर 3 — असली OUTPUT: GROUPED BARS (बाएँ) और SORTED BARH (दाएँ)图 3 — 真实输出:分组柱状图(左)与排序水平条形图(右)
Grouped bar chart and sorted horizontal bar chart 0 5 10 15 20 1.6 2.5 Books 3.7 5.8 Clothing 11.1 18.9 Electronics 8.6 13.6 Furniture 0.8 1.2 Grocery average spend (₹ thousand) — ax.bar + ax.bar_labelऔसत ख़र्च (₹ हज़ार) — ax.bar + ax.bar_label平均消费(千卢比)—— ax.bar + ax.bar_label Under 4040 से कम40 岁以下 40 and over40 और ऊपर40 岁及以上 Grocery ₹0.5M Books ₹0.9M Furniture ₹2.2M Clothing ₹3.1M Electronics ₹4.0M total revenue, sorted — ax.barhकुल revenue, sorted — ax.barh总收入(已排序)—— ax.barh

Customers aged 40 and over spend more in every category (they are more often in higher income brackets). Electronics brings the most money (₹4.0M) even though Clothing has more orders.

40 और ऊपर की उम्र के ग्राहक हर category में ज़्यादा ख़र्च करते हैं (वे ज़्यादा बार ऊँचे income brackets में हैं)। Electronics सबसे ज़्यादा पैसा लाता है (₹4.0M), जबकि Clothing के orders ज़्यादा हैं।

40 岁及以上的顾客在每个类别上都花得更多(他们更常处于较高收入档)。虽然 Clothing 订单更多,但 Electronics 带来的收入最多(₹4.0M)。

🏷️
Two Handy Shortcutsदो काम के Shortcuts两个实用技巧

ax.bar_label(bars, fmt="%.1f") writes the value on every bar (matplotlib ≥ 3.4). ax.set_xticks(x, labels, rotation=30, ha="right") sets tick positions and labels in one call (≥ 3.5). Sort bars by value before you plot — a ranked chart is much easier to read.

ax.bar_label(bars, fmt="%.1f") हर bar पर मान लिखता है (matplotlib ≥ 3.4)। ax.set_xticks(x, labels, rotation=30, ha="right") एक ही call में tick positions और labels तय करता है (≥ 3.5)। Plot करने से पहले bars को मान के हिसाब से sort करें — ranked chart पढ़ना कहीं आसान है।

ax.bar_label(bars, fmt="%.1f") 会在每根柱上写出数值(matplotlib ≥ 3.4)。ax.set_xticks(x, labels, rotation=30, ha="right") 一次设置刻度位置和标签(≥ 3.5)。画图前按数值排序 —— 排好序的图更易读。


SectionSection第 04 节

Scatter Plot — Four Variables at Once 🔵Scatter Plot — एक साथ चार Variables 🔵散点图 —— 同时展示四个变量 🔵

ax.scatter() can show up to four variables in one picture: x position, y position, colour (c=) and size (s=). Note that s is the marker area in points², not its width.

ax.scatter() एक तस्वीर में चार variables तक दिखा सकता है: x स्थिति, y स्थिति, रंग (c=) और आकार (s=)। ध्यान दें कि s marker का क्षेत्रफल है (points² में), चौड़ाई नहीं।

ax.scatter() 一张图最多能展示四个变量:x 位置、y 位置、颜色(c=)和大小(s=)。注意 s 是标记的面积(单位 points²),不是宽度。

# 4) Four variables in one scatter: x, y, colour and size — plus an annotation
fig, ax = plt.subplots(figsize=(9, 6), layout="constrained")
sc = ax.scatter(df["age"], df["purchase_amount"],
                c=df["rating"], cmap="viridis",          # colour = 3rd variable
                s=df["delivery_days"] * 8,              # size   = 4th variable
                alpha=0.6, edgecolors="white", linewidths=0.4)
ax.set_yscale("log")
fig.colorbar(sc, ax=ax, label="Customer rating")
top = df.loc[df["purchase_amount"].idxmax()]
ax.annotate(f"Largest order: ₹{top.purchase_amount:,.0f}",
            xy=(top.age, top.purchase_amount), xytext=(top.age - 25, top.purchase_amount * 0.9),
            arrowprops=dict(arrowstyle="->", color="#dc2626"), color="#dc2626",
            bbox=dict(boxstyle="round,pad=0.3", facecolor="#fde68a", alpha=0.4))
ax.set(xlabel="Customer age", ylabel="Purchase amount (₹, log scale)",
       title="Age vs purchase — colour = rating, size = delivery days")
fig.savefig("scatter.png")
print(f"largest order: age {top.age}, ₹{top.purchase_amount:,.0f}, {top.product_category}, "
      f"rating {top.rating:.0f}, {top.delivery_days} delivery days")
OUTPUT
largest order: age 62, ₹80,680, Electronics, rating 3, 6 delivery days
🔵 PICTURE 4 — REAL OUTPUT: COLOUR = RATING, SIZE = DELIVERY DAYSतस्वीर 4 — असली OUTPUT: रंग = RATING, आकार = DELIVERY दिन图 4 — 真实输出:颜色 = 评分,大小 = 配送天数
Scatter: x age, y purchase, colour rating, size delivery days ₹0.3k ₹1k ₹3k ₹10k ₹30k ₹100k 20 30 40 50 60 customer age · y on log scale (ax.set_yscale("log"))ग्राहक की उम्र · y log scale पर (ax.set_yscale("log"))顾客年龄 · y 轴为对数刻度(ax.set_yscale("log")) Largest order: ₹80,680 1 2 3 4 5 Customer rating (colorbar)Customer rating (colorbar)顾客评分(色条)

700 customers plus the largest order (₹80,680, age 62). Big circles (slow delivery) tend to be dark (low rating) — the −0.71 link from the heatmap, visible without a single number.

700 ग्राहक और सबसे बड़ा order (₹80,680, उम्र 62)। बड़े घेरे (धीमी delivery) ज़्यादातर गहरे (कम rating) हैं — heatmap वाला −0.71 संबंध, बिना किसी संख्या के दिखता है।

700 位顾客外加最大的一笔订单(₹80,680,年龄 62)。大圆(配送慢)往往颜色深(评分低)—— 热力图里的 −0.71 关系,不看数字也能看出来。

🧮 ax.annotate() — Point to What Mattersax.annotate() — ज़रूरी चीज़ की ओर इशाराax.annotate() —— 指向重点
Basicमूल基本
ax.annotate("text", xy=(x_point, y_point), xytext=(x_text, y_text)) — xy is the point, xytext is where the label sits.
ax.annotate("text", xy=(x_point, y_point), xytext=(x_text, y_text)) — xy वह point है, xytext वहाँ label बैठता है।
ax.annotate("text", xy=(x_point, y_point), xytext=(x_text, y_text)) —— xy 是被指的点,xytext 是文字的位置。
Arrowतीर箭头
arrowprops=dict(arrowstyle="->", color="red", lw=1.5). Other styles: "-|>", "fancy", "simple".
arrowprops=dict(arrowstyle="->", color="red", lw=1.5)। दूसरी styles: "-|>", "fancy", "simple"।
arrowprops=dict(arrowstyle="->", color="red", lw=1.5)。其他样式:"-|>"、"fancy"、"simple"。
BoxBox文本框
bbox=dict(boxstyle="round,pad=0.3", facecolor="#fde68a", alpha=0.4) puts the text in a box.
bbox=dict(boxstyle="round,pad=0.3", facecolor="#fde68a", alpha=0.4) text को box में रखता है।
bbox=dict(boxstyle="round,pad=0.3", facecolor="#fde68a", alpha=0.4) 给文字加一个框。
Find the pointPoint ढूँढें找到该点
Do not type coordinates by hand. Find them from the data: top = df.loc[df["purchase_amount"].idxmax()].
Coordinates हाथ से न लिखें। उन्हें data से निकालें: top = df.loc[df["purchase_amount"].idxmax()]।
不要手写坐标,从数据中求出来:top = df.loc[df["purchase_amount"].idxmax()]。
LIVELIVE互动Encode More Variablesऔर Variables Encode करें编码更多变量

300 customers. Choose what colour and size show, switch the colormap, and change transparency.

300 ग्राहक। चुनें कि रंग और आकार क्या दिखाएँ, colormap बदलें, और पारदर्शिता बदलें।

300 位顾客。选择颜色和大小表示什么,切换色图,调整透明度。

c
s
cmap


SectionSection第 05 节

Histogram and KDE — Distributions 📉Histogram और KDE — Distributions 📉直方图与 KDE —— 分布 📉

ax.hist() returns three things: the bar heights n, the bin edges bins, and the bar objects patches. Because the bars are objects, you can recolour them one by one. With density=True the bars have area 1, so a KDE curve (from scipy.stats.gaussian_kde) fits on the same scale.

ax.hist() तीन चीज़ें लौटाता है: bar की ऊँचाइयाँ n, bin के किनारे bins, और bar objects patches। Bars objects हैं, इसलिए आप उन्हें एक-एक करके नया रंग दे सकते हैं। density=True से bars का कुल क्षेत्रफल 1 होता है, इसलिए KDE curve (scipy.stats.gaussian_kde से) उसी scale पर बैठती है।

ax.hist() 返回三样东西:柱高 n、分组边界 bins 和柱对象 patches。因为柱是对象,你可以逐个改颜色。设置 density=True 后柱的总面积为 1,因此 KDE 曲线(来自 scipy.stats.gaussian_kde)能画在同一刻度上。

# 5) Histogram + KDE, bars coloured by side of the mean; overlapping group histograms
from scipy.stats import gaussian_kde
data = df["purchase_amount"].to_numpy()
fig, axes = plt.subplots(1, 2, figsize=(12, 5), layout="constrained")

n, bins, patches = axes[0].hist(data, bins=40, range=(0, 30000), density=True,
                                color="#60a5fa", alpha=0.7, edgecolor="white", linewidth=0.4)
mean_val, med = data.mean(), np.median(data)
for patch, left in zip(patches, bins[:-1]):
    if left >= mean_val:
        patch.set_facecolor("#f59e0b")                    # bins at or right of the mean
xs = np.linspace(0, 30000, 300)
axes[0].plot(xs, gaussian_kde(data)(xs), color="#7c3aed", label="KDE")
axes[0].axvline(mean_val, color="#f59e0b", linestyle="--", label=f"Mean ₹{mean_val:,.0f}")
axes[0].axvline(med, color="#16a34a", linestyle="--", label=f"Median ₹{med:,.0f}")
axes[0].legend()

for name, colour in zip(["Low", "Medium", "High"], ["#60a5fa", "#f87171", "#34d399"]):
    vals = np.log10(df.loc[df["income_bracket"] == name, "purchase_amount"])
    axes[1].hist(vals, bins=30, alpha=0.5, color=colour, label=name, density=True)
axes[1].set_xlabel("log10(purchase amount)"); axes[1].legend(title="Income")
fig.savefig("hist.png")
print(f"mean ₹{mean_val:,.0f}  median ₹{med:,.0f}  bins at/after mean: {(bins[:-1] >= mean_val).sum()} of 40")
print("median spend:", df.groupby("income_bracket")["purchase_amount"].median().reindex(["Low", "Medium", "High"]).to_dict())
OUTPUT
mean ₹5,335 median ₹2,900 bins at/after mean: 32 of 40 median spend: {'Low': 1965.0, 'Medium': 2585.0, 'High': 4115.0}
📉 PICTURE 5 — REAL OUTPUT: COLOURED HISTOGRAM + KDE (LEFT), OVERLAPPING GROUPS (RIGHT)तस्वीर 5 — असली OUTPUT: रंगीन HISTOGRAM + KDE (बाएँ), OVERLAP करते GROUPS (दाएँ)图 5 — 真实输出:着色直方图 + KDE(左),重叠的分组直方图(右)
Histogram coloured by mean with KDE, and overlapping histograms by income median ₹2,900 mean ₹5,335 ₹0k ₹10k ₹20k ₹30k blue: below mean · amber: at or above mean · purple: KDEनीला: mean से नीचे · amber: mean या ऊपर · बैंगनी: KDE蓝:低于均值 · 琥珀色:不低于均值 · 紫:KDE Low Medium High ₹0.1k ₹1k ₹10k ₹100k alpha=0.5 lets the groups show through each otheralpha=0.5 से groups एक-दूसरे के पार दिखते हैंalpha=0.5 让各组互相透出

Left: most of the bins (32 of 40) are at or above the mean, but they hold few customers — a long right tail. Right: on a log scale, the High income group sits clearly to the right.

बाएँ: ज़्यादातर bins (40 में से 32) mean या उससे ऊपर हैं, पर उनमें कम ग्राहक हैं — लंबी right tail। दाएँ: log scale पर High income group साफ़ तौर पर दाईं ओर है।

左:大多数分组(40 个中的 32 个)不低于均值,但其中顾客很少 —— 右侧长尾。右:在对数刻度上,高收入组明显偏右。

🔧
Small Fix in the Original Loopमूल Loop में छोटा सुधार原循环的小修正

bins has one more value than patches (41 edges for 40 bars). zip(patches, bins) still works because zip stops at the shorter list, but zip(patches, bins[:-1]) says clearly that you use each bar's left edge. For skewed money data, a log-scale x-axis (right panel) shows group differences much better.

bins में patches से एक मान ज़्यादा होता है (40 bars के लिए 41 किनारे)। zip(patches, bins) फिर भी चलता है क्योंकि zip छोटी list पर रुक जाता है, पर zip(patches, bins[:-1]) साफ़ बताता है कि आप हर bar का बायाँ किनारा इस्तेमाल कर रहे हैं। Skewed पैसे वाले data के लिए log-scale x-axis (दायाँ panel) groups का अंतर कहीं बेहतर दिखाता है।

bins 比 patches 多一个值(40 根柱有 41 个边界)。zip(patches, bins) 仍然能运行,因为 zip 在较短的列表处停止,但 zip(patches, bins[:-1]) 更清楚地表明你用的是每根柱的左边界。对于偏态的金额数据,对数刻度的 x 轴(右图)能更好地显示组间差异。


SectionSection第 06 节

Subplots — Many Charts in One Figure 🧩Subplots — एक Figure में कई Charts 🧩子图 —— 一个 Figure 里的多张图 🧩

plt.subplots(nrows, ncols) makes a grid of Axes. It is the main layout tool for dashboards and side-by-side comparisons. Watch what it returns: the shape of axes depends on the grid size.

plt.subplots(nrows, ncols) Axes का grid बनाता है। Dashboards और साथ-साथ तुलना के लिए यह मुख्य layout tool है। ध्यान दें कि यह क्या लौटाता है: axes का shape grid के आकार पर निर्भर है।

plt.subplots(nrows, ncols) 创建一个 Axes 网格,是做仪表盘和并排比较的主要布局工具。注意它的返回值:axes 的形状取决于网格大小。

# 6) Subplots: a 2×2 dashboard, and an uneven layout with subplot_mosaic
fig, axes = plt.subplots(2, 2, figsize=(12, 8), layout="constrained")
fig.suptitle("Sales Dashboard — 2025", fontsize=16, fontweight="bold")
axes[0, 0].plot(months, revenue); axes[0, 0].set_title("Revenue trend")
axes[0, 1].barh(order.index, order.to_numpy()); axes[0, 1].set_title("Revenue by category")
axes[1, 0].hist(df["age"], bins=12); axes[1, 0].set_title("Age distribution")
axes[1, 1].scatter(df["age"], df["purchase_amount"], s=4, alpha=0.4)
axes[1, 1].set_yscale("log"); axes[1, 1].set_title("Age vs spend")
fig.savefig("dashboard.png")
print("axes array shape:", axes.shape, "| top-right is axes[0, 1]")

fig2, axd = plt.subplot_mosaic([["trend", "trend"], ["cat", "age"]], figsize=(10, 7), layout="constrained")
axd["trend"].plot(daily["date"], daily["revenue"], linewidth=0.8)     # wide panel on top
print("mosaic panels:", list(axd))
OUTPUT
axes array shape: (2, 2) | top-right is axes[0, 1] mosaic panels: ['trend', 'cat', 'age']
🧩 PICTURE 6 — REAL OUTPUT: A 2×2 DASHBOARDतस्वीर 6 — असली OUTPUT: 2×2 DASHBOARD图 6 — 真实输出:2×2 仪表盘
2 by 2 subplot dashboard Sales Dashboard — 2025 fig.suptitle() axes[0, 0] Revenue trend axes[0, 1] Revenue by category Grocery Books Furniture Clothing Electronics axes[1, 0] Age distribution axes[1, 1] Age vs spend fig, axes = plt.subplots(2, 2, layout="constrained") — each panel is its own Axesfig, axes = plt.subplots(2, 2, layout="constrained") — हर panel अपना अलग Axes हैfig, axes = plt.subplots(2, 2, layout="constrained") —— 每个面板都是独立的 Axes
LIVELIVE互动Subplot Builder — What Does plt.subplots Return?Subplot Builder — plt.subplots क्या लौटाता है?子图构建器 —— plt.subplots 返回什么?

Change rows and columns, then click a panel to see how to reach it. Try layout = none with 3 columns.

Rows और columns बदलें, फिर किसी panel पर click करके देखें कि उस तक कैसे पहुँचें। 3 columns के साथ layout = none आज़माएँ।

改变行数和列数,再点击某个面板,看看如何访问它。试试 3 列时设 layout = none。

sharex
layout

🧮 Subplots Layout CheatsheetSubplots Layout Cheatsheet子图布局速查
GridGrid网格
fig, axes = plt.subplots(nrows, ncols, figsize=(w, h), layout="constrained")
fig, axes = plt.subplots(nrows, ncols, figsize=(w, h), layout="constrained")
fig, axes = plt.subplots(nrows, ncols, figsize=(w, h), layout="constrained")
Shared axesShared axes共享坐标轴
plt.subplots(2, 1, sharex=True) — both panels use the same x range; zoom one and the other follows.
plt.subplots(2, 1, sharex=True) — दोनों panels एक ही x range इस्तेमाल करते हैं; एक को zoom करें तो दूसरा भी साथ चलता है।
plt.subplots(2, 1, sharex=True) —— 两个面板共用 x 范围;缩放一个,另一个跟着变。
Uneven sizesअसमान आकार不等大小
fig, axd = plt.subplot_mosaic([["A", "A"], ["B", "C"]]) — returns a dict: axd["A"] spans the full top row.
fig, axd = plt.subplot_mosaic([["A", "A"], ["B", "C"]]) — dict लौटाता है: axd["A"] पूरी ऊपरी row में फैला है।
fig, axd = plt.subplot_mosaic([["A", "A"], ["B", "C"]]) —— 返回一个字典:axd["A"] 占满整个第一行。
Hide a panelPanel छिपाएँ隐藏面板
In a 2×3 grid with 5 charts: axes[1, 2].set_visible(False) or fig.delaxes(axes[1, 2]). (In a 2×2 grid, axes[1, 2] does not exist — it raises IndexError.)
5 charts वाले 2×3 grid में: axes[1, 2].set_visible(False) या fig.delaxes(axes[1, 2])। (2×2 grid में axes[1, 2] मौजूद नहीं — IndexError आता है।)
在放 5 张图的 2×3 网格中:axes[1, 2].set_visible(False) 或 fig.delaxes(axes[1, 2])。(2×2 网格里没有 axes[1, 2] —— 会报 IndexError。)
Loop over allसब पर loop遍历全部
for ax in axes.flat: ax.grid(alpha=0.3) works for any grid shape.
for ax in axes.flat: ax.grid(alpha=0.3) किसी भी grid shape पर चलता है।
for ax in axes.flat: ax.grid(alpha=0.3) 适用于任意网格形状。
Spacingदूरी间距
Prefer layout="constrained". Older code uses plt.tight_layout(); manual control: fig.subplots_adjust(hspace=0.4).
layout="constrained" बेहतर है। पुराना code plt.tight_layout() इस्तेमाल करता है; हाथ से नियंत्रण: fig.subplots_adjust(hspace=0.4)।
优先用 layout="constrained"。旧代码用 plt.tight_layout();手动控制:fig.subplots_adjust(hspace=0.4)。

SectionSection第 07 节

Heatmap with imshow() 🌡️imshow() से Heatmap 🌡️用 imshow() 画热力图 🌡️

ax.imshow() draws any 2-D array as a grid of coloured cells. It is the base for correlation heatmaps, pivot tables and confusion matrices. You add the numbers yourself with ax.text().

ax.imshow() किसी भी 2-D array को रंगीन cells के grid के रूप में बनाता है। Correlation heatmaps, pivot tables और confusion matrices का यही आधार है। संख्याएँ आप ax.text() से ख़ुद जोड़ते हैं।

ax.imshow() 把任意二维数组画成彩色格子网格,是相关热力图、透视表和混淆矩阵的基础。格子里的数字需要你用 ax.text() 自己加。

# 7) A correlation heatmap with ax.imshow() and a value in every cell
cols = ["age", "income_code", "purchase_amount", "delivery_days", "rating"]
corr = df[cols].corr().to_numpy(); n = len(cols)
fig, ax = plt.subplots(figsize=(7, 6), layout="constrained")
im = ax.imshow(corr, cmap="coolwarm", vmin=-1, vmax=1)
ax.grid(False)                                   # the style's grid would cut through the cells
fig.colorbar(im, ax=ax, fraction=0.046, pad=0.04)
for i in range(n):
    for j in range(n):
        ax.text(j, i, f"{corr[i, j]:.2f}", ha="center", va="center", fontweight="bold",
                color="white" if abs(corr[i, j]) > 0.6 else "black")
ax.set_xticks(range(n), cols, rotation=45, ha="right")
ax.set_yticks(range(n), cols)
ax.set_title("Correlation matrix (Pearson)")
fig.savefig("heatmap.png")
print(np.round(corr, 2))
OUTPUT
[[ 1. 0.68 0.21 0. -0.02] [ 0.68 1. 0.31 -0.01 -0. ] [ 0.21 0.31 1. -0. -0.01] [ 0. -0.01 -0. 1. -0.71] [-0.02 -0. -0.01 -0.71 1. ]]
🌡️ PICTURE 7 — REAL OUTPUT: ax.imshow() CORRELATION MATRIXतस्वीर 7 — असली OUTPUT: ax.imshow() CORRELATION MATRIX图 7 — 真实输出:ax.imshow() 相关矩阵
imshow correlation heatmap age 1.00 0.68 0.21 0.00 -0.02 income_code 0.68 1.00 0.31 -0.01 0.00 purchase_amount 0.21 0.31 1.00 0.00 -0.01 delivery_days 0.00 -0.01 0.00 1.00 -0.71 rating -0.02 0.00 -0.01 -0.71 1.00 age income_code purchase_amount delivery_days rating +1.0 +0.5 0 −0.5 −1.0

Text turns white on dark cells (|r| > 0.6). Strongest links: age–income 0.68 and delivery–rating −0.71.

गहरे cells पर text सफ़ेद हो जाता है (|r| > 0.6)। सबसे मज़बूत संबंध: age–income 0.68 और delivery–rating −0.71।

深色格子上文字变白(|r| > 0.6)。最强的关联:age–income 0.68,delivery–rating −0.71。

🕸️
Gotcha: the Grid Cuts Through imshowध्यान दें: Grid imshow को काटता है陷阱:网格线会穿过 imshow

If your style turns the grid on (seaborn and ggplot styles do), grid lines are drawn across the heatmap cells. Call ax.grid(False) after imshow. Also, imshow keeps square cells by default; pass aspect="auto" only if you want the cells to stretch.

अगर आपकी style grid चालू करती है (seaborn और ggplot styles करती हैं), तो grid lines heatmap cells के आर-पार बनती हैं। imshow के बाद ax.grid(False) बुलाएँ। साथ ही, imshow default रूप से cells को वर्गाकार रखता है; aspect="auto" तभी दें जब cells को फैलाना हो।

如果样式开启了网格(seaborn 和 ggplot 样式都会),网格线会穿过热力图格子。在 imshow 之后调用 ax.grid(False)。另外,imshow 默认保持方形格子;只有想拉伸格子时才传 aspect="auto"。


SectionSection第 08 节

Box Plot and Violin Plot 🎻Box Plot और Violin Plot 🎻箱线图与小提琴图 🎻

ax.boxplot() shows the median, quartiles, whiskers and outliers. ax.violinplot() adds the full shape, using a KDE drawn on both sides. Money data is very skewed, so both plots below use log10 of the amount, with ₹ tick labels added by a formatter.

ax.boxplot() median, quartiles, whiskers और outliers दिखाता है। ax.violinplot() दोनों तरफ़ बनी KDE से पूरा आकार जोड़ता है। पैसे का data बहुत skewed है, इसलिए नीचे के दोनों plots राशि का log10 इस्तेमाल करते हैं, और ₹ tick labels एक formatter से जोड़े गए हैं।

ax.boxplot() 显示中位数、四分位数、须线和异常值。ax.violinplot() 用两侧对称的 KDE 补上完整形状。金额数据非常偏,所以下面两图都用金额的 log10,并用格式化器加上 ₹ 刻度标签。

# 8) Notched box plot and violin plot of the same groups (on log10 of the amount)
cats = ["Grocery", "Books", "Clothing", "Furniture", "Electronics"]
groups = [np.log10(df.loc[df["product_category"] == c, "purchase_amount"]).to_numpy() for c in cats]
colors = ["#0d9488", "#7c3aed", "#3b82f6", "#d97706", "#ea580c"]
fig, (ax1, ax2) = plt.subplots(1, 2, figsize=(12, 5), sharey=True, layout="constrained")

bp = ax1.boxplot(groups, tick_labels=cats, patch_artist=True, notch=True,
                 orientation="vertical", widths=0.5)   # 'vert=' is deprecated since 3.11
for patch, c in zip(bp["boxes"], colors):
    patch.set_facecolor(c); patch.set_alpha(0.6)
vp = ax2.violinplot(groups, showmedians=True)
for body, c in zip(vp["bodies"], colors):
    body.set_facecolor(c); body.set_alpha(0.5)
ax2.set_xticks(range(1, 6), cats)
ax1.yaxis.set_major_formatter(mticker.FuncFormatter(lambda v, _: f"₹{10 ** v:,.0f}"))
fig.savefig("box_violin.png")
for c, g in zip(cats, groups):
    q1, med, q3 = np.percentile(g, [25, 50, 75]); half = 1.57 * (q3 - q1) / np.sqrt(len(g))   # notch rule
    print(f"{c:<12} n={len(g):<4} median ₹{10 ** med:>6,.0f}   notch ₹{10 ** (med - half):,.0f} – ₹{10 ** (med + half):,.0f}")
OUTPUT
Grocery n=485 median ₹ 830 notch ₹781 – ₹882 Books n=418 median ₹ 1,755 notch ₹1,636 – ₹1,883 Clothing n=634 median ₹ 4,070 notch ₹3,862 – ₹4,289 Furniture n=198 median ₹ 9,155 notch ₹8,314 – ₹10,081 Electronics n=265 median ₹11,830 notch ₹10,923 – ₹12,812
🎻 PICTURE 8 — REAL OUTPUT: NOTCHED BOX PLOTS (LEFT), VIOLINS (RIGHT)तस्वीर 8 — असली OUTPUT: NOTCHED BOX PLOTS (बाएँ), VIOLINS (दाएँ)图 8 — 真实输出:带凹口的箱线图(左),小提琴图(右)
Notched box plots and violin plots on log scale ₹0.1k ₹1k ₹10k ₹100k ₹0.1k ₹1k ₹10k ₹100k Grocery Grocery Books Books Clothing Clothing Furniture Furniture Electronics Electronics ax.boxplot(..., notch=True, patch_artist=True) ax.violinplot(..., showmedians=True)

No two notches overlap, so all five medians very likely differ. On a log scale the groups look roughly symmetric — the skew was mostly a scale effect.

कोई भी दो notches overlap नहीं करते, इसलिए पाँचों medians बहुत संभवतः अलग हैं। Log scale पर groups लगभग सममित दिखते हैं — skew ज़्यादातर scale का असर था।

没有两个凹口重叠,所以五个中位数很可能都不同。在对数刻度上各组大致对称 —— 偏态主要来自刻度。

🆕
Modern Arguments (matplotlib 3.9+)नए Arguments (matplotlib 3.9+)新参数(matplotlib 3.9+)

vert=True is deprecated since 3.11 (it will be removed in 3.13): use orientation="vertical" or "horizontal". The labels= argument of boxplot was renamed tick_labels= in 3.9. The notch is a rough 95% interval for the median: median ± 1.57 × IQR / √n.

vert=True 3.11 से deprecated है (3.13 में हटेगा): orientation="vertical" या "horizontal" इस्तेमाल करें। boxplot का labels= argument 3.9 में tick_labels= हो गया। Notch median का लगभग 95% interval है: median ± 1.57 × IQR / √n।

vert=True 自 3.11 起已弃用(将在 3.13 移除):请用 orientation="vertical" 或 "horizontal"。boxplot 的 labels= 参数在 3.9 改名为 tick_labels=。凹口是中位数的大约 95% 区间:中位数 ± 1.57 × IQR / √n。

LIVELIVE互动What a Box Plot HidesBox Plot क्या छिपाता है箱线图隐藏了什么

300 values from two groups. Pull the groups apart and compare the box (left) with the violin (right).

दो groups से 300 मान। Groups को अलग खींचें और box (बाएँ) की violin (दाएँ) से तुलना करें।

来自两组的 300 个值。把两组拉开,比较箱线图(左)和小提琴图(右)。


SectionSection第 09 节

Styles and Saving Figures 💾Styles और Figures Save करना 💾样式与保存图片 💾

A style sheet changes many rcParams at once. plt.style.use() changes every later chart; with plt.style.context("ggplot"): changes only the code inside the block. The picture below uses the real colours each style sets.

Style sheet एक साथ कई rcParams बदलती है। plt.style.use() बाद के हर chart को बदलता है; with plt.style.context("ggplot"): सिर्फ़ block के अंदर के code को बदलता है। नीचे की तस्वीर हर style के असली रंग इस्तेमाल करती है।

样式表一次修改许多 rcParams。plt.style.use() 影响之后所有的图;with plt.style.context("ggplot"): 只影响代码块内部。下图使用了每种样式真实设置的颜色。

🎨 PICTURE 9 — THE SAME DATA IN FOUR BUILT-IN STYLESतस्वीर 9 — चार BUILT-IN STYLES में वही DATA图 9 — 同一数据的四种内置样式
The same chart in four matplotlib styles 50 65 80 Jan … Dec seaborn-v0_8-darkgrid 50 65 80 Jan … Dec dark_background 50 65 80 Jan … Dec ggplot 50 65 80 Jan … Dec bmh

Values read from matplotlib itself. Note: seaborn-v0_8-darkgrid changes the background and grid but keeps the default colour cycle; bmh uses dashed grid lines and thicker lines (2.0).

मान ख़ुद matplotlib से पढ़े गए हैं। ध्यान दें: seaborn-v0_8-darkgrid पृष्ठभूमि और grid बदलता है पर default colour cycle रखता है; bmh dashed grid lines और मोटी lines (2.0) इस्तेमाल करता है।

数值直接读取自 matplotlib。注意:seaborn-v0_8-darkgrid 改变了背景和网格,但保留默认颜色循环;bmh 使用虚线网格和更粗的线(2.0)。

# 9) Save once, in the right format
import os
fig, ax = plt.subplots(figsize=(6, 4), layout="constrained")
ax.plot(months, revenue, marker="o")
ax.set(title="Revenue 2025", ylabel="₹ thousand per day")
for name, kw in [("chart.png", dict(dpi=300)), ("chart.pdf", {}), ("chart.svg", {})]:
    fig.savefig(name, bbox_inches="tight", **kw)
    print(f"{name:<10} {os.path.getsize(name) / 1024:6.1f} KB")
OUTPUT
chart.png 102.2 KB chart.pdf 15.3 KB chart.svg 30.9 KB
FormatFormat格式Typeप्रकार类型Use it forकब इस्तेमाल करें用途
.pngraster (pixels)raster (pixels)位图(像素)Web, slides, notebooks. Use dpi=300 for print.Web, slides, notebooks। Print के लिए dpi=300।网页、幻灯片、笔记本。打印用 dpi=300。
.pdfvectorvector矢量Papers and reports (LaTeX accepts PDF directly). Stays sharp at any size.Papers और reports (LaTeX सीधे PDF लेता है)। किसी भी आकार पर तीखा रहता है।论文和报告(LaTeX 可直接使用 PDF)。任意缩放都清晰。
.svgvectorvector矢量Web pages and further editing in Inkscape / Illustrator.Web pages और Inkscape / Illustrator में आगे editing।网页,以及在 Inkscape / Illustrator 中继续编辑。
.epsvector (old)vector (पुराना)矢量(旧)Only if a journal asks for it. It has no transparency, so alpha is lost.तभी जब journal माँगे। इसमें transparency नहीं होती, इसलिए alpha खो जाता है।仅在期刊要求时使用。它不支持透明度,alpha 会丢失。
✂️
bbox_inches="tight" and Vector Sizebbox_inches="tight" और Vector का आकारbbox_inches="tight" 与矢量文件大小

bbox_inches="tight" trims empty margins and stops labels from being cut off when saving. A vector file stores every point as an object, so a scatter plot with 100,000 points can become a huge, slow PDF. In that case pass rasterized=True to the scatter call, or save as PNG.

bbox_inches="tight" ख़ाली हाशिये काटता है और save करते समय labels कटने से रोकता है। Vector file हर point को object के रूप में रखती है, इसलिए 100,000 points वाला scatter plot बहुत बड़ा और धीमा PDF बन सकता है। तब scatter call में rasterized=True दें, या PNG में save करें।

bbox_inches="tight" 会裁掉空白边距,防止保存时标签被截断。矢量文件把每个点都存成对象,所以有 10 万个点的散点图会变成巨大而缓慢的 PDF。这时在 scatter 调用中加 rasterized=True,或保存为 PNG。


SectionSection第 10 节

Make the Practice Data 🐍Practice Data बनाएँ 🐍生成练习数据 🐍

These are the same two files used in the Data Visualisation tutorial. The patterns (older → higher income, category → spend, slow delivery → low rating, an October–November peak) are built in on purpose. Run this before the other blocks.

ये वही दो files हैं जो Data Visualisation tutorial में इस्तेमाल हुईं। Patterns (बड़ी उम्र → ज़्यादा income, category → ख़र्च, धीमी delivery → कम rating, अक्टूबर–नवंबर की चोटी) जानबूझकर डाले गए हैं। बाक़ी blocks से पहले इसे चलाएँ।

这就是“数据可视化”教程中用到的两个文件。其中的规律(年龄越大收入越高、类别决定消费、配送慢评分低、10–11 月高峰)都是有意内置的。请先运行它,再运行其他代码块。

# 0) Build two practice datasets that contain real patterns to find
import numpy as np, pandas as pd
rng = np.random.default_rng(11)

# --- customers.csv: one row per customer ---
n = 2000
age = rng.integers(18, 66, n)
p_hi = np.clip((age - 18) / 60, 0.05, 0.75)                 # older -> more likely higher income
income_code = np.minimum(3, rng.binomial(3, p_hi))
brackets = np.array(["Low", "Medium", "High", "Very High"])
cats = rng.choice(["Electronics", "Furniture", "Clothing", "Books", "Grocery"], n, p=[.15, .1, .3, .2, .25])
cat_base = pd.Series({"Electronics": 9.0, "Furniture": 8.7, "Clothing": 7.9, "Books": 7.0, "Grocery": 6.3})[cats].to_numpy()
spend = np.exp(cat_base + 0.35 * income_code + rng.normal(0, 0.45, n)).round(-1)
delivery = rng.integers(1, 11, n)
rating = np.clip(np.round(5.2 - 0.28 * delivery + rng.normal(0, 0.8, n)), 1, 5)
pd.DataFrame({"age": age, "income_bracket": brackets[income_code], "income_code": income_code,
              "product_category": cats, "purchase_amount": spend,
              "delivery_days": delivery, "rating": rating}).to_csv("customers.csv", index=False)

# --- daily_sales.csv: two years of daily revenue (₹ thousand) ---
days = pd.date_range("2024-01-01", "2025-12-31", freq="D")
t = np.arange(len(days))
trend = 40 + 20 * t / len(days)
weekly = np.where(days.dayofweek >= 5, 1.18, 1.0)
festive = 1 + 0.45 * np.exp(-((days.dayofyear - 305) / 18) ** 2) + 0.25 * np.exp(-((days.dayofyear - 358) / 6) ** 2)
revenue = np.asarray(trend * weekly * festive * rng.normal(1, 0.07, len(days)))
for d, f in [("2024-03-15", 2.2), ("2025-02-01", 5.0), ("2025-06-10", 0.2)]:   # flash sale, data error, outage
    revenue[days.get_loc(d)] *= f
pd.DataFrame({"date": days, "revenue": revenue.round(2)}).to_csv("daily_sales.csv", index=False)
print("customers.csv:", n, "rows   daily_sales.csv:", len(days), "rows")
OUTPUT
customers.csv: 2000 rows daily_sales.csv: 731 rows

SectionSection第 11 节

Golden Rules of Matplotlib 🏆Matplotlib के सुनहरे नियम 🏆Matplotlib 黄金法则 🏆

🎯 9 Rules for Clear, Professional Figuresसाफ़ और Professional Figures के 9 नियम清晰专业图表的 9 条法则
1
Use fig, ax = plt.subplots() and call methods on ax. Keep the quick plt.plot() style for throwaway one-panel charts.
fig, ax = plt.subplots() इस्तेमाल करें और methods ax पर बुलाएँ। जल्दी वाला plt.plot() तरीक़ा सिर्फ़ एक panel वाले कच्चे charts के लिए रखें।
使用 fig, ax = plt.subplots(),在 ax 上调用方法。快速的 plt.plot() 写法只留给一次性的单面板图。
2
Let matplotlib handle spacing: create figures with layout="constrained" (or call fig.tight_layout()), and save with bbox_inches="tight" so nothing is cut off.
Spacing matplotlib को सँभालने दें: figures layout="constrained" से बनाएँ (या fig.tight_layout() बुलाएँ), और bbox_inches="tight" से save करें ताकि कुछ न कटे।
让 matplotlib 处理间距:用 layout="constrained" 创建图(或调用 fig.tight_layout()),保存时加 bbox_inches="tight",避免内容被截断。
3
Hide the top and right spines for a cleaner look: ax.spines[["top", "right"]].set_visible(False), or set it once in rcParams.
साफ़ रूप के लिए ऊपर और दाईं spines छिपाएँ: ax.spines[["top", "right"]].set_visible(False), या rcParams में एक बार तय करें।
隐藏上边和右边的边框让图更简洁:ax.spines[["top", "right"]].set_visible(False),或在 rcParams 中一次设好。
4
Label every axis with its unit — "Revenue per day (₹ thousand)", not "Revenue". Use a tick formatter for ₹, %, or k.
हर axis पर इकाई के साथ label दें — "Revenue per day (₹ thousand)", सिर्फ़ "Revenue" नहीं। ₹, % या k के लिए tick formatter इस्तेमाल करें।
每个坐标轴都写上单位 —— “每日收入(千卢比)”,而不是“收入”。₹、% 或 k 用刻度格式化器处理。
5
Save PNG at dpi=300 for print, and PDF or SVG when the figure may be resized. Use rasterized=True for huge scatter plots.
Print के लिए PNG dpi=300 पर save करें, और जब figure का आकार बदल सकता हो तो PDF या SVG। बहुत बड़े scatter plots के लिए rasterized=True।
打印用 PNG 并设 dpi=300;图可能被缩放时用 PDF 或 SVG。超大散点图用 rasterized=True。
6
Use ax.annotate() to point at the key fact on the chart — the peak, the drop, the outlier. Find its coordinates from the data, not by hand.
Chart पर मुख्य बात की ओर इशारा करने के लिए ax.annotate() इस्तेमाल करें — चोटी, गिरावट, outlier। इसके coordinates data से निकालें, हाथ से नहीं।
用 ax.annotate() 指出图上的关键事实 —— 峰值、下跌、异常点。坐标要从数据中求,而不是手写。
7
Set rcParams (or a style) once at the top of the notebook, so every figure in a report shares fonts, sizes and colours.
rcParams (या style) notebook के ऊपर एक बार तय करें, ताकि report के हर figure के fonts, sizes और रंग एक जैसे हों।
在笔记本开头一次设好 rcParams(或样式),让报告中所有图的字体、字号和颜色一致。
8
Pick colormaps on purpose: viridis / cividis for ordered values, coolwarm when 0 is the middle, tab10 for categories. Avoid jet.
Colormaps सोचकर चुनें: क्रम वाले मानों के लिए viridis / cividis, जब 0 बीच में हो तो coolwarm, categories के लिए tab10। jet से बचें।
有目的地选择色图:有序数值用 viridis / cividis,以 0 为中心用 coolwarm,类别用 tab10。避免 jet。
9
Look at the shape before trusting a summary plot: a box plot can hide two groups; check with a violin, histogram or strip plot.
Summary plot पर भरोसा करने से पहले आकार देखें: box plot दो groups छिपा सकता है; violin, histogram या strip plot से जाँचें।
相信汇总图之前先看形状:箱线图可能隐藏两个群体;用小提琴图、直方图或带状散点图检查。
🧮
Key Takeawayमुख्य सीख核心要点

Matplotlib asks you to write more code, but in return every part of the chart is yours to control. Learn the Figure → Axes → artist model, use the ax methods, and you can fix any chart — including the ones that seaborn and pandas make for you.

Matplotlib में ज़्यादा code लिखना पड़ता है, पर बदले में chart का हर हिस्सा आपके नियंत्रण में रहता है। Figure → Axes → artist model सीखें, ax methods इस्तेमाल करें, और आप कोई भी chart ठीक कर सकते हैं — seaborn और pandas के बनाए charts भी।

Matplotlib 需要多写一些代码,但作为回报,图表的每个部分都由你掌控。掌握 Figure → Axes → artist 模型,使用 ax 的方法,你就能修好任何图 —— 包括 seaborn 和 pandas 替你画的那些。