Plotly是一个强大的交互式数据可视化库,它可以让你创建出具有高度交互性的图表。与Matplotlib和Seaborn不同,Plotly生成的图表可以:
本文将带你掌握Plotly的核心技能。
Plotly是一个交互式数据可视化库,支持创建交互式图表和仪表板。
# 使用pip安装
pip install plotly pandas numpy
# 或使用conda安装
conda install plotly pandas numpy
import plotly.express as px
import plotly.graph_objects as go
import pandas as pd
import numpy as np
print("Plotly版本:", px.__version__)
print("环境搭建成功!")
散点图可以悬停查看每个点的详细信息。
import plotly.express as px
import pandas as pd
import numpy as np
# 加载示例数据
tips = px.data.tips()
# 创建交互式散点图
fig = px.scatter(tips,
x='total_bill',
y='tip',
color='sex',
size='size',
hover_data=['day', 'time'],
title='账单金额与小费的关系',
labels={'total_bill': '账单金额 ($)', 'tip': '小费 ($)'},
color_discrete_map={'Male': '#4ECDC4', 'Female': '#FF6B6B'})
# 更新布局
fig.update_layout(
title_font_size=16,
xaxis_title_font_size=12,
yaxis_title_font_size=12,
legend_title_font_size=12,
height=600,
width=900
)
# 显示图表
fig.show()
柱状图可以悬停查看具体数值。
fig = px.bar(tips,
x='day',
y='total_bill',
color='sex',
barmode='group',
title='每天的账单金额',
labels={'total_bill': '账单金额 ($)', 'day': '星期'},
color_discrete_map={'Male': '#4ECDC4', 'Female': '#FF6B6B'})
fig.update_layout(
title_font_size=16,
height=600,
width=900
)
fig.show()
折线图适合展示时间序列数据。
# 创建时间序列数据
np.random.seed(42)
dates = pd.date_range('2024-01-01', '2024-12-31', freq='D')
values1 = np.cumsum(np.random.randn(365)) + 100
values2 = np.cumsum(np.random.randn(365)) + 100
df_line = pd.DataFrame({
'日期': dates,
'产品A': values1,
'产品B': values2
})
# 转换为长格式
df_line_melt = df_line.melt('日期', var_name='产品', value_name='销售额')
fig = px.line(df_line_melt,
x='日期',
y='销售额',
color='产品',
title='产品销售趋势',
labels={'销售额': '销售额', '日期': '日期'},
color_discrete_map={'产品A': '#4ECDC4', '产品B': '#FF6B6B'})
fig.update_layout(
title_font_size=16,
height=600,
width=1000,
hovermode='x unified'
)
fig.show()
饼图可以悬停查看每个部分的占比。
fig = px.pie(tips,
values='total_bill',
names='day',
title='每天的账单金额占比',
color_discrete_sequence=px.colors.qualitative.Set2)
fig.update_layout(
title_font_size=16,
height=600,
width=800
)
fig.update_traces(
textposition='inside',
textinfo='percent+label',
hovertemplate='%{label}: $%{value:.2f}<br>占比: %{percent}'
)
fig.show()
直方图可以悬停查看每个区间的频率。
fig = px.histogram(tips,
x='total_bill',
color='sex',
nbins=20,
title='账单金额分布',
labels={'total_bill': '账单金额 ($)'},
color_discrete_map={'Male': '#4ECDC4', 'Female': '#FF6B6B'},
marginal='box') # 添加边际图
fig.update_layout(
title_font_size=16,
height=600,
width=900,
barmode='overlay'
)
fig.update_traces(opacity=0.7)
fig.show()
Plotly的3D图表非常强大。
iris = px.data.iris()
fig = px.scatter_3d(iris,
x='sepal_length',
y='sepal_width',
z='petal_length',
color='species',
size='petal_width',
title='鸢尾花数据的3D可视化',
labels={'sepal_length': '萼片长度',
'sepal_width': '萼片宽度',
'petal_length': '花瓣长度'},
color_discrete_map={'setosa': '#FF6B6B',
'versicolor': '#4ECDC4',
'virginica': '#45B7D1'})
fig.update_layout(
title_font_size=16,
height=700,
width=900,
scene=dict(
xaxis_title='萼片长度',
yaxis_title='萼片宽度',
zaxis_title='花瓣长度'
)
)
fig.show()
密度热力图可以展示两个变量的联合分布。
fig = px.density_heatmap(tips,
x='total_bill',
y='tip',
marginal_x='histogram',
marginal_y='histogram',
title='账单金额与小费的密度热力图',
labels={'total_bill': '账单金额 ($)', 'tip': '小费 ($)'},
color_continuous_scale='Viridis')
fig.update_layout(
title_font_size=16,
height=700,
width=900
)
fig.show()
平行坐标图适合展示多变量数据。
fig = px.parallel_coordinates(iris,
color='species_id',
title='鸢尾花数据的平行坐标图',
color_continuous_scale=px.colors.diverging.Tealrose,
color_continuous_midpoint=2)
fig.update_layout(
title_font_size=16,
height=600,
width=1000
)
fig.show()
小提琴图可以展示数据分布。
fig = px.violin(tips,
y='total_bill',
x='day',
color='sex',
box=True,
points='all',
title='每天的账单金额分布',
labels={'total_bill': '账单金额 ($)', 'day': '星期'},
color_discrete_map={'Male': '#4ECDC4', 'Female': '#FF6B6B'})
fig.update_layout(
title_font_size=16,
height=600,
width=900
)
fig.show()
旭日图适合展示层级数据。
# 创建层级数据
data = {
'类别': ['电子产品', '电子产品', '电子产品', '配件', '配件', '配件'],
'产品': ['智能手机', '笔记本电脑', '平板电脑', '耳机', '充电器', '保护壳'],
'销售额': [50000, 40000, 30000, 15000, 10000, 5000]
}
df_sunburst = pd.DataFrame(data)
fig = px.sunburst(df_sunburst,
path=['类别', '产品'],
values='销售额',
title='产品销售构成',
color='类别',
color_discrete_map={'电子产品': '#4ECDC4', '配件': '#FF6B6B'})
fig.update_layout(
title_font_size=16,
height=700,
width=700
)
fig.show()
添加下拉菜单可以动态切换数据。
import plotly.graph_objects as go
# 创建数据
np.random.seed(42)
x = np.linspace(0, 10, 100)
y1 = np.sin(x)
y2 = np.cos(x)
y3 = np.tan(x)
fig = go.Figure()
# 添加三个轨迹
fig.add_trace(go.Scatter(x=x, y=y1, name='sin(x)', visible=True))
fig.add_trace(go.Scatter(x=x, y=y2, name='cos(x)', visible=False))
fig.add_trace(go.Scatter(x=x, y=y3, name='tan(x)', visible=False))
# 更新菜单
fig.update_layout(
updatemenus=[
dict(
buttons=list([
dict(
label='sin(x)',
method='update',
args=[{'visible': [True, False, False]},
{'title': '正弦函数'}]),
dict(
label='cos(x)',
method='update',
args=[{'visible': [False, True, False]},
{'title': '余弦函数'}]),
dict(
label='tan(x)',
method='update',
args=[{'visible': [False, False, True]},
{'title': '正切函数'}])
]),
direction='down',
showactive=True,
)
],
title='正弦函数',
height=600,
width=900
)
fig.show()
滑块可以动态调整参数。
# 创建数据
x = np.linspace(0, 10, 100)
fig = go.Figure()
# 添加初始轨迹
fig.add_trace(go.Scatter(x=x, y=np.sin(x), name='sin(x)'))
# 创建滑块步骤
steps = []
for freq in np.arange(0.5, 3.1, 0.5):
step = dict(
method='update',
args=[{'y': [np.sin(freq * x)]},
{'title': f'正弦函数 (频率={freq})'}],
label=f'{freq:.1f}'
)
steps.append(step)
# 添加滑块
fig.update_layout(
sliders=[dict(
active=0,
currentvalue={"prefix": "频率: "},
pad={"t": 50},
steps=steps
)],
title='正弦函数 (频率=0.5)',
height=600,
width=900
)
fig.show()
我们有一份销售数据,包含以下字段:
import plotly.express as px
import plotly.graph_objects as go
import pandas as pd
import numpy as np
# 创建模拟数据
np.random.seed(42)
dates = pd.date_range('2024-01-01', '2024-12-31', freq='D')
products = ['智能手机', '笔记本电脑', '平板电脑', '耳机', '充电器']
categories = ['电子产品', '电子产品', '电子产品', '配件', '配件']
data = {
'date': np.random.choice(dates, 1000),
'product': np.random.choice(products, 1000),
'category': np.random.choice(categories, 1000),
'quantity': np.random.randint(1, 10, 1000),
'price': np.random.choice([2999, 5999, 1999, 299, 99], 1000)
}
df = pd.DataFrame(data)
df['revenue'] = df['quantity'] * df['price']
df['month'] = df['date'].dt.month
# 1. 销售趋势分析
daily_sales = df.groupby('date')['revenue'].sum().reset_index()
fig = px.line(daily_sales,
x='date',
y='revenue',
title='2024年每日销售趋势',
labels={'revenue': '销售额', 'date': '日期'})
fig.update_layout(
title_font_size=16,
height=500,
width=1000,
hovermode='x unified'
)
fig.update_traces(
line_color='#45B7D1',
line_width=2
)
fig.show()
# 2. 产品销售排名
top_products = df.groupby('product')['revenue'].sum().sort_values(ascending=False).reset_index()
fig = px.bar(top_products,
x='product',
y='revenue',
title='销售额前10的产品',
labels={'revenue': '销售额', 'product': '产品'},
color='revenue',
color_continuous_scale='Viridis')
fig.update_layout(
title_font_size=16,
height=500,
width=900
)
fig.update_traces(
texttemplate='%{y:,.0f}',
textposition='outside'
)
fig.show()
# 3. 价格与销售额的关系
fig = px.scatter(df,
x='price',
y='revenue',
color='category',
size='quantity',
hover_data=['product'],
title='价格与销售额的关系',
labels={'price': '价格', 'revenue': '销售额', 'category': '类别'},
color_discrete_map={'电子产品': '#4ECDC4', '配件': '#FF6B6B'})
fig.update_layout(
title_font_size=16,
height=600,
width=900
)
fig.show()
# 4. 月度销售情况
monthly_sales = df.groupby('month')['revenue'].sum().reset_index()
month_names = ['1月', '2月', '3月', '4月', '5月', '6月',
'7月', '8月', '9月', '10月', '11月', '12月']
monthly_sales['month_name'] = monthly_sales['month'].map(lambda x: month_names[x-1])
fig = px.bar(monthly_sales,
x='month_name',
y='revenue',
title='2024年月度销售额',
labels={'revenue': '销售额', 'month_name': '月份'},
color='revenue',
color_continuous_scale='Viridis')
fig.update_layout(
title_font_size=16,
height=500,
width=900
)
fig.update_traces(
texttemplate='%{y:,.0f}',
textposition='outside'
)
fig.show()
# 5. 交互式仪表板(组合图表)
fig = go.Figure()
# 添加销售额趋势
fig.add_trace(go.Scatter(
x=daily_sales['date'],
y=daily_sales['revenue'],
name='销售额',
yaxis='y',
line_color='#45B7D1'
))
# 添加移动平均线
daily_sales['MA7'] = daily_sales['revenue'].rolling(7).mean()
fig.add_trace(go.Scatter(
x=daily_sales['date'],
y=daily_sales['MA7'],
name='7日移动平均',
yaxis='y',
line_color='#FF6B6B',
line_dash='dash'
))
fig.update_layout(
title='销售趋势与移动平均',
title_font_size=16,
height=500,
width=1000,
yaxis=dict(title='销售额'),
hovermode='x unified'
)
fig.show()
# 创建一个图表
fig = px.scatter(tips, x='total_bill', y='tip', color='sex')
# 导出为HTML文件
fig.write_html('interactive_chart.html')
print("图表已导出为 interactive_chart.html")
# 需要安装kaleido
# pip install kaleido
# 导出为PNG
fig.write_image('chart.png', width=1200, height=800, scale=2)
print("图表已导出为 chart.png")
# 导出为SVG
fig.write_image('chart.svg')
print("图表已导出为 chart.svg")
# 导出为PDF
fig.write_image('chart.pdf')
print("图表已导出为 chart.pdf")
Plotly让数据可视化变得生动而有趣。通过本文的学习,你已经掌握了:
Plotly的交互性能让你的数据故事更加生动,让读者能够主动探索数据。记住,好的交互式可视化应该既美观又实用,让用户能够真正从交互中获得洞见!
小贴士:Plotly图表默认显示在浏览器中,你可以通过右上角的工具栏进行缩放、平移、下载等操作。探索这些功能,让你的可视化体验更好!