[英]Discontinuous horizontal bar plot
Consider the following data frame考虑以下数据框
A B
2022-09-28 1.3 0.0
2022-09-29 1.3 0.0
2022-09-30 1.3 0.9
2022-10-01 1.3 0.9
2022-10-02 0.0 0.9
2022-10-03 0.0 0.9
2022-10-04 0.0 0.0
2022-10-05 0.1 0.0
2022-10-06 0.1 0.0
2022-10-07 0.1 0.0
I would need a horizontal bar plot with two vertical levels (A and B) and the date on the x-axis.我需要一个水平条 plot,它具有两个垂直水平(A 和 B)和 x 轴上的日期。 The length of the bars (barwidth) equals the time intervals of nonzero values and the linewidth (bar height) the average of the values.
条形的长度(条宽)等于非零值的时间间隔,线宽(条形高度)等于值的平均值。
For the example we would have two bars at the A level.例如,我们将在 A 级别设置两个栏。 The first one from 2022-09-28 to 2022-10-01 with linewidth 1.3 and the second one from 2022-10-05 to 2022-10-07 with linewidth 0.1.
第一个从 2022-09-28 到 2022-10-01,线宽 1.3,第二个从 2022-10-05 到 2022-10-07,线宽 0.1。 On the B level there would be one bar only from 2022-09-30 to 2022-10-03 with linewidth 0.9.
在 B 级别上,只有从 2022-09-30 到 2022-10-03 的一根柱线,线宽为 0.9。
This is pretty close, but it is a solution for one bar per level only. 这非常接近,但它是每个级别仅一个条的解决方案。
You can use Matplotlib's broken_barh function to plot various discontinuous ('broken') horizontal bar plots.您可以使用 Matplotlib 的broken_barh function 到 plot 各种不连续(“破碎”)水平条形图。 The trick is to feed the data in the dataframe to
broken_barh
correctly: you need to create (x start, x duration)
for each part of the discontinuous bar plot.诀窍是将 dataframe 中的数据正确地提供给
broken_barh
:您需要为不连续柱 plot 的每个部分创建(x start, x duration)
。
For example, A has two parts as you mentioned.例如,A 有您提到的两个部分。 One part would be
(2022-09-28, 3 days)
with linewidth 1.3, and the second part would be (2022-10-05, 2 days)
with linewidth 0.1.一部分是
(2022-09-28, 3 days)
,线宽为 1.3,第二部分是(2022-10-05, 2 days)
,线宽为 0.1。 We would feed broken_barh
with x ranges [(2022-09-28, 3 days), (2022-10-05, 2 days)]
and linewidth [1.3, 0.1]
.我们将为
broken_barh
提供 x 范围[(2022-09-28, 3 days), (2022-10-05, 2 days)]
和线宽[1.3, 0.1]
。
import matplotlib.pyplot as plt
import pandas as pd
if __name__ == '__main__':
# Create dataframe
df_dates = pd.date_range('2022-09-28', periods=10)
df = pd.DataFrame({'A': [1.3, 1.3, 1.3, 1.3, 0.0, 0.0, 0.0, 0.1, 0.1, 0.1],
'B': [0.0, 0.0, 0.9, 0.9, 0.9, 0.9, 0.0, 0.0, 0.0, 0.0]},
index=df_dates)
# xranges and linewidth we will feed matplotlib later
a_xranges = []
a_lw = []
# Find unique values in A - aka the parts of the A broken bar plot
for lw_value in df['A'].unique().tolist():
if lw_value != 0.0: # skip 0.0, we will not plot it
# Find rows where linewidth for the A values is located
idx = df.index[df['A'] == lw_value].tolist()
sub_df = df.loc[idx]
# Find where the bar plot starts for x axis and x duration
x_range = (sub_df.index[0], sub_df.index[-1] - sub_df.index[0]) # (x start, x duration)
# Add x range and linewidth values for that part
a_xranges.append(x_range)
a_lw.append(lw_value)
a_xranges
and a_lw
are in the correct format for broken_barh
. a_xranges
和a_lw
是broken_barh
的正确格式。 Matplotlib will manage the pandas dates so you don't have to worry about date formatting. Matplotlib 将管理 pandas 日期,因此您不必担心日期格式。
You can repeat the same for B - you could also make a function and call it instead of adding the same loop to clean up your code.您可以对 B 重复相同的操作 - 您也可以制作一个 function 并调用它,而不是添加相同的循环来清理您的代码。
b_xranges = []
b_lw = []
for lw_value in df['B'].unique().tolist():
if lw_value != 0.0:
idx = df.index[df['B'] == lw_value].tolist()
sub_df = df.loc[idx]
x_range = (sub_df.index[0], sub_df.index[-1] - sub_df.index[0])
b_xranges.append(x_range)
b_lw.append(lw_value)
# Start figure
fig, ax = plt.subplots(figsize=(12, 5))
# Plot A bar plot
# The (10,9) is for the y axis (ymin, y duration)
ax.broken_barh(a_xranges, (10, 9), edgecolor='k', facecolor='white', linewidth=a_lw)
# Plot B bar plot
ax.broken_barh(b_xranges, (20, 9), edgecolor='k', facecolor='white', linewidth=b_lw)
ax.set_ylabel("Level")
ax.set_yticks([15, 25], labels=['A', 'B'])
ax.set_xlabel("Date")
plt.show()
If you wanted the bars closer, narrower, etc... you could play around with the y-values (10,9)
and (20,9)
values I gave them.如果你想让条形更近、更窄等……你可以使用我给它们的 y 值
(10,9)
和(20,9)
值。 Hope this helps - cheers!希望这会有所帮助 - 干杯!
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.