【问题标题】:Plotly: How to set up grouped subplots?Plotly:如何设置分组的子图?
【发布时间】:2021-10-18 07:45:58
【问题描述】:

我正在尝试使用 Plotly 将分组箱线图绘制为网格,其中包含来自数据框的数据。例如,如果我们有一个数据框,

import plotly.express as px
df = px.data.tips() 

total_bill  tip sex smoker  day time    size
0   16.99   1.01    Female  No  Sun Dinner  2
1   10.34   1.66    Male    No  Sun Dinner  3
2   21.01   3.50    Male    No  Sun Dinner  3
3   23.68   3.31    Male    No  Sun Dinner  2
4   24.59   3.61    Female  No  Sun Dinner  4

我可以如下绘制一个图(例如:day = Friday):

import plotly.graph_objects as go
import plotly.express as px

df_plot=df[df['day']== 'Fri']
fig = px.box(df_plot, x='time', y="total_bill", color="sex",width=600, height=400)
fig.show()

如果我想绘制多个子图,例如,每天一个,我不知道如何在 plotly 中做到这一点。这是我尝试过的:

fig = make_subplots(rows=2, cols=2)

for v in range(4):
  for i, met in enumerate(df['day'].unique()): #'Sun', 'Sat', 'Thur', 'Fri'
    df_plot=df[df['day']== met] 
    for t in px.box(df_plot, x="time", y=f"total_bill", color='sex').data:
        fig.add_trace(t, row=(v//2)+1, col=(v%2)+1)

fig.update_layout(
    boxmode="group", margin={"l": 0, "r": 0, "t": 20, "b": 0}
).update_traces(showlegend=True) 

这给出了一个看起来很奇怪的情节。我究竟做错了什么?另外,在带有情节的子情节网格中,如何为每个情节绘制一个图例而不是图例。

【问题讨论】:

    标签: python pandas plotly subplot


    【解决方案1】:
    • plotly express最简单的方法是使用facet参数px box
    • 复制您的示例,2 列和 2 行
    import plotly.express as px
    df = px.data.tips() 
    df.loc[df["day"].eq("Sun")]
    
    px.box(df.loc[df["day"].eq("Sun")], x='time', y="total_bill", color="sex",width=600, height=400).show()
    px.box(df, x='time', y="total_bill", color="sex", facet_col="day", facet_col_wrap=2, width=600, height=400).show()
    
    

    【讨论】:

    • 谢谢。这将创建具有相等 y 轴比例的子图。有没有办法改变它?
    【解决方案2】:

    您已经收到了似乎可以产生预期结果的答案。但是由于您似乎很想知道如何使用您指定的设置来执行此操作,所以我也想向您展示如何做到这一点。而且我还确保下面的完整 sn-p 也会处理图例。

    情节

    您原来设置的问题似乎源于fig.add_trace(t, row=(v//2)+1, col=(v%2)+1)。你的情节变得奇怪的原因是for t in px.box(df_plot, x="time", y=f"total_bill", color='sex').data: 产生的痕迹没有正确地索引到子情节。 (v//2)+1 看起来不错,但 col=(v%2)+1) 有点问题。你需要的是一个在1 and 2 之间变化的索引。在下面的 sn-p 中,您可以看到我已经解决了这个问题:

    from itertools import cycle
    cols = cycle([1,2])
    c = next(cols)
    

    这可能不是最有效的方法,但我一直使用它来应对其他挑战,在这种情况下它也可以解决问题。如果您打印出c,您会看到:[1, 1, 2, 2, 1, 1, 2, 2]。这正是您需要确保第一个子图的两条第一条轨迹最终出现在子图 1 row = 1col = 1 中,依此类推。

    关于你关于传说的次要问题,这是通过以下方式处理的:

    fig.add_trace(t.update(showlegend=True if i == 0 else False), row=r, col=c)
    

    完成sn-p

    import plotly.express as px
    from plotly.subplots import make_subplots
    from itertools import cycle
    
    df = px.data.tips()
    
    fig = make_subplots(rows=2, cols=2, subplot_titles = df['day'].unique())
    
    cols = cycle([1,2])
    
    for i, met in enumerate(df['day'].unique()): #'Sun', 'Sat', 'Thur', 'Fri'
        df_plot=df[df['day']== met].sort_values(['time', 'sex'], ascending = False)
        c = next(cols)
        for t in px.box(df_plot, x="time", y="total_bill", color='sex').data:
            r = (i//2)+1
    #         print(c)
            fig.add_trace(t.update(showlegend=True if i == 0 else False), row=r, col=c)
                
    fig.update_layout(
        boxmode="group", margin={"l": 0, "r": 0, "t": 20, "b": 0}
    )#.update_traces(showlegend=True) 
    
    fig.show()
    

    编辑:

    如果您想在此设置中添加任何内容,例如 y 轴标题,只需添加:

    titles = cycle(df['day'].unique())
    fig.for_each_yaxis(lambda y: y.update(title = next(titles)))
    

    或者,如果我误解了你,而你只想在 yaxes 中添加 total_bill,只需使用:

    fig.update_yaxes(title = 'total_bill')
    

    【讨论】:

    • 谢谢。是否可以包含 y 轴标签(而不是显示子图标题)?
    • @DushiFdz 你想让'Sun',... 在y 轴上吗?
    • 是的,我想添加 y 轴和 x 轴标签,而不是子图标题。
    • @DushiFdz 看看我最新添加的内容。
    猜你喜欢
    • 2020-10-21
    • 2020-11-22
    • 2021-12-26
    • 2020-09-03
    • 2019-07-27
    • 2020-12-04
    • 2020-11-25
    • 2017-01-04
    • 2020-07-23
    相关资源
    最近更新 更多