从零开始的数据分析之旅
Matplotlib和Seaborn生成静态图片,而Plotly生成交互式图表——鼠标悬停显示数据、缩放平移、点击筛选、动态动画。在数据报告和仪表盘中,交互式图表让读者自己探索数据,远比静态图更有说服力。
import plotly.graph_objects as go
import numpy as np
x = np.linspace(0, 10, 100)
fig = go.Figure()
fig.add_trace(go.Scatter(x=x, y=np.sin(x), mode='lines',
name='sin(x)', line=dict(color='#3b82f6', width=2)))
fig.add_trace(go.Scatter(x=x, y=np.cos(x), mode='lines',
name='cos(x)', line=dict(color='#60a5fa', width=2, dash='dash')))
fig.update_layout(title='交互折线图', template='plotly_dark')
fig.write_html('line.html') # 导出为独立HTML
import plotly.express as px
df = px.data.iris()
fig = px.scatter(df, x='sepal_width', y='sepal_length', color='species',
size='petal_length', hover_data=['petal_width'],
title='鸢尾花交互散点图', template='plotly_dark')
fig = px.scatter_3d(df, x='sepal_length', y='sepal_width',
z='petal_length', color='species',
title='3D散点图', template='plotly_dark')
gap = px.data.gapminder()
fig = px.scatter(gap, x='gdpPercap', y='lifeExp',
animation_frame='year', animation_group='country',
size='pop', color='continent', hover_name='country',
log_x=True, size_max=50, range_y=[25, 90],
title='全球发展动态', template='plotly_dark')
| 格式 | 方法 | 用途 |
|---|---|---|
| HTML | fig.write_html() | 独立交互网页 |
| PNG | fig.write_image() | 静态图片(需kaleido) |
| JSON | fig.to_json() | 数据交换 |
| Dash | dash.Dash() | Web应用 |
# 导出为独立HTML(无需服务器即可打开)
fig.write_html('chart.html', include_plotlyjs='cdn')
# 嵌入到网页
fig.write_html('chart.html', include_plotlyjs=False,
full_html=False) # 只输出div+script
write_html默认包含完整的Plotly.js库(~3MB)。如果页面已加载Plotly.js,用include_plotlyjs=False可大幅减小文件。import plotly.express as px
# 柱状图
fig = px.bar(px.data.medals_long(), x='nation', y='count',
color='medal', barmode='group', template='plotly_dark')
# 饼图
fig = px.pie(px.data.gapminder().query("year==2007 and continent=='Asia'"),
values='pop', names='country', template='plotly_dark')
# 地理散点图
gap = px.data.gapminder().query("year==2007")
fig = px.scatter_geo(gap, locations='iso_alpha', size='pop',
color='continent', template='plotly_dark')
import plotly.graph_objects as go
# 自定义悬停
fig = go.Figure()
fig.add_trace(go.Scatter(
x=[1,2,3], y=[4,5,6], mode='markers+text',
text=['A','B','C'],
hovertemplate='X: %{x}<br>Y: %{y}<br>标签: %{text}<extra></extra>'
))
# 范围滑块
fig.update_xaxes(rangeslider_visible=True)
#!/usr/bin/env python3
# Plotly交互 — 完整实战
import plotly.graph_objects as go
import plotly.express as px
import numpy as np
import pandas as pd
import os
# ============ 交互折线图 ============
x = np.linspace(0, 10, 100)
fig1 = go.Figure()
fig1.add_trace(go.Scatter(x=x, y=np.sin(x), mode='lines', name='sin(x)',
line=dict(color='#3b82f6', width=2)))
fig1.add_trace(go.Scatter(x=x, y=np.cos(x), mode='lines', name='cos(x)',
line=dict(color='#60a5fa', width=2, dash='dash')))
fig1.update_layout(title='交互折线图', template='plotly_dark')
fig1.write_html('line.html')
print("交互折线图已保存")
# ============ 交互散点图 ============
df = px.data.iris()
fig2 = px.scatter(df, x='sepal_width', y='sepal_length', color='species',
size='petal_length', hover_data=['petal_width'],
title='鸢尾花交互散点图', template='plotly_dark')
fig2.write_html('scatter.html')
print("交互散点图已保存")
# ============ 3D散点图 ============
fig3 = px.scatter_3d(df, x='sepal_length', y='sepal_width', z='petal_length',
color='species', title='3D散点图', template='plotly_dark')
fig3.write_html('3d.html')
print("3D散点图已保存")
# ============ 动画图 ============
gap = px.data.gapminder()
fig4 = px.scatter(gap, x='gdpPercap', y='lifeExp', animation_frame='year',
animation_group='country', size='pop', color='continent',
hover_name='country', log_x=True, size_max=50,
range_y=[25, 90], title='全球发展动态', template='plotly_dark')
fig4.write_html('animate.html')
print("动画图已保存")
# ============ 直方图 ============
np.random.seed(42)
data = pd.DataFrame({'值': np.random.randn(500), '组': np.random.choice(['A','B','C'], 500)})
fig5 = px.histogram(data, x='值', color='组', nbins=30, barmode='overlay',
title='交互直方图', template='plotly_dark')
fig5.write_html('hist.html')
print("直方图已保存")
# 验证文件大小
for f in ['line.html', 'scatter.html', '3d.html', 'animate.html', 'hist.html']:
print(f" {f}: {os.path.getsize(f)/1024:.1f}KB")
print("\n✅ Python验证通过 — 交互图表+导出HTML")
| 格式 | 大小 | 交互 | 离线 | 推荐场景 |
|---|---|---|---|---|
| HTML(含JS) | 3-5MB | ✅ | ✅ | 独立分享 |
| HTML(CDN) | 5-50KB | ✅ | ❌ | 网页嵌入 |
| PNG | 100-500KB | ❌ | ✅ | 报告/PPT |
| SVG | 50-200KB | ❌ | ✅ | 矢量打印 |
| JSON | 1-10KB | ✅ | ✅ | 数据交换 |
write_html()导出独立交互网页template='plotly_dark'深色主题# Plotly速查
import plotly.express as px
import plotly.graph_objects as go
# Express (快速)
fig = px.scatter(df, x='A', y='B', color='C', size='D')
fig = px.line(df, x='X', y='Y', color='组')
fig = px.bar(df, x='类别', y='值', barmode='group')
fig = px.histogram(df, x='值', nbins=30)
# Graph Objects (精细)
fig = go.Figure()
fig.add_trace(go.Scatter(x=x, y=y, mode='lines'))
fig.add_trace(go.Bar(x=categories, y=values))
# 导出
fig.write_html('chart.html')
fig.show()