我有一个由 3 列组成的数据框:日期、名称、数字。有 5 个日期(可能会根据数据提取运行的时间而变化),每个日期有 10 个名称。同一名称可以出现在多个日期中,也可以只出现在一个日期中。数字可以是正数也可以是负数。数据按日期 (
ascending=True
) 排序,然后按数字 (ascending=False
) 排序。
我正在尝试使用plotlyexpress绘制一个图表,该图表在Y轴上有数字,在轴上有日期,条形由报告者着色。条形图应按照每个日期从最大到最小的数量排序。
使用此代码时,第一个日期的排序是正确的,但此后某些条形图之间存在间隙,并且排序错误,例如在负数条形图之后绘制正条形图。
fig = px.bar(df, x="Date", y="Number", color="Name", barmode="group")
我尝试过使用
fig.update_layout(yaxis={'categoryorder': 'total ascending'})
但这似乎没有任何作用。
请有人帮我格式化此图表,以便没有间隙,并且所有日期的顺序都是正确的。
经过进一步调查,似乎顺序是在 x 轴的第一个值(例如 Day1)上设置的,然后保持不变。因此,如果某个名称在 Day1 中,但在 Day2 中没有,那么 Day2 中将会有一个空格。如果某个名称没有出现在第 1 天,但出现在第 2 天,那么该条将会出现并结束,即使它代表的数字比前一个条更大。
本质上,我需要强制 Plotly Express 对每个 X 值的条形图进行独立排序。
下面的代码重现了我的问题,尽管只有 2 个日期而不是 5 个,但它仍然说明了问题。
import pandas as pd
import plotly.express as px
df = pd.DataFrame({
"Name": ["Joe", "Tom", "Tim", "Alex", "Ben", "Steve", "Nick", "Alan", "Jack", "George", "Joe", "Tom", "Tim", "Leo", "Alex", "Ben", "Nick", "Alan", "Jack", "George"],
"Date": (["01-01-2024"] * 10) + (["01-02-2024"] * 10),
"Number": [0.5, 0.4, 0.3, 0.2, 0.1, -0.1, -0.2, -0.3, -0.4, -0.5, 0.5, 0.4, 0.3, 0.2, 0.1, -0.1, -0.2, -0.3, -0.4, -0.5]
})
df["Date"] = pd.to_datetime(df["Date"])
df.sort_values(by=["Date", "Number"], ascending=[True, False], inplace=True)
print(df)
fig=px.bar(df, x="Date", y="Number", color="Name", barmode="group")
fig.show()
在plotly.express中,我认为这种显示是因为我为颜色编码设置了类别变量。我通过使用图形对象来绘制按日期提取的数据帧的每一行来创建图形。每个名称的颜色编码是通过创建离散色阶值和名称的字典并将它们设置为标记颜色来完成的。我还使用循环过程使重复的图例变得独特。此外,x 轴仅限于特定时间段和图形大小。
import plotly.graph_objects as go
import plotly.express as px
colors = px.colors.qualitative.Set3
names = df['Name'].unique()
color_dict = {k:v for k,v in zip(names, colors)}
print(color_dict)
fig = go.Figure()
for d in df['Date'].unique():
dff = df.query('Date == @d')
for n in dff['Name'].unique():
dfn = dff.query('Name == @n')
fig.add_trace(go.Bar(
x=dfn['Date'],
y=dfn['Number'],
marker=dict(color=color_dict[n]),
name=n,
width=60*60*1000
)
)
names = set()
fig.for_each_trace(
lambda trace:
trace.update(showlegend=False)
if (trace.name in names) else names.add(trace.name))
fig.update_layout(xaxis_range=['2023-12-31','2024-01-03'])
fig.update_layout(height=500, width=800, barmode='group')
fig.show()