ARTICLE DETAIL

建站实战干货

来自一线的建站与推广经验沉淀,每一条都经过真实交付验证。

Python数据可视化实战:常用统计图场景与matplotlib避坑指南

2026/9/13 13:17:28 拓冰建站 浏览量
Python数据可视化实战:常用统计图场景与matplotlib避坑指南 拿到一批数据想用Python画个图看看分布和趋势结果代码跑通了一看又丑又乱这是很多朋友初学可视化时的共同经历。我最早接触matplotlib时也踩过不少坑折腾一阵才发现统计图的坑大多不在语法上——做错选择、参数没配好、把不该画的图画错了才是问题。所以这篇东西不打算按API文档那样逐条列而是把常用统计图的适用场景、源代码实现、输出效果含义和避坑经验放在一起做成一个“查表即用”的汇总。内容覆盖matplotlib、seaborn和pandas自带绘图基于我实际项目中经常用到的场景来写。无论你是刚接触Python数据分析还是已经有基础但总在出图上卡壳照着代码走一遍应该能解决你八成以上的画图需求。1. 画图前先想明白常见统计图到底在解决什么问题1.1 选择图表不是看哪个“好看”而是看你想表达什么我见过不少新手一上来就用折线图结果X轴根本不是连续型数据画出来跟心电图似的毫无意义。选统计图的核心逻辑只有一条先确定你的数据是什么类型再确定你想让读者看到什么结论。比如你想看一个变量的分布是否集中直方图比其他图都直接想比较几个类别的数值高低柱状图最清楚想观察两个变量之间的相关关系散点图永远是最佳起点。拿我自己的经验举例做销售数据分析时团队里经常有人问“本月各区域的销售额差距大不大”这种问题就应该画箱线图它把最小值、下四分位、中位数、上四分位、最大值全部压缩在一张图里分布形态和异常点一览无余。如果只是随便画个柱状图就只能看到每个点的高低看不到背后的离散程度信息损耗非常严重。1.2 六种常用统计图的适用场景速查表这张表是我自己整理后一直保存在笔记里的每次画图前都会先过一遍图类型适用数据核心问题常用工具折线图时间序列、连续变量数值随顺序如何变化matplotlib, pandas柱状图类别数据、离散变量各类别数值差异有多大matplotlib, seaborn散点图两个连续变量变量之间是否有相关关系matplotlib, seaborn直方图/密度图单个连续变量数据的分布形态如何matplotlib, seaborn箱线图类别连续变量分布和异常值情况如何seaborn, matplotlib饼图类别占比数据部分占整体的比例matplotlib需要特别说明的是饼图。很多可视化专家不推荐饼图因为人眼对面积的感知并不精确当类别超过5个或者占比差异不明显时饼图就会变得很难读。我个人的建议是分类不超过5个、且只看占比时用饼图没问题一旦涉及精确对比还是回归柱状图或者用环形图来改善可读性。2. matplotlib快速上手一张图背后的三层结构2.1 Figure画板、Axes画纸、Axis刻度的分工很多教程一上来就甩plt.plot()不是说不能用但如果你不理解背后结构后面做子图、调坐标轴就会一头雾水。换个生活化的说法Figure 是整个大白板Axes 是白板上的一张张画纸Axis 是画纸边缘的刻度尺。一张画板上可以贴多张画纸区分不同图表每张画纸各自带上下左右四把刻度尺。下意识去看下面的骨架代码几乎所有matplotlib自定义操作都能落在这三层的任一层上import matplotlib.pyplot as plt # 创建一个画板figure以及里面的1行1列第1张画纸axes fig, ax plt.subplots(figsize(8, 5)) # 在这张画纸上画线 ax.plot([1, 2, 3, 4], [10, 20, 15, 30]) # 修改这张画纸的标题和坐标轴标签 ax.set_title(示例折线图) ax.set_xlabel(时间点) ax.set_ylabel(数值) # 展示画板 plt.show()这里的 ax 对象才是你真正打交道的对象它拥有plot、scatter、bar、hist、boxplot等全套绘图方法。之前用plt.xxx系列函数其实是一个简洁入口背后仍然会创建 Figure 和 Axes只是隐藏了细节。理解这层差异之后你会发现复杂的论文图、商业报告图其实都是由多个Axes组合出来的。2.2 基础配置字体、画布尺寸、分辨率和风格代码写得再漂亮图一出来全是方块字这是中文系统的经典问题。根本原因是matplotlib默认字体里没有中文字符。我的惯例是每次写分析脚本时头几行固定填一份字体配置import matplotlib.pyplot as plt # 微软雅黑在Windows系统下很常见Linux服务器上可换成文泉驿或Noto Sans CJK plt.rcParams[font.sans-serif] [Microsoft YaHei, SimHei, WenQuanYi Zen Hei] plt.rcParams[axes.unicode_minus] False # 解决负号显示成方块的问题两个参数一个管字体回退一个管负号正常显示建议直接放到脚本首部全局生效。画布尺寸和分辨率我会在创建画板时一并处理fig, ax plt.subplots(figsize(10, 6), dpi100)figsize 单位是英寸横向10英寸、纵向6英寸约等于4:3的宽高比适合大多数场景。如果用默认值(6.4, 4.8)图一旦挤字段就会被拉得很憋屈。dpi 是每英寸点数屏幕展示100就够了要打印或者放论文里建议调到200以上线条和文字才不会发虚。风格上matplotlib提供了几个内置主题plt.style.use(ggplot)是深色背景、网格线条风格seaborn-v0_8-whitegrid比较清爽我日常用白底网格居多因为网格线能帮读者更快对齐数值。2.3 一步到位的保存图片技巧保存图片时用plt.savefig()而不是截图可以保证尺寸和分辨率完全可控。注意这个操作要在plt.show()之前或者在同一个画布仍然存活的时候做否则可能存到空文件。我常用的写法是fig.savefig(output/销售趋势图.png, dpi200, bbox_inchestight)bbox_inchestight会自动裁剪掉多余白边让图片四周贴合坐标轴和标题发到文档里不会留一大片空白。3. 常见统计图的源代码示例与效果解读3.1 折线图趋势与时间序列的主场折线图的核心场景是连续变量随时间或顺序变化。我用一份模拟的月度销售额数据来做演示。直接从pandas生成DataFrame然后用matplotlib画图这是实际工作中最高频的流程import numpy as np import pandas as pd import matplotlib.pyplot as plt plt.rcParams[font.sans-serif] [Microsoft YaHei, SimHei] plt.rcParams[axes.unicode_minus] False # 构造数据12个月模拟递增趋势加一点波动 months [f{i}月 for i in range(1, 13)] sales [12.5, 13.8, 15.2, 14.7, 16.9, 18.3, 19.6, 20.1, 21.5, 23.8, 25.2, 27.6] df pd.DataFrame({月份: months, 销售额: sales}) fig, ax plt.subplots(figsize(10, 5)) ax.plot(df[月份], df[销售额], markero, linewidth2, label月销售额) ax.set_title(2024年月度销售额趋势, fontsize15) ax.set_xlabel(月份) ax.set_ylabel(销售额万元) ax.grid(True, linestyle--, alpha0.5) ax.legend() fig.tight_layout() plt.show()代码其实不难关键点有三个markero让每个数据点上显示圆点标记不然只有一根线读者很难对应具体数值。linewidth2加粗曲线小尺寸预览时也能看清走势。grid(True, linestyle--, alpha0.5)加虚线网格透明度不要太高否则喧宾夺主。从输出图里读者第一眼能抓住的是销售额大体在持续上升中间4月出现一次小回落之后保持涨势。这就是折线图最擅长的事情——趋势比具体数值更醒目。如果图里有多个系列要记得用label区分并补上ax.legend()图例否则多条线会混成一团。3.2 柱状图类别对比的第一选择柱状图适合横轴是非连续类别、纵轴是数值的对比场景。还是用销售数据这次看各产品线的销量对比如下categories [手机, 笔记本, 平板, 耳机, 智能手表] quantities [320, 245, 187, 510, 268] fig, ax plt.subplots(figsize(9, 5)) # 用不同的温和颜色填充并去除柱子边框 bars ax.bar(categories, quantities, color[#5B9BD5, #ED7D31, #A5A5A5, #70AD47, #FFC000]) # 数据标签在每根柱子上方显示数值 for bar in bars: height bar.get_height() ax.text(bar.get_x() bar.get_width()/2, height 8, f{height}, hacenter, vabottom, fontsize10) ax.set_title(各产品线季度销量对比, fontsize15) ax.set_ylabel(销量件) ax.grid(axisy, linestyle--, alpha0.5) plt.show()这个例子加入了两个实用增强每根柱子顶部用ax.text()标出数值省去读者从坐标轴反推数值的麻烦。bar.get_x()拿到柱子左下角x坐标再加上bar.get_width()/2就能定位到柱子正中线上方。grid(axisy)只画水平网格线竖线省去版面看起来更干净。柱状图最常见的错误有三个柱宽设置不合理导致柱子之间挤压或过疏颜色太花哨导致视觉焦点分散类别顺序没有排序导致读者看不出高低规律。我的经验是如果不是要刻意按自然顺序比如月份展示最好按数值从高到低排序再画。排过序的柱状图信息传递效率远高于乱序。3.3 散点图关联关系的侦察兵散点图用来判断两个连续变量是否相关。之前做过一次广告投入和销售额的关系分析数据是模拟的但规律很典型np.random.seed(42) n 80 ad_spend np.random.uniform(5, 60, n) # 广告投入万元 sales 8 1.8 * ad_spend np.random.normal(0, 6, n) # 销售额万元 fig, ax plt.subplots(figsize(8, 6)) ax.scatter(ad_spend, sales, alpha0.7, s40, edgecolorwhite, linewidth0.5) ax.set_title(广告投入与销售额的散点图, fontsize15) ax.set_xlabel(广告投入万元) ax.set_ylabel(销售额万元) # 拟合一条回归线看更直观 slope, intercept np.polyfit(ad_spend, sales, 1) x_fit np.linspace(ad_spend.min(), ad_spend.max(), 50) ax.plot(x_fit, slope * x_fit intercept, colorred, linestyle--, linewidth2) plt.show()np.random.seed(42)的作用是让随机序列可复现你跑代码也能得到同样的点这是数据分析和教学演示的好习惯。从散点图上可以直观看出数据点沿着左下到右上的方向聚集说明广告投入和销售额正相关。我再用np.polyfit做了一阶多项式拟合把趋势线叠加到图上这种叠加会让相关性更加清晰。alpha0.7控制点透明度数据点重叠多的时候透明度的价值非常明显——不透明的点叠在一起就是一团黑透明的点能看出浓度差异。3.4 直方图与密度图分布形态的X光片当你想了解一个变量的分布是否均匀、是否偏向某一侧、是否存在异常峰直方图是最直接的。比如分析用户在线时长的分布用模拟数据演示np.random.seed(7) session_minutes np.concatenate([ np.random.normal(25, 8, 400), # 主体用户集中在25分钟左右 np.random.normal(65, 10, 50) # 少数重度用户集中在65分钟左右 ]) fig, ax plt.subplots(figsize(9, 5)) ax.hist(session_minutes, bins25, color#70AD47, alpha0.7, edgecolorwhite) ax.set_title(用户在线时长分布直方图, fontsize15) ax.set_xlabel(在线时长分钟) ax.set_ylabel(用户人数) plt.show()bins25表示把数据分成25个区间。bins选的过大直方图会变成锯齿状选得过小又看不清细节。我个人经验是“小数据量区间尽量少于样本量的平方根大数据量用30-50个区间基本不会翻车”。从上图可以明显看出一个主峰值和一个次峰值说明用户群里存在两种截然不同的使用习惯——这就是直方图的发现能力。如果想看更平滑的分布曲线可以叠加核密度估计。seaborn对这类任务支持非常好import seaborn as sns sns.set_theme(stylewhitegrid) fig, ax plt.subplots(figsize(9, 5)) sns.histplot(session_minutes, bins25, kdeTrue, color#4472C4, axax) ax.set_title(用户在线时长分布直方图密度曲线, fontsize15) ax.set_xlabel(在线时长分钟) ax.set_ylabel(频数 / 密度) plt.show()注意直方图和密度图在y轴单位上不一样直方图统计的是落在每个区间的样本数密度曲线下的总面积是1。所以如果两个图画在同一张图上y轴刻度不能直接互通阅读读者只需要看图形态、不需要读具体数值时问题不大做正式的汇报图时需要留意这一点。3.5 箱线图分布和异常值一网打尽箱线图一个盒子就把中位数、四分位数范围、异常值全部交代清楚了。它特别适合“类别对比分布差异”的组合场景。比如按不同运营方案对比用户转化率np.random.seed(10) # 三个方案的转化率数据% plan_a np.random.normal(5.8, 1.2, 60) plan_b np.random.normal(6.5, 2.0, 60) plan_c np.random.normal(6.0, 1.5, 60) fig, ax plt.subplots(figsize(8, 6)) data [plan_a, plan_b, plan_c] # patch_artistTrue 让箱子填充颜色 bp ax.boxplot(data, labels[方案A, 方案B, 方案C], patch_artistTrue, showmeansTrue) colors [#ED7D31, #5B9BD5, #70AD47] for patch, color in zip(bp[boxes], colors): patch.set_facecolor(color) patch.set_alpha(0.7) ax.set_title(不同运营方案的用户转化率分布, fontsize15) ax.set_ylabel(转化率%) plt.show()逐段解释这个箱线图的读法每个箱子中间那根横线是中位数如果它在箱子中间偏上或偏下说明数据分布不对称。箱子上下边缘是上下四分位数箱子高度就是四分位距反映中间50%的数据有多分散。箱子外伸出的“须”一直延伸到非异常边界再远一点的圆点就是异常值。我在参数里加了showmeansTrue箱子里的三角形标记就是均值。中位数和均值的位置关系能很快告诉你数据是否有偏态。方案B的箱子明显比方案A高说明B的转化率总体上更高但B的箱子也更长说明B的稳定性稍差、波动更大。这种信息用柱状图根本看不出来这就是箱线图不可替代的地方。3.6 饼图与环形图占比展示的正确姿势饼图虽然经常被吐槽但用于少数类别的占比展示时直观度确实无可替代。我用环形图版本它比传统饼图好在中心可以留白放重点文字视觉上更清爽labels [国产剧, 综艺, 动画, 纪录片, 其他] shares [42, 28, 15, 10, 5] fig, ax plt.subplots(figsize(7, 7)) # 生成环形图wedgeprops里设宽度 wedges, texts, autotexts ax.pie( shares, labelslabels, autopct%.1f%%, startangle90, counterclockFalse, wedgeprops{width: 0.45, edgecolor: white} ) ax.set_title(平台内容播放时长占比, fontsize15) # 让每个占比标签稍微往外挪一点避免贴字 for text in autotexts: text.set_fontsize(11) text.set_color(white) plt.show()控制为一个环形再在中心添加文字是常用做法ax.text(0, 0, 总计\n100%, hacenter, vacenter, fontsize13, fontweightbold)注意饼图的几个雷区各部分之和必须是100%或归一化成百分比。分类不要超过5个“其他”兜底是好习惯。如果有“确实占比极小”的分类比如1%画出来就是一条细线读了等于没读建议直接并入“其他”。startangle90是从12点钟方向开始排布counterclockFalse控制方向两者结合可以让最大的扇区从顶部开始符合阅读习惯。4. 多图组合与细节增强让图表从“能看”到“耐看”4.1 子图布局一张大图讲清一个完整故事分析报告里一张图讲一件事是理想状态但有时候你需要把同一组数据的不同侧面放在一起对比。用subplots创建多行多列的子图网格是很成熟的做法。比如把销量趋势、渠道占比和用户分布放在一张大画板上fig, axes plt.subplots(2, 2, figsize(14, 10)) # 左上折线趋势 axes[0, 0].plot(months, sales, markero, color#5B9BD5) axes[0, 0].set_title(月度销售趋势) # 右上渠道占比柱状图 axes[0, 1].bar([直营, 代理, 电商], [260, 180, 320], color[#ED7D31, #A5A5A5, #70AD47]) axes[0, 1].set_title(渠道销量对比) # 左下用户在线时长分布直方图 axes[1, 0].hist(session_minutes, bins20, color#4472C4, alpha0.7) axes[1, 0].set_title(用户时长分布) # 右下转化率箱线图 axes[1, 1].boxplot(data, labels[A, B, C]) axes[1, 1].set_title(转化率分布) fig.tight_layout() plt.show()axes[0, 0]这种索引方式对应2行2列的四个子图位置。每个子图都是独立的Axes对象可以分别调用各自的绘图方法和设置函数。fig.tight_layout()特别重要它自动调整子图之间的间距避免标题和坐标轴重叠。共同标题可以用fig.suptitle()加在整个大画板上方。4.2 双Y轴两组不同量纲的数据画在一张图上当你想对比销售额和利润率这两个量纲完全不同的指标时双Y轴是实用方案。比如看“销售额涨了多少”和“利润率变化”是否同步fig, ax1 plt.subplots(figsize(10, 5)) x np.arange(1, 13) sales_values [120, 135, 148, 141, 160, 175, 189, 195, 210, 232, 248, 265] profit_rates [12.1, 12.5, 11.8, 12.3, 12.9, 12.2, 11.5, 11.2, 10.8, 11.0, 10.5, 10.2] # 左轴画柱状图 ax1.bar(x, sales_values, color#5B9BD5, alpha0.7, label销售额) ax1.set_xlabel(月份) ax1.set_ylabel(销售额万元, color#5B9BD5) # 创建共享x轴的第二个坐标轴 ax2 ax1.twinx() ax2.plot(x, profit_rates, color#ED7D31, markero, linewidth2, label利润率) ax2.set_ylabel(利润率%, color#ED7D31) plt.show()twinx()会创建一个和原轴共享x坐标、但y轴独立的新坐标轴。这样销售额柱状图用左轴刻度利润率折线用右轴刻度互不干扰。不过要提醒一句双Y轴有时候会误导读者如果两边的起始刻度范围差异过大视觉上的“高低对比”可能会失真。所以除非两组数据量纲确实完全不同否则优先考虑分两个子图并排展示更稳妥。4.3 seaborn一行代码提升图表档次如果你的数据是规整的DataFrame那seaborn在很多场景下能带来观赏性和信息量的双重提升。它的核心优势是对数据框友好——datadf加上列名就能干活。以散点趋势和箱线图为例import seaborn as sns # 保持中文字体设置 plt.rcParams[font.sans-serif] [Microsoft YaHei, SimHei] plt.rcParams[axes.unicode_minus] False df pd.DataFrame({ 广告投入: ad_spend, 销售额: sales }) fig, ax plt.subplots(figsize(9, 6)) sns.regplot(datadf, x广告投入, y销售额, scatter_kws{alpha: 0.6, s: 45}, line_kws{color: red, linestyle: --}, axax) ax.set_title(广告投入 vs 销售额seaborn回归图, fontsize15) plt.show()regplot自动完成“散点线性回归线置信区间带”在很多分析报告里单靠这一张图就能替代“散点图相关检验”两步工作。seaborn还有pairplot对一个多列DataFrame一次性生成所有两两变量的散点图和分布图数据探索阶段尤其好用tips sns.load_dataset(tips) sns.pairplot(tips, hueday, paletteSet2) plt.show()运行出来会是一张大型矩阵图主对角线是每个变量的直方图其他位置是两两散点图并按day这个类别着色。五分钟之内你就能大概了解整个数据集的变量关系和分组差异比逐个画图高效太多。5. 常见问题排查与独家避坑技巧5.1 中文乱码或负号显示方块这是最常遇到的问题原因和解决办法都很统一matplotlib默认字体库不含中文字形负号又用了特殊的Unicode字符。处理方法就是文章开头那两行rcParams设置。我汇总一下可能的情况现象原因解决方式中文变方块默认字体无中文设置font.sans-serif为系统已有中文字体负号变方块负号编码问题rcParams[axes.unicode_minus] False图片保存后字体变乱保存时未重设字体保存前重新执行字体配置Linux服务器上无微软雅黑系统未装中文字体安装wqy-zenhei或Noto Sans CJK或用matplotlib.font_manager指定字体路径设置字体后如果还不行可以用matplotlib.font_manager手动定位字体文件路径import matplotlib.font_manager as fm font_path /usr/share/fonts/truetype/wqy/wqy-zenhei.ttc # 以实际路径为准 my_font fm.FontProperties(fnamefont_path) fig, ax plt.subplots() ax.set_title(中文标题, fontpropertiesmy_font) plt.show()这种方式适合字体文件路径明确的场景不会因为rcParams没生效而抓狂。5.2 横坐标标签太密集画折线或者柱状图时如果x轴有几百个类别默认设置会把所有标签叠在一起完全没法看。我的经验是分情况处理如果x轴本身就是时间序列可以直接用plt.xticks(rotation45)旋转角度如果标签实在太多就手动指定一部分刻度显示# 假设有100个日期 x_dates pd.date_range(2024-01-01, periods100, freqD) values np.random.randn(100).cumsum() fig, ax plt.subplots(figsize(12, 5)) ax.plot(x_dates, values) # 只显示第0、20、40、60、80天的刻度 ticks x_dates[::20] ax.set_xticks(ticks) ax.set_xticklabels([d.strftime(%Y-%m-%d) for d in ticks], rotation30) plt.show()x_dates[::20]是Python切片的步长取法每隔20天取一个刻度100天就只剩6个刻度。同时把日期格式化成2024-01-01的样子并旋转30度基本不会再有文字重叠问题。如果你的分析目标是看长期趋势而非每一天的具体波动还可以用pd.date_range的resample(ME)或resample(W)把数据聚合到月/周级别再画效果更干净。5.3 柱状图类别顺序不对或不按预期排序pandas、matplotlib对类别顺序的处理规则不一样导致同样的数据有时顺序错乱。如果你是直接传字符串列表给bar顺序一般就是列表顺序但如果你用df.plot(kindbar)x轴顺序则是DataFrame原有行顺序排序后画图更容易表达“哪个最高”df_sorted df.sort_values(销售额, ascendingFalse) fig, ax plt.subplots(figsize(9, 5)) ax.bar(df_sorted[月份], df_sorted[销售额], color#70AD47) ax.set_title(按销售额降序排列) ax.tick_params(axisx, rotation45) plt.show()如果想固定自然顺序比如月份1-12用pd.Categorical指定categories即可。这种情况在使用seaborn的barplot时需要特别注意因为它的order参数要显式传sns.barplot(datadf, x月份, y销售额, ordermoths_order)5.4 数据点太多导致图糊成一团当你有几万甚至几百万个数据点的时候普通散点图会渲染成一片实色看不出密度差异。这种情况我有两个处理方向一是用alpha降低透明度让重叠区域颜色更深视觉上产生密度层次感。二是改用sns.kdeplot或hexbin绘制密度图。hexbin把平面划分成六边形格子每个格子里的点数用颜色深浅表示大数据量下效果远胜散点。fig, ax plt.subplots(figsize(8, 6)) hb ax.hexbin(ad_spend, sales, gridsize30, cmapYlOrRd) fig.colorbar(hb, axax, label数据点数量) ax.set_title(广告投入与销售额密度图hexbin) ax.set_xlabel(广告投入万元) ax.set_ylabel(销售额万元) plt.show()gridsize30控制网格粗细cmapYlOrRd控制颜色渐变。用上这个方案即使10万量级的数据点也能在数秒内渲染出清晰的分布形态。5.5 画图时使用现成代码模板减少重复劳动多画几次之后你会发现自己常用的就那么几种组合。我自己会维护一个plotting_templates.py文件里面写好封装的函数比如quick_line(df, x, y)、quick_bar(df, x, y, title)、quick_hist(series, bins)等。每次有新需求直接调用然后微调参数出图速度能快一倍以上。顺手写一个空的骨架模板给你def quick_line(df, x_col, y_col, title趋势图): fig, ax plt.subplots(figsize(10, 5)) ax.plot(df[x_col], df[y_col], markero, linewidth2) ax.set_title(title, fontsize15) ax.set_xlabel(x_col) ax.set_ylabel(y_col) ax.grid(True, linestyle--, alpha0.5) fig.tight_layout() return fig, ax封装之后重复的东西不再重复新手阶段可以先手写几遍理解原理熟练之后再开始抽函数。6. 最后再分享几个我踩过之后记住的经验第一个关于数据准备。画图之前务必先确认数据类型时间列是不是datetime64数值列是不是数值类型。我见过很多次df[月份]是字符串类型导致折线图的x轴顺序变成“1、10、11、12、2……”这种按字典序排序的乱序。最稳妥的做法是先运行df.info()或df.dtypes检查数据类型不对就先用pd.to_datetime()或astype(float)转换。第二个关于配色和可读性。默认的matplotlib配色表在板报和论文里都偏淡但离“好读”仍有一定距离。没有设计基础的建议直接用seaborn的sns.set_theme()配色或者参考颜色工具网站配一组主题色。每张图颜色最多4-5种多一个维度就多一份脑力负担。分类超过6个的图别硬用颜色区分改用分组或面板图。第三个关于交互式探索。静态matplotlib适合出报告但你在做数据探索时数据量一旦大起来静态图看不过来会错过细节。推荐安装plotly用一行plotly.express.scatter(df, x广告投入, y销售额, hover_data[日期])就能得到可缩放、可悬停查看详情的交互图。顺带一提用Jupyter Notebook时深度排查可以用%matplotlib widget把matplotlib自带的交互模式打开缩放平移都很方便。第四个关于机器学习模型的可视化。如果你除了统计图还做模型分析建议把预测值、真实值、残差画成三张图放在一起对比折线图看预测贴合程度、散点图看残差分布、直方图看残差是否集中在0附近。这套组合能快速判断模型是否存在系统性偏差比看单一指标要直观很多。可视化本质上是探索数据、验证结论的外部工具代码写得再顺也不能离开“你想从数据里找什么”这个大前提。先把这个问题想清楚再打开编辑器你的图自然就有灵魂了。