1. 从零开始你的第一个Matplotlib图形大家好我是老张在数据分析和算法工程这块摸爬滚打了十几年用Matplotlib画过的图少说也有几千张了。今天我想抛开那些复杂的官方文档用最接地气的方式带你从“画出一条线”开始一步步玩转这个Python可视化的“老大哥”。无论你是刚入门的数据分析师还是需要经常出图的科研工作者相信我看完这篇你就能摆脱对画图的恐惧甚至开始享受创造清晰图表的乐趣。Matplotlib是什么简单说它就是Python里用来把数据变成图画的“神笔”。你给它一组数字它就能帮你画出折线图、柱状图、散点图等等。它的强大之处在于从最简单的草图到能直接放进学术论文里的精美图表它都能搞定。很多人一开始觉得它参数多有点难上手但其实只要掌握了几个核心套路就会发现它非常灵活和直观。咱们先解决最紧要的问题安装和导入。如果你用的是pip打开命令行输入pip install matplotlib就行。如果用Anaconda那更简单通常它已经自带了。安装好后在Python脚本的开头我们永远会写下这句“咒语”import matplotlib.pyplot as plt这里的plt是我们给matplotlib.pyplot这个模块起的小名几乎是全世界Python数据分析师的约定俗成用起来特别方便。现在让我们画第一张图。想象一下你记录了一周里每天的最高气温单位摄氏度[16, 18, 17, 13, 11, 11, 13]。你想看看这周的温度趋势。代码简单到不可思议plt.plot([1, 2, 3, 4, 5, 6, 7], [16, 18, 17, 13, 11, 11, 13]) plt.show()对就这两行plt.plot()是画折线图的函数第一个列表是X轴的值星期一到星期天第二个列表是Y轴的值温度。plt.show()则是魔法指令告诉程序“图画好了显示出来吧” 运行后你会弹出一个窗口里面有一条连接七个点的折线。恭喜你你的第一个Matplotlib图形诞生了不过这个默认的图看起来有点“简陋”窗口大小不合适线条也直接顶到了边框。别急这才是我们定制化的开始。在画图之前我们通常先创建一块“画布”设定好它的大小和精度plt.figure(figsize(8, 4), dpi100)figsize控制画布的宽和高单位是英寸(8,4)表示宽8英寸、高4英寸这是一个比较适合放在报告里的横向矩形比例。dpi是“每英寸点数”你可以理解为分辨率dpi100是屏幕显示的常用值如果你要保存为印刷用的高清图片可以调到300甚至更高。把创建画布的代码加上再运行一次。你会发现图像的边框留白更合理了。这就是Matplotlib的工作流先准备画布figure再在上面作画plot最后展示或保存show/save。记住这个流程后面所有的复杂图表都是在这个基础上搭建的。2. 让图表“会说话”添加辅助信息与样式美化画出一条线只是第一步。一个专业的图表必须能清晰地传达信息。这意味着我们需要添加标题、坐标轴标签、刻度、网格线等等让看图的人一眼就知道这是什么数据、代表了什么。我见过太多人做出的图表自己看得懂别人却一头雾水问题就出在这些细节上。让我们给刚才的温度折线图加上“灵魂”。假设X轴是时间20:00到21:00的每一分钟Y轴是温度。我们需要做以下几件事设置中文字体这是中文用户第一个要踩的“坑”。Matplotlib默认不支持中文直接设置会显示成小方框。解决方法很简单在导入plt后加上这几行from pylab import mpl mpl.rcParams[font.sans-serif] [SimHei] # 指定默认字体为黑体 mpl.rcParams[axes.unicode_minus] False # 解决负号‘-’显示为方块的问题当然你也可以指定其他系统里有的中文字体比如‘Microsoft YaHei’微软雅黑。添加标题和轴标签plt.xlabel(“时间”) plt.ylabel(“温度 (℃)”) plt.title(“20:00-21:00室内温度变化趋势”, fontsize16)xlabel和ylabel非常直白。title里的fontsize参数可以调整标题字体大小让重点更突出。自定义刻度默认的刻度可能太密或不符合我们的阅读习惯。比如我们有60个分钟点全部显示就太挤了。x range(60) # 0到59代表60分钟 # 我们想每5分钟显示一个刻度标签 x_ticks list(x)[::5] # 刻度位置[0, 5, 10, ... 55] x_tick_labels [f“20:{i:02d}” for i in x_ticks] # 生成 [“20:00”, “20:05”, ...] plt.xticks(x_ticks, x_tick_labels) # 设置X轴刻度位置和标签plt.xticks()的第一个参数是刻度位置的列表第二个参数是对应位置的标签列表。plt.yticks()用法相同。添加网格线网格线能帮助读者更准确地读取数据点的值。plt.grid(True, linestyle--, alpha0.5)linestyle可以设置线型常用的有‘-‘实线、‘–‘虚线、‘:’点线、‘-.’点划线。alpha是透明度范围0到10.5表示半透明让网格线不那么刺眼起到辅助而不干扰的作用。保存图表图表最终往往要插入报告或PPT中保存为图片文件是必须的。plt.savefig(‘temperature_trend.png’, dpi300, bbox_inches‘tight’)savefig一定要在plt.show()之前调用因为show()之后会清空图表。dpi参数这里再次指定保存的精度。bbox_inches‘tight’是一个神器它能自动裁剪掉图片周围多余的白边让保存的图片紧凑又好看。把这些功能全部组合起来你的图表就从“草稿”升级为“成品”了。我个人的习惯是在调试阶段用plt.show()在窗口查看定稿后注释掉show()直接用savefig保存高清图片。多试试不同的颜色、线型和字体大小找到最适合你应用场景的搭配。记住好的可视化审美和功能同样重要。3. 进阶技巧在同一坐标系中绘制多条曲线实际工作中我们很少只对比一组数据。更多时候我们需要将多组数据放在同一个坐标系中进行对比比如比较两个城市同一时段的气温、对比同一产品不同季度的销量等等。Matplotlib处理这种情况非常优雅核心思想就是多次调用plt.plot()。让我们延续温度的例子这次我们同时绘制“北京”和“上海”某天24小时的气温变化。首先准备数据这里我用随机数模拟import random hours range(24) temp_beijing [random.uniform(5, 15) for _ in hours] # 北京温度在5-15度波动 temp_shanghai [random.uniform(10, 20) for _ in hours] # 上海温度在10-20度波动现在在一个坐标系里画出两条线plt.figure(figsize(10, 5)) plt.plot(hours, temp_beijing, label‘北京’) plt.plot(hours, temp_shanghai, label‘上海’) plt.legend() # 显示图例 plt.show()运行代码你会看到两条不同颜色的线。Matplotlib会自动为不同的plot调用分配不同的颜色。但是如果我们需要打印黑白图表或者想指定特定的颜色和线型来区分就需要手动设置plot的参数。颜色与线型plot函数可以通过color和linestyle参数进行详细定制。plt.plot(hours, temp_beijing, color‘blue’, linestyle‘-’, linewidth2, label‘北京’) plt.plot(hours, temp_shanghai, color‘red’, linestyle‘--’, linewidth1.5, label‘上海’)color可以用颜色英文单词‘red’ ‘green’ ‘blue’也可以用简写‘r’ ‘g’ ‘b’或者更强大的十六进制颜色码‘#FF5733’。linestyle‘-‘实线‘–‘虚线‘:’点线‘-.’点划线。linewidth控制线条粗细。图例Legend当有多条线时图例是必不可少的。注意必须在plot时通过label参数为每条线命名然后调用plt.legend()来显示图例。legend()函数本身也有很多玩法plt.legend(loc‘upper right’, fontsize‘medium’, frameonFalse)loc图例位置。可以用字符串如‘best’自动找最佳位置、‘upper left’也可以用数字代码0-10。fontsize控制图例字体大小。frameon设为False可以去掉图例的边框让图表看起来更简洁。标记数据点Marker如果你的数据点较少或者你想突出显示每个样本的位置可以加上标记。plt.plot(hours, temp_beijing, ‘o-’, label‘北京’) # ‘o-’ 表示圆形标记和实线这里用了缩写格式字符串‘o-‘它同时指定了标记marker、线型linestyle和颜色color。常见的标记有‘o’圆点、‘s’方块、‘^’三角形、‘D’菱形。把城市温度对比图的所有元素都加上你的代码看起来应该很完整了。通过调整颜色、线型和标记即使是在黑白印刷物上读者也能清晰地区分不同的数据系列。这是数据分析报告专业性的重要体现。我个人的经验是在正式报告中尽量使用颜色对比鲜明但又不刺眼的搭配比如深蓝和暗红并确保图例说明清晰无误。4. 构建复杂布局使用subplots创建多个坐标系有时候我们不想把所有曲线都挤在一个图里。比如你想并排展示四个季度的销售数据或者上下对比同一指标在不同年份的表现。这时候就需要用到plt.subplots()函数来创建包含多个坐标系的画布。这是从“画一张图”到“设计一个仪表板”的关键一步。plt.subplots()的核心参数是nrows和ncols分别指定子图的行数和列数。它返回两个对象一个是整个**图形Figure对象fig另一个是包含所有坐标系Axes**对象的数组axes。理解这两个概念很重要Figure图形可以理解为最大的画布或画纸。Axes坐标系是画布上一个个具体的绘图区域每个Axes都有自己的X轴、Y轴、标题等。我们来创建一个1行2列的子图布局分别绘制北京和上海的24小时温度fig, axes plt.subplots(nrows1, ncols2, figsize(14, 5), dpi100)这行代码创建了一个画布fig上面并排摆了2个坐标系。axes是一个一维数组axes[0]是左边的图axes[1]是右边的图。如果创建的是2行2列nrows2, ncols2那么axes就是一个2x2的二维数组需要通过axes[0, 0]、axes[0, 1]等方式来访问。接下来我们分别在两个坐标系上绘图。注意方法从面向过程的plt.xxx()变成了面向对象的axes.xxx()# 在第一个坐标系左图画北京温度 axes[0].plot(hours, temp_beijing, color‘b’, label‘北京’) axes[0].set_xlabel(‘时间 (小时)’) axes[0].set_ylabel(‘温度 (℃)’) axes[0].set_title(‘北京市24小时温度变化’) axes[0].legend() axes[0].grid(True, alpha0.3) # 在第二个坐标系右图画上海温度 axes[1].plot(hours, temp_shanghai, color‘r’, label‘上海’) axes[1].set_xlabel(‘时间 (小时)’) axes[1].set_ylabel(‘温度 (℃)’) axes[1].set_title(‘上海市24小时温度变化’) axes[1].legend() axes[1].grid(True, alpha0.3) # 调整子图之间的间距避免标题和标签重叠 plt.tight_layout() plt.savefig(‘two_cities_temperature.png’) plt.show()看到区别了吗设置标题不再是plt.title()而是axes[0].set_title()。所有针对特定坐标系的操作都要通过对应的axes对象来完成。plt.tight_layout()是一个自动调整子图参数如间距的函数强烈建议在子图较多时使用它能省去你手动调整边距的麻烦。subplots函数还有更多高级参数可以玩转布局。比如sharexTrue或shareyTrue可以让所有子图共享同一个X轴或Y轴刻度这在对比数据时非常有用能让读者一眼看出尺度差异。再比如你可以通过subplot_kw参数为每个子图传递一些通用设置。当你需要制作包含折线图、柱状图、饼图等多种图表类型的综合仪表板时subplots提供的这种网格化布局能力就是你的王牌工具。5. 探索更多图表类型散点图、柱状图与直方图折线图看趋势但数据世界丰富多彩我们需要不同的“镜头”来观察。Matplotlib内置了数十种图表类型最常用的除了折线图就是散点图、柱状图和直方图。掌握这几种就能应对90%的可视化场景。散点图Scatter Plot用于观察两个变量之间的关系比如身高和体重、广告投入和销售额。它擅长揭示相关性、聚类和异常值。# 模拟学生数学和物理成绩 math_scores [85, 72, 90, 65, 88, 70, 95, 60] physics_scores [82, 70, 88, 60, 85, 68, 92, 55] plt.figure(figsize(8, 6)) plt.scatter(math_scores, physics_scores, c‘green’, alpha0.7, edgecolors‘black’, s100) # c: 颜色 alpha: 点透明度 edgecolors: 边缘颜色 s: 点的大小 plt.xlabel(‘数学成绩’) plt.ylabel(‘物理成绩’) plt.title(‘学生数学与物理成绩散点图’) plt.grid(True, linestyle‘:’, alpha0.4) plt.show()plt.scatter()比plot更适合画散点因为它可以方便地控制每个点的大小s、颜色c甚至可以是一个数组根据数值映射颜色和透明度alpha。从这张图里你很容易看出数学和物理成绩呈正相关趋势。柱状图Bar Chart用于比较不同类别的数据大小比如不同产品的销量、各月份的收入。# 模拟某公司上半年各产品销量 products [‘产品A’, ‘产品B’, ‘产品C’, ‘产品D’, ‘产品E’] sales [120, 95, 150, 80, 200] plt.figure(figsize(10, 6)) bars plt.bar(products, sales, color[‘skyblue’, ‘lightgreen’, ‘salmon’, ‘gold’, ‘violet’]) plt.xlabel(‘产品名称’) plt.ylabel(‘销量 (万件)’) plt.title(‘上半年各产品销量对比’) # 在柱子上方显示具体数值 for bar in bars: height bar.get_height() plt.text(bar.get_x() bar.get_width()/2., height 3, f’{height}’, ha‘center’, va‘bottom’) plt.ylim(0, max(sales)*1.2) # 设置Y轴范围为顶部文字留出空间 plt.show()plt.bar()绘制垂直柱状图plt.barh()则绘制水平柱状图。给柱子添加数据标签是一个提升图表可读性的好习惯上面用plt.text()循环实现的正是这个功能。ha和va分别控制文本的水平对齐和垂直对齐方式。直方图Histogram用于展示数值型数据的分布情况比如一群人的年龄分布、一次考试的成绩分布。它会把数据划分到多个连续的区间称为“箱子”或“bin”然后统计每个区间里有多少个数据点。import numpy as np # 模拟生成1000个服从正态分布的成绩数据 np.random.seed(42) # 固定随机种子确保每次运行结果一致 scores np.random.normal(loc75, scale10, size1000) # 平均分75标准差10 plt.figure(figsize(10, 6)) plt.hist(scores, bins30, color‘steelblue’, edgecolor‘black’, alpha0.7) # bins: 将数据分成多少组 edgecolor: 柱子边缘颜色 plt.xlabel(‘考试分数’) plt.ylabel(‘学生人数’) plt.title(‘1000名学生考试成绩分布直方图’) plt.grid(True, axis‘y’, alpha0.3) # 只显示横向网格线 plt.show()plt.hist()的bins参数是关键。bins数量太少分布会过于粗糙太多则图形会显得破碎。需要根据数据量和分布特点来调整。从这张图可以清晰看出大部分学生的成绩集中在平均分75分左右呈现出经典的“钟形”正态分布曲线。直方图是探索数据底层分布规律不可或缺的工具。6. 高级定制与实战案例绘制函数图像与组合图表当你熟悉了基本图表后就可以挑战一些更高级的应用了。比如用Matplotlib绘制数学函数图像或者将多种图表类型组合在一张图中以传达更丰富的信息。绘制函数图像这是Matplotlib的“老本行”结合NumPy库非常方便。假设我们想画出正弦函数y sin(x)在区间[-2π, 2π]上的图像。import numpy as np x np.linspace(-2*np.pi, 2*np.pi, 1000) # 在-2π到2π之间生成1000个均匀的点 y np.sin(x) plt.figure(figsize(12, 6)) plt.plot(x, y, ‘b-’, linewidth2, label‘y sin(x)’) plt.axhline(y0, color‘k’, linestyle‘-’, linewidth0.5) # 画出y0的黑色参考线 plt.axvline(x0, color‘k’, linestyle‘-’, linewidth0.5) # 画出x0的黑色参考线 plt.xlabel(‘x’) plt.ylabel(‘sin(x)’) plt.title(‘正弦函数图像’) plt.legend() plt.grid(True, alpha0.3) # 设置X轴刻度为π的倍数 xticks [-2*np.pi, -np.pi, 0, np.pi, 2*np.pi] xtick_labels [‘-2π’, ‘-π’, ‘0’, ‘π’, ‘2π’] plt.xticks(xticks, xtick_labels) plt.show()这里的关键是np.linspace生成了足够密集的采样点使得画出来的曲线非常光滑。plt.axhline()和plt.axvline()用于添加水平和垂直的参考线在函数图像中标注坐标轴非常有用。自定义X轴刻度为π的倍数也让图像更具数学美感。组合图表实战在一个坐标系里混合使用折线图和柱状图可以同时展示趋势和具体数值。例如展示一家公司各季度的营收柱状图和利润率折线图使用右侧Y轴。# 模拟数据 quarters [‘Q1’, ‘Q2’, ‘Q3’, ‘Q4’] revenue [520, 480, 610, 730] # 营收单位万元 profit_rate [0.15, 0.12, 0.18, 0.22] # 利润率 fig, ax1 plt.subplots(figsize(10, 6)) # 左侧Y轴绘制营收柱状图 color_bar ‘tab:blue’ ax1.set_xlabel(‘季度’) ax1.set_ylabel(‘营收 (万元)’, colorcolor_bar) bars ax1.bar(quarters, revenue, colorcolor_bar, alpha0.7, label‘营收’) ax1.tick_params(axis‘y’, labelcolorcolor_bar) # 在柱顶添加数据标签 for bar in bars: height bar.get_height() ax1.text(bar.get_x() bar.get_width()/2., height 10, f’{height}’, ha‘center’, va‘bottom’, colorcolor_bar) # 创建共享X轴的第二Y轴 ax2 ax1.twinx() color_line ‘tab:red’ ax2.set_ylabel(‘利润率’, colorcolor_line) ax2.plot(quarters, profit_rate, colorcolor_line, marker‘o’, linewidth2, label‘利润率’) ax2.tick_params(axis‘y’, labelcolorcolor_line) # 设置利润率Y轴范围为0到0.3更美观 ax2.set_ylim(0, 0.3) # 合并图例需要分别从两个轴获取句柄和标签 lines_1, labels_1 ax1.get_legend_handles_labels() lines_2, labels_2 ax2.get_legend_handles_labels() ax1.legend(lines_1 lines_2, labels_1 labels_2, loc‘upper left’) plt.title(‘2023年公司季度营收与利润率’) fig.tight_layout() plt.show()这个案例用到了几个高级技巧双Y轴通过ax1.twinx()创建一个与ax1共享X轴的新坐标系ax2。ax2的Y轴在右侧用于表示利润率。区分颜色两个Y轴及其刻度标签、数据系列使用了不同的颜色‘tab:blue’ 和 ‘tab:red’通过tick_params设置避免混淆。合并图例由于数据系列分布在两个坐标系中我们需要手动获取它们的图例句柄和标签然后合并显示在一个图例里。这种组合图表能在一张图上呈现两个量纲不同但密切相关的指标信息密度很高是商业分析报告中非常受欢迎的样式。多练习几次你就能根据自己想要表达的故事灵活组合各种图形元素了。画图的最高境界不是炫技而是让数据自己开口讲故事。