Plotly:排序多类别条形图
Plotly: Sort multicategory bar chart
我在对多类别图表进行排序时遇到一些问题。
一些示例代码。
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"))
如您所见,tick 2 在 tick 1 之前。发生这种情况是因为 'Rhino' 是类型列表中的第一个,它将创建 tick 0 和 2。狮子条在 tick 之后添加1.
但是现在我怎样才能正确地对条形进行排序呢?
PS。 'barmode': 'stack'
是故意的。即使在这个测试例子中没有使用它。
我可以修复订单,但不能修复 born/died 订单。我打算逐行绘制,所以我需要玩 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")
我在对多类别图表进行排序时遇到一些问题。
一些示例代码。
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"))
如您所见,tick 2 在 tick 1 之前。发生这种情况是因为 'Rhino' 是类型列表中的第一个,它将创建 tick 0 和 2。狮子条在 tick 之后添加1. 但是现在我怎样才能正确地对条形进行排序呢?
PS。 'barmode': 'stack'
是故意的。即使在这个测试例子中没有使用它。
我可以修复订单,但不能修复 born/died 订单。我打算逐行绘制,所以我需要玩 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")