Matplotlib 使用 plt.barh 绘制时间线时的奇怪行为

问题描述 投票:0回答:1

我有一个

events
的数据框。我想绘制这些事件以显示一天的时间线。

event_start     event_end   event_type
0   2024-09-12 21:59:00     2024-09-13 05:09:00     Stop
1   2024-09-13 01:26:00     2024-09-13 02:00:00     Farming
2   2024-09-13 02:00:00     2024-09-13 02:35:00     Active
3   2024-09-13 02:35:00     2024-09-13 06:11:00     Farming
4   2024-09-13 02:35:00     2024-09-13 06:11:00     Farming
5   2024-09-13 06:11:00     2024-09-13 07:27:00     Active
6   2024-09-13 07:27:00     2024-09-13 07:47:00     Stop
7   2024-09-13 07:47:00     2024-09-13 08:00:00     Active
8   2024-09-13 08:00:00     2024-09-13 08:06:00     Stop
9   2024-09-13 08:06:00     2024-09-13 08:07:00     Active
10  2024-09-13 08:07:00     2024-09-13 08:16:00     Stop
11  2024-09-13 08:16:00     2024-09-13 08:18:00     Active
12  2024-09-13 08:18:00     2024-09-13 08:45:00     Stop
13  2024-09-13 08:45:00     2024-09-13 09:00:00     Active
14  2024-09-13 09:00:00     2024-09-13 09:31:00     Stop
15  2024-09-13 09:31:00     2024-09-13 10:24:00     Active
16  2024-09-13 10:24:00     2024-09-13 10:32:00     Stop
17  2024-09-13 10:32:00     2024-09-13 10:37:00     Active
18  2024-09-13 10:37:00     2024-09-13 16:29:00     Stop
19  2024-09-13 16:29:00     2024-09-13 16:34:00     Active

我尝试使用 matplotlib.pyplot.barh 进行绘图,但最后一个事件(从 16:29 开始到 16:34(活动)结束)被绘制为从 16:39 到大约 18:30 的块。我不明白为什么。 这是我正在使用的plot_timeline 函数。

def plot_timeline(events):
    df_events = events

    plt.figure(figsize=(12, 6))

    for _, row in df_events.iterrows():
        color_map = {
            'Active': 'lightblue',
            'Idling': 'red',
            'Stop': 'black',
            'Farming': 'green'
        }
        print(f"start : {row['event_start']}, end : {row['event_end']}, type : {row['event_type']}")
        plt.barh(y=0, width=(row['event_end'] - row['event_start']).total_seconds() / 3600, 
                 left=row['event_start'], 
                 color=color_map.get(row['event_type'], 'lightblue'))

    plt.xlim(pd.to_datetime(f"{df_events['event_start'].dt.date.iloc[-1]} 04:00"),
             pd.to_datetime(f"{df_events['event_start'].dt.date.iloc[-1]} 23:00"))

    plt.gca().xaxis.set_major_locator(mdates.HourLocator(interval=1))
    plt.gca().xaxis.set_major_formatter(mdates.DateFormatter('%H:%M'))

    plt.title('Timeline of Events')
    plt.xlabel('Time')
    plt.yticks([])  
    plt.grid(axis='x', linestyle='--', alpha=0.7)
    plt.tight_layout()
    plt.show()
plot_timeline(events)

Incorrect Timeline

(编辑):打印输出

start : 2024-09-12 21:59:00, end : 2024-09-13 05:09:00, type : Stop
start : 2024-09-13 01:26:00, end : 2024-09-13 02:00:00, type : Farming
start : 2024-09-13 02:00:00, end : 2024-09-13 02:35:00, type : Active
start : 2024-09-13 02:35:00, end : 2024-09-13 06:11:00, type : Farming
start : 2024-09-13 02:35:00, end : 2024-09-13 06:11:00, type : Farming
start : 2024-09-13 06:11:00, end : 2024-09-13 07:27:00, type : Active
start : 2024-09-13 07:27:00, end : 2024-09-13 07:47:00, type : Stop
start : 2024-09-13 07:47:00, end : 2024-09-13 08:00:00, type : Active
start : 2024-09-13 08:00:00, end : 2024-09-13 08:06:00, type : Stop
start : 2024-09-13 08:06:00, end : 2024-09-13 08:07:00, type : Active
start : 2024-09-13 08:07:00, end : 2024-09-13 08:16:00, type : Stop
start : 2024-09-13 08:16:00, end : 2024-09-13 08:18:00, type : Active
start : 2024-09-13 08:18:00, end : 2024-09-13 08:45:00, type : Stop
start : 2024-09-13 08:45:00, end : 2024-09-13 09:00:00, type : Active
start : 2024-09-13 09:00:00, end : 2024-09-13 09:31:00, type : Stop
start : 2024-09-13 09:31:00, end : 2024-09-13 10:24:00, type : Active
start : 2024-09-13 10:24:00, end : 2024-09-13 10:32:00, type : Stop
start : 2024-09-13 10:32:00, end : 2024-09-13 10:37:00, type : Active
start : 2024-09-13 10:37:00, end : 2024-09-13 16:29:00, type : Stop
start : 2024-09-13 16:29:00, end : 2024-09-13 16:34:00, type : Active
python matplotlib
1个回答
0
投票

picture

看来使用

Rectangles
变得更容易了。

第一部分致力于拥有某种数据框,这并不重要,请参阅函数

put_r

另请注意,向图中添加矩形不会更改轴限制,但您已经使用了

plt.xlim()
...

最终我绘制了一些散点,以便可以绘制图例。

import matplotlib.pyplot as plt
import matplotlib.dates as md
from matplotlib.patches import Rectangle
from datetime import datetime, timedelta

data = ''''\
0   2024-09-12 21:59:00     2024-09-13 05:09:00     Stop
1   2024-09-13 01:26:00     2024-09-13 02:00:00     Farming
2   2024-09-13 02:00:00     2024-09-13 02:35:00     Active
3   2024-09-13 02:35:00     2024-09-13 06:11:00     Farming
4   2024-09-13 02:35:00     2024-09-13 06:11:00     Farming
5   2024-09-13 06:11:00     2024-09-13 07:27:00     Active
6   2024-09-13 07:27:00     2024-09-13 07:47:00     Stop
7   2024-09-13 07:47:00     2024-09-13 08:00:00     Active
8   2024-09-13 08:00:00     2024-09-13 08:06:00     Stop
9   2024-09-13 08:06:00     2024-09-13 08:07:00     Active
10  2024-09-13 08:07:00     2024-09-13 08:16:00     Stop
11  2024-09-13 08:16:00     2024-09-13 08:18:00     Active
12  2024-09-13 08:18:00     2024-09-13 08:45:00     Stop
13  2024-09-13 08:45:00     2024-09-13 09:00:00     Active
14  2024-09-13 09:00:00     2024-09-13 09:31:00     Stop
15  2024-09-13 09:31:00     2024-09-13 10:24:00     Active
16  2024-09-13 10:24:00     2024-09-13 10:32:00     Stop
17  2024-09-13 10:32:00     2024-09-13 10:37:00     Active
18  2024-09-13 10:37:00     2024-09-13 16:29:00     Stop
19  2024-09-13 16:29:00     2024-09-13 16:34:00     Active'''
data = dict(zip(
    'index start_day start_time end_day end_time type'.split(),
    zip(*[l.split() for l in data.split('\n')])
))
data['start'] = [datetime.fromisoformat(dt) for dt in (' '.join(t) for t in zip(data['start_day'], data['start_time']))]
data['end'] = [datetime.fromisoformat(dt) for dt in (' '.join(t) for t in zip(data['end_day'], data['end_time']))]

color = {'Active':  'lightblue',
         'Idling':  'red',
         'Stop':    'lightgrey',
         'Farming': 'green'}

def put_r(d1, d2, color):
    plt.gca().add_patch(
        Rectangle((d1, 0), d2-d1, 1,
                  linewidth=0.5, edgecolor='k',
                  facecolor=color, alpha=0.8))

fig, ax = plt.subplots(figsize=(11,4), layout='constrained', edgecolor='k')
plt.xlim(datetime(2024, 9, 13, 4), datetime(2024, 9, 13, 23))
for d1, d2, t in zip(*[data[s] for s in 'start end type'.split()]):
    print(d1, d2, t.rjust(8), color[t])
    put_r(d1, d2, color[t])

for t, c in color.items():
    ax.scatter(datetime(2024, 9, 13, 4)-timedelta(minutes=1), 0, color=c, label=t)

plt.title('Timeline of Events')

plt.xlabel('Time')
ax.xaxis.set_major_locator(md.HourLocator(interval=1))
ax.xaxis.set_major_formatter(md.DateFormatter('%H:%M'))

ax.set_yticks([])
ax.set_ylim(0, 1)
plt.legend()
plt.show()
© www.soinside.com 2019 - 2024. All rights reserved.