快速成功数据科学
towardsdatascience.com/chart-wars-stacked-bar-chart-vs-heatmap-959423de6fee
当你需要比较两个共享同一个数值变量的分类变量时,哪种可视化方式最为有效?如果你第一反应是“堆积条形图”,这并不奇怪——尤其是在时间紧迫的情况下,这种选择很常见。
然而,堆积条形图往往容易造成视觉混乱。以下示例使用了来自劳工统计局的公共领域数据,其中两个分类变量分别为“支出类型”(如食品、交通等)和“年龄段”,数值变量则是“总支出百分比”。
https://github.com/OpenDocCN/towardsdatascience-blog-zh-2024/raw/master/docs/img/b06adbd076e970ba39f65a065b682df9.png堆积条形图(作者绘制)
虽然从整体上看最大支出类别较为明显,但若要按年龄段进行细分分析,则非常困难,即便借助放大工具也难以清晰辨识。此外,x轴的累计值超过了100%,进一步加剧了误解风险。
改用分组条形图会稍有改善,但阅读体验依然不够直观:
https://github.com/OpenDocCN/towardsdatascience-blog-zh-2024/raw/master/docs/img/522408151ede51dd664dfd1a0631136c.png分组条形图(作者绘制)
面对此类图表时,人们常常质疑:作者是否真正理解数据呈现的目的?还是有意让信息变得模糊不清?
相比之下,热图提供了一种更优的替代方案。热图利用颜色在二维网格中表示数值大小,能够更高效地传达复杂关系。
下面是同一组数据转换为热图后的表现形式:
https://github.com/OpenDocCN/towardsdatascience-blog-zh-2024/raw/master/docs/img/2df18cead23e2996292b0d98e6483aaf.png热图(作者绘制)
相较于传统的条形图,热图具备多项优势:视觉上更加简洁美观,避免了条形图常见的拥挤感;每个单元格尺寸一致,确保小数值不会被忽略;同时还能直接标注具体数值,提升可读性。
通过该热图,可以迅速识别出主要支出项,并清晰观察到不同年龄层之间的变化趋势。显著差异一目了然,而颜色变化平缓的行则表明该类支出在各年龄段中相对稳定。
例如,可以看出:
- 住房 是最大的支出项目,且在整个生命周期中保持高位稳定;
- 食物 的支出比例基本恒定;
- 交通 支出从青年阶段到老年阶段呈缓慢下降趋势;
- 医疗保健 开支大约增长了三倍;
- 保险 类支出显著减少;
- 现金捐赠(如对子女或慈善机构的支持)则随年龄增长稳步上升。
接下来将介绍如何使用 Python 中的 pandas 和 Plotly Express 库来生成上述热图。
热图绘制代码实现
以下代码首先将 CSV 文件加载为 pandas DataFrame,随后调用 Plotly Express 将其绘制成热图。所用数据源自美国人口普查局编制的 2021 年《消费者支出调查》简化版本。
注意:由于部分影响较小的类别(如“阅读”、“烟草”和“杂项”)已被剔除,因此各支出类别的百分比总和不会精确等于 100%。
导入库并加载数据
本项目依赖两个第三方库:pandas 和 plotly_express。相关安装方法可通过其官方文档获取。
数据文件通过 GIST 提供的 URL 直接加载,并将“Expenditure Type”列设为 DataFrame 的索引,以便后续绘图操作。
import pandas as pd
import plotly_express as px
# 从指定URL读取CSV文件并创建DataFrame
df = pd.read_csv('https://bit.ly/3RsVQkF', header=1)
df.set_index('Expenditure Type', inplace=True)
display(df)
https://github.com/OpenDocCN/towardsdatascience-blog-zh-2024/raw/master/docs/img/157635dc6759d83cae3c56bc6a320ff7.png
完整的 DataFrame(作者提供)
表中数值代表各类别在总支出中所占百分比。再次说明,因已排除若干低占比类别,故总和不等于100%。
绘制热图
Plotly Express 在功能上类似于 Seaborn 之于 Matplotlib 的角色:它为 Plotly 提供了更高层次、更易用的接口,支持以极少代码实现多样化可视化效果。
下面这段代码比标准的 Plotly Express 示例略显复杂,原因在于加入了单元格内的数值标注功能。此外,颜色映射方案也由原先的黄-橙-棕色调替换为灰色系,以增强可读性和专业感。
YlOrBr热图由 Plotly Express 的 px.imshow() 方法创建,其主要输入包括一个 DataFrame、坐标轴标签、颜色映射设置以及图表标题。其中,x 轴表示“年龄区间”,y 轴为“支出类型”,颜色深浅反映“支出占比”的数值大小,并采用灰度色彩方案进行渲染。
在生成图像后,通过循环结构对每个单元格添加文本标注:
for i, expenditure_type in enumerate(df.index):
for j, age_bracket in enumerate(df.columns):
fig.add_annotation(x=j, y=i,
text=str(df.loc[expenditure_type, age_bracket]),
showarrow=False)
for
该段代码逐一遍历行索引(支出类型)和列索引(年龄区间),利用 fig.add_annotation() 将对应的数据值以文字形式嵌入到热图的每一个格子中。虽然颜色梯度本身已能传达数值差异,但显式标注显著提升了可读性。注释字体设置为 Arial,字号 12,颜色为深红色,确保清晰可见。
接下来是对整体布局的调整:
- 图形宽度设为 600,高度为 1000,适应较长的垂直结构;
- 边距参数设定为左侧 20、右侧 10、顶部 20、底部 20;
- x 轴与 y 轴的刻度标签均使用 “Arial Black” 字体,使其加粗显示;
- 关闭右侧的颜色条(color scale),因为在每个单元格已有数值标注的情况下,颜色刻度不再是必需的。
标题部分包含 HTML 换行符(<br>)来控制位置:
title='<br><br>2021 Expenditure (Percent) by Age Bracket'
<br>
这一技巧用于避免 Plotly Express 默认将标题置于过高的位置,从而优化视觉对齐效果。若不添加换行符,标题会距离图表主体太远,影响美观。
最终生成的热图如下所示,采用了灰色至深灰的配色方案:
imshow()
值得注意的是,Plotly Express 所生成的图表是动态交互式的。当鼠标悬停在某个热图单元格上时,会弹出一个信息窗口,显示该位置的具体数据内容:
add_annotations()
这种“悬停提示”功能极大增强了图表的信息承载能力。尤其在颜色相近或标注密集导致辨识困难时,用户可通过悬停精确获取数值。此外,它还支持展示原始 DataFrame 中未直接用于绘图的附加字段,实现更丰富的数据探索。
关于热图的优势总结
热图通过二维矩阵结合颜色强度来表现数据量级,非常适合揭示变量间的潜在模式、相关性或异常区域。相较于堆积条形图等替代方案,热图具备以下优势:
- 所有单元格尺寸一致,避免小数值被视觉压缩或忽略;
- 每个格子均可独立标注,提升信息透明度;
- 适合同时比较多个分类维度下的数据分布。
借助 pandas DataFrame 与 Plotly Express 的集成接口,构建高质量热图变得极为简便。只需几行代码即可完成从数据到可视化输出的全过程,且默认支持交互功能,便于深入分析。
如何选择合适的图表类型?
在数据叙事过程中,最关键的决策之一是选用恰当的图表形式。如果对此存在困惑,可以参考两个权威资源:“从数据到可视化”网站和“数据故事讲述”图表指南。它们系统地梳理了不同数据场景下最优的可视化策略,是数据从业者常用的实用工具。
改进版的堆积条形图思路
尽管本文重点在于热图,但也应意识到,在某些情境下,传统堆积条形图可能存在局限,例如难以分辨底层小类别的贡献。而热图提供了一种更为均衡、直观的替代方案,尤其适用于高维分类数据的并列比较。
堆积条形图在某些情况下依然具有其独特的价值。其中,一种被称为“Marimekko”图表的变体,因其兼具视觉吸引力和信息表达能力,往往能带来出色的展示效果:towardsdatascience.com/chart-wars-stacked-bar-chart-vs-heatmap-959423de6fee
通过 Python,我们可以创建既美观又具备实际应用价值的 Marimekko 图表,使其在数据可视化中发挥更大作用。

雷达卡


京公网安备 11010802022788号







