Plotly:如何结合 make_subplots() 和 ff.create_distplot()?

2022-01-21 00:00:00 python plotly plotly-python

问题描述

使用 plotly 创建多个子图既简单又优雅.考虑以下示例,该示例并排绘制来自数据框的两个系列:

剧情:

代码:

# 导入从 plotly.subplots 导入 make_subplots将 plotly.figure_factory 导入为 ff导入 plotly.graph_objs将熊猫导入为 pd将 numpy 导入为 np# 数据np.random.seed(123)frame_rows = 40n_plots = 6#frame_columns = ['V_'+str(e) for e in list(range(1,n_plots+1))]frame_columns = ['V_1', 'V_2']df = pd.DataFrame(np.random.uniform(-10,10,size=(frame_rows, len(frame_columns))),index=pd.date_range('1/1/2020', period=frame_rows),列=frame_columns)df=df.cumsum()+100df.iloc[0]=100# 情节设置plot_rows=1plot_cols=2fig = make_subplots(rows=plot_rows, cols=plot_cols)# 情节跟踪fig.add_trace(go.Scatter(x=df.index, y=df['V_1']), row=1, col=1)fig.add_trace(go.Scatter(x=df.index, y=df['V_2']), row=1, col=2)图.show()

go.Scatter() 对象替换为

但我似乎找不到将此设置与 ff.create_distplot() 结合使用的方法:

分布图:

带有 distplot 的代码:

# 导入从 plotly.subplots 导入 make_subplots将 plotly.figure_factory 导入为 ff导入 plotly.graph_objs将熊猫导入为 pd将 numpy 导入为 np# 数据np.random.seed(123)frame_rows = 40n_plots = 6#frame_columns = ['V_'+str(e) for e in list(range(1,n_plots+1))]frame_columns = ['V_1', 'V_2']df = pd.DataFrame(np.random.uniform(-10,10,size=(frame_rows, len(frame_columns))),index=pd.date_range('1/1/2020', period=frame_rows),列=frame_columns)df=df.cumsum()+100df.iloc[0]=100# 情节设置plot_rows=1plot_cols=2fig = make_subplots(rows=plot_rows, cols=plot_cols)# 情节跟踪fig.add_trace(go.Scatter(x=df.index, y=df['V_1']), row=1, col=1)#fig.add_trace(go.Scatter(x=df.index, y=df['V_2']), row=1, col=2)# 分布图hist_data = [df['V_1'].values, df['V_2'].values]group_labels = ['第 1 组','第 2 组']#fig2 = ff.create_distplot(hist_data, group_labels)# 结合 make_subplots、go.Scatter 和 ff.create_distplot(fig.add_trace(ff.create_distplot(hist_data, group_labels), row=1, col=2)图.show()

这会引发一个相当大的 ValueError.

原因似乎是 go.Scatter()ff.create_distplot() 返回两种不同的数据类型;plotly.graph_objs.Scatterplotly.graph_objs._figure.Figure 分别.并且它确实似乎 make_subplots 不适用于后者.或者有人知道解决这个问题的方法吗?

感谢您的任何建议!

解决方案

事实证明你不能直接这样做,因为 make_subplots() 不会接受 plotly.graph_objs._figure.Figure 对象直接作为 add_trace() 的参数.但是您可以构建一个 ff.create_distplot' 和 窃取" 该图中的数据并将它们应用到 go 的组合中make_subplots() 中接受 的.Histogramgo.Scatter() 对象.你甚至可以对地毯/边距图做同样的事情.

剧情:

代码:

# 导入从 plotly.subplots 导入 make_subplots将 plotly.figure_factory 导入为 ff导入 plotly.graph_objs将熊猫导入为 pd将 numpy 导入为 np# 数据np.random.seed(123)frame_rows = 40n_plots = 6#frame_columns = ['V_'+str(e) for e in list(range(1,n_plots+1))]frame_columns = ['V_1', 'V_2']df = pd.DataFrame(np.random.uniform(-10,10,size=(frame_rows, len(frame_columns))),index=pd.date_range('1/1/2020', period=frame_rows),列=frame_columns)df=df.cumsum()+100df.iloc[0]=100# 情节设置plot_rows=2plot_cols=2fig = make_subplots(rows=plot_rows, cols=plot_cols)# 情节跟踪fig.add_trace(go.Scatter(x=df.index, y=df['V_1']), row=1, col=1)fig.add_trace(go.Scatter(x=df.index, y=df['V_2']), row=2, col=1)# 分布图hist_data = [df['V_1'].values, df['V_2'].values]group_labels = ['第 1 组','第 2 组']fig2 = ff.create_distplot(hist_data, group_labels)fig.add_trace(go.Histogram(fig2['data'][0],marker_color='蓝色'), 行=1, 列=2)fig.add_trace(go.Histogram(fig2['data'][1],标记颜色='红色'), 行=1, 列=2)fig.add_trace(go.Scatter(fig2['data'][2],线=dict(颜色='蓝色',宽度=0.5)), 行=1, 列=2)fig.add_trace(go.Scatter(fig2['data'][3],线=字典(颜色='红色',宽度=0.5)), 行=1, 列=2)# 模仿 ff.create_distplot 的地毯/边距图df['地毯 1'] = 1.1df['地毯 2'] = 1fig.add_trace(go.Scatter(x=df['V_1'], y = df['rug 1'],模式='标记',标记=dict(颜色='蓝色',符号='line-ns-open')), 行=2, 列=2)fig.add_trace(go.Scatter(x=df['V_2'], y = df['rug 2'],模式='标记',标记=dict(颜色='红色',符号='line-ns-open')), 行=2, 列=2)# 对 rugplot 进行一些手动调整fig.update_yaxes(range=[0.95,1.15], tickfont=dict(color='rgba(0,0,0,0)', size=14), row=2, col=2)fig.update_layout(showlegend=False)图.show()

Creating multiple subplots using plotly is both easy and elegant. Consider the following example that plots two series from a dataframe side by side:

Plot:

Code:

# imports
from plotly.subplots import make_subplots
import plotly.figure_factory as ff
import plotly.graph_objs as go
import pandas as pd
import numpy as np

# data
np.random.seed(123)
frame_rows = 40
n_plots = 6
#frame_columns = ['V_'+str(e) for e in list(range(1,n_plots+1))]
frame_columns = ['V_1', 'V_2']
df = pd.DataFrame(np.random.uniform(-10,10,size=(frame_rows, len(frame_columns))),
                  index=pd.date_range('1/1/2020', periods=frame_rows),
                    columns=frame_columns)
df=df.cumsum()+100
df.iloc[0]=100

# plotly setup
plot_rows=1
plot_cols=2
fig = make_subplots(rows=plot_rows, cols=plot_cols)

# plotly traces
fig.add_trace(go.Scatter(x=df.index, y=df['V_1']), row=1, col=1)
fig.add_trace(go.Scatter(x=df.index, y=df['V_2']), row=1, col=2)


fig.show()

Replace the go.Scatter() object with similar objects is easy:

Plot:

But I can't seem to find a way to combine this setup with ff.create_distplot():

Distplot:

Code with distplot:

# imports
from plotly.subplots import make_subplots
import plotly.figure_factory as ff
import plotly.graph_objs as go
import pandas as pd
import numpy as np

# data
np.random.seed(123)
frame_rows = 40
n_plots = 6
#frame_columns = ['V_'+str(e) for e in list(range(1,n_plots+1))]
frame_columns = ['V_1', 'V_2']
df = pd.DataFrame(np.random.uniform(-10,10,size=(frame_rows, len(frame_columns))),
                  index=pd.date_range('1/1/2020', periods=frame_rows),
                    columns=frame_columns)
df=df.cumsum()+100
df.iloc[0]=100

# plotly setup
plot_rows=1
plot_cols=2
fig = make_subplots(rows=plot_rows, cols=plot_cols)

# plotly traces
fig.add_trace(go.Scatter(x=df.index, y=df['V_1']), row=1, col=1)
#fig.add_trace(go.Scatter(x=df.index, y=df['V_2']), row=1, col=2)

# distplot
hist_data = [df['V_1'].values, df['V_2'].values]
group_labels = ['Group 1', 'Group 2']
#fig2 = ff.create_distplot(hist_data, group_labels)

# combine make_subplots, go.Scatter and ff.create_distplot(
fig.add_trace(ff.create_distplot(hist_data, group_labels), row=1, col=2)

fig.show()

This raises a ValueError of considerable size.

The reason seems to be that go.Scatter() and ff.create_distplot() return two different data types; plotly.graph_objs.Scatter and plotly.graph_objs._figure.Figure, respectively. And it sure seems that make_subplots will not work with the latter. Or does someone know a way around this?

Thank you for any suggestions!

解决方案

It turns out that you can't do this directly since make_subplots() won't accept a plotly.graph_objs._figure.Figure object as an argument for add_trace() directly. But you can build an ff.create_distplot' and "steal" the data from that figure and apply them in a combination of go.Histogram and go.Scatter() objects that are accepted in make_subplots(). You could even do the same thing with the rug / margin plot.

Plot:

Code:

# imports
from plotly.subplots import make_subplots
import plotly.figure_factory as ff
import plotly.graph_objs as go
import pandas as pd
import numpy as np

# data
np.random.seed(123)
frame_rows = 40
n_plots = 6
#frame_columns = ['V_'+str(e) for e in list(range(1,n_plots+1))]
frame_columns = ['V_1', 'V_2']
df = pd.DataFrame(np.random.uniform(-10,10,size=(frame_rows, len(frame_columns))),
                  index=pd.date_range('1/1/2020', periods=frame_rows),
                    columns=frame_columns)
df=df.cumsum()+100
df.iloc[0]=100

# plotly setup
plot_rows=2
plot_cols=2
fig = make_subplots(rows=plot_rows, cols=plot_cols)

# plotly traces
fig.add_trace(go.Scatter(x=df.index, y=df['V_1']), row=1, col=1)
fig.add_trace(go.Scatter(x=df.index, y=df['V_2']), row=2, col=1)

# distplot
hist_data = [df['V_1'].values, df['V_2'].values]
group_labels = ['Group 1', 'Group 2']
fig2 = ff.create_distplot(hist_data, group_labels)

fig.add_trace(go.Histogram(fig2['data'][0],
                           marker_color='blue'
                          ), row=1, col=2)

fig.add_trace(go.Histogram(fig2['data'][1],
                           marker_color='red'
                          ), row=1, col=2)

fig.add_trace(go.Scatter(fig2['data'][2],
                         line=dict(color='blue', width=0.5)
                        ), row=1, col=2)

fig.add_trace(go.Scatter(fig2['data'][3],
                         line=dict(color='red', width=0.5)
                        ), row=1, col=2)

# rug / margin plot to immitate ff.create_distplot
df['rug 1'] = 1.1
df['rug 2'] = 1
fig.add_trace(go.Scatter(x=df['V_1'], y = df['rug 1'],
                       mode = 'markers',
                       marker=dict(color = 'blue', symbol='line-ns-open')
                        ), row=2, col=2)

fig.add_trace(go.Scatter(x=df['V_2'], y = df['rug 2'],
                       mode = 'markers',
                       marker=dict(color = 'red', symbol='line-ns-open')
                        ), row=2, col=2)

# some manual adjustments on the rugplot
fig.update_yaxes(range=[0.95,1.15], tickfont=dict(color='rgba(0,0,0,0)', size=14), row=2, col=2)
fig.update_layout(showlegend=False)

fig.show()

相关文章