简体   繁体   English

python plotly - 堆叠+分组条形图

[英]python plotly - stacked + grouped bar chart

I'm trying to create a bar chart using plotly in python, which is both stacked and grouped.我正在尝试使用 python 中的 plotly 创建条形图,该条形图既堆叠又分组。
Toy example (money spent and earned in different years):玩具示例(不同年份的花费和收入):

import pandas as pd
import plotly.graph_objs as go

data = pd.DataFrame(
    dict(
        year=[2000,2010,2020],
        var1=[10,20,15],
        var2=[12,8,18],
        var3=[10,17,13],
        var4=[12,11,20],
    )
)

fig = go.Figure(
    data = [
        go.Bar(x=data['year'], y=data['var1'], offsetgroup=0, name='spent on fruit'),
        go.Bar(x=data['year'], y=data['var2'], offsetgroup=0, base=data['var1'], name='spent on toys'),
        go.Bar(x=data['year'], y=data['var3'], offsetgroup=1, name='earned from stocks'),
        go.Bar(x=data['year'], y=data['var4'], offsetgroup=1, base=data['var3'], name='earned from gambling'),
    ]
)
fig.show()   

The result seems fine at first:结果一开始似乎很好: 在此处输入图像描述 But watch what happens when I turn off eg "spent on fruit":但是请注意当我关闭例如“花在水果上”时会发生什么: 在此处输入图像描述 The "spent on toys" trace remains floating instead of starting from 0. “花在玩具上”的轨迹保持浮动,而不是从 0 开始。
Can this be fixed?这可以解决吗? or maybe the whole offsetgroup + base approach won't work here.或者也许整个offsetgroup + base方法在这里不起作用。 But what else can I do?但我还能做什么?
Thanks!谢谢!

Update: according to this Github issue , stacked, grouped bar plots are being developed for future plotly versions, so this probably won't be an issue anymore.更新:根据这个 Github 问题,正在为未来的 plotly 版本开发堆叠的分组条形图,所以这可能不再是问题了。

There doesn't seem to be a way to create both stacked and grouped bar charts in Plotly, but there is a workaround that might resolve your issue. 似乎没有办法在 Plotly 中创建堆叠和分组条形图,但有一种解决方法可以解决您的问题。 You will need to create subgroups, then use a stacked bar in Plotly to plot the bars one at a time, plotting var1 and var2 with subgroup1, and var3 and var4 with subgroup2.您将需要创建子组,然后在 Plotly 到 plot 中使用堆叠条形图,一次一个地绘制条形图,将var1var2与 subgroup1 一起绘制, var3var4与 subgroup2 一起绘制。

This solution gives you the functionality you want, but changes the formatting and aesthetic of the bar chart.此解决方案为您提供所需的功能,但会更改条形图的格式和美感。 There will be equal spacing between each bar as from Plotly's point of view these are stacked bars (and not grouped bars), and I couldn't figure out a way to eliminate the subgroup1 and subgroup2 text without also getting rid of the years in the x-axis ticks.从 Plotly 的角度来看,每个条之间的间距将相等,这些条是堆叠条(而不是分组条),而且我想不出一种方法来消除 subgroup1 和 subgroup2 文本,而无需摆脱x 轴刻度。 Any Plotly experts please feel free to chime in and improve my answer!任何 Plotly 专家请随时加入并改进我的答案!

import pandas as pd
import plotly.graph_objs as go

df = pd.DataFrame(
    dict(
        year=[2000,2010,2020],
        var1=[10,20,15],
        var2=[12,8,18],
        var3=[10,17,13],
        var4=[12,11,20],
    )
)
        
fig = go.Figure()

fig.update_layout(
    template="simple_white",
    xaxis=dict(title_text="Year"),
    yaxis=dict(title_text="Count"),
    barmode="stack",
)

groups = ['var1','var2','var3','var4']
colors = ["blue","red","green","purple"]
names = ['spent on fruit','spent on toys','earned from stocks','earned from gambling']

i = 0
for r, n, c in zip(groups, names, colors):
    ## put var1 and var2 together on the first subgrouped bar
    if i <= 1:
        fig.add_trace(
            go.Bar(x=[df.year, ['subgroup1']*len(df.year)], y=df[r], name=n, marker_color=c),
        )
    ## put var3 and var4 together on the first subgrouped bar
    else:
        fig.add_trace(
            go.Bar(x=[df.year, ['subgroup2']*len(df.year)], y=df[r], name=n, marker_color=c),
        )
    i+=1

fig.show()   

在此处输入图像描述

Plotly Express (part of recent plotly library version) offers a facet_col parameter for its bar chart (and other charts as well), which allows one to set an additional grouping column: Plotly Express (最近的plotly库版本的一部分)为其条形图(以及其他图表)提供了facet_col参数,它允许设置额外的分组列:

Values from this column or array_like are used to assign marks to facetted subplots in the horizontal direction.此列或 array_like 中的值用于在水平方向上为多面子图分配标记。

To make it work I had to reshape the example data:为了使它工作,我不得不重塑示例数据:

import pandas as pd

data = pd.DataFrame(
    dict(
        year=[*[2000, 2010, 2020]*4],
        var=[*[10, 20, 15], *[12, 8, 18], *[10, 17, 13], *[12, 11, 20]],
        names=[
            *["spent on fruit"]*3,
            *["spent on toys"]*3,
            *["earned from stocks"]*3,
            *["earned from gambling"]*3,
        ],
        groups=[*["subgroup1"]*6, *["subgroup2"]*6]
    )
)
year var变量 names名字 groups团体
0 0 2000 2000 10 10 spent on fruit花在水果上 subgroup1亚组1
1 1 2010 2010 20 20 spent on fruit花在水果上 subgroup1亚组1
2 2 2020 2020 15 15 spent on fruit花在水果上 subgroup1亚组1
3 3 2000 2000 12 12 spent on toys花在玩具上 subgroup1亚组1
4 4 2010 2010 8 8 spent on toys花在玩具上 subgroup1亚组1
5 5 2020 2020 18 18 spent on toys花在玩具上 subgroup1亚组1
6 6 2000 2000 10 10 earned from stocks从股票中赚取 subgroup2亚组2
7 7 2010 2010 17 17 earned from stocks从股票中赚取 subgroup2亚组2
8 8 2020 2020 13 13 earned from stocks从股票中赚取 subgroup2亚组2
9 9 2000 2000 12 12 earned from gambling赌博赚来的 subgroup2亚组2
10 10 2010 2010 11 11 earned from gambling赌博赚来的 subgroup2亚组2
11 11 2020 2020 20 20 earned from gambling赌博赚来的 subgroup2亚组2

Once it's in this format (I believe this is called the "tall format") you can plot it with one function call:一旦它采用这种格式(我相信这被称为“高格式”),您可以通过一个 function 调用 plot 它:

import plotly_express as px

fig = px.bar(data, x="groups", y="var", facet_col="year", color="names")
fig.show()

Plotly 表示分组和堆叠的条形图

If you want to hide the subgroup labels you can update the x-axis:如果要隐藏子组标签,可以更新 x 轴:

fig.update_xaxes(visible=False)

Plotly 表示条形图分组和堆叠,没有 x 轴标签

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM