1.3 基础绘图函数 本节摘要:Matplotlib 把"画一张图"浓缩成几个核心函数——plot 画折线、scatter 画散点、bar 画柱状、hist 画直方图。这四个函数覆盖了绝大多数入门需求,但真正该学的不是函数名,而是"什么数据配什么图形"的判断力:折线看趋势、散点看关系、柱状比大小、直方图看分布。本节逐个拆开这四个函数的用法、关键参数和适用场景,最后把四者放在一张决策图里对比,帮你建立起"拿到数据先想图形"的习惯。
本节摘要:Matplotlib 把"画一张图"浓缩成几个核心函数——plot 画折线、scatter 画散点、bar 画柱状、hist 画直方图。这四个函数覆盖了绝大多数入门需求,但真正该学的不是函数名,而是"什么数据配什么图形"的判断力:折线看趋势、散点看关系、柱状比大小、直方图看分布。本节逐个拆开这四个函数的用法、关键参数和适用场景,最后把四者放在一张决策图里对比,帮你建立起"拿到数据先想图形"的习惯。
阅读完本节,你应当能够:
新手画图最常见的错误,不是写错函数名,而是拿到数据就随手挑一个函数往上套。折线图能画,散点图也能画,画出来都"像那么回事",但表达的东西可能完全不对。
所以要先把选图的逻辑立起来。你画一张图,本质是在回答一个问题;不同的图回答不同的问题:
把这四条想清楚,选图基本不会错。下面这张决策图把这套判断画成了流程:
💡 关键直觉:先问"这张图要回答什么问题",再选函数。函数只是手段,问题才是目的。反过来——先选函数再想问题——十有八九会把图做偏。
plot 是最基础也最常用的函数。它把一系列点按顺序用线段连起来,用来表达"一个量随另一个量连续变化"的趋势,比如股价随日期、气温随小时、销售额随月份。
最常用的调用是 plot(x, y),把横轴数据 x 和纵轴数据 y 传进去。如果你只传一个 y,省略 x,Matplotlib 会自动用 0、1、2、3 这样的序号当横轴——这在数据本身没有明确横坐标时很方便。
import matplotlib.pyplot as plt days = [1, 2, 3, 4, 5, 6, 7] temp = [22, 24, 21, 25, 28, 27, 26] fig, ax = plt.subplots() ax.plot(days, temp) ax.set_xlabel("第几天") ax.set_ylabel("气温") ax.set_title("一周气温趋势")
plot 有一个很实用的能力:一次画多条线。连续调多次 plot,每条线会叠在同一个坐标系里,配合 label 参数,就能同时对比多条趋势。
fig, ax = plt.subplots() ax.plot(days, [22, 24, 21, 25, 28, 27, 26], label="A 市") ax.plot(days, [18, 19, 20, 22, 21, 23, 24], label="B 市") ax.legend()
这条 label 配合 legend 的写法,是让多线图可读的关键,1.4 节讲图例时还会深入。现在先记住:要给每条线起个名字,图才能看懂。
scatter 不连线,它把每个数据点单独画成一个标记。用途是看两个连续变量之间的关系——比如身高和体重、广告投入和销售额、学习时长和考试分数。
import matplotlib.pyplot as plt import numpy as np np.random.seed(0) ad_cost = np.random.rand(60) * 100 # 广告投入,0 到 100 sales = ad_cost * 1.5 + np.random.rand(60) * 20 # 销售额,大致随投入上升 fig, ax = plt.subplots() ax.scatter(ad_cost, sales) ax.set_xlabel("广告投入") ax.set_ylabel("销售额")
散点图真正厉害的地方在于,它还能把第三维信息塞进去:用点的大小 s 编码一个量,用点的颜色 c 编码另一个量。这样一张二维散点图能同时表达四个维度的信息。
city_size = np.random.rand(60) * 500 + 50 # 城市规模,用点的大小表示 profit = sales - ad_cost * 0.8 # 利润率,用颜色表示 fig, ax = plt.subplots() sc = ax.scatter(ad_cost, sales, s=city_size, c=profit, cmap="viridis", alpha=0.6) fig.colorbar(sc, ax=ax, label="利润率")
这里 s=city_size 让点有大有小,c=profit 让点有深有浅,cmap 指定颜色的映射方案,colorbar 加一个色条解释颜色含义。这套"大小加颜色编码额外维度"的手法,是散点图区别于折线图的核心价值。
⚠️ 常见坑:
scatter的点太多时会又慢又糊。上千个点还能接受,几十万上百万个点就该考虑抽样或换plot(plot画点比scatter快,因为scatter为每个点单独建一个对象)。数据量大时,速度是实打实的代价。
bar 画柱状图,用于几个并列类别之间的数值比较。它的横轴不是连续数值,而是"类别"——不同产品、不同地区、不同月份。柱子的高度就是每个类别对应的数值。
import matplotlib.pyplot as plt products = ["手机", "电脑", "平板", "耳机", "手表"] revenue = [320, 450, 180, 90, 140] fig, ax = plt.subplots() ax.bar(products, revenue) ax.set_xlabel("产品") ax.set_ylabel("销售额(万元)")
注意这里的横轴 products 是字符串类别,不是数字。柱状图的意义就在于:每个柱子代表一个独立的类别,柱子之间是并列关系,不是先后关系。这一点和折线图有本质区别——折线图强调"连续的变化",柱状图强调"离散的比较"。
bar 有几个常用参数:width 控制柱子粗细,color 控制颜色,bottom 可以把柱子从某个高度往上叠(做堆叠柱状图)。这些在需要"分组对比"或"堆叠占比"时会用到。
fig, ax = plt.subplots() x = [1, 2, 3, 4, 5] last_year = [200, 300, 150, 250, 180] this_year = [320, 450, 180, 300, 140] ax.bar([i - 0.2 for i in x], last_year, width=0.4, label="去年") ax.bar([i + 0.2 for i in x], this_year, width=0.4, label="今年") ax.set_xticks(x) ax.set_xticklabels(products) ax.legend()
这段代码演示了分组柱状图的做法:把两组柱子各自往左、往右错开一点,再用 width 收窄,让它们并排而不是重叠。这是对比"去年 vs 今年"这类场景的标准手法。
hist 画直方图,它回答的问题是"这一大串数值,大致长什么样"。它把数据分成若干个等宽的区间(叫 bin),数每个区间里落了多少个值,用柱子高度表示频数。柱状图是"类别比较",直方图是"分布统计"——这是两个最容易混的图,务必分清。
import matplotlib.pyplot as plt import numpy as np np.random.seed(0) scores = np.random.randn(2000) * 15 + 70 # 均值 70、标准差 15 的成绩 fig, ax = plt.subplots() ax.hist(scores, bins=30) ax.set_xlabel("分数") ax.set_ylabel("人数")
这里 bins=30 把分数范围切成 30 个小区间。bins 是最该调的参数:切太粗,分布细节看不清;切太细,柱子太多全是噪声。通常先试 10 到 50 之间,看着图再调。
hist 还有两个有用的开关:density=True 会把柱子高度从"频数"变成"概率密度",让总面积归一化成 1,适合把不同样本量的分布放一起对比;cumulative=True 则画累积分布,看"小于某个值的有多少"。
💡 关键直觉:柱状图
bar和直方图hist都长柱子,但一个问"各类谁大谁小"(横轴是类别),一个问"数值怎么分布"(横轴是数值区间)。判断标准看横轴:横轴是并列类别,是 bar;横轴是连续数值的区间,是 hist。
把四个函数并排看,差异会非常清楚。下面这张表是选图时的速查:
| 函数 | 图形 | 横轴是什么 | 回答的问题 | 典型场景 |
|---|---|---|---|---|
| plot | 折线 | 连续数值或顺序 | 趋势怎么走 | 股价、气温、销售随时间 |
| scatter | 散点 | 连续数值 | 两个变量什么关系 | 身高体重、投入产出 |
| bar | 柱状 | 并列类别 | 各类谁大谁小 | 各产品、各地区、各月 |
| hist | 直方图 | 数值区间 | 数值怎么分布 | 成绩、收入、尺寸分布 |
⚠️ 别用错图:把"各月销售额"画成散点图、把"身高体重关系"画成柱状图,都是常见的错误。图错了,结论也跟着错——比如把趋势画成散点,读者会误以为你在强调"点的离散",而看不到"连续上升"这条主线。

一句话点题:plot 看趋势、scatter 看关系、bar 比大小、hist 看分布——四种图形,四个不同的问题,选对了图,数据自己会说话。
前面例子里的数据都是手写的 Python 列表,但实际数据往往来自 NumPy 数组或 Pandas 的 DataFrame。好消息是,这些绘图函数对输入"来者不拒"——列表、元组、NumPy 数组、Pandas 的 Series,都能直接喂进去。
import matplotlib.pyplot as plt import numpy as np x = np.linspace(0, 2 * np.pi, 100) # NumPy 数组 y = np.sin(x) fig, ax = plt.subplots() ax.plot(x, y)
真正要留意的是另一件事:x 和 y 的长度必须一致。 一个 100 个点、另一个 50 个点,plot 会直接报错。这个错在数据清洗不干净时特别常见——比如去掉了某几行的缺失值,结果 x 和 y 的维度对不上了。报错时先别怀疑库,先查两边长度。
还有一个细节:plot 接受的是"序列",它不在乎序列从哪来。这意味着任何能产出数值序列的东西——一个生成器、一个函数算出来的结果——都能作为输入。这种"输入宽松"的设计,正是 Matplotlib 能和整个 Python 数据生态无缝咬合的原因之一。
四个函数不是互斥的,它们可以叠加在同一个 Axes 上。这是 Matplotlib 很灵活的一点:先画一条折线表示趋势,再叠一层散点强调原始观测值,甚至再加柱状图做对比。
import matplotlib.pyplot as plt import numpy as np x = np.arange(10) y = np.random.rand(10) * 10 fig, ax = plt.subplots() ax.plot(x, y, label="趋势线") ax.scatter(x, y, label="原始观测点") ax.legend()
这种"折线加散点"的组合,是数据报告里的常见做法:折线表达趋势,散点把每个真实观测值标出来,让读者既看到整体走势,又看到原始数据的离散程度。两个函数作用在同一个 ax 上,图就自然叠在一起。
组合的边界在于:不同图形要服务于同一个坐标系。 折线和散点能轻松叠加,因为横纵轴含义一致;柱状图和直方图却很少叠在一起,因为一个横轴是类别、一个横轴是数值区间,硬叠只会让读者困惑。能不能叠,看两条信息的坐标系是否兼容。
💡 关键直觉:绘图函数是"往同一个坐标系上添元素",不是"每次新建一张图"。同一个 ax 上调多次绘图函数,元素就层层叠加。理解了这一点,你就能自由组合出折线加散点、柱状加标注这类复合图。
把选图这件事落到实战,有三个错最常出现,值得提前打预防针。
第一个错,把并列类别画成折线图。比如五个城市的销售额,用折线连起来,读图的人会以为五个城市之间有个"先后递进"的关系,但其实它们是并列的五个类别。并列类别该用柱状图,用折线是暗示了不存在的连续性。
第二个错,把单变量分布画成柱状图。一组成绩数据,如果你先手动数好"每个分数段有多少人"再画 bar,效果上没错,但绕了远路——hist 一步就能完成"分箱加计数"。分不清 bar 和 hist 的人,往往就是在这里多干了活。
第三个错,画了多条线却不加图例。两条以上的线叠在一起,没有图例就是两条无名线,读者完全无法判断谁是谁。加 label 再 legend,成本两行代码,价值却是让整张图从"看不懂"变成"一目了然"。
⚠️ 别偷这个懒:图例不是可选项,多线图里它是"必选项"。没有图例的多线图,等于把一半信息丢在画布外。
下一节我们不再换函数,而是给已经画出来的图"上妆"——颜色、线型、标记、刻度、图例这些常用参数,怎么让图从"能看"变成"好读"。