资讯详情

散点图衍生图形全解析:从气泡图到分箱与拟合线,玩转数据可视化

📅 2026/10/22 12:07:37 | 华诺云谱 👁 阅读
散点图衍生图形全解析:从气泡图到分箱与拟合线,玩转数据可视化
散点图大概是数据可视化里最“不起眼”的基础图形之一两个坐标轴、一堆点看起来谁都会画。但你真把它放进项目里就会发现散点图的扩展空间比想象中大得多。这篇内容专门梳理散点图的衍生图形——也就是在基础散点图上通过增加维度编码、叠加统计信息、拆分视图、引入交互等方式演化出来的一整族图形包括气泡图、散点图矩阵、六边形分箱图、带拟合线的散点图、分组分面散点图等等。如果你画散点图还停留在“两个数组扔进绘图函数”的水平或者画了好几张但总觉得信息量不够、表达不到位这篇内容能帮你把这一个基础图形真正玩出花样。1. 先聊清楚散点图为什么值得有一堆“衍生”1.1 散点图到底在表达什么散点图的核心思路非常朴素一张表里有很多行数据每一行有一些数值属性挑出其中两个属性分别映射到横轴和纵轴每一行数据就变成了图上的一个点。这听起来平平无奇但它的厉害之处在于点与点之间的相对位置、整体分布形态能非常直观地回答“两个变量到底有没有关系、关系大概是什么样”这类问题。拿我自己的使用经验来说每次拿到一份新数据第一件事几乎都是画几组散点图。你用表格看两列数据看几百行也看不出个所以然但把两组数字摆在坐标平面上点的走势一下就清楚了。正相关是一团向右上角爬升的云负相关是向右下角坠落的云无关则是一团均匀分布的散点多模态的情况可能出现好几坨点聚在一起。这种“一眼看形态”的能力是散点图经久不衰的根本原因。1.2 三个天然限制逼出了衍生图形不过基础散点图有三个很明显的限制这也是衍生图形出现的动机。第一它默认只能表达两个数值维度。现实中的分析任务往往不止两个变量比如在看价格和销量的关系时还得考虑营销投入、地区差异、时间段等因素。这个时候只画一张基础散点图相当于把其他重要信息全丢掉了。第二它对数据量很敏感。几千个点还好几十万个点堆在一起点与点重叠成一片黑色墨团什么关系都看不出来了。这可不是散点图本身不好而是我们缺少处理“过度绘制”的手段。第三它只展示点位不提供统计结论。散点图能让你“看到”趋势但不能直接告诉你趋势有多强、斜率是多少、哪些点算是异常。所以需要把拟合线、置信区间、分组均值这类统计信息叠加到图上。衍生图形本质上都在解决这些限制要么增加新的编码通道颜色、大小、形状要么引入统计量密度、回归线、置信区间要么拆分视图分面、矩阵要么增加时态与交互动画、悬浮提示。理解了“散点图缺什么”你就能理解“衍生图形补了什么”。2. 四类最常见的散点图衍生图形逐一说透2.1 气泡图给散点图加上第三个数值维度气泡图是所有衍生图形里门槛最低、也最容易用歪的一个。它的思路是在原有x、y位置不变的前提下把第三个数值变量映射到点的大小通常是点的面积或半径上。先说说适用场景。当你想看“两个变量的关系是否受到第三个数值变量影响”时气泡图很合适。比如分析某产品的销量和利润关系时把“营销投入”映射为气泡大小你就能一眼看出投入越大的产品销量和利润大体上是更高还是更低三者之间的联动关系一下子有了画面。实现上主流绘图库都有现成参数。用matplotlib画气泡图在scatter里加一个s参数就好s接收一个数组数组里每个值对应一个点的面积。seaborn里更省事scatterplot方法直接有size参数传列名就行。import numpy as np import matplotlib.pyplot as plt x np.random.rand(50) * 10 y x np.random.randn(50) * 0.5 size np.random.lognormal(3, 0.5, 50) # 把 size 缩放到适合视觉比较的面积范围避免极端值撑爆画布 size_scaled 20 (size - size.min()) / (size.max() - size.min()) * 480 plt.scatter(x, y, ssize_scaled, alpha0.7) plt.xlabel(X变量) plt.ylabel(Y变量) plt.title(气泡图示例) plt.show()这里有个非常容易踩的坑在matplotlib中s参数默认解释为“点的面积”单位是像素平方不是半径。很多人直接拿原始数值传给s如果数值范围是1到100画出来的气泡看起来差异很小可一旦数值跨度比较大比如从1到1000点的面积会按1000倍膨胀小点小到看不见、大点大到溢出画布。更夸张的是如果你用半径去映射半径增长一倍面积增长四倍视觉上会严重夸大差异。我的习惯是在传给s之前先做一次归一化或缩放把原始数值缩放到比如20到500的区间再传进去。而且这里的数值本身要按面积理解不是按半径视觉大小才比较贴近真实比例。如果你用seaborn的size参数它内部会做一些处理但你还是可以通过size_max控制最大尺寸。气泡图还有一个常被忽略的问题人对“面积大小”的判断不如对“长度大小”判断准确。面积翻倍的气泡在观感上往往达不到“翻倍”的效果。所以如果你要用气泡大小做严肃的对比最好在图里标注清楚每个气泡对应的具体数值或者在图注里说明映射规则避免误导读者。2.2 散点图矩阵多变量两两配对的“体检表”当变量数量一下子变成四五个、六七个时两两组合的可能性就多了。散点图矩阵做的事情其实特别朴素把所有数值变量两两组合每个组合画一张小散点图然后按行和列排成一个矩阵。这样你一眼就能扫过所有变量配对的关系快速定位“哪两个变量之间可能有戏”。散点图矩阵的经典实现是用seaborn的pairplot一行代码就能出一个很漂亮的结果对角线位置默认放每个变量的直方图非对角线位置放两两散点图。如果加hue参数点还会按类别着色不同群体的关系差异也会显现出来。import seaborn as sns # df 为模拟数据数值列 一个分组列 sns.pairplot(df, hue城市等级)用散点图矩阵最典型的场景是做数据分析前期的探索阶段。在我自己的项目流程里拿到一份新数据先跑pairplot看一下大体关系再决定哪些变量值得进一步建模、哪些变量之间可能存在共线性、哪些变量有明显离群值。它能帮你快速建立对数据集的整体直觉省去一个个手动画图的时间。但散点图矩阵也有明显的边界。首先变量一多矩阵就会变得非常庞大。5个变量就是5×525个子图10个变量就是100个子图图已经大得没办法看了。所以一般建议把变量控制在4到6个以内多出来的变量要么当作类别变量用hue区分要么直接不放进去。其次矩阵里每一张子图的坐标轴尺度是各自独立的你看到的“关系强弱”在不同子图之间不能直接横向比。有些库支持共享轴这样更公平但也要防止个别离群值把其他点的分布压得扁扁的什么都看不出来。2.3 六边形分箱图点多了以后的密度方案如果你有几十万甚至上百万条数据直接画散点图的后果是所有点叠成一团墨色边缘偶尔有几根毛刺完全无法分辨分布结构。很多人第一反应是调低点的透明度但这只能缓解小规模数据的问题数据量一大怎么调都不够。这个时候就该上分箱图了。六边形分箱图hexbin的思路是把二维平面划分成一个个小格子然后统计每个格子里落入多少个点用格子颜色的深浅表示计数大小。这样点的数量从“成千上万个点”被压缩成“几百个格子”画出来的图既保留了大致的分布形状又不会因为点重叠而糊掉。分箱图在本质上就是一种二维直方图只不过把通常的方形网格换成了六边形网格。为什么非得用六边形而不是正方形因为六边形在几何上更接近圆形六个方向上的相邻格子中心距是相同的做出来的密度图不会出现“沿着某个方向看起来特别密集”的各向异性视觉上更均匀。很多地理信息系统里也用六边形网格做区域统计就是看中它的邻接关系均匀。在matplotlib里画六边形分箱图非常方便import matplotlib.pyplot as plt hb plt.hexbin(x, y, gridsize30, cmapviridis, mincnt1) plt.colorbar(hb, label点计数) plt.xlabel(X变量) plt.ylabel(Y变量) plt.title(六边形分箱图示例) plt.show()gridsize控制划分的格子数量值越大格子越细。返回值里可以取到每个格子的计数如果觉得默认配色不好看还可以换不同的colormap。不少绘图场景会去掉空格子mincnt1只显示有数据的区域否则大范围空白区域会让颜色条分布失衡。其实除了hexbin核密度估计散点图用等高线表示密度也是大数据量下散点图的重要补充。两者差异在于分箱图是离散的格子能直接看到每个区域的大概计数等高线密度图是平滑的连续曲线视觉上更好看但计算量大一些、也不方便读出具体数量。我通常把hexbin当作快速筛查工具看数据形态等高线密度图留到需要去汇报演示的场合再用。2.4 叠加拟合线的散点图从看到关系走向量化关系散点图告诉你有关系回归线告诉你关系有多强、方向是什么、能不能用一条线概括。在散点图上叠加拟合线和置信区间是统计建模前最常用的可视化组合也是衍生图形里含金量最高的一类。这里的核心问题不是“怎么画线”而是“该用什么模型画线”。很多人拿到一组数据不管三七二十一叠一条线性回归直线然后看R²多少。这个习惯非常危险。因为散点图上的点如果呈现出弯曲形态比如先升后降、指数增长、对数衰减线性的拟合结果不仅差而且会误导你对关系的判断。正确做法是先观察点的形态再决定拟合函数。线性关系用线性回归没问题明显的U形或倒U形就得考虑多项式回归或样条回归数据呈对数、指数形态可能要做变量变换。在探索阶段也可以用局部回归先画一条非参数的平滑曲线让数据本身告诉你趋势的大致形状再决定正式建模方向。实现上用matplotlib需要手动算拟合线import numpy as np import matplotlib.pyplot as plt coeffs np.polyfit(x, y, deg2) # 二阶多项式拟合 x_line np.linspace(x.min(), x.max(), 200) y_line np.polyval(coeffs, x_line) plt.scatter(x, y, alpha0.6) plt.plot(x_line, y_line, colorred, linewidth2) plt.xlabel(X变量) plt.ylabel(Y变量) plt.title(散点图叠加拟合线) plt.show()用seaborn就简单得多regplot或lmplot直接帮你把回归线和置信区间画好。regplot适合单个子图lmplot适合分面绘图两者的底层逻辑一致。这里我想多说一句置信区间seaborn默认画出来的半透明色带是拟合线的不确定区间看到这个区间宽窄你就能判断拟合线的可信度。区间越宽说明数据点对拟合线的“投票”越分散对这条线的解释就越要谨慎。如果要展示不同组别的回归差异可以给lmplot加hue参数每个组会有自己的拟合线和置信区间。比如分析不同地区的销量和价格关系分组的回归线能清楚显示哪些地区价格敏感性高、哪些地区不太敏感。这种带统计推断的散点图衍生形式已经从“描述数据”升级到了“支撑决策”。3. 再往深处走分组、分面、阈值与交互3.1 分组着色散点图让分类变量的作用现形上面说的都是给散点图增加数值维度但实际问题里还有大量分类变量地区、品类、渠道、用户群。最直接给分类变量留位置的方法就是点着色。颜色本身是一个编码通道和x、y两个数值轴完全不冲突。分组着色后的散点图能揭示一个极其重要的信息整体看起来没有关系的两个变量可能在某个类别内部其实有关系只是方向相反相互抵消了。这个现象在统计学里被称为“辛普森悖论”的可视化体现。如果你不分颜色只看整体云团可能觉得“无关”一旦按类别着色就会发现每个类别的点群其实各自沿一条清晰的趋势线移动。实现上seaborn的scatterplot提供hue参数matplotlib可以循环取颜色或者用c参数传一个颜色数组。有一个细节值得注意类别数不宜太多。颜色通道不像坐标轴那么精确人眼能轻松分辨的颜色类别很有限。一般3到6个类别用颜色很清晰超过7个就会开始眼花缭乱。此时更合适的做法是转到分面图。3.2 分面散点图按类别拆出独立坐标系分面就是把数据按某个分类变量切割成多个子数据集每个子数据集在独立的小坐标轴上绘制散点图最后按网格排列。分面图本质上和分组着色表达的信息一样但组织形式完全不同。着色把所有点放在一个图里再用颜色区分分面是物理上拆分出多个小图互不干扰。两者怎么选我的经验是看你要强调什么。如果想让读者比较“整体与局部”的关系在一个图里着色更直观如果想让读者分别独立观察每个组内部的关系分面更清晰。类别数量多时、或者每个类别的点特别多时分面几乎是更优选择因为点的重叠问题在每个小图里都会有所缓解。seaborn里有一个很称手的工具relplot。它同时支持散点图和线图kindscatter时就是散点图col、row参数能把类别变量映射到列方向和行方向。比如你想看不同渠道、不同产品类型两个分类维度下的价格-销量关系设置col渠道, row产品类型一张大图里就会出现一个行列网格每个单元格都是某个组合的散点图。这个功能在探索性数据分析阶段非常实用一张图就能同时覆盖两个分类维度加上x、y两个数值维度和颜色维度信息密度远超普通散点图。分面图的唯一问题是子图太多时整张图会变得很大阅读负担也跟着上升。所以实际使用中我会控制分面维度在1到2个如果超过两个就事先做筛选只保留最重要的分类组合。3.3 带阈值参考线的散点图当监控仪表盘用散点图不仅能看趋势还能当“监控仪表盘”来用。做法很简单在图上画若干条水平或垂直参考线把平面划分成正常区域和异常区域再结合点的颜色或形状标记出异常样本。这种带阈值的散点图在质量检测、风险监控、指标异常预警等场景里非常常见。具体怎么操作假设你要监控一批设备的温度与振动指标正常工作时两者大体落在一个椭圆形区域内出了异常就会偏离。你可以先在历史正常数据上拟合一个椭圆边界比如基于协方差的马氏距离椭圆然后把新数据点画上去落在椭圆外的点用红色标出。这种图的价值在于把“异常”从抽象数字变成了可见的空间位置谁都能一眼看出哪些点在区间之外。如果不做椭圆这么复杂也可以简单画几条参考线。matplotlib里用axhline和axvline画水平、垂直线标注区域用axhspan和axvspan填充半透明色带。我自己的经验是这类图配合文本标注效果最好在异常点旁边标注简短说明或序号大大降低沟通成本。3.4 动态与交互散点图让点“活”起来静态散点图画得再好遇到需要展示时间演变或者查看每个点细节的场景就显得不够用了。这时候可以上交互散点图鼠标悬停时显示该点的详细字段点击可以缩放平移中间用时间轴播放动态变化。交互式散点图的典型实现是plotly express的scatter方法。它的语法和seaborn很接近但输出的是HTML页面自带悬浮提示、缩放、图例开关。如果数据里有一列表示时间给scatter加上animation_frame参数就能生成一个可播放的动画每一帧是一张散点图随时间轴流动点的位置在图上“奔跑”。这个玩法在展示用户轨迹、资产价格、传感器时序等场景非常出效果。import plotly.express as px fig px.scatter( df, x价格, y销量, size营销投入, color城市等级, animation_frame时间周期, hover_data[产品编号], ) fig.show()不过做交互图时我要提醒一下性能问题。点超过几千个之后plotly在浏览器里的响应会明显变慢。我的做法是交互图只放抽样后的数据或聚合后的数据维持在上千个点以内完整数据的探索分析还是在静态图里完成。另外交互图虽然交互性强但分享给别人的时候要确保对方环境能打开HTML文件或者直接用plotly导出静态图片作为备份。4. 实操演示把衍生散点图串进一个真实分析流程4.1 一个模拟场景和基础图起点为了让前面这些图不流于概念我模拟一个分析场景某产品在不同城市的投放数据包含售价、销量、营销投入、城市等级、时间周期等字段。数据量不大但足够演示。第一步一定是画最朴素的散点图。x轴放售价y轴放销量。这一步的意义是建立基准认知快速确认两个变量的总体关系形态。如果这一步已经出现明显的非线性趋势后面加回归线时就要小心选择模型形式。import matplotlib.pyplot as plt plt.scatter(df[售价], df[销量], alpha0.6) plt.xlabel(售价) plt.ylabel(销量) plt.title(基础散点图售价 vs 销量) plt.show()4.2 按业务问题逐步叠加图形要素接下来想看看营销投入的影响就把营销投入映射到气泡大小。用s参数传入缩放后的面积数组。这里有个小细节营销投入的分布可能严重右偏最大的投资金额比中位数大很多直接线性缩放会出现一个超大泡泡盖住整张图。我一般会先对营销投入做对数变换再缩放到合适的面积范围这样气泡大小分布更均匀。再往下一步把“城市等级”这个分类变量用颜色编码并叠加一条去掉异常点后的线性回归线。我说一下为什么要“去掉异常点后再拟合”某些极端值比如新品首发期的特殊定价会严重拉偏回归线导致整体趋势失真。实际操作时我会先画一条基于全量数据的拟合线再画一条基于95%分位以内数据的拟合线两条线对比如果差异很大说明拟合结果对离群点敏感需要在报告里特别说明。如果同一张图里颜色太多会乱再把每个城市等级的散点图拆分成三个小图分开展示。用relplotcol城市等级。三个小图并排每个子图里价格和销量的关系一目了然比混在一起着色视图清楚得多。4.3 用“先密度、再抽样、后交互”处理大数据量如果这个分析方法要扩展到全国百万条数据别急着用普通散点图。我建议先用hexbin快速看全量的密度分布再抽样几千条做交互式散点图最后再考虑要不要用六边形分箱图作为最终展示形式。这个“先密度、再抽样、后交互”的组合思路是我个人比较推荐的大体量数据标准路径。先密度是用最小的成本看全量分布再抽样是让交互图保持流畅后交互是让读者能进一步探索细节。三步下来既不会在数据量面前崩掉又能保持图形应有的表达力。5. 常见问题与排查避坑实录5.1 点太多全糊成一团怎么处理这是最常碰到的问题。从小到大排列解决方案第一调透明度alpha适合几千点的场景能看出大致密度第二抽样比如从10万条数据里随机抽1万条牺牲一点细节换可读性第三用hexbin或密度等高线适合上百万的数据第四如果点有内在分层比如不同组别有不同聚集区域可以考虑聚类后只画聚类中心或轮廓。先判断数据量和关系复杂度再选不要一概而论。5.2 气泡大小看起来失真怎么排查先检查是不是用了半径而不是面积来映射。如果面积按原始数值线性映射数值跨度特别大时大泡会盖住其他点。解决办法是归一化或对数变换然后控制最大最小面积。另外为了让读者能准确理解大小编码图里最好有图例说明“气泡面积对应某个具体数值”。5.3 矩阵图和分面图画出来又大又乱怎么办变量多的时候矩阵会爆炸解决办法是不要把所有变量都放进矩阵先做相关性筛选只保留和业务目标强相关的4到6个变量。分面图同理如果每个分组里的数据量很少宁可合并相近分组或者退回到着色方案。一张干净图的重要程度远高于一张堆满信息的图。5.4 颜色区分不明显或打印失效怎么办分组散点图常用颜色编码但打印成黑白或阅读者是色盲时就会出问题。规避方案优先选色盲友好的配色如viridis或cividis加形状通道辅助区分在图上直接标注组别文字而不是只靠图例。我自己见过不少同事辛苦画了彩色图打印出来全灰一片点名批评都不为过。5.5 拟合线跟点的趋势对不上是什么原因这种情况通常不是画图问题而是模型选择问题。可以试试局部回归先画一条平滑曲线看看数据真正的形态再决定用几阶多项式或是否需要变量变换。不要一上来就用线性模型并试图强行解释。尤其当数据的形态是“中间高两头低”或“先快后慢”时线性回归的结论几乎没有参考价值。6. 我的一点使用心得说实话散点图是我平时工作中使用频率最高的图形。它足够快、足够准能直接引导接下来的分析方向。衍生图形真正让我受益的地方是它拓宽了散点图的表达能力让我在面对多维数据、海量数据、或者要做决策汇报时不必放弃这张我最熟悉的图而是可以对它进行扩展让它继续承载更复杂的分析任务。最后分享一个我自己的习惯无论画什么衍生图下笔之前都先问自己三个问题。第一个新增的维度——颜色、大小、分面——是否真的需要如果读者不关心营销投入的差异就不必硬加气泡大小。第二个颜色或大小是否可能误导读者面积翻倍在观感上绝不会是翻倍如果存在误导就要加标注。第三个这张图在全量数据和抽样数据上结论是否一致如果只在抽样后成立需要特别注明。问完这三个问题再决定画哪种衍生图形出图质量会稳定很多。
📝

华诺云谱内容团队

资深建站顾问 · 行业研究员

10年+企业数字化服务经验,专注智能建站、SEO优化与品牌营销,持续输出建站技巧、行业洞察与营销干货,已帮助5000+企业实现数字化增长。

你可能需要的服务

订阅华诺云谱资讯周报

每周一封,精选建站技巧、SEO与营销干货,直达邮箱。已有 8,000+ 企业主订阅,助你少走弯路。

↑