You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Matplotlib使用bottom和height参数绘制时间轴条形图时出现数据显示异常的问题

Matplotlib使用bottom和height参数绘制时间轴条形图时出现数据显示异常的问题

嘿,我来帮你分析下这个问题!你遇到的条形图显示异常的情况,核心原因其实很简单——同一天的多个活动被挤在了x轴的同一个位置,导致它们的条形重叠在一起,视觉上看起来像是高度莫名累加,超过了24小时的上限。

问题根源拆解

你现在的代码把所有活动的x值都设为对应的日期,当同一天有多个活动时,matplotlib会把这些条形全部画在同一个x坐标点上。比如某天有两个活动:一个从2点到5点,另一个从19点到20点45分,这两个条形会完全重叠在一起,视觉上就会变成从2点延伸到20点45分的长条形,自然就突破了24小时的范围。你检查values["days"]就能发现,里面有大量重复的日期,这些重复日期对应的条形都挤在了同一个位置,最终导致了显示异常。

解决方案一:给同一天的活动添加x轴偏移

我们可以给同一天的每个活动分配一个小的x轴偏移量,让它们在日期位置上并排显示,避免重叠。修改后的代码如下:

import os, uuid, matplotlib
matplotlib.use('Agg')
import matplotlib.pyplot as plt
import pandas as pd
import datetime
import matplotlib.ticker
import matplotlib.dates
import numpy as np
from collections import defaultdict

dataset = pd.read_csv('input_df_3a3333a0-fd5d-4630-8707-5fc23cb0b326.csv')

plt.figure(figsize=(5.55555555555556,4.16666666666667), dpi=72)

# 数据预处理部分和你原来的一致
test_date_time = dataset.to_numpy().tolist()
test_date_time = list(filter(lambda x: type(x[0]) is not float, test_date_time))
test_date_time = [(datetime.datetime.fromisoformat(x[0]), datetime.datetime.fromisoformat(x[1])) for x in test_date_time]
test_date_time = sorted(test_date_time, key=lambda x:x[0])

# 按日期分组,整理每日的活动数据
daily_activities = defaultdict(list)
for start, end in test_date_time:
    day = start.date()
    start_hour = start.hour + start.minute/60 + start.second/3600
    duration = (end - start).total_seconds()/3600
    daily_activities[day].append((start_hour, duration))

# 准备绘图数据,添加偏移量
x_values = []
bottom_values = []
height_values = []
bar_width = 0.2  # 单个条形的宽度,可根据需求调整

for day, activities in daily_activities.items():
    num_activities = len(activities)
    # 计算偏移量,让同一天的条形居中排列
    offsets = np.linspace(-bar_width*(num_activities-1)/2, bar_width*(num_activities-1)/2, num_activities)
    # 将日期转换为matplotlib可识别的数值格式
    day_num = matplotlib.dates.date2num(day)
    for i, (start_hour, duration) in enumerate(activities):
        x_values.append(day_num + offsets[i])
        bottom_values.append(start_hour)
        height_values.append(duration)

# 绘制条形图
plt.bar(x=x_values, height=height_values, bottom=bottom_values, width=bar_width)

# 配置x轴为日期格式,优化显示
plt.gca().xaxis.set_major_formatter(matplotlib.dates.DateFormatter('%Y-%m-%d'))
plt.gca().xaxis.set_major_locator(matplotlib.dates.DayLocator())
plt.gcf().autofmt_xdate()  # 旋转日期标签,避免重叠

# 配置y轴范围和标签
plt.ylim(0, 24)
plt.ylabel('Time (Hours)')
plt.xlabel('Date')

plt.show()

解决方案二:使用broken_barh绘制更适配的时间轴图

其实你想要的效果更接近甘特图,用broken_barh(水平分段条形图)来实现会更直观,代码示例如下:

import os, uuid, matplotlib
matplotlib.use('Agg')
import matplotlib.pyplot as plt
import pandas as pd
import datetime
import matplotlib.ticker
import matplotlib.dates
import numpy as np

dataset = pd.read_csv('input_df_3a3333a0-fd5d-4630-8707-5fc23cb0b326.csv')

plt.figure(figsize=(8,6), dpi=72)

# 数据预处理
test_date_time = dataset.to_numpy().tolist()
test_date_time = list(filter(lambda x: type(x[0]) is not float, test_date_time))
test_date_time = [(datetime.datetime.fromisoformat(x[0]), datetime.datetime.fromisoformat(x[1])) for x in test_date_time]
test_date_time = sorted(test_date_time, key=lambda x:x[0])

# 给每个日期分配一个y轴位置,方便区分不同日期的活动
days = sorted(list({start.date() for start, end in test_date_time}))
day_to_y = {day: i+1 for i, day in enumerate(days)}

# 绘制每个活动的分段条形
for start, end in test_date_time:
    day_y = day_to_y[start.date()]
    # 计算活动的起始时间(当天的秒数)和持续时长
    start_seconds = (start - datetime.datetime.combine(start.date(), datetime.time(0,0,0))).total_seconds()
    duration_seconds = (end - start).total_seconds()
    plt.broken_barh([(start_seconds, duration_seconds)], (day_y - 0.4, 0.8), facecolors='blue')

# 配置y轴为日期标签
plt.yticks([i+1 for i in range(len(days))], [day.strftime('%Y-%m-%d') for day in days])
# 配置x轴为时分格式
plt.xlabel('Time of Day')
plt.xlim(0, 24*3600)
plt.gca().xaxis.set_major_formatter(plt.FuncFormatter(lambda x, pos: f'{int(x//3600)}:{int((x%3600)//60):02d}'))
plt.gca().xaxis.set_major_locator(matplotlib.ticker.MultipleLocator(3600))

plt.tight_layout()
plt.show()

备注:内容来源于stack exchange,提问作者Loufylouf

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.04.14 13:59:30