繁体   English   中英

python / plotly(快递)中的堆叠条形图 plot:条形图的分组/排序

[英]Stacked bar plot in python / plotly (express): grouping / ordering of bars

我在 dataframe 中有数据,我想使用堆叠条 plot plot:

test_df = pd.DataFrame([[1, 5, 1, 'A'], [2, 10, 1, 'B'], [3, 3, 1, 'A']], columns = ('ID', 'Value', 'Bucket', 'Type'))

如果我将 plot 与 Plotly Express 一起使用,我会得到彼此堆叠并正确排序的条形(基于索引):

fig = px.bar(test_df, x='Bucket', y='Value', barmode='stack')

但是,我想根据类型为数据着色,因此我为 go

fig = px.bar(test_df, x='Bucket', y='Value', barmode='stack', color='Type')

在此处输入图像描述

这行得通,但现在排序混乱了,因为现在所有条形图都按类型分组。 我查看了 Plotly Express 的文档,找不到单独指定条形排序的方法。 关于如何做到这一点的任何提示?

我在这里找到了这个,但情况有点不同,那里提到的选项似乎对我没有帮助: How to disable plotly express from grouping bars based on color?

编辑:这进入了正确的方向,但不是使用 Plotly Express,而是使用 Plotly graph_objects:

import plotly.graph_objects as go
test_df = pd.DataFrame([[1, 5, 1, 'A', 'red'], [2, 10, 1, 'B', 'blue'], [3, 3, 1, 'A', 'red']], columns = ('ID', 'Value', 'Bucket', 'Type', 'Color'))
fig = go.Figure()
fig.add_trace(go.Bar(x=test_df["Bucket"], y=test_df["Value"], marker_color=test_df["Color"]))

Output: 在此处输入图像描述

不过,我更喜欢 Express 版本,因为那里有很多东西更容易处理(Legend、Hover 属性等)。

我能理解您的问题的唯一方法是您不希望B堆叠在A之上,而是相反。 如果是这种情况,那么您可以通过以下方式获得您想要的东西:

fig.data = fig.data[::-1]
fig.layout.legend.traceorder = 'reversed'

在此处输入图像描述

一些细节:

fig.data = fig.data[::-1]只是颠倒了痕迹出现在fig.data中的顺序,最终出现在绘制的图形本身中。 然而,这也会颠倒图例的顺序。 因此,如果没有fig.layout.legend.traceorder = 'reversed' ,结果将是:

在此处输入图像描述

因此,完整的解决方法如下所示:

fig.data = fig.data[::-1]
fig.layout.legend.traceorder = 'reversed'

完整代码:

import pandas as px
import plotly.express as px
test_df = pd.DataFrame([[1, 5, 1, 'A'], [2, 10, 1, 'B'], [3, 3, 1, 'A']], columns = ('ID', 'Value', 'Bucket', 'Type'))
fig = px.bar(test_df, x='Bucket', y='Value', barmode='stack', color='Type')
fig.data = fig.data[::-1]
fig.layout.legend.traceorder = 'reversed'
fig.show()

好的,很抱歉耽搁了这么久,但我终于开始解决这个问题了。
我的解决方案可能不是最直接的解决方案,但它确实有效。

基本思想是使用 graph_objects 而不是 express,然后遍历 dataframe 并将每个条添加为单独的跟踪。 这样,每个跟踪都可以获得一个可以以某种方式分组的名称(如果将所有条添加到单个跟踪中,这是不可能的,或者至少我找不到方法)。 不幸的是,图例的顺序是混乱的(如果你有超过 2 个桶),目前 plotly 没有办法对其进行排序。 但那是小事。

困扰我的主要事情是,如果 plotly.express 允许按特定列手动排序条形,这可能会容易得多。 也许我会把它作为建议提交。

import pandas as pd
import plotly.graph_objects as go
import plotly.io as pio
pio.renderers.default = "browser"

test_df = pd.DataFrame(
    [[1, 5, 1, 'B'], [3, 3, 1, 'A'], [5, 10, 1, 'B'],
     [2, 8, 2, 'B'], [4, 5, 2, 'A'], [6, 3, 2, 'A']],
    columns = ('ID', 'Value', 'Bucket', 'Type'))
# add named colors to the dataframe based on type
test_df.loc[test_df['Type'] == 'A', 'Color'] = 'Crimson'
test_df.loc[test_df['Type'] == 'B', 'Color'] = 'ForestGreen'
# ensure that the dataframe is sorted by the values
test_df.sort_values('ID', inplace=True)

fig = go.Figure()
# it's tedious to iterate over each item, but only this way we can ensure that everything is correctly ordered and labelled
# Set up legend_show_dict to check if an item should be shown or not. This should be only done for the first occurrence to avoid duplication.
legend_show_dict = {}
for i, row in test_df.iterrows():
    if row['Type'] in legend_show_dict:
        legend_show = legend_show_dict[row['Type']]
    else:
        legend_show = True
        legend_show_dict[row['Type']] = False
    fig.add_trace(
        go.Bar(
            x=[row['Bucket']],
            y=[row['Value']],
            marker_color=row['Color'],
            name=row['Type'],
            legendgroup=row['Type'],
            showlegend=legend_show,
            hovertemplate="<br>".join([
            'ID: ' + str(row['ID']),
            'Value: ' + str(row['Value']),
            'Bucket: ' + str(row['Value']),
            'Type: ' + row['Type'],
            ])
           ))
fig.update_layout(
    xaxis={'categoryorder': 'category ascending', 'title': 'Bucket'},
    yaxis={'title': 'Value'},
    legend={'traceorder': 'normal'}
    )
fig.update_layout(barmode='stack', font_size=20)
fig.show()

这就是它应该看起来的样子:
输出

暂无
暂无

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

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