跳转到内容

3.4.4 交互式可视化

  • 理解静态图 vs 交互图的区别
  • 掌握 Plotly Express 快速绑图
  • 了解交互式仪表盘的概念

Plotly 最适合按“什么时候要让用户自己探索图表”来理解:

Plotly 交互式仪表盘图

所以这节真正想解决的是:

  • 交互图到底在补静态图的哪一层能力
  • 什么时候它是加分,什么时候反而会显得多余

对比静态图(Matplotlib/Seaborn)交互图(Plotly)
鼠标悬停不支持显示详细数据
缩放拖动不支持自由缩放和平移
数据筛选不支持可点击图例隐藏/显示
导出保存为图片图片 + HTML 网页
使用场景论文、报告数据探索、网页展示
flowchart LR
A["我的图表需要<br/>交互吗?"] --> B{"使用场景"}
B -->|"论文/报告/PPT"| C["Matplotlib / Seaborn<br/>静态图足够"]
B -->|"数据探索/演示"| D["Plotly<br/>交互更方便"]
B -->|"网站/仪表盘"| E["Plotly + Dash<br/>交互式应用"]
style C fill:#e3f2fd,stroke:#1565c0,color:#333
style D fill:#e8f5e9,stroke:#2e7d32,color:#333
style E fill:#fff3e0,stroke:#e65100,color:#333

你可以把 Plotly 理解成:

  • 一张可以拿在手里自己翻看、放大和筛选的图

静态图更像:

  • 已经印好的海报

交互图更像:

  • 带放大镜和筛选按钮的电子地图

所以它最适合:

  • 读者自己继续探索

而不是所有场景都强行加交互。


# 安装
# python -m pip install --upgrade plotly
# Plotly Express:快速绑图(推荐)
import plotly.express as px
# Plotly Graph Objects:更底层的控制
import plotly.graph_objects as go
import pandas as pd
import numpy as np

Plotly Express 是 Plotly 的高级接口,一行代码就能创建漂亮的交互式图表。

更稳的顺序通常是:

  1. 先用 px.scatter()px.line()px.bar() 熟悉基本交互
  2. 再看热力图、3D 和动画图
  3. 最后再看仪表盘和网页展示

这样会比一开始就扑到 Dash 上更不容易乱。

# 使用内置数据集
df = px.data.iris()
fig = px.scatter(df, x="sepal_width", y="sepal_length",
color="species", # 按物种分颜色
size="petal_length", # 用花瓣长度控制点大小
hover_data=["petal_width"], # 悬停显示花瓣宽度
title="鸢尾花数据集 - 交互式散点图")
fig.show()

运行后,你会看到一个可以悬停、缩放、拖动的图表!

df = px.data.gapminder()
# 筛选中国、美国、日本的数据
countries = df[df["country"].isin(["China", "United States", "Japan"])]
fig = px.line(countries, x="year", y="gdpPercap",
color="country",
title="中美日人均 GDP 变化",
labels={"gdpPercap": "人均 GDP(美元)", "year": "年份", "country": "国家"})
fig.show()
df = px.data.tips()
fig = px.bar(df, x="day", y="total_bill", color="sex",
barmode="group", # "group" 分组, "stack" 堆叠
title="各日消费(按性别分组)",
labels={"total_bill": "消费金额", "day": "星期", "sex": "性别"})
fig.show()
df = px.data.tips()
fig = px.histogram(df, x="total_bill", color="time",
nbins=20,
marginal="box", # 边际图:"box", "violin", "rug"
title="消费金额分布(带边际箱线图)")
fig.show()
df = px.data.tips()
fig = px.box(df, x="day", y="total_bill", color="smoker",
notched=True, # 带缺口的箱线图
title="各日消费分布(按是否吸烟)")
fig.show()
# 饼图
fig = px.pie(df, names="day", values="total_bill",
title="各日消费占比",
hole=0.3) # hole > 0 变成甜甜圈图
fig.show()

# 计算相关系数
df = px.data.iris()
numeric_cols = df.select_dtypes(include="number")
corr = numeric_cols.corr()
fig = px.imshow(corr, text_auto=".2f",
color_continuous_scale="RdBu_r",
title="鸢尾花特征相关性热力图")
fig.show()
df = px.data.iris()
fig = px.scatter_3d(df, x="sepal_length", y="sepal_width", z="petal_length",
color="species",
title="鸢尾花 3D 散点图(可旋转!)")
fig.show()

你可以用鼠标拖动旋转这个 3D 图,从不同角度观察数据。

df = px.data.gapminder()
fig = px.scatter(df, x="gdpPercap", y="lifeExp",
size="pop", color="continent",
hover_name="country",
animation_frame="year", # 按年份播放动画
animation_group="country",
log_x=True,
range_x=[100, 100000],
range_y=[25, 90],
title="各国发展轨迹(1952-2007)")
fig.show()

点击播放按钮,可以看到各国在不同年份的变化。这就是著名的 Hans Rosling 气泡图


fig = px.scatter(px.data.iris(), x="sepal_width", y="sepal_length",
color="species")
fig.update_layout(
title=dict(text="自定义标题", font=dict(size=20)),
xaxis_title="萼片宽度 (cm)",
yaxis_title="萼片长度 (cm)",
template="plotly_white", # 模板主题
width=800,
height=500,
legend_title="品种"
)
fig.show()
模板名风格
"plotly"默认蓝色背景
"plotly_white"白底(推荐)
"plotly_dark"深色背景
"ggplot2"R ggplot 风格
"simple_white"极简白底

一个很适合初学者先记的判断表

Section titled “一个很适合初学者先记的判断表”
你的目标更稳的第一反应
给论文或报告出图静态图优先
自己探索数据细节Plotly 很合适
给别人做网页演示Plotly 很合适
只是想“更炫”先停一下,想清楚有没有必要

这个表特别适合新人,因为它会把“交互图很酷”重新拉回成一个使用场景判断。

# 保存为交互式 HTML
fig.write_html("my_chart.html")
# 保存为静态图片(需安装 kaleido)
# python -m pip install --upgrade kaleido
fig.write_image("my_chart.png", scale=2)
fig.write_image("my_chart.svg")

特性MatplotlibSeabornPlotly
交互性
美观度一般
学习难度
定制能力极强
输出格式图片/PDF图片/PDFHTML/图片
适合场景论文/精细控制快速统计图数据探索/展示

在实际工作中,你可能需要将多个交互式图表组合成一个仪表盘(Dashboard)。

常用工具:

工具特点
Plotly DashPython 代码构建,功能强大
Streamlit最简单,几行代码就能做应用
GradioAI 模型演示专用
PanelJupyter 生态集成好

一个简单的 Dash 示例(了解即可):

# python -m pip install --upgrade dash
from dash import Dash, html, dcc
import plotly.express as px
app = Dash(__name__)
df = px.data.gapminder().query("year == 2007")
fig = px.scatter(df, x="gdpPercap", y="lifeExp", size="pop",
color="continent", hover_name="country", log_x=True)
app.layout = html.Div([
html.H1("世界发展指标仪表盘"),
dcc.Graph(figure=fig)
])
# 运行:python app.py,然后打开 http://127.0.0.1:8050
# app.run(debug=True)

学完这一页,至少保留这张证据卡:

问题
这张图表回答的是比较、分布、趋势,还是关系
图表选择
折线图、柱状图、散点图、直方图、箱线图、热力图或交互式仪表板
工件
保存的图表图片/html 以及所用的数据切片
失败检查
尺度误导、图表过载、聚合错误或缺少标签
期望产出
带有一句说明洞察的图表成果
Plotly Express 函数图表类型
px.scatter()散点图
px.line()折线图
px.bar()柱状图
px.histogram()直方图
px.box()箱线图
px.pie()饼图
px.imshow()热力图
px.scatter_3d()3D 散点图

Plotly 的核心优势就是交互——鼠标悬停查看数据、缩放细看局部、动画展示变化。在数据探索和结果展示时非常好用。

  • Plotly 的核心价值不是炫,而是让读者能继续探索数据
  • 交互图最适合数据探索、网页展示和演示场景
  • 第一次学时先掌握 px.scatter / px.line / px.bar 这几类就够用了

# 加载 gapminder 数据集
# 1. 用 px.scatter 画出 2007 年各国 gdpPercap vs lifeExp 的关系
# - 用 pop 控制点大小,continent 控制颜色
# - 悬停显示 country
# 2. 用 px.line 画出中国 1952-2007 年的 lifeExp 变化
# 加载 tips 数据集
# 1. 用 px.histogram 画消费金额分布,用 marginal="violin" 添加边际图
# 2. 用 px.box 按星期比较消费金额
# 用 gapminder 数据集制作动画散点图
# 展示 1952-2007 年各国 gdpPercap vs lifeExp 的变化
# 用 animation_frame="year"
参考实现与讲解
  • Gapminder 风格散点图要有意识地映射 x、y、size、color 和 hover text。hover 字段应帮助回答问题,而不是把所有列都塞进去。
  • 国家或产品趋势线要先按时间排序,并确认 x 轴是日期或有序年份字段。未排序的时间数据会画出误导性的折线。
  • 动态图必须服务于稳定的问题。如果动画反而妨碍比较,就补一张静态摘要图或最终帧说明。