在数据分析和数据可视化领域,静态图表(如Matplotlib生成的图片)已无法满足交互式探索的需求。Plotly作为一款开源的交互式可视化库,支持生成动态折线图、地理热力图、3D散点图等丰富图表,既能在Jupyter Notebook中交互展示,也能导出为HTML文件分享。本文从环境搭建、基础语法到实战案例,全方位讲解Plotly核心可视化类型的实现方法,适合数据分析、数据科学从业者学习。
一、前置准备:环境搭建与核心优势
1. 安装Plotly库
Plotly支持Python 3.7+版本,通过pip即可完成安装,推荐同时安装pandas用于数据处理:
# 基础安装(推荐稳定版)
pip install plotly==5.17.0 pandas==2.0.3 numpy==1.24.3
# 若需地理可视化(如热力图),安装地图依赖
pip install geopandas plotly-geo
安装完成后,在Python脚本中导入验证:
import plotly
import plotly.express as px
import plotly.graph_objects as go
print(f"Plotly版本:{plotly.__version__}") # 输出版本号即安装成功
2. Plotly核心优势
- 全交互性:支持缩放、平移、悬停显示数据详情、图例筛选等操作;
- 多格式导出:可导出为HTML、PNG、PDF等格式,HTML文件保留交互功能;
- 丰富图表类型:覆盖折线图、柱状图、热力图、3D图、地理图等上百种图表;
- 跨环境兼容:支持Jupyter Notebook、Web应用(Django/Flask)、Python脚本等场景。
3. 两种核心使用方式
plotly.express(简称px):高阶API,代码简洁,适合快速生成常见图表;plotly.graph_objects(简称go):底层API,自定义程度高,适合复杂图表制作。
二、实战1:动态折线图(时间序列数据可视化)
动态折线图适用于展示数据随时间的变化趋势,支持悬停显示具体数值、缩放查看细节、图例隐藏/显示系列数据等操作。
1. 准备测试数据
以某城市近12个月的气温和降水量数据为例:
import pandas as pd
import numpy as np
# 生成模拟时间序列数据
months = pd.date_range(start='2024-01', end='2025-01', freq='M').strftime('%Y-%m')
temperature = np.random.normal(20, 5, size=12) # 平均气温20℃,波动5℃
precipitation = np.random.uniform(10, 100, size=12) # 降水量10-100mm
# 构建DataFrame
df = pd.DataFrame({
'月份': months,
'平均气温(℃)': temperature.round(1),
'降水量(mm)': precipitation.round(1)
})
print("时间序列数据:")
print(df)
2. 基础动态折线图(px实现)
import plotly.express as px
# 创建折线图
fig = px.line(
df, # 数据源
x='月份', # x轴:月份
y='平均气温(℃)', # y轴:气温
title='2024年某城市月均气温变化趋势', # 图表标题
labels={'平均气温(℃)': '月均气温(℃)'}, # 轴标签自定义
markers=True, # 显示数据点标记
hover_data={'降水量(mm)': True} # 悬停时显示降水量
)
# 自定义样式(可选)
fig.update_layout(
xaxis_title='月份', # x轴标题
yaxis_title='气温(℃)', # y轴标题
font={'family': 'SimHei', 'size': 12}, # 字体(SimHei支持中文)
hovermode='x unified' # 悬停时显示同一x轴位置的所有数据
)
# 显示图表(Jupyter中直接显示,脚本中生成HTML)
fig.show()
# 导出为HTML文件(保留交互功能)
fig.write_html('temperature_trend.html')
3. 多系列折线图(go实现)
如需在同一张图中展示气温和降水量(双Y轴),使用go实现更灵活:
import plotly.graph_objects as go
# 创建图表对象
fig = go.Figure()
# 添加气温折线(左Y轴)
fig.add_trace(go.Scatter(
x=df['月份'],
y=df['平均气温(℃)'],
name='平均气温', # 图例名称
mode='lines+markers', # 线+标记点
line={'color': 'red', 'width': 2}, # 线条样式
hovertemplate='月份:%{x}<br>气温:%{y}℃<extra></extra>' # 悬停提示自定义
))
# 添加降水量折线(右Y轴)
fig.add_trace(go.Scatter(
x=df['月份'],
y=df['降水量(mm)'],
name='降水量',
mode='lines+markers',
line={'color': 'blue', 'width': 2},
yaxis='y2', # 指定右Y轴
hovertemplate='月份:%{x}<br>降水量:%{y}mm<extra></extra>'
))
# 布局设置
fig.update_layout(
title='2024年某城市气温&降水量变化',
xaxis_title='月份',
yaxis=dict(title='气温(℃)', side='left', titlefont={'color': 'red'}), # 左Y轴
yaxis2=dict(title='降水量(mm)', side='right', overlaying='y', titlefont={'color': 'blue'}), # 右Y轴
font={'family': 'SimHei', 'size': 12},
legend={'x': 0.05, 'y': 0.95} # 图例位置
)
fig.show()
fig.write_html('temp_rain_trend.html')
三、实战2:地理热力图(空间数据可视化)
地理热力图(Choropleth)适用于展示数据在地理区域上的分布,如各省份销售额、各城市人口密度等。
1. 准备地理数据
以中国各省份2024年GDP数据为例(模拟数据):
import pandas as pd
# 中国省份列表(含港澳台)
provinces = [
'北京市', '天津市', '河北省', '山西省', '内蒙古自治区',
'辽宁省', '吉林省', '黑龙江省', '上海市', '江苏省',
'浙江省', '安徽省', '福建省', '江西省', '山东省',
'河南省', '湖北省', '湖南省', '广东省', '广西壮族自治区',
'海南省', '重庆市', '四川省', '贵州省', '云南省',
'西藏自治区', '陕西省', '甘肃省', '青海省', '宁夏回族自治区',
'新疆维吾尔自治区', '香港特别行政区', '澳门特别行政区', '台湾省'
]
# 生成模拟GDP数据(单位:万亿元)
gdp_data = pd.DataFrame({
'省份': provinces,
'GDP(万亿元)': np.random.uniform(1, 15, size=34).round(2)
})
print("各省份GDP数据:")
print(gdp_data.head())
2. 绘制中国省份地理热力图
Plotly默认支持中国省份的地理编码,核心是指定locationmode='china-province':
import plotly.express as px
# 创建地理热力图
fig = px.choropleth(
gdp_data,
locations='省份', # 地理区域列
locationmode='china-province', # 地理编码模式(中国省份)
color='GDP(万亿元)', # 颜色映射的数值列
color_continuous_scale='Reds', # 颜色方案(红系)
title='2024年中国各省份GDP分布',
labels={'GDP(万亿元)': 'GDP(万亿元)'}, # 颜色条标签
hover_name='省份', # 悬停时显示的名称
hover_data={'GDP(万亿元)': ':,.2f'} # 悬停时GDP格式
)
# 自定义布局
fig.update_layout(
font={'family': 'SimHei', 'size': 12},
geo=dict(
scope='china', # 地图范围:中国
showlakes=True, # 显示湖泊
lakecolor='lightblue', # 湖泊颜色
showrivers=True, # 显示河流
rivercolor='lightblue' # 河流颜色
)
)
fig.show()
fig.write_html('china_gdp_heatmap.html')
3. 世界国家地理热力图(拓展)
若需绘制世界范围的热力图,只需调整locationmode和地理编码:
# 加载Plotly内置世界GDP数据
df = px.data.gapminder().query("year == 2007")
# 世界GDP热力图
fig = px.choropleth(
df,
locations='iso_alpha', # 国家ISO编码
color='gdpPercap', # 人均GDP
hover_name='country', # 悬停显示国家名
color_continuous_scale=px.colors.sequential.Plasma,
title='2007年世界各国人均GDP分布'
)
fig.update_layout(geo={'scope': 'world'})
fig.show()
fig.write_html('world_gdp_heatmap.html')
四、实战3:3D散点图(高维数据可视化)
3D散点图适用于展示三维数据的分布关系,如三维特征的聚类结果、物理实验的三维坐标数据等。
1. 准备3D数据
以鸢尾花数据集为例(4维特征,选取3维制作3D散点图):
from sklearn.datasets import load_iris
# 加载鸢尾花数据集
iris = load_iris()
df_3d = pd.DataFrame(
iris.data[:, :3], # 取前3个特征:花萼长度、花萼宽度、花瓣长度
columns=['花萼长度(cm)', '花萼宽度(cm)', '花瓣长度(cm)']
)
df_3d['品种'] = [iris.target_names[i] for i in iris.target] # 品种名称
print("鸢尾花3D数据:")
print(df_3d.head())
2. 绘制3D散点图
import plotly.express as px
# 创建3D散点图
fig = px.scatter_3d(
df_3d,
x='花萼长度(cm)', # X轴
y='花萼宽度(cm)', # Y轴
z='花瓣长度(cm)', # Z轴
color='品种', # 按品种着色
symbol='品种', # 按品种显示不同标记
size_max=10, # 标记最大尺寸
title='鸢尾花数据集3D散点图',
hover_data={'花萼长度(cm)': ':,.2f', '花萼宽度(cm)': ':,.2f', '花瓣长度(cm)': ':,.2f'}
)
# 自定义布局
fig.update_layout(
font={'family': 'SimHei', 'size': 12},
scene=dict(
xaxis_title='花萼长度(cm)',
yaxis_title='花萼宽度(cm)',
zaxis_title='花瓣长度(cm)',
camera=dict(eye=dict(x=1.5, y=1.5, z=1)) # 相机视角调整
)
)
fig.show()
fig.write_html('iris_3d_scatter.html')
3. 动态3D散点图(go实现,支持自定义标记)
import plotly.graph_objects as go
# 按品种分组数据
setosa = df_3d[df_3d['品种'] == 'setosa']
versicolor = df_3d[df_3d['品种'] == 'versicolor']
virginica = df_3d[df_3d['品种'] == 'virginica']
# 创建3D散点图
fig = go.Figure()
# 添加setosa品种
fig.add_trace(go.Scatter3d(
x=setosa['花萼长度(cm)'],
y=setosa['花萼宽度(cm)'],
z=setosa['花瓣长度(cm)'],
mode='markers',
name='setosa',
marker=dict(size=6, color='red', opacity=0.8)
))
# 添加versicolor品种
fig.add_trace(go.Scatter3d(
x=versicolor['花萼长度(cm)'],
y=versicolor['花萼宽度(cm)'],
z=versicolor['花瓣长度(cm)'],
mode='markers',
name='versicolor',
marker=dict(size=6, color='green', opacity=0.8)
))
# 添加virginica品种
fig.add_trace(go.Scatter3d(
x=virginica['花萼长度(cm)'],
y=virginica['花萼宽度(cm)'],
z=virginica['花瓣长度(cm)'],
mode='markers',
name='virginica',
marker=dict(size=6, color='blue', opacity=0.8)
))
# 布局设置
fig.update_layout(
title='鸢尾花3D散点图(自定义标记)',
font={'family': 'SimHei', 'size': 12},
scene=dict(
xaxis_title='花萼长度(cm)',
yaxis_title='花萼宽度(cm)',
zaxis_title='花瓣长度(cm)'
)
)
fig.show()
fig.write_html('iris_3d_scatter_custom.html')
五、核心技巧:避坑与优化
1. 解决中文显示乱码问题
Plotly默认字体不支持中文,需在update_layout中指定中文字体(如SimHei、Microsoft YaHei):
fig.update_layout(
font={'family': 'SimHei', 'size': 12} # SimHei(黑体)适配大部分场景
)
2. 自定义颜色方案
- 连续颜色:
px.colors.sequential.Reds/Blues/Viridis等; - 离散颜色:
px.colors.qualitative.Set1/Pastel1等; - 自定义颜色列表:
color_discrete_map={'品种1': '#FF0000', '品种2': '#00FF00'}。
3. 图表交互优化
hovermode:设置悬停模式('x'/'y'/'x unified');hovertemplate:自定义悬停提示内容,<extra></extra>隐藏默认额外信息;legend:调整图例位置(x/y参数)、是否显示等。
4. 导出高清图片
默认导出的图片分辨率较低,可通过write_image指定分辨率:
# 需先安装依赖
pip install kaleido
fig.write_image('iris_3d.png', width=1200, height=800, scale=2) # scale为缩放倍数
六、常见问题排查
1. 地理热力图显示异常
- 原因:省份名称格式不统一(如“广西”vs“广西壮族自治区”); 解决:统一省份名称为全称(如“广西壮族自治区”);
- 原因:
locationmode设置错误; 解决:中国省份需指定locationmode='china-province'。
2. 3D散点图交互卡顿
- 原因:数据量过大(如10万+样本);
解决:采样后可视化,或降低标记尺寸(
size_max)、透明度(opacity)。
3. 图表在Jupyter中不显示
- 原因:Plotly渲染模式问题;
解决:在Notebook开头添加:
import plotly.io as pio pio.renderers.default = 'notebook' # 或 'iframe'/'browser'