1. 从数据到洞察为什么你需要掌握Matplotlib如果你已经用Python处理过一些数据无论是用Pandas清洗了表格还是用NumPy做了些计算你可能会发现面对一堆冰冷的数字你很难快速理解它们背后的故事。数据本身是沉默的而可视化就是让数据开口说话的语言。Matplotlib作为Python生态中历史最悠久、功能最强大的绘图库就是这门语言的“标准发音”。我刚开始接触数据分析时也经历过这个阶段辛辛苦苦算出了均值、方差、回归系数但给同事或老板看时对方往往一脸茫然。直到我把这些数字变成一张清晰的折线图、一个直观的柱状图整个数据的趋势、对比和异常才瞬间变得一目了然。Matplotlib不仅仅是“画图工具”它是你分析思维的延伸是将复杂结论进行高效沟通的桥梁。无论你是学生需要完成课题报告是工程师要监控系统指标还是分析师需要呈现业务洞察从简单的数据探索到复杂的学术出版级图表Matplotlib几乎都能胜任。它的学习曲线前期可能稍显陡峭尤其是其略显复杂的两种接口风格面向对象的plt.subplots和基于状态的plt.plot常常让新手困惑。但一旦掌握了其核心逻辑和几个关键“套路”你就会发现它的强大与灵活。本篇总结不会面面俱到地罗列所有API而是聚焦于我多年使用中总结出的最核心、最高频、最易错的知识点目标是让你能用最短的时间画出“专业”的图表避开我当年踩过的那些坑。2. 核心架构与两种绘图哲学理解“状态”与“对象”Matplotlib的设计哲学是它一切复杂性的根源也是其强大灵活性的基础。很多初学者照着教程画出了第一张图但稍微想修改或组合图表时就寸步难行根本原因在于没理解其底层架构。2.1 两种接口风格快速脚本与精细控制Matplotlib提供了两种主要的使用方式我习惯称它们为“快速脚本式”和“精细控制式”。快速脚本式Pyplot / 基于状态这是我们最常见、入门教程最常用的方式它源自MATLAB的风格。import matplotlib.pyplot as plt import numpy as np x np.linspace(0, 10, 100) y np.sin(x) plt.figure(figsize(8, 5)) # 创建一个图形 plt.plot(x, y, labelsin(x), colorblue, linewidth2) # 在当前图形和坐标轴上绘图 plt.title(A Simple Sine Wave) plt.xlabel(X Axis) plt.ylabel(Y Axis) plt.legend() plt.grid(True, linestyle--, alpha0.5) plt.show()这种方式非常直观plt.plot()、plt.xlabel()这些函数仿佛在操作一个“当前活跃的”图表和坐标轴。Matplotlib在背后帮你维护了一个“状态机”记录当前正在操作的图形Figure和坐标轴Axes。对于简单的、一次性的绘图这种方式写起来很快。注意这种方式的弊端在需要绘制多子图Subplots或对图表元素进行复杂、精细的后置调整时就会暴露。因为你很难精确地指定要修改的是哪个具体的坐标轴对象代码逻辑会变得隐晦且容易出错。精细控制式面向对象 / OO这是更被推荐的、尤其是用于构建复杂图表或封装成函数的方法。它显式地创建并引用图形和坐标轴对象。import matplotlib.pyplot as plt import numpy as np # 显式创建图形和坐标轴对象 fig, ax plt.subplots(figsize(8, 5)) # fig是图形容器ax是坐标轴对象 x np.linspace(0, 10, 100) y np.sin(x) # 所有绘图和设置都通过ax对象进行 ax.plot(x, y, labelsin(x), colorblue, linewidth2) ax.set_title(A Simple Sine Wave (OO Style)) ax.set_xlabel(X Axis) ax.set_ylabel(Y Axis) ax.legend() ax.grid(True, linestyle--, alpha0.5) plt.show() # 显示图形这个函数两种风格通用关键就在于fig, ax plt.subplots()这一行。fig代表整个画布Figure你可以把它想象成一张空白的纸或一个相框。ax代表这张纸上的一个坐标系Axes一张纸上可以有多个坐标系子图。之后所有的绘图命令plot,scatter、设置标题set_title、设置坐标轴标签set_xlabel等都通过调用ax对象的方法来完成。这种方式代码意图清晰对象引用明确非常适合构建复杂可视化。我的选择建议对于在Jupyter Notebook中进行快速数据探索你可以混用两种风格。但对于任何你打算保存、复用或可能变得复杂的脚本从一开始就使用面向对象风格。这会让你的代码更健壮后期维护成本大大降低。2.2 核心对象层级Figure, Axes, Axis, Artist理解Matplotlib的对象模型能让你真正驾驭它Figure图形顶级容器相当于画布。可以设置画布大小figsize、DPI分辨率、背景色等。一个Figure可以包含多个Axes。Axes坐标轴这是绝大多数绘图动作发生的地方。一个Axes包含两个2D图或三个3D图Axis对象以及数据表示的绘图区域如线、点、柱。我们常说的“一个子图”通常就是指一个Axes对象。ax.plot()就是在Axes上画线。Axis轴代表坐标轴控制刻度Tick、刻度标签Tick Label、轴线Spine的显示和范围。Artist艺术家几乎所有在图形上能看到的东西都是一个Artist对象Figure、Axes、Axis、Line2D线、Text文本、Rectangle矩形等。这为我们提供了极其精细的控制能力。当你调用ax.plot()时它创建了一个Line2D艺术家对象并将其添加到ax中。ax.set_xlabel()创建了一个Text对象。这种层级关系意味着你可以通过ax.get_children()查看Axes的所有子艺术家也可以直接获取某个特定的线条对象来修改其属性。3. 核心绘图类型与实战参数解析掌握了基本架构我们来看看如何用Matplotlib绘制最常见的几种图表。这里的关键不是记住所有参数而是理解每个参数如何影响图表的信息传达效果。3.1 折线图趋势展示的基石折线图用于展示数据随时间或其他连续变量的变化趋势。fig, ax plt.subplots(figsize(10, 6)) # 示例数据模拟两种产品随时间月的销量 months np.arange(1, 13) product_a [20, 22, 25, 28, 30, 33, 35, 34, 32, 30, 28, 26] product_b [15, 18, 22, 25, 28, 30, 31, 29, 27, 24, 21, 19] # 绘制两条折线 line_a, ax.plot(months, product_a, markero, linestyle-, linewidth2, color#2E86AB, labelProduct A) line_b, ax.plot(months, product_b, markers, linestyle--, linewidth2, color#A23B72, labelProduct B) # 关键参数解析 # marker: 数据点标记。o圆点s方块^上三角*星号无标记。 # linestyle: 线型。-实线--虚线-.点划线:点线。 # linewidth (lw): 线宽。数字越大线越粗。 # color: 颜色。支持英文名、十六进制码如#FF5733、RGB元组。 # label: 图例标签。需配合 ax.legend() 显示。 ax.set_title(Monthly Sales Trend (2023), fontsize14, fontweightbold) ax.set_xlabel(Month, fontsize12) ax.set_ylabel(Sales (k units), fontsize12) ax.set_xticks(months) # 明确设置x轴刻度位置 ax.set_xticklabels([fM{i} for i in months], rotation45) # 设置刻度标签并旋转 ax.legend(locupper left, frameonTrue, shadowTrue) # 添加图例 ax.grid(True, axisy, linestyle:, alpha0.7) # 只显示y轴网格线 # 添加数值标注一个实用技巧 for x, y in zip(months, product_a): ax.text(x, y0.5, f{y}, hacenter, vabottom, fontsize9, color#2E86AB) for x, y in zip(months, product_b): ax.text(x, y-0.8, f{y}, hacenter, vatop, fontsize9, color#A23B72) plt.tight_layout() # 自动调整子图参数使图形元素不重叠 plt.show()实操心得plt.tight_layout()是你的好朋友。在图表元素标题、标签、刻度较多或子图复杂时调用它可以自动调整布局避免重叠。通常在plt.show()或fig.savefig()前调用。直接使用颜色名称如red,blue虽然方便但图表多了容易单调且不专业。推荐使用十六进制颜色码或Matplotlib的tab10、Set2等色彩映射Colormap中的颜色视觉上更协调。例如colorplt.cm.tab10(0)。为折线添加数据点标记marker能让读者更清晰地定位具体数值尤其在数据点较少时。但数据点非常密集时建议去掉标记或使用更小的标记尺寸markersize。3.2 散点图与气泡图相关性与分布探索散点图用于研究两个连续变量之间的关系气泡图则通过点的大小引入第三个维度。fig, (ax1, ax2) plt.subplots(1, 2, figsize(14, 6)) # 创建1行2列的子图 # 示例数据身高、体重、年龄 np.random.seed(42) n 50 height np.random.normal(170, 8, n) # 均值170cm标准差8 weight height * 0.5 np.random.normal(0, 10, n) # 体重与身高粗略相关 age np.random.randint(18, 35, n) income np.random.lognormal(10, 0.3, n) # 模拟收入第三个维度 # 子图1基本散点图 scatter1 ax1.scatter(height, weight, cage, cmapviridis, alpha0.7, edgecolorsw, linewidth0.5) ax1.set_title(Height vs. Weight (Color by Age), fontsize12) ax1.set_xlabel(Height (cm)) ax1.set_ylabel(Weight (kg)) # 添加颜色条 cbar1 fig.colorbar(scatter1, axax1) cbar1.set_label(Age) # 子图2气泡图用点大小表示收入 # 将收入数据归一化到合适的点大小范围例如 20 到 500 size_min, size_max 20, 500 income_norm (income - income.min()) / (income.max() - income.min()) sizes size_min income_norm * (size_max - size_min) scatter2 ax2.scatter(height, weight, ssizes, cage, cmapplasma, alpha0.6, edgecolorsk, linewidth0.5) ax2.set_title(Height vs. Weight (Bubble by Income, Color by Age), fontsize12) ax2.set_xlabel(Height (cm)) ax2.set_ylabel(Weight (kg)) # 为气泡图创建图例需要手动模拟 for income_val in [np.percentile(income, 25), np.percentile(income, 50), np.percentile(income, 75)]: size_val size_min ((income_val - income.min()) / (income.max() - income.min())) * (size_max - size_min) ax2.scatter([], [], ssize_val, cgray, alpha0.6, edgecolorsk, labelf{income_val:.0f}k) ax2.legend(titleIncome, locupper left, frameonTrue) plt.tight_layout() plt.show()关键参数解析c: 数据点的颜色。可以是一个单一颜色字符串也可以是一个与数据点等长的数值序列此时颜色由数值通过色彩映射cmap决定。cmap: 色彩映射。viridis,plasma,coolwarm,RdYlBu等都是很好的选择。对于顺序数据如年龄使用顺序色彩映射对于分类数据使用定性色彩映射如tab10。s: 数据点的大小。可以是标量所有点一样大或与数据点等长的序列气泡图。alpha: 透明度范围0到1。在点重叠时非常有用可以显示密度。edgecolors: 点的边缘颜色。设置为w白色或k黑色可以让点在复杂背景下更清晰。注意事项创建气泡图的图例比较麻烦因为scatter的s参数是序列时不会自动生成图例。上面的代码演示了一种手动创建图例的方法。气泡图容易因点的大小重叠造成视觉误导需谨慎使用并确保大小差异能准确反映数据差异。3.3 柱状图与直方图分类比较与分布观察柱状图用于比较不同类别的数值直方图用于展示单个连续变量的分布。fig, (ax1, ax2) plt.subplots(1, 2, figsize(14, 6)) # 子图1分组柱状图 categories [Q1, Q2, Q3, Q4] sales_2022 [120, 135, 158, 190] sales_2023 [130, 145, 170, 210] x np.arange(len(categories)) # 类别的位置索引 width 0.35 # 柱子的宽度 bars1 ax1.bar(x - width/2, sales_2022, width, label2022, colorskyblue, edgecolorblack, hatch/) bars2 ax1.bar(x width/2, sales_2023, width, label2023, colorlightcoral, edgecolorblack, hatch\\) ax1.set_title(Quarterly Sales Comparison, fontsize13) ax1.set_xlabel(Quarter) ax1.set_ylabel(Sales (k units)) ax1.set_xticks(x) ax1.set_xticklabels(categories) ax1.legend() # 在柱子上方添加数值标签 def autolabel(bars): for bar in bars: height bar.get_height() ax1.annotate(f{height}, xy(bar.get_x() bar.get_width() / 2, height), xytext(0, 3), # 垂直偏移 textcoordsoffset points, hacenter, vabottom, fontsize10) autolabel(bars1) autolabel(bars2) # 子图2直方图与密度曲线 np.random.seed(123) data np.concatenate([np.random.normal(60, 10, 500), np.random.normal(90, 5, 300)]) # 双峰分布 # 绘制直方图 n, bins, patches ax2.hist(data, bins30, densityTrue, alpha0.7, colorsteelblue, edgecolorblack, labelHistogram) # 绘制核密度估计曲线 from scipy.stats import gaussian_kde kde gaussian_kde(data) x_kde np.linspace(data.min(), data.max(), 1000) ax2.plot(x_kde, kde(x_kde), colordarkred, linewidth2.5, labelKDE) ax2.set_title(Distribution of Scores with KDE, fontsize13) ax2.set_xlabel(Score) ax2.set_ylabel(Density) ax2.legend() ax2.grid(True, axisy, alpha0.3) plt.tight_layout() plt.show()柱状图要点bar函数接收x坐标通常是类别索引和高度。分组时需要手动计算每组柱子的位置x - width/2,x width/2。hatch参数可以设置柱子的填充图案如/,\\,|,-,x,o在黑白打印或区分相似颜色时非常有用。使用annotate或text为柱子添加数据标签能极大提升图表的可读性。直方图要点bins参数至关重要。太少会丢失细节太多会产生噪音。可以传递一个整数等宽区间数也可以传递一个序列指定每个区间的边界。auto,fd,sturges等是自动计算的方法。densityTrue会将纵坐标归一化为“密度”使得直方图总面积积分为1便于与概率密度函数如上面的KDE曲线叠加比较。结合核密度估计KDE可以更平滑地展示数据分布形状尤其适用于探索性数据分析。4. 图表的美化与自定义从“能看”到“好看”默认的Matplotlib图表风格比较基础。花一点时间进行美化能让你的图表在报告或演示中脱颖而出。4.1 全局样式设置一键切换专业风格Matplotlib提供了多种预定义的样式表Style Sheets可以一次性改变颜色、字体、线宽等所有视觉元素。# 查看所有可用样式 print(plt.style.available) # 应用样式在创建图形之前 plt.style.use(seaborn-v0_8-darkgrid) # 我常用的一个带网格线颜色鲜艳 # 其他推荐seaborn-v0_8-whitegrid, ggplot, fivethirtyeight, seaborn-v0_8-poster用于海报 fig, ax plt.subplots(figsize(8,5)) x np.linspace(0, 2*np.pi, 100) for i in range(5): ax.plot(x, np.sin(x i*0.5), lw2, labelfPhase shift {i*0.5:.1f}) ax.set_title(Styled Plot with Multiple Lines) ax.set_xlabel(X) ax.set_ylabel(Y) ax.legend() plt.tight_layout() plt.show()使用样式表是快速提升图表美观度的最有效方法。你可以选择一个最喜欢的作为项目默认样式。4.2 坐标轴与刻度的精细控制坐标轴是图表的骨架精细调整能让数据呈现更清晰。fig, ax plt.subplots(figsize(9, 6)) x np.linspace(0.1, 10, 200) y x ** 2 ax.plot(x, y, lw2.5) # 1. 设置坐标轴范围 ax.set_xlim([0, 12]) ax.set_ylim([-10, 120]) # 故意留出一些空间 # 2. 设置刻度位置和标签 ax.set_xticks([0, 2, 4, 6, 8, 10, 12]) ax.set_xticklabels([Zero, Two, Four, Six, Eight, Ten, Twelve], rotation30, fontsize10) ax.set_yticks([0, 25, 50, 75, 100]) # 使用格式化字符串设置刻度标签 ax.set_yticklabels([0, 25, 50, 75, 100]) # 3. 设置对数坐标轴对于指数增长数据非常有用 # ax.set_xscale(log) # ax.set_yscale(log) # 4. 设置坐标轴标签和标题的字体属性 ax.set_xlabel(Independent Variable (X), fontsize12, fontweightsemibold, labelpad10) # labelpad增加标签与轴的距离 ax.set_ylabel(Dependent Variable (Y), fontsize12, fontweightsemibold) ax.set_title(Customizing Axes and Ticks in Detail, fontsize14, fontweightbold, pad15) # 5. 调整坐标轴线Spines ax.spines[top].set_visible(False) # 隐藏顶部轴线 ax.spines[right].set_visible(False) # 隐藏右侧轴线 # ax.spines[left].set_position((outward, 10)) # 将左侧轴线向外移动10点 # ax.spines[bottom].set_position((outward, 10)) # 6. 添加水平/垂直参考线 ax.axhline(y50, colorgray, linestyle:, linewidth1, alpha0.7) # 水平线 ax.axvline(x5, colorgray, linestyle:, linewidth1, alpha0.7) # 垂直线 # 填充区域 ax.fill_between(x, y10, y220, colorgreen, alpha0.2, labelLow Region) ax.fill_between(x, y180, y2120, colorred, alpha0.2, labelHigh Region) ax.legend(locupper left) plt.tight_layout() plt.show()实操心得隐藏顶部和右侧的轴线spines是现代简洁图表风格的常见做法。axhline和axvline是添加阈值线、基准线的利器。fill_between则非常适合用于标注置信区间、目标范围或异常区域。对于跨越多个数量级的数据如微生物数量、金融收益率务必考虑使用对数坐标轴set_xscale(log)它能将指数增长转化为线性关系更便于观察。4.3 图例、注释与文本的艺术清晰的图例和恰到好处的注释能直接提升图表的叙事能力。fig, ax plt.subplots(figsize(10, 6)) x np.linspace(0, 4*np.pi, 200) line1, ax.plot(x, np.sin(x), b-, lw2, labelSine Wave) line2, ax.plot(x, np.cos(x), r--, lw2, labelCosine Wave) line3, ax.plot(x, 0.5*np.sin(2*x), g:, lw3, labelFast Sine) # 1. 高级图例设置 legend ax.legend(locupper right, # 位置best, upper left, lower center等 frameonTrue, # 是否有边框 shadowTrue, # 阴影 fancyboxTrue, # 圆角边框 framealpha0.9, # 边框透明度 edgecolorblack, # 边框颜色 titleWave Types, # 图例标题 title_fontsize11, fontsize10, ncol1) # 图例列数水平排列时可设为1 # 2. 添加指向性注释箭头 # 找到sin(x)的第一个峰值点 peak_idx np.argmax(np.sin(x)) peak_x, peak_y x[peak_idx], np.sin(x)[peak_idx]) ax.annotate(First Peak of sin(x), xy(peak_x, peak_y), # 箭头指向的点 xytext(peak_x2, peak_y-0.2), # 文本起始位置 arrowpropsdict(arrowstyle-, connectionstylearc3,rad.2, colorblue, lw1.5), fontsize11, hacenter) # 3. 添加无箭头文本注释 ax.text(2, 0.8, Phase Difference\nBetween Waves, # \n可以换行 styleitalic, bbox{boxstyle: round, facecolor: wheat, alpha: 0.8, pad: 0.6}, fontsize10, hacenter) # 4. 在图形内部添加图形如矩形、椭圆 from matplotlib.patches import Rectangle, Circle rect Rectangle((5, -0.8), 3, 0.6, linewidth1.5, edgecolorpurple, facecolornone, linestyle--) ax.add_patch(rect) ax.text(6.5, -0.5, Zoom-in Area, colorpurple, hacenter) circle Circle((10, 0), radius0.15, colororange, alpha0.4) ax.add_patch(circle) ax.set_title(Mastering Legends and Annotations, fontsize14) ax.set_xlabel(Phase (radians)) ax.set_ylabel(Amplitude) ax.grid(True, alpha0.3) plt.tight_layout() plt.show()注意事项annotate的xytext参数决定了文本框的位置arrowprops字典则详细控制了箭头的样式。connectionstyle可以创建弯曲的箭头避免穿过其他图表元素。text函数更简单适合不需要箭头的纯文本标注。bbox参数可以为文本添加一个背景框使其在复杂的图表背景上更清晰。直接使用add_patch添加Rectangle,Circle,Ellipse,Arrow等图形对象是进行高级图表标注的强力手段。5. 多子图与复杂布局构建仪表板视图将多个相关图表组织在一个图形中是进行数据对比和综合展示的常用方式。5.1 使用plt.subplots创建规则网格这是创建多子图最直接、最常用的方法。# 创建一个2行3列的图形网格并共享x轴和y轴 fig, axs plt.subplots(nrows2, ncols3, figsize(15, 10), sharexTrue, shareyTrue, constrained_layoutTrue) # axs 是一个2x3的numpy数组每个元素是一个Axes对象 # constrained_layoutTrue 是比 tight_layout 更现代的自动布局管理器推荐使用 # 生成一些示例数据 x np.linspace(0, 2*np.pi, 100) functions [np.sin, np.cos, np.tan, np.sinh, np.cosh, lambda x: np.exp(-x)*np.sin(5*x)] titles [sin(x), cos(x), tan(x), sinh(x), cosh(x), Damped Oscillation] for i, ax in enumerate(axs.flat): # 使用 .flat 进行迭代 if i len(functions): y functions[i](x) # 对tan函数处理无穷大值否则图会变形 if titles[i] tan(x): y np.clip(y, -10, 10) # 将值限制在[-10, 10]之间 ax.axhline(y0, colorblack, linewidth0.5, alpha0.5) ax.axvline(xnp.pi/2, colorred, linestyle:, alpha0.7, labelAsymptote) ax.axvline(x3*np.pi/2, colorred, linestyle:, alpha0.7) ax.plot(x, y, lw2) ax.set_title(titles[i], fontsize11) ax.grid(True, alpha0.3) if i 3: # 只有底部一行显示x轴标签 ax.set_xlabel(x) if i % 3 0: # 只有第一列显示y轴标签 ax.set_ylabel(f(x)) if titles[i] tan(x): ax.legend(fontsize9) # 为整个图形添加一个总标题 fig.suptitle(Common Mathematical Functions, fontsize16, fontweightbold, y1.02) plt.show()关键技巧sharexTrue和shareyTrue可以让子图共享坐标轴节省空间且便于比较。共享后只需设置最外侧子图的标签即可。constrained_layoutTrue参数在创建图形时启用它能自动调整子图间的间距和图形边缘通常比最后调用plt.tight_layout()效果更好、更可控。使用axs.flat可以方便地遍历所有子图坐标轴即使是不规则的子图布局通过gridspec创建。5.2 使用GridSpec实现复杂的不规则布局当需要创建大小不一、跨行跨列的子图时GridSpec是终极武器。import matplotlib.gridspec as gridspec fig plt.figure(figsize(12, 8)) # 定义一个3行3列的网格 gs gridspec.GridSpec(3, 3, figurefig, height_ratios[1, 2, 1], width_ratios[2, 1, 1]) # 创建子图通过切片指定位置 ax_main fig.add_subplot(gs[0:2, 0:2]) # 占据前两行前两列左上角大图 ax_right fig.add_subplot(gs[0:2, 2]) # 占据前两行第三列右侧长条图 ax_bottom_left fig.add_subplot(gs[2, 0]) # 占据第三行第一列 ax_bottom_mid fig.add_subplot(gs[2, 1]) # 占据第三行第二列 ax_bottom_right fig.add_subplot(gs[2, 2]) # 占据第三行第三列 # 在主图ax_main中绘制 x_main np.random.randn(500) y_main np.random.randn(500) colors_main np.arctan2(y_main, x_main) # 用一个与位置相关的值作为颜色 ax_main.scatter(x_main, y_main, ccolors_main, cmaphsv, alpha0.6, s20, edgecolorsnone) ax_main.set_title(Main Scatter Plot (Relationship), fontsize13) ax_main.set_xlabel(Feature X) ax_main.set_ylabel(Feature Y) ax_main.grid(True, alpha0.3) # 在右侧ax_right绘制Y的分布直方图 ax_right.hist(y_main, bins30, orientationhorizontal, colorskyblue, edgecolorblack, alpha0.7) ax_right.set_title(Distribution of Y, fontsize11) ax_right.set_xlabel(Count) ax_right.grid(True, axisx, alpha0.3) ax_right.sharey(ax_main) # 与主图共享Y轴 # 在底部三个小图中绘制X的分布和统计 ax_bottom_left.hist(x_main, bins30, colorlightcoral, edgecolorblack, alpha0.7) ax_bottom_left.set_title(Distribution of X, fontsize11) ax_bottom_left.set_xlabel(X Value) ax_bottom_left.set_ylabel(Count) ax_bottom_left.grid(True, alpha0.3) ax_bottom_mid.boxplot([x_main, y_main], labels[X, Y], patch_artistTrue, boxpropsdict(facecolorlightgreen)) ax_bottom_mid.set_title(Box Plot Comparison, fontsize11) ax_bottom_mid.grid(True, axisy, alpha0.3) ax_bottom_right.pie([np.sum(x_main0), np.sum(x_main0)], labels[X0, X0], autopct%1.1f%%, colors[gold, lightblue], explode(0.05, 0)) ax_bottom_right.set_title(Proportion of X Sign, fontsize11) fig.suptitle(Dashboard: Multi-View Data Analysis, fontsize15, fontweightbold) plt.tight_layout() plt.show()GridSpec核心概念height_ratios和width_ratios参数控制各行和各列的相对高度和宽度。通过gs[row_start:row_end, col_start:col_end]这样的切片语法来定义子图占据的网格区域。索引从0开始遵循Python的切片规则左闭右开。这种布局方式非常适合创建包含主图、侧边栏、底部状态栏的仪表板式图表。6. 保存与导出生成高质量的图片文件画出满意的图表后最后一步就是将其保存为文件。6.1 基本保存与格式选择fig, ax plt.subplots(figsize(8, 5)) # ... (绘制图表的代码) ... # 保存图形 fig.savefig(my_plot.png, # 文件名 dpi300, # 分辨率用于印刷建议300以上屏幕显示72-150即可 bbox_inchestight, # 紧贴图形内容去除多余白边 pad_inches0.1, # 在紧贴的基础上添加一点内边距 facecolorwhite, # 图形背景色 edgecolornone # 图形边缘色 )关键参数格式通过扩展名指定。.png无损支持透明、.jpg有损文件小、.svg矢量无限缩放适合出版物、.pdf矢量适合文档嵌入。dpi(Dots Per Inch)决定输出图像的像素密度。dpi乘以图形尺寸英寸就是最终图像的像素尺寸。例如figsize(8,5)英寸dpi100则生成800x500像素的图片。bbox_inchestight这是最重要的参数之一。它能自动计算图形的边界框裁剪掉周围多余的白边。在保存包含图例、标签的图表时务必使用。6.2 解决保存时图例或标签被截断的问题即使使用了bbox_inchestight有时非常复杂的布局仍可能被截断。终极解决方案是使用constrained_layout或手动调整。# 方法1在创建图形时使用 constrained_layout 推荐 fig, ax plt.subplots(figsize(8,5), constrained_layoutTrue) # ... 绘图 ... fig.savefig(plot_with_constrained_layout.png, dpi150) # 方法2如果已经创建了图形可以手动调整子图布局 fig, ax plt.subplots(figsize(8,5)) # ... 绘图 ... fig.tight_layout(rect[0, 0, 1, 0.95]) # rect参数调整子图区域[left, bottom, right, top] # 例如 rect[0, 0, 1, 0.95] 表示子图区域占据图形宽度的100%高度的95%为上方标题留出空间 fig.savefig(plot_manual_adjust.png, dpi150)6.3 保存为透明背景fig, ax plt.subplots(figsize(8,5), facecolornone) # 图形背景透明 ax.plot([1,2,3], [1,4,9], lw3) ax.set_title(Plot with Transparent Background) # 将坐标轴区域背景也设为透明 ax.set_facecolor(none) fig.savefig(transparent_plot.png, dpi150, transparentTrue) # 关键参数将transparentTrue和图形、坐标轴的背景色设置为none结合可以生成背景完全透明的PNG图片便于嵌入到其他演示文稿或网页中。最后的小技巧在Jupyter Notebook中可以使用%matplotlib inline后接%config InlineBackend.figure_format retina或svg来获得更清晰的内嵌显示效果。但保存文件时仍应使用fig.savefig并指定高dpi。