Plotly 交互可视化
问题
Plotly 适合什么场景?如何创建交互式图表和数据看板?
答案
Plotly 定位
| 维度 | Matplotlib/Seaborn | Plotly |
|---|---|---|
| 输出 | 静态图片 | 交互 HTML |
| 操作 | 无 | 悬停、缩放、筛选 |
| 看板 | 不支持 | Dash 框架 |
| API | 命令式 | 声明式 |
| 适用 | 论文、脚本 | 报告、Web、看板 |
Plotly Express(快速出图)
Plotly Express 常用图表
import plotly.express as px
import pandas as pd
# 内置数据集
df = px.data.gapminder()
df_2007 = df[df['year'] == 2007]
# 1. 散点图(悬停显示国家信息)
fig = px.scatter(
df_2007,
x='gdpPercap', y='lifeExp',
size='pop', color='continent',
hover_name='country',
log_x=True,
title='2007 年全球 GDP vs 预期寿命'
)
fig.show()
# 2. 柱状图
top10 = df_2007.nlargest(10, 'pop')
fig = px.bar(
top10, x='country', y='pop',
color='continent',
title='2007 年人口 Top 10'
)
fig.show()
# 3. 折线图(多国 GDP 趋势)
countries = ['China', 'United States', 'Japan', 'Germany']
fig = px.line(
df[df['country'].isin(countries)],
x='year', y='gdpPercap',
color='country',
title='人均 GDP 趋势'
)
fig.show()
高级图表
特殊图表类型
import plotly.express as px
import plotly.graph_objects as go
# 1. 漏斗图
fig = px.funnel(
pd.DataFrame({
'stage': ['访问', '注册', '下单', '付款', '复购'],
'count': [10000, 3000, 1500, 1200, 400]
}),
x='count', y='stage',
title='用户转化漏斗'
)
fig.show()
# 2. 桑基图(流转路径)
fig = go.Figure(go.Sankey(
node=dict(label=['首页', '列表页', '详情页', '购物车', '支付', '流失']),
link=dict(
source=[0, 0, 1, 1, 2, 2, 3, 3],
target=[1, 5, 2, 5, 3, 5, 4, 5],
value= [600, 400, 400, 200, 300, 100, 250, 50]
)
))
fig.update_layout(title='用户行为路径')
fig.show()
# 3. 热力图
import numpy as np
fig = px.imshow(
np.random.rand(7, 24),
labels=dict(x='小时', y='星期', color='活跃度'),
x=[f'{h}:00' for h in range(24)],
y=['周一', '周二', '周三', '周四', '周五', '周六', '周日'],
color_continuous_scale='YlOrRd',
title='用户活跃热力图'
)
fig.show()
动画图表
时间轴动画
import plotly.express as px
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()
Graph Objects(精细控制)
组合多类型图表
import plotly.graph_objects as go
months = ['1月', '2月', '3月', '4月', '5月', '6月']
revenue = [120, 135, 140, 155, 170, 180]
cost = [80, 85, 90, 95, 100, 105]
profit_rate = [33, 37, 36, 39, 41, 42]
fig = go.Figure()
# 柱状图:收入和成本
fig.add_trace(go.Bar(x=months, y=revenue, name='收入', marker_color='#2196F3'))
fig.add_trace(go.Bar(x=months, y=cost, name='成本', marker_color='#FF9800'))
# 折线图:利润率(次 Y 轴)
fig.add_trace(go.Scatter(
x=months, y=profit_rate,
name='利润率%', yaxis='y2',
mode='lines+markers',
line=dict(color='#4CAF50', width=3)
))
fig.update_layout(
title='月度财务概览',
yaxis=dict(title='金额(万元)'),
yaxis2=dict(title='利润率(%)', overlaying='y', side='right'),
barmode='group'
)
fig.show()
Dash 看板(简介)
Dash 简易看板结构
# pip install dash
from dash import Dash, html, dcc
import plotly.express as px
app = Dash(__name__)
df = px.data.gapminder()
app.layout = html.Div([
html.H1('全球数据看板'),
dcc.Dropdown(
id='continent-dropdown',
options=[{'label': c, 'value': c} for c in df['continent'].unique()],
value='Asia'
),
dcc.Graph(id='scatter-plot'),
dcc.Graph(id='line-plot')
])
# 回调函数根据筛选更新图表(略)
# @app.callback(Output('scatter-plot', 'figure'), Input('continent-dropdown', 'value'))
if __name__ == '__main__':
app.run(debug=True)
常见面试问题
Q1: Plotly 和 Matplotlib 怎么选?
答案:
- Matplotlib/Seaborn:论文、报告中需要静态高质量图
- Plotly:需要交互(悬停、缩放、筛选)的场景
- Plotly + Dash:需要搭建 Web 看板
- 实际工作中两者经常搭配使用
Q2: 如何导出 Plotly 图表?
答案:
# 交互 HTML(推荐)
fig.write_html('chart.html')
# 静态图片(需安装 kaleido)
fig.write_image('chart.png', scale=2)
fig.write_image('chart.svg')
fig.write_image('chart.pdf')
Q3: Plotly Express 和 Graph Objects 什么区别?
答案:
- Plotly Express (px):高级接口,一行代码出图,接受 DataFrame
- Graph Objects (go):底层接口,精细控制每个元素
- 通常先用 px 快速出图,需要深度定制时切换到 go