划分子图 subplots
import plotly.io as pio
import plotly.express as px
import plotly.graph_objects as go
from plotly.subplots import make_subplots
import pandas as pd
import numpy as np
# 设置plotly默认主题
pio.templates.default = 'plotly_white'
# 设置pandas打印时显示所有列
pd.set_option('display.max_columns', None)
make_subplots 常用参数介绍及示例
详细参数见:https://plotly.com/python-api-reference/plotly.subplots.html#subplots
- rows:子图网格中的行数。
- 大于0的整数,默认为1
- cols:子图网格中的列数。
- 大于0的整数,默认为1
- shared_xaxes:为2D笛卡尔坐标系的子图分配共享x坐标轴。
- 布尔类型或字符串类型,默认值为
False
。True
或'columns'
表示同一列子图共享坐标轴;'rows'
表示同一行子图共享坐标轴;'all'
表示所有子图共享坐标轴
- 布尔类型或字符串类型,默认值为
- shared_yaxes:为2D笛卡尔坐标系的子图分配共享y坐标轴。
- 布尔类型或字符串类型,默认值为
False
。'columns'
表示同一列子图共享坐标轴;True
或'rows'
表示同一行子图共享坐标轴;'all'
表示所有子图共享坐标轴
- 布尔类型或字符串类型,默认值为
- horizontal_spacing:设置每列子图之间的间隔,对所有列应用。
- 必须为 0~1 之间的浮点数,默认值为0.2
- vertical_spacing:设置每行子图之间的间隔,对所有行应用。
- 必须为 0~1 之间的浮点数,默认值为0.3
- subplot_titles:每个子图的标题,按照行优先的顺序(从左到右,从上到下)
- 字符串列表 或
None
(默认值),列表长度必须等于子图个数(不一定等于rows * cols
),如果不想为其中某个子图设置标题,只需将列表中对应位置的标题设置为""
(空字符串)。
- 字符串列表 或
- specs:设置每个子图的规格:子图类型、行/列跨度和间隔。
specs
参数传入一个二维列表,列表中的元素为字典。二维列表的维度为rows * cols
,每个位置对应一个子图。如果想删除某个位置的子图,只需将二维列表中对应位置的值设置为None
specs
中的每个条目都是一个字典,可用的参数为:- type:子图的类型(字符串类型,默认值为
'xy'
),可以为:'xy'
:2D 笛卡尔坐标系,适用于 scatter、bar等图表'scene'
:3D 笛卡尔坐标系,适用于 scatter3d、cone等图表'polar'
:极坐标系,适用于 scatterpolar、barpolar等图表'ternary'
:三元坐标,适用于 scatterternary 等图表'mapbox'
:地图,适用于 scattermapbox等图表'domain'
:独特位置的子图,适用于 pie、parcoords、parcats等图表- 图表类型名:可以使用要绘制的图表名,进而自动推断子图的类型,比如
'type': 'bar'
- secondary_y:是否创建第二纵坐标轴,第二纵坐标位于图表的右侧,只有
tpye='xy'
时才可以使用。布尔类型。 - colspan:该子图所占的列数,默认为1,大于0,小于
cols
的整数。 - rowspan:该子图所占的行数,默认为1,大于0,小于
rows
的整数。 - l:填充(padding)左侧格子(cell),浮点数,默认为 0.0
- r:填充(padding)右侧格子(cell),浮点数,默认为 0.0
- t:填充(padding)顶部格子(cell),浮点数,默认为 0.0
- b:填充(padding)底部格子(cell),浮点数,默认为 0.0
- 例如:specs=[[{}, {}], [{‘colspan’ : 2}, None]],specs=[[{‘rowspan’ : 2}, {}], [None, {}]]
- insets:嵌入图的规格,嵌入图是覆盖在网格子图上的子图。
- 传入字典列表 或
None
(默认值),insets
中的每个条目都是一个字典,可用的参数为:- cell:默认值为
(1, 1)
,元组类型(row, col)
表示子图的索引,以便将插入的坐标轴覆盖在上面 - type:子图类型。字符串类型,默认值为
'xy'
,与specs
的type
一样。 - l:填充嵌入图左侧,以格子(该子图的网格)宽度为标准,浮点数,默认为0.0
- w:嵌入图的宽度,以格子(该子图的网格)宽度为标准,浮点数 或
'to_end'
(默认值),表示网格右侧 - b:填充嵌入图底部,以格子(该子图的网格)高度为标准,浮点数,默认为0.0
- h:嵌入图的高度,以格子(该子图的网格)高度为标准,浮点数 或
'to_end'
(默认值),表示网格顶部
- cell:默认值为
- 传入字典列表 或
- column_widths:设置列宽度,列表中的长度为
cols
的每一列的相对宽度,列表的值会被标准化(缩放为0~1),并用于为各列子图分配整体宽度(不包含填充(padding)) - row_heights:设置行高度,列表中的长度为
'rows'
的每一行的相对高度。 - column_titles:每一列子图的标题,在每一列最上面的子图上面放置一个标题。
- 字符串列表 或
None
(默认值),如果某列不想要标题,可以将对应位置设置为''
(空字符串)
- 字符串列表 或
- row_titles:每一行子图的标题,在每一行最右侧的子图右边放置一个标题。
- 字符串列表 或
None
(默认值),如果某列不想要标题,可以将对应位置设置为''
(空字符串)
- 字符串列表 或
- x_title:放置在最下方正中间的标题,字符串或
None
(默认值) - y_title:放置在最左侧正中间的标题,字符串或
None
(默认值)
注:以下所有使用 make_subplots 的代码,均可使用 fig = go.Figure().set_subplots() 替代
参数完全相同,不必导入 from plotly.subplots import make_subplots
# 创建一个3行1列的子图
# 等价于 fig = go.Figure().set_subplots(rows=3, cols=1)
fig = make_subplots(rows=3, cols=1)
# 使用row、col参数,为指定子图添加图表
fig.append_trace(go.Scatter(
x=[3, 4, 5],
y=[1000, 1100, 1200],
), row=1, col=1)
fig.append_trace(go.Scatter(
x=[2, 3, 4],
y=[100, 110, 120],
), row=2, col=1)
fig.append_trace(go.Scatter(
x=[0, 1, 2],
y=[10, 11, 12]
), row=3, col=1)
fig.update_layout(height=600, width=600, title_text="Stacked Subplots")
fig.write_image('../pic/subplots_1.png', scale=10)
fig.show()
# 自定义宽度
fig = make_subplots(rows=1, cols=2, column_widths=[0.7, 0.3])
fig.add_trace(go.Scatter(x=[1, 2, 3], y=[4, 5, 6]),
row=1, col=1)
fig.add_trace(go.Scatter(x=[20, 30, 40], y=[50, 60, 70]),
row=1, col=2)
fig.write_image('../pic/subplots_2.png', scale=10)
fig.show()
# 自定义每个子图的坐标轴属性
fig = make_subplots(
rows=2, cols=2, subplot_titles=("Plot 1", "Plot 2", "Plot 3", "Plot 4")
)
# Add traces
fig.add_trace(go.Scatter(x=[1, 2, 3], y=[4, 5, 6]), row=1, col=1)
fig.add_trace(go.Scatter(x=[20, 30, 40], y=[50, 60, 70]), row=1, col=2)
fig.add_trace(go.Scatter(x=[300, 400, 500], y=[600, 700, 800]), row=2, col=1)
fig.add_trace(go.Scatter(x=[4000, 5000, 6000], y=[7000, 8000, 9000]), row=2, col=2)
# Update xaxis properties
# 使用 row、col参数指定设置某个子图的坐标轴属性
'''
也可以使用 fig.update_layout(xaxis={...}, xaxis2={...}, xaxis3={...} ... , yaxis={...} ...)
'''
fig.update_xaxes(title_text="xaxis 1 title", row=1, col=1)
fig.update_xaxes(title_text="xaxis 2 title", range=[10, 50], row=1, col=2)
fig.update_xaxes(title_text="xaxis 3 title", showgrid=False, row=2, col=1)
fig.update_xaxes(title_text="xaxis 4 title", type="log", row=2, col=2)
# Update yaxis properties
fig.update_yaxes(title_text="yaxis 1 title", row=1, col=1)
fig.update_yaxes(title_text="yaxis 2 title", range=[40, 80], row=1, col=2)
fig.update_yaxes(title_text="yaxis 3 title", showgrid=False, row=2, col=1)
fig.update_yaxes(title_text="yaxis 4 title", row=2, col=2)
# Update title and height
fig.update_layout(title_text="Customizing Subplot Axes", height=700)
fig.write_image('../pic/subplots_3.png', scale=10)
fig.show()
# 共享 x 坐标轴
fig = make_subplots(rows=3, cols=1,
shared_xaxes=True,
vertical_spacing=0.05)
fig.add_trace(go.Scatter(x=[0, 1, 2], y=[10, 11, 12]),
row=3, col=1)
fig.add_trace(go.Scatter(x=[2, 3, 4], y=[100, 110, 120]),
row=2, col=1)
fig.add_trace(go.Scatter(x=[3, 4, 5], y=[1000, 1100, 1200]),
row=1, col=1)
fig.update_layout(height=600, width=600,
title_text="Stacked Subplots with Shared X-Axes")
fig.write_image('../pic/subplots_4.png', scale=10)
fig.show()
# 共享y轴
fig = make_subplots(rows=2, cols=2, shared_yaxes=True)
fig.add_trace(go.Scatter(x=[1, 2, 3], y=[2, 3, 4]),
row=1, col=1)
fig.add_trace(go.Scatter(x=[20, 30, 40], y=[5, 5, 5]),
row=1, col=2)
fig.add_trace(go.Scatter(x=[2, 3, 4], y=[600, 700, 800]),
row=2, col=1)
fig.add_trace(go.Scatter(x=[4000, 5000, 6000], y=[7000, 8000, 9000]),
row=2, col=2)
fig.update_layout(height=600, width=600,
title_text="Multiple Subplots with Shared Y-Axes")
fig.write_image('../pic/subplots_5.png', scale=10)
fig.show()
# 自定义子图大小
fig = make_subplots(
rows=2, cols=2,
specs=[[{}, {}],
[{"colspan": 2}, None]],
subplot_titles=("First Subplot","Second Subplot", "Third Subplot"))
fig.add_trace(go.Scatter(x=[1, 2], y=[1, 2]),
row=1, col=1)
fig.add_trace(go.Scatter(x=[1, 2], y=[1, 2]),
row=1, col=2)
fig.add_trace(go.Scatter(x=[1, 2, 3], y=[2, 1, 2]),
row=2, col=1)
fig.update_layout(showlegend=False, title_text="Specs with Subplot Title")
fig.write_image('../pic/subplots_6.png', scale=10)
fig.show()
fig = make_subplots(
rows=5, cols=2,
specs=[[{}, {"rowspan": 2}],
[{}, None],
[{"rowspan": 2, "colspan": 2}, None],
[None, None],
[{}, {}]],
print_grid=True)
fig.add_trace(go.Scatter(x=[1, 2], y=[1, 2], name="(1,1)"), row=1, col=1)
fig.add_trace(go.Scatter(x=[1, 2], y=[1, 2], name="(1,2)"), row=1, col=2)
fig.add_trace(go.Scatter(x=[1, 2], y=[1, 2], name="(2,1)"), row=2, col=1)
fig.add_trace(go.Scatter(x=[1, 2], y=[1, 2], name="(3,1)"), row=3, col=1)
fig.add_trace(go.Scatter(x=[1, 2], y=[1, 2], name="(5,1)"), row=5, col=1)
fig.add_trace(go.Scatter(x=[1, 2], y=[1, 2], name="(5,2)"), row=5, col=2)
fig.update_layout(height=600, width=600, title_text="specs examples")
fig.write_image('../pic/subplots_7.png', scale=10)
fig.show()
# 子图类型
fig = make_subplots(
rows=2, cols=2,
specs=[[{"type": "xy"}, {"type": "polar"}],
[{"type": "domain"}, {"type": "scene"}]],
)
'''
也可以为:specs=[[{'type': 'bar'}, {'type': 'barpolar'}],
[{'type': 'pie'}, {'type': 'scatter3d'}]]
'''
fig.add_trace(go.Bar(y=[2, 3, 1]),
row=1, col=1)
fig.add_trace(go.Barpolar(theta=[0, 45, 90], r=[2, 3, 1]),
row=1, col=2)
fig.add_trace(go.Pie(values=[2, 3, 1]),
row=2, col=1)
fig.add_trace(go.Scatter3d(x=[2, 3, 1], y=[0, 0, 0],
z=[0.5, 1, 2], mode="lines"),
row=2, col=2)
fig.update_layout(height=700, showlegend=False)
fig.write_image('../pic/subplots_8.png', scale=10)
fig.show()
# 子图开启第二纵轴
fig = make_subplots(
rows=2, cols=2,
specs=[[{"type": "xy", 'secondary_y': True}, {"type": "polar"}],
[{"type": "domain"}, {"type": "scene"}]],
y_title='title'
)
'''
也可以为:specs=[[{'type': 'bar'}, {'type': 'barpolar'}],
[{'type': 'pie'}, {'type': 'scatter3d'}]]
'''
# 使用 secondary_y 参数选择该图相对的 y轴坐标
fig.add_trace(go.Bar(y=[2, 3, 1]),
row=1, col=1, secondary_y=False)
fig.add_trace(go.Scatter(x=[0, 1, 2], y=[4, 10, 7]),
row=1, col=1, secondary_y=True)
fig.add_trace(go.Barpolar(theta=[0, 45, 90], r=[2, 3, 1]),
row=1, col=2)
fig.add_trace(go.Pie(values=[2, 3, 1]),
row=2, col=1)
fig.add_trace(go.Scatter3d(x=[2, 3, 1], y=[0, 0, 0],
z=[0.5, 1, 2], mode="lines"),
row=2, col=2)
fig.update_layout(height=700, showlegend=False)
fig.write_image('../pic/subplots_9.png', scale=10)
fig.show()
# 绘制嵌入图
fig = make_subplots(
rows=1, cols=2,
insets=[{'cell': (1, 1), 'type': 'xy',
'l':0.5, 'w': 0.4, 'b':0.5, 'h':0.3}],
)
# print(fig)
fig.add_trace(go.Scatter(
x=[1, 2, 3, 4], y=[10, 7, 4, 6],
), row=1, col=1)
fig.add_trace(go.Scatter(
x=[1, 2, 3, 4], y=[10, 13, 4, 6],
), row=1, col=2)
# 嵌入图需要指明绘制的坐标轴,可以使用 print(fig) 查看所有坐标轴
fig.add_trace(go.Scatter(
x=[1, 2, 3, 4], y=[10, 13, 4, 6],
xaxis='x3', yaxis='y3'
))
fig.update_layout(showlegend=False)
fig.write_image('../pic/subplots_10.png', scale=10)
fig.show()