Foundations of Data Science 📂 Descriptive Statistics · 5 of 11 129 min read

Understanding Box Plots

A box plot is a visual summary of quartiles, IQR and outliers in a single chart. Learn how to read, build and interpret box plots with real stories and Python code using Matplotlib and Seaborn.

🌐
SectionSection第 01 节

The Problem Box Plots SolveBox Plots कौन सी समस्या हल करते हैं箱线图解决什么问题

You have 100 house prices. Printing all 100 numbers tells you nothing at a glance. The mean can be pulled up by one mansion. Q1, the median and Q3 help — but that is several numbers to keep in your head.

आपके पास 100 घरों की कीमतें हैं। सारी 100 संख्याएँ छापने से एक नज़र में कुछ पता नहीं चलता। एक बँगला mean को ऊपर खींच सकता है। Q1, median और Q3 मदद करते हैं — पर इतनी संख्याएँ दिमाग़ में रखना मुश्किल है।

你有 100 个房价。把 100 个数全打印出来,一眼看不出任何东西。均值会被一座豪宅拉高。Q1、中位数和 Q3 有帮助 —— 但要同时记住好几个数字。

A box plot (also called a box-and-whisker plot) puts these numbers into one small picture. It shows the median, the spread of the middle 50%, how far the typical values reach, and every outlier — all at once.

Box plot (जिसे box-and-whisker plot भी कहते हैं) इन संख्याओं को एक छोटी तस्वीर में रख देता है। यह median, बीच के 50% का फैलाव, आम values कहाँ तक जाती हैं, और हर outlier — सब एक साथ दिखाता है।

箱线图(也叫箱须图,box-and-whisker plot)把这些数字放进一张小图里。它同时展示中位数、中间 50% 的离散程度、典型值的范围,以及每一个离群点。

💡
Who Invented It?इसे किसने बनाया?是谁发明的?

John Tukey introduced the box-and-whisker plot around 1970 and made it famous in his 1977 book Exploratory Data Analysis — the same book that gives the 1.5 × IQR outlier rule. A simpler "range bar" (a box without the outlier rule) had appeared earlier, in Mary Eleanor Spear's 1952 book on charts. A box plot is a summary: it keeps five numbers and the outliers, and throws the rest away. That makes it compact, but it can hide details such as two peaks (you will see this in Section 4).

John Tukey ने box-and-whisker plot लगभग 1970 में पेश किया और अपनी 1977 की किताब Exploratory Data Analysis में इसे मशहूर किया — वही किताब जिसमें 1.5 × IQR outlier नियम है। इससे पहले, Mary Eleanor Spear की 1952 की charts वाली किताब में एक आसान "range bar" (outlier नियम के बिना box) आ चुका था। Box plot एक सारांश है: यह पाँच संख्याएँ और outliers रखता है, बाक़ी छोड़ देता है। इसलिए यह छोटा है, पर दो peaks जैसी बातें छिपा सकता है (Section 4 में देखेंगे)।

John Tukey 在 1970 年左右提出了箱须图,并在 1977 年的著作《探索性数据分析》中让它广为人知 —— 1.5 × IQR 离群点规则也出自这本书。更早之前,Mary Eleanor Spear 在 1952 年的图表书中画过一种更简单的“范围条”(没有离群点规则的箱子)。 箱线图是一种概括:它保留五个数字和离群点,其余信息都丢掉了。所以它很紧凑,但会隐藏某些细节,比如双峰(第 4 节会看到)。


SectionSection第 02 节

Box Plots in Pictures — Understand Before the Mathsतस्वीरों में Box Plots — गणित से पहले समझें图解箱线图 — 先理解,再算数

📊 FROM DOTS TO A BOX PLOTDOTS से BOX PLOT तक从点到箱线图
From dots to a box plot ① ② 25% 25% 25% 25% ③ 0 10 20 30 40 50 60 70

① Sort the data and draw every value as a dot. ② Cut it into four groups with the same number of dots at Q1, the median and Q3. ③ Draw the middle 50% as a box. The whiskers reach the last dots inside the fences; points beyond the fences stay as dots. Blue = inside the box, grey = covered by the whiskers, red = outliers.

① Data sort करें और हर value को dot बनाएँ। ② Q1, median और Q3 पर इसे बराबर dots वाले चार groups में काटें। ③ बीच के 50% को box बनाएँ। Whiskers fences के अंदर के आख़िरी dots तक जाते हैं; fences से बाहर के points dots ही रहते हैं। नीला = box के अंदर, grey = whiskers में, लाल = outliers.

① 把数据排序,每个值画成一个点。② 在 Q1、中位数和 Q3 处切成点数相同的四组。③ 把中间 50% 画成箱体。须线延伸到围栏内的最后一个点;围栏外的点仍单独画出。蓝 = 箱体内,灰 = 须线覆盖,红 = 离群点。

📐 SHAPE → BOX PLOTSHAPE → BOX PLOT形状 → 箱线图
Box plots of three shapes SymmetricSymmetric对称 median in the middle,median बीच में,中位数居中, whiskers equalwhiskers बराबर须线等长 Right-skewedRight-skewed右偏 median nearer Q1,median Q1 के पास,中位数靠近 Q1, long right whiskerलंबा दायाँ whisker右须线长 Left-skewedLeft-skewed左偏 median nearer Q3,median Q3 के पास,中位数靠近 Q3, long left whiskerलंबा बायाँ whisker左须线长

Each histogram (top) and its box plot (bottom) come from the same 300 values. Skew shows up as a long whisker on one side and dots on that side.

हर histogram (ऊपर) और उसका box plot (नीचे) एक ही 300 values से बने हैं। Skew एक तरफ़ लंबे whisker और उसी तरफ़ के dots से दिखता है।

每个直方图(上)和它的箱线图(下)来自同样的 300 个值。偏斜表现为一侧的须线很长,并且离群点也在那一侧。

LIVELIVE互动Box Plot Anatomy — Click Each PartBox Plot की बनावट — हर हिस्से पर Click करें箱线图结构 — 逐个点击各部分

Click a button to highlight one part. The box plot is drawn from the 19 dots below it, and every number is calculated live.

किसी button पर click करके एक हिस्सा highlight करें। Box plot नीचे के 19 dots से बना है, और हर संख्या live calculate होती है।

点击按钮高亮某一部分。箱线图由下方 19 个点画成,每个数字都是实时计算的。


SectionSection第 03 节

Anatomy of a Box PlotBox Plot की बनावट箱线图的组成

A box plot is built from the five-number summary — minimum, Q1, median, Q3, maximum — plus the 1.5 × IQR rule for outliers. It has five visible parts:

Box plot five-number summary से बनता है — minimum, Q1, median, Q3, maximum — और outliers के लिए 1.5 × IQR नियम से। इसके पाँच दिखने वाले हिस्से हैं:

箱线图由五数概括(最小值、Q1、中位数、Q3、最大值)加上 1.5 × IQR 离群点规则构成。它有五个可见部分:

📦 The Five Parts of a Box PlotBox Plot के पाँच हिस्से箱线图的五个部分
BoxBox箱体
The rectangle runs from Q1 to Q3. It holds the middle 50% of the data, and its length is the IQR. A short box means the typical values are close together; a long box means they are spread out.
आयत Q1 से Q3 तक जाता है। इसमें data का बीच का 50% है, और इसकी लंबाई IQR है। छोटा box = आम values पास-पास; लंबा box = फैली हुई।
矩形从 Q1 到 Q3,装着中间 50% 的数据,长度就是 IQR。箱子短说明典型值很集中;箱子长说明很分散。
Median lineMedian line中位线
The line inside the box is the median (Q2). Half of the values are below it, half above. Its position gives a hint about skew — read it together with the whiskers.
Box के अंदर की line median (Q2) है। आधी values इसके नीचे, आधी ऊपर। इसकी जगह skew का संकेत देती है — इसे whiskers के साथ पढ़ें।
箱体内部的线是中位数(Q2)。一半的值在它下面,一半在上面。它的位置能提示偏斜 —— 要结合须线一起看。
WhiskersWhiskers须线
Lines from each side of the box to the last data point still inside the fence. They stop at a real data value, so they are often shorter than the fence. They are the minimum and maximum only when there are no outliers.
Box के दोनों ओर से उस आख़िरी data point तक की lines जो अभी fence के अंदर है। ये एक असली value पर रुकती हैं, इसलिए अक्सर fence से छोटी होती हैं। ये minimum और maximum तभी होती हैं जब कोई outlier न हो।
从箱体两侧延伸到仍在围栏内的最后一个数据点的线。它们停在真实的数据值上,所以常常比围栏短。只有没有离群点时,它们才是最小值和最大值。
FencesFences围栏
Invisible limits at Q1 − 1.5 × IQR and Q3 + 1.5 × IQR. They are usually not drawn. A whisker can never go past a fence.
Q1 − 1.5 × IQR और Q3 + 1.5 × IQR पर अदृश्य सीमाएँ। ये आम तौर पर बनाई नहीं जातीं। Whisker कभी fence के पार नहीं जाता।
位于 Q1 − 1.5 × IQR 和 Q3 + 1.5 × IQR 的隐形界限,通常不画出来。须线永远不会越过围栏。
Outlier dotsOutlier dots离群点
Every value beyond a fence is drawn as its own dot. Three dots = three values. They are not automatically errors — they are values to check.
Fence से बाहर की हर value अपना अलग dot बनती है। तीन dots = तीन values. ये अपने-आप ग़लतियाँ नहीं हैं — ये जाँचने लायक values हैं।
每个超出围栏的值都单独画成一个点。三个点 = 三个值。它们不一定是错误 —— 而是需要核查的值。

Calculating the salary box plot step by stepSalary box plot को step-by-step calculate करना分步计算工资箱线图

Salaries (£k): [32, 33, 34, 48, 49, 51, 72, 75, 78, 95, 120, 380]. We use the same method as Matplotlib and NumPy (linear interpolation).

Salaries (£k): [32, 33, 34, 48, 49, 51, 72, 75, 78, 95, 120, 380]. हम वही तरीका इस्तेमाल करते हैं जो Matplotlib और NumPy करते हैं (linear interpolation)।

工资(£k):[32, 33, 34, 48, 49, 51, 72, 75, 78, 95, 120, 380]。我们使用与 Matplotlib 和 NumPy 相同的方法(线性插值)。

🧮 Five numbers → box plotपाँच संख्याएँ → box plot五个数 → 箱线图
Q1
Position (12 − 1) × 0.25 = 2.75 → 34 + 0.75 × (48 − 34) = 44.5
Position (12 − 1) × 0.25 = 2.75 → 34 + 0.75 × (48 − 34) = 44.5
位置 (12 − 1) × 0.25 = 2.75 → 34 + 0.75 × (48 − 34) = 44.5
Median
Average of the 6th and 7th values: (51 + 72) / 2 = 61.5
6वीं और 7वीं value का औसत: (51 + 72) / 2 = 61.5
第 6 和第 7 个值的平均:(51 + 72) / 2 = 61.5
Q3
Position (12 − 1) × 0.75 = 8.25 → 78 + 0.25 × (95 − 78) = 82.25
Position (12 − 1) × 0.75 = 8.25 → 78 + 0.25 × (95 − 78) = 82.25
位置 (12 − 1) × 0.75 = 8.25 → 78 + 0.25 × (95 − 78) = 82.25
IQR
82.25 − 44.5 = 37.75
82.25 − 44.5 = 37.75
82.25 − 44.5 = 37.75
FencesFences围栏
44.5 − 1.5 × 37.75 = −12.125 and 82.25 + 1.5 × 37.75 = 138.875
44.5 − 1.5 × 37.75 = −12.125 और 82.25 + 1.5 × 37.75 = 138.875
44.5 − 1.5 × 37.75 = −12.125,82.25 + 1.5 × 37.75 = 138.875
WhiskersWhiskers须线
Lowest value ≥ −12.125 is 32. Highest value ≤ 138.875 is 120 — the whisker stops there, not at 138.875.
−12.125 या उससे बड़ी सबसे छोटी value 32 है। 138.875 या उससे छोटी सबसे बड़ी value 120 है — whisker वहीं रुकता है, 138.875 पर नहीं।
≥ −12.125 的最小值是 32。≤ 138.875 的最大值是 120 —— 须线停在这里,而不是 138.875。
OutliersOutliers离群点
380 > 138.875 → drawn as a dot
380 > 138.875 → एक dot के रूप में
380 > 138.875 → 画成一个点
ℹ️
Hand Method Gives Slightly Different Numbersहाथ वाला तरीका थोड़ी अलग संख्याएँ देता है手算方法的结果略有不同

The "split into halves" method from school gives Q1 = 41 and Q3 = 86.5 for the same data. Both are accepted. The box plot looks almost the same, and the CTO is an outlier either way. Software (Matplotlib, seaborn, pandas) uses the linear method shown above.

स्कूल वाला "आधे हिस्सों में बाँटो" तरीका इसी data के लिए Q1 = 41 और Q3 = 86.5 देता है। दोनों मान्य हैं। Box plot लगभग एक जैसा दिखता है, और CTO दोनों तरह से outlier है। Software (Matplotlib, seaborn, pandas) ऊपर वाला linear तरीका इस्तेमाल करते हैं।

课本上“对半分”的方法对同一数据得到 Q1 = 41、Q3 = 86.5。两种都被认可。箱线图看起来几乎一样,CTO 无论如何都是离群点。软件(Matplotlib、seaborn、pandas)使用上面的线性方法。

LIVELIVE互动Build a Box Plot Point by PointPoint-by-Point Box Plot बनाएँ逐点搭建箱线图

Add and remove points. Watch the whiskers jump to the last point inside each fence, and watch a point turn red the moment it crosses a fence.

Points जोड़ें और हटाएँ। देखें कि whiskers हर fence के अंदर के आख़िरी point तक कैसे कूदते हैं, और fence पार करते ही point कैसे लाल हो जाता है।

添加和删除点。观察须线如何跳到每个围栏内的最后一个点,以及一个点越过围栏时如何立刻变红。


SectionSection第 04 节

How to Read a Box PlotBox Plot कैसे पढ़ें如何读懂箱线图

What you seeआप क्या देखते हैं你看到的What it usually meansइसका आम मतलब通常意味着What to doक्या करें怎么做
Short boxछोटा box箱子短Middle 50% is tightly packed — small IQRबीच का 50% पास-पास — छोटा IQR中间 50% 很集中 —— IQR 小Typical values are consistentआम values एक जैसी हैं典型值很稳定
Long boxलंबा box箱子长Middle 50% is spread out — large IQRबीच का 50% फैला हुआ — बड़ा IQR中间 50% 很分散 —— IQR 大Expect high variabilityज़्यादा उतार-चढ़ाव मानें要预期较大的波动
Median nearer Q1 + long right whiskerMedian Q1 के पास + लंबा दायाँ whisker中位数靠近 Q1 + 右须线长Right (positive) skewRight (positive) skew右偏(正偏)Report the median, not only the meanसिर्फ़ mean नहीं, median बताएँ报告中位数,而不只是均值
Median nearer Q3 + long left whiskerMedian Q3 के पास + लंबा बायाँ whisker中位数靠近 Q3 + 左须线长Left (negative) skewLeft (negative) skew左偏(负偏)Report the median, not only the meanसिर्फ़ mean नहीं, median बताएँ报告中位数,而不只是均值
Dots beyond a whiskerWhisker से बाहर dots须线外有点Values beyond the 1.5 × IQR fence1.5 × IQR fence से बाहर की values超出 1.5 × IQR 围栏的值Investigate: error, rare event or real extreme?जाँचें: ग़लती, दुर्लभ घटना या असली extreme?调查:错误、罕见事件还是真实极端值?
Many dotsबहुत सारे dots很多离群点Heavy tails or skew — or simply a very large datasetभारी tails या skew — या बस बहुत बड़ा dataset厚尾或偏斜 —— 也可能只是数据量很大Check n and a histogram before calling them errorsग़लती कहने से पहले n और histogram देखें在称之为错误之前,先看 n 和直方图
⚠️
Median Position Is Only a HintMedian की जगह सिर्फ़ एक संकेत है中位数位置只是一个提示

A median off-centre usually signals skew, but not always: with small samples it can move a lot by chance, and some skewed data has a centred median. Look at the whisker lengths and outlier side too. "Right-skewed means mean > median" is a common rule of thumb, but it also has exceptions.

Median का बीच से हटना आम तौर पर skew बताता है, पर हमेशा नहीं: छोटे samples में यह संयोग से बहुत हिल सकता है, और कुछ skewed data में median बीच में होता है। Whiskers की लंबाई और outliers किस तरफ़ हैं, यह भी देखें। "Right-skewed का मतलब mean > median" एक आम अंगूठा-नियम है, पर इसके भी अपवाद हैं।

中位数偏离中心通常意味着偏斜,但并不总是:小样本时它会因偶然大幅移动,有些偏斜数据的中位数也居中。还要看须线长度和离群点在哪一侧。“右偏意味着均值 > 中位数”是常用的经验法则,但也有例外。

🎯
The 5-Second Box Plot Check5-सेकंड Box Plot जाँच5 秒箱线图检查

1. Where is the median? (typical value) 2. How long is the box? (spread of the middle 50%) 3. Are the whiskers equal? (skew) 4. Any dots, and on which side? (outliers). Then look at a histogram before drawing strong conclusions.

1. Median कहाँ है? (आम value) 2. Box कितना लंबा है? (बीच के 50% का फैलाव) 3. क्या whiskers बराबर हैं? (skew) 4. कोई dots, और किस तरफ़? (outliers). फिर पक्के निष्कर्ष से पहले histogram देखें।

1. 中位数在哪?(典型值)2. 箱子多长?(中间 50% 的离散程度)3. 两条须线一样长吗?(偏斜)4. 有离群点吗?在哪一侧?(离群点)。下结论前,再看一眼直方图。

LIVELIVE互动Same Data, Two Views — Histogram vs Box Plotएक ही Data, दो नज़रिये — Histogram vs Box Plot同一数据,两种视角 — 直方图 vs 箱线图

Pick a shape. The histogram and the box plot below it show the same 400 values; the orange diamond is the mean. Try "Two peaks" and "Flat" — then hide the histogram and test yourself.

एक shape चुनें। Histogram और उसके नीचे का box plot एक ही 400 values दिखाते हैं; नारंगी diamond mean है। "दो peaks" और "सपाट" आज़माएँ — फिर histogram छिपाकर ख़ुद को परखें।

选择一种形状。直方图和下面的箱线图展示的是同样的 400 个值;橙色菱形是均值。试试“双峰”和“平坦” —— 然后隐藏直方图考考自己。

LIVELIVE互动Why Big Datasets Show Many Outlier Dotsबड़े Datasets में बहुत से Outlier Dots क्यों为什么大数据集会有很多离群点

The data is perfect normal data, with no errors. Increase n and count the red dots.

Data एकदम सही normal data है, कोई ग़लती नहीं। n बढ़ाएँ और लाल dots गिनें।

数据是完美的正态数据,没有任何错误。增大 n,数一数红点。


SectionSection第 05 节

Drawing Box Plots in PythonPython में Box Plots बनाना用 Python 画箱线图

⚠️
Matplotlib Changed — Old Code BreaksMatplotlib बदल गया — पुराना Code टूटता हैMatplotlib 已更新 —— 旧代码会报错

Many online examples use labels= and vert=False. In Matplotlib 3.9 labels was renamed to tick_labels, and it has now been removed — old code stops with TypeError: unexpected keyword argument 'labels'. vert is deprecated in favour of orientation='horizontal' (added in 3.10). All code below is tested on Matplotlib 3.11 and seaborn 0.13.

बहुत से online उदाहरण labels= और vert=False इस्तेमाल करते हैं। Matplotlib 3.9 में labels का नाम tick_labels हो गया, और अब इसे हटा दिया गया है — पुराना code TypeError: unexpected keyword argument 'labels' के साथ रुक जाता है। vert deprecated है, उसकी जगह orientation='horizontal' (3.10 में जोड़ा गया) है। नीचे का सारा code Matplotlib 3.11 और seaborn 0.13 पर test किया गया है।

很多网上的例子使用 labels= 和 vert=False。Matplotlib 3.9 把 labels 改名为 tick_labels,现在旧名已被移除 —— 旧代码会报 TypeError: unexpected keyword argument 'labels'。vert 已弃用,改用 orientation='horizontal'(3.10 新增)。下面所有代码都在 Matplotlib 3.11 和 seaborn 0.13 上测试过。

Basic box plot with MatplotlibMatplotlib से basic box plot用 Matplotlib 画基础箱线图

import matplotlib.pyplot as plt
from matplotlib.cbook import boxplot_stats

salaries = [32, 33, 34, 48, 49, 51,
            72, 75, 78, 95, 120, 380]          # £ thousands

fig, ax = plt.subplots(figsize=(10, 3.5))
bp = ax.boxplot(salaries, orientation='horizontal',   # Matplotlib 3.10+
                patch_artist=True, widths=0.5)        # patch_artist lets us fill the box

bp['boxes'][0].set(facecolor='#378add', alpha=0.3)
bp['medians'][0].set(color='#1d9e75', linewidth=2.5)
bp['fliers'][0].set(marker='o', markerfacecolor='none',
                    markeredgecolor='#e24b4a', markersize=8)

ax.set_title('Salary Distribution — Box Plot', fontsize=13)
ax.set_xlabel('Salary (£k)')
ax.set_yticks([])
plt.tight_layout()
plt.show()

# The exact numbers Matplotlib used to draw the plot
s = boxplot_stats(salaries)[0]
print(f"Q1 = {s['q1']}, median = {s['med']}, Q3 = {s['q3']}, IQR = {s['iqr']}")
print(f"Whiskers end at {s['whislo']} and {s['whishi']}")
print(f"Outliers (fliers): {s['fliers'].tolist()}")
OUTPUT
Q1 = 44.5, median = 61.5, Q3 = 82.25, IQR = 37.75 Whiskers end at 32 and 120 Outliers (fliers): [380]
Output plot: one outlier dot at £380k.
Output plot: one outlier dot at £380k.
Output plot: £380k पर एक outlier dot.
输出图:£380k 处有一个离群点。

boxplot_stats() returns the exact numbers Matplotlib drew — the same values we calculated by hand in Section 3.

boxplot_stats() वही संख्याएँ लौटाता है जिनसे Matplotlib ने plot बनाया — वही values जो हमने Section 3 में हाथ से निकालीं।

boxplot_stats() 返回 Matplotlib 实际绘图用的数字 —— 和我们在第 3 节手算的完全一样。

Comparing several groups side by sideकई groups की साथ-साथ तुलना并排比较多个组

import matplotlib.pyplot as plt
from matplotlib.cbook import boxplot_stats

departments = {
    'Engineering': [65, 72, 78, 85, 90, 95, 68, 74, 82, 88, 150],
    'Marketing':   [45, 48, 52, 55, 58, 61, 65, 47, 53, 60, 110],
    'Sales':       [35, 40, 48, 52, 55, 60, 70, 42, 50, 58, 200],
    'HR':          [38, 42, 44, 46, 48, 50, 52, 43, 47, 49,  90],
}

fig, ax = plt.subplots(figsize=(10, 5))
colors = ['#378add', '#1d9e75', '#ba7517', '#7f77dd']

bp = ax.boxplot(list(departments.values()),
                tick_labels=list(departments.keys()),   # was labels= before 3.9
                patch_artist=True, widths=0.5)

for patch, color in zip(bp['boxes'], colors):
    patch.set(facecolor=color, alpha=0.3)
for median in bp['medians']:
    median.set(color='#1a1d2e', linewidth=2)
for flier in bp['fliers']:
    flier.set(marker='o', markerfacecolor='none',
              markeredgecolor='#e24b4a', markersize=8)

ax.set_title('Salary Distribution by Department', fontsize=13)
ax.set_ylabel('Salary (£k)')
ax.grid(axis='y', alpha=0.3)
plt.tight_layout()
plt.show()

for name, s in zip(departments, boxplot_stats(list(departments.values()))):
    print(f"{name:<12} median {s['med']:>5}  IQR {s['iqr']:>5}  outliers {s['fliers'].tolist()}")
OUTPUT
Engineering median 82.0 IQR 16.0 outliers [150] Marketing median 55.0 IQR 10.5 outliers [110] Sales median 52.0 IQR 14.0 outliers [200] HR median 47.0 IQR 6.0 outliers [90]
Output plot: each department has one high outlier.
Output plot: each department has one high outlier.
Output plot: हर department में एक ऊँचा outlier.
输出图:每个部门都有一个偏高的离群点。

Box plot with seabornseaborn से box plot用 seaborn 画箱线图

import seaborn as sns
import pandas as pd
import matplotlib.pyplot as plt

data = {
    'salary': [65,72,78,85,90,95,68,74,82,88,150,
               45,48,52,55,58,61,65,47,53,60,110,
               35,40,48,52,55,60,70,42,50,58,200],
    'dept':   ['Engineering']*11 + ['Marketing']*11 + ['Sales']*11
}
df = pd.DataFrame(data)

fig, ax = plt.subplots(figsize=(10, 5))
sns.boxplot(data=df, x='dept', y='salary',
            hue='dept', legend=False,          # seaborn 0.13+: palette needs hue
            palette=['#378add', '#1d9e75', '#ba7517'],
            width=0.5, linewidth=1.5,
            flierprops=dict(marker='o', markerfacecolor='none',
                            markeredgecolor='#e24b4a', markersize=8), ax=ax)
ax.set_title('Salary Distribution by Department', fontsize=13)
ax.grid(axis='y', alpha=0.3)
plt.tight_layout()
plt.show()

# Same numbers as a table
print(df.groupby('dept')['salary'].quantile([0.25, 0.5, 0.75]).unstack().round(2))
OUTPUT
0.25 0.50 0.75 dept Engineering 73.0 82.0 89.0 Marketing 50.0 55.0 60.5 Sales 45.0 52.0 59.0
Output plot (seaborn).
Output plot (seaborn).
Output plot (seaborn).
输出图(seaborn)。

In seaborn 0.13+, passing palette without hue gives a warning, so we set hue='dept', legend=False.

seaborn 0.13+ में hue के बिना palette देने पर warning आती है, इसलिए हम hue='dept', legend=False लगाते हैं।

在 seaborn 0.13+ 中,只传 palette 不传 hue 会发出警告,所以我们设置 hue='dept', legend=False。


SectionSection第 06 节

Reading Box Plots — Three Real StoriesBox Plots पढ़ना — तीन असली कहानियाँ读箱线图 — 三个真实故事

Story 1 — The reliable machineकहानी 1 — भरोसेमंद machine故事 1 — 靠谱的机器

import numpy as np
import matplotlib.pyplot as plt

machine_a = [19.8, 20.0, 20.1, 19.9, 20.2, 20.0, 19.8, 20.1, 20.0, 19.9]
machine_b = [14.0, 26.0, 18.0, 22.0, 20.0, 28.0, 12.0, 24.0, 16.0, 20.0]

fig, ax = plt.subplots(figsize=(8, 4))
bp = ax.boxplot([machine_a, machine_b],
                tick_labels=['Machine A', 'Machine B'],
                patch_artist=True)

bp['boxes'][0].set(facecolor='#1d9e75', alpha=0.3)
bp['boxes'][1].set(facecolor='#e24b4a', alpha=0.3)

ax.axhline(20, color='#7f77dd', linestyle='--', alpha=0.5, label='Target: 20g')
ax.set_title('Biscuit Weight — Machine A vs Machine B')
ax.set_ylabel('Weight (g)')
ax.legend()
plt.tight_layout()
plt.show()

for name, w in [('A', machine_a), ('B', machine_b)]:
    q1, q3 = np.percentile(w, [25, 75])
    print(f"Machine {name}: mean {np.mean(w):.2f} g, median {np.median(w):.2f} g, "
          f"IQR {q3 - q1:.2f} g, range {min(w)}–{max(w)} g")
print("Outlier dots:", [len(f.get_ydata()) for f in bp['fliers']])
OUTPUT
Machine A: mean 19.98 g, median 20.00 g, IQR 0.18 g, range 19.8–20.2 g Machine B: mean 20.00 g, median 20.00 g, IQR 7.00 g, range 12.0–28.0 g Outlier dots: [0, 0]
Output plot: same centre, very different spread.
Output plot: same centre, very different spread.
Output plot: एक ही केंद्र, बहुत अलग फैलाव।
输出图:中心相同,离散程度大不相同。
✅
What the Box Plot Shows at a GlanceBox Plot एक नज़र में क्या दिखाता है箱线图一眼就能看出什么

Machine A: a tiny box hugging the 20 g line (IQR 0.18 g). Machine B: a big box (IQR 7 g) and long whiskers from 12 g to 28 g. Both have the same median (20 g) and almost the same mean. Note: Machine B has no outlier dots — its values are widely spread but evenly, so nothing crosses a fence. A bad process does not always produce outliers.

Machine A: 20 g line से चिपका एक छोटा box (IQR 0.18 g). Machine B: बड़ा box (IQR 7 g) और 12 g से 28 g तक लंबे whiskers. दोनों का median एक (20 g) और mean लगभग एक है। ध्यान दें: Machine B में कोई outlier dot नहीं — उसकी values बहुत फैली हैं पर बराबर से, इसलिए कोई fence पार नहीं करती। ख़राब process हमेशा outliers नहीं देता।

机器 A:一个紧贴 20 g 线的小箱子(IQR 0.18 g)。机器 B:一个大箱子(IQR 7 g),须线从 12 g 延伸到 28 g。两者中位数相同(20 g),均值也几乎相同。注意:机器 B 没有离群点 —— 它的值分布很广但很均匀,没有越过围栏。糟糕的工艺并不总会产生离群点。

Story 2 — Exam scores of two classesकहानी 2 — दो classes के exam scores故事 2 — 两个班的考试成绩

import numpy as np
import matplotlib.pyplot as plt

np.random.seed(0)
class_a = np.clip(np.random.normal(68, 5, 40), 0, 100)
class_b = np.clip(np.random.normal(65, 18, 40), 0, 100)   # scores can't pass 100

fig, ax = plt.subplots(figsize=(8, 4))
bp = ax.boxplot([class_a, class_b], tick_labels=['Class A', 'Class B'],
                patch_artist=True,
                flierprops=dict(marker='o', markerfacecolor='none',
                                markeredgecolor='#e24b4a', markersize=7))
bp['boxes'][0].set(facecolor='#378add', alpha=0.3)
bp['boxes'][1].set(facecolor='#ba7517', alpha=0.3)
ax.set_title('Exam Score Distribution — Two Classes')
ax.set_ylabel('Score'); ax.set_ylim(0, 110); ax.grid(axis='y', alpha=0.3)
plt.tight_layout(); plt.show()

for name, c, f in [('A', class_a, bp['fliers'][0]), ('B', class_b, bp['fliers'][1])]:
    q1, q2, q3 = np.percentile(c, [25, 50, 75])
    print(f"Class {name}: median {q2:.1f}, IQR {q3 - q1:.1f}, "
          f"outlier dots {np.round(f.get_ydata(), 1).tolist()}")
print("Students on exactly 100 in Class B:", int((class_b == 100).sum()))
OUTPUT
Class A: median 69.6, IQR 6.3, outlier dots [55.2] Class B: median 57.4, IQR 18.7, outlier dots [100.0] Students on exactly 100 in Class B: 1
Output plot: Class B is lower and much more spread out.
Output plot: Class B is lower and much more spread out.
Output plot: Class B नीचे है और बहुत ज़्यादा फैली हुई है।
输出图:B 班更低,而且分散得多。
⚠️
Look Closely at That Dot at 100100 वाले Dot को ध्यान से देखें仔细看 100 分的那个点

Class B's outlier dot is a student who scored exactly 100. The simulated score was above 100, and np.clip cut it to 100. Clipping (or a test with a maximum mark) can create a pile-up at the limit. Always ask why a dot is there before calling it an error — here it is a top student.

Class B का outlier dot एक छात्र है जिसने ठीक 100 अंक पाए। Simulated score 100 से ऊपर था, और np.clip ने उसे 100 पर काट दिया। Clipping (या अधिकतम अंक वाला test) सीमा पर values का ढेर बना सकता है। किसी dot को ग़लती कहने से पहले हमेशा पूछें कि वह क्यों है — यहाँ यह एक topper है।

B 班的离群点是一位正好考了 100 分的学生。模拟分数超过了 100,被 np.clip 截成 100。截断(或有满分上限的考试)会让数值堆在边界上。把一个点判为错误之前,先问它为什么在那里 —— 这里它是一位尖子生。

Story 3 — Spotting sensor faultsकहानी 3 — Sensor की ख़राबी पकड़ना故事 3 — 发现传感器故障

import numpy as np
import matplotlib.pyplot as plt

np.random.seed(1)
normal = np.random.normal(21, 0.5, 50)        # 50 good readings around 21 °C
faulty = np.append(normal, [35.2, 38.7, 2.1])  # 3 faulty readings

fig, ax = plt.subplots(figsize=(8, 4))
bp = ax.boxplot(faulty, orientation='horizontal', patch_artist=True,
                flierprops=dict(marker='D', markerfacecolor='#e24b4a',
                                markeredgecolor='#e24b4a', markersize=9))
bp['boxes'][0].set(facecolor='#378add', alpha=0.25)
bp['medians'][0].set(color='#1d9e75', linewidth=2)
ax.set_title('Room Temperature — Sensor Readings')
ax.set_xlabel('Temperature (°C)'); ax.set_yticks([])
for x, h in [(2.1, 1.3), (35.2, 1.3), (38.7, 1.42)]:   # stagger labels
    ax.annotate('Faulty reading', xy=(x, 1), xytext=(x, h),
                fontsize=9, color='#e24b4a', ha='center',
                arrowprops=dict(arrowstyle='->', color='#e24b4a'))
plt.tight_layout(); plt.show()

fliers = np.sort(bp['fliers'][0].get_xdata())
print("Outlier dots:", fliers.round(2).tolist())
print(f"Mean with faults {faulty.mean():.2f} °C, without {normal.mean():.2f} °C")
print(f"Median with faults {np.median(faulty):.2f} °C, without {np.median(normal):.2f} °C")
OUTPUT
Outlier dots: [2.1, 35.2, 38.7] Mean with faults 21.23 °C, without 20.99 °C Median with faults 20.91 °C, without 20.91 °C
Output plot: the three faulty readings sit far outside the tiny box.
Output plot: the three faulty readings sit far outside the tiny box.
Output plot: तीनों ख़राब readings छोटे box से बहुत दूर हैं।
输出图:三个故障读数远离那个很小的箱子。

The three faults are caught, and they move the mean (21.23 °C vs 20.99 °C) while the median stays at 20.91 °C. In a real system you would remove these readings only after confirming the sensor fault.

तीनों ख़राबियाँ पकड़ी गईं, और वे mean को हिलाती हैं (21.23 °C vs 20.99 °C) जबकि median 20.91 °C पर रहता है। असली system में आप इन readings को sensor की ख़राबी पक्की होने के बाद ही हटाएँगे।

三个故障都被抓到了。它们改变了均值(21.23 °C vs 20.99 °C),而中位数仍是 20.91 °C。在真实系统中,只有确认传感器故障后才应删除这些读数。

LIVELIVE互动Compare Groups — Test YourselfGroups की तुलना — ख़ुद को परखें比较各组 — 自我测验

Answer each question by reading the box plots only. Then turn on the raw points to see the data behind each box.

हर सवाल का जवाब सिर्फ़ box plots पढ़कर दें। फिर हर box के पीछे का data देखने के लिए raw points चालू करें।

只看箱线图回答每个问题。然后打开原始点,看看每个箱子背后的数据。


SectionSection第 07 节

Box Plot vs Histogram — Which to Use?Box Plot vs Histogram — कौन सा इस्तेमाल करें?箱线图 vs 直方图 — 用哪个?

Situationस्थिति场景Box plotBox plot箱线图HistogramHistogram直方图
Comparing many groupsबहुत से groups की तुलना比较多个组Betterबेहतर更好Gets clutteredभीड़ हो जाती है容易杂乱
Spotting outliersOutliers पकड़ना发现离群点Each one drawn and flaggedहर एक बनता और चिह्नित होता है逐个画出并标记Visible as lonely bars, not flaggedअकेली bars के रूप में दिखते हैं, चिह्नित नहीं表现为孤立的柱子,但不标记
Seeing the shapeShape देखना看分布形状Limitedसीमित有限Betterबेहतर更好
Quartiles and medianQuartiles और median四分位数和中位数Drawn directlyसीधे बने होते हैं直接画出Must be calculatedCalculate करने पड़ते हैं需要另外计算
Small space in a reportReport में कम जगह报告中节省空间Compactछोटा紧凑Takes more spaceज़्यादा जगह占用更多空间
Two peaks (bimodal)दो peaks (bimodal)双峰Hiddenछिपे रहते हैं被隐藏Clearसाफ़ दिखते हैं清晰可见
Very small samples (n < 10)बहुत छोटे samples (n < 10)极小样本(n < 10)Quartiles are shakyQuartiles अस्थिर四分位数不稳定Bins are shakyBins अस्थिर分箱不稳定
📐
Best Practiceसबसे अच्छा तरीका最佳实践

Use a histogram first to see the shape of one variable. Use box plots to compare groups or summarise data in little space. For small datasets, draw the raw points on top of the box (seaborn: sns.stripplot after sns.boxplot), so nobody mistakes 8 values for a smooth distribution.

एक variable का shape देखने के लिए पहले histogram इस्तेमाल करें। Groups की तुलना या कम जगह में सारांश के लिए box plots लें। छोटे datasets में box के ऊपर raw points भी बनाएँ (seaborn: sns.boxplot के बाद sns.stripplot), ताकि कोई 8 values को एक smooth distribution न समझ ले।

先用直方图看单个变量的形状。比较多组或在有限空间里做概括时,用箱线图。数据量小时,在箱子上叠加原始点(seaborn:先 sns.boxplot 再 sns.stripplot),免得有人把 8 个值误当作平滑的分布。


SectionSection第 08 节

Golden RulesGolden Rules黄金法则

🎯 Box Plots — Key RulesBox Plots — मुख्य नियम箱线图 — 关键规则
1
The whiskers stop at the last data point inside the fence — not at the fence, and not always at the min or max. A short whisker means there is no data near the fence.
Whiskers fence के अंदर के आख़िरी data point पर रुकते हैं — fence पर नहीं, और हमेशा min या max पर भी नहीं। छोटा whisker = fence के पास कोई data नहीं।
须线停在围栏内的最后一个数据点 —— 不是围栏本身,也不一定是最小值或最大值。须线短说明围栏附近没有数据。
2
Read skew from the whole picture: median position, whisker lengths and which side the dots are on. One clue alone can mislead.
Skew पूरी तस्वीर से पढ़ें: median की जगह, whiskers की लंबाई और dots किस तरफ़ हैं। अकेला एक संकेत गुमराह कर सकता है।
根据整张图判断偏斜:中位数位置、须线长度、离群点在哪一侧。只看一条线索可能会被误导。
3
Box plots shine when comparing groups: side-by-side boxes show at once which group has the higher median, more spread or more outliers.
Box plots groups की तुलना में सबसे अच्छे हैं: साथ-साथ के boxes तुरंत दिखाते हैं कि किस group का median ऊँचा, फैलाव ज़्यादा या outliers ज़्यादा हैं।
箱线图最适合比较各组:并排的箱子一眼就能看出哪组中位数更高、离散更大或离群点更多。
4
An outlier dot is a question, not a verdict. Large datasets, heavy tails, skew and clipping all create dots without any error.
Outlier dot एक सवाल है, फ़ैसला नहीं। बड़े datasets, भारी tails, skew और clipping — सब बिना किसी ग़लती के dots बनाते हैं।
离群点是一个问题,而不是结论。大数据集、厚尾、偏斜和截断都会在没有错误的情况下产生离群点。
5
Box plots hide two peaks and gaps. Check a histogram, or overlay the raw points, before trusting the shape.
Box plots दो peaks और gaps छिपाते हैं। Shape पर भरोसा करने से पहले histogram देखें, या raw points ऊपर बनाएँ।
箱线图会隐藏双峰和空隙。相信形状之前,先看直方图,或叠加原始点。
6
In Matplotlib use tick_labels= (not labels=) and orientation='horizontal' (not vert=False). Use patch_artist=True only when you want to fill the boxes with colour — outliers are shown by default.
Matplotlib में tick_labels= (न कि labels=) और orientation='horizontal' (न कि vert=False) इस्तेमाल करें। patch_artist=True सिर्फ़ तब लगाएँ जब boxes में रंग भरना हो — outliers default में दिखते हैं।
在 Matplotlib 中使用 tick_labels=(不是 labels=)和 orientation='horizontal'(不是 vert=False)。只有想给箱子填色时才用 patch_artist=True —— 离群点默认就会显示。