【问题标题】:Plotly: Sort multicategory bar chartPlotly:排序多类别条形图
【发布时间】:2020-09-23 22:10:59
【问题描述】:

我在排序多类别图表时遇到了一些问题。

一些示例代码。

import pandas as pd
import plotly.graph_objects as go

data = [
    [0, "Born", 4, "Rhino"],  # commenting this line will also reverse sub category sorting
    [0, "Died", -1, "Rhino"],
    [1, "Born", 4, "Lion"],
    [1, "Died", -1, "Lion"],
    [2, "Born", 12, "Rhino"],
    [2, "Died", -5, "Lion"],
]
z_data = list(zip(*data))

df = pd.DataFrame({
    "tick": z_data[0],
    "category": z_data[1],
    "value": z_data[2],
    "type": z_data[3],
})
df = df.sort_values(by=['tick', 'category', 'value', 'type'])
print(df)
fig = go.Figure()
for t in df.type.unique():
    plot_df = df[df.type == t]
    fig.add_trace(go.Bar(
        x=[plot_df.tick, plot_df.category],
        y=abs(plot_df.value),
        name=t,
    ))
fig.update_layout({
    'barmode': 'stack',
    'xaxis': {
        'title_text': "Tick",
        'tickangle': -90,
    },
    'yaxis': {
        'title_text': "Value",
    },
})
fig.write_html(str("./diagram.html"))

正如您所见,第 2 刻在第 1 刻之前。这是因为“Rhino”是类型列表中的第一个,这将创建第 0 和第 2 刻。在第 1 刻之后添加了狮子条。 但是我现在如何正确排序条形?

附言。 'barmode': 'stack' 是故意的。即使在这个测试示例中没有使用它。

【问题讨论】:

    标签: python plotly plotly-python


    【解决方案1】:

    我能够修正刻度,但不能修正出生/死亡顺序。我打算逐行绘制,所以我需要玩 showlegend

    数据

    import pandas as pd
    import plotly.graph_objects as go
    data = [
        [0, "Born", 4, "Rhino"],  # commenting this line will also reverse sub category sorting
        [0, "Died", -1, "Rhino"],
        [1, "Born", 4, "Lion"],
        [1, "Died", -1, "Lion"],
        [2, "Born", 12, "Rhino"],
        [2, "Died", -5, "Lion"],
    ]
    # you don't really need to zip here
    df = pd.DataFrame(data, columns=["tick", "category", "value", "type"])
    df["value"] = df["value"].abs()
    

    设置颜色

    如果您有更多类型,这里有可以帮助您的答案。检查doc

    color_diz = {"Rhino": "blue", "Lion": "red"}
    df["color"] = df["type"].map(color_diz)
    

    显示图例

    这里我想展示每种类型第一次出现的图例

    grp = df.groupby("type")\
            .apply(lambda x: x.index.min())\
            .reset_index(name="idx")
    
    df = pd.merge(df, grp, on=["type"], how="left")
    
    df["showlegend"] = df.index == df["idx"]
    

    要绘制的数据

    print(df)
    
       tick category  value   type color  idx  showlegend
    0     0     Born      4  Rhino  blue    0        True
    1     0     Died      1  Rhino  blue    0       False
    2     1     Born      4   Lion   red    2        True
    3     1     Died      1   Lion   red    2       False
    4     2     Born     12  Rhino  blue    0       False
    5     2     Died      5   Lion   red    2       False
    

    情节

    fig = go.Figure()
    for i, row in df.iterrows():
        fig.add_trace(
            go.Bar(x=[[row["tick"]], [row["category"]]],
                   y=[row["value"]],
                   name=row["type"],
                   marker_color=row["color"],
                   showlegend=row["showlegend"],
                   legendgroup=row["type"] # Fix legend
                   ))
        
    fig.update_layout({
        'barmode': 'stack',
        'xaxis': {
            'title_text': "Tick",
            'tickangle': -90,
        },
        'yaxis': {
            'title_text': "Value",
        },
    })
    fig.show()
    

    编辑

    如果您有更多type,您可以使用以下技巧。

    首先我生成不同的类型

    import string
    import numpy as np
    import pandas as pd
    import plotly.express as px
    
    df = pd.DataFrame({"type":np.random.choice(list(string.ascii_lowercase), 100)})
    

    然后我从doc 中挑选一个颜色序列并将它们放入字典中

    color_dict = {k:v for k,v in enumerate(px.colors.qualitative.Plotly)}
    

    然后我将唯一的type 放在数据框上

    df_col = pd.DataFrame({"type": df["type"].unique()})
    

    我根据它们的索引为它们每个分配一个颜色

    df_col["color"] = (df_col.index%len(color_dict)).map(color_dict)
    

    最后我合并到原来的df

    df = pd.merge(df, df_col, on=["type"], how="left")
    

    【讨论】:

    • 如果您有更多类别,有没有办法自动将颜色应用于同一类别?
    • 同样,这并不能解决图例的问题,因为如果你想隐藏所有的狮子,显示的图例项只与一个条相关联。
    • @IceflowerS 我使用legendgroup 修复了图例。见情节部分。
    • 谢谢,帮了大忙!我用这个作为颜色:python df_col = pd.DataFrame({ "type": df["type"].unique(), "color": seaborn.color_palette("bright", len(df["type"].unique())).as_hex(), })
    猜你喜欢
    • 2017-03-02
    • 2019-03-10
    • 2020-02-28
    • 2018-12-07
    • 2022-08-23
    • 2021-12-28
    • 2021-07-13
    • 1970-01-01
    • 2011-07-21
    相关资源
    最近更新 更多