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

如何将编码时长的broken_barh图表转换为折线图或热力图?

问题描述

我有一份编码时长数据,以字典形式存储:键是日期,值是包含编码开始时间(秒数,从0点开始算)及时长的元组列表。已经用matplotlib的broken_barh绘制了断裂水平条形图,但没法直观看到一天中哪个时段的编码天数(对应时段的会话数量)最多,想转换成折线图或热力图,Y轴为对应时段的编码天数,该怎么实现?

原条形图代码:

for i,subSessions in enumerate(sessions.values()):
    plt.broken_barh(subSessions, (i,1))
months = {}
start = getStartMonth()
for month in period_range(start=start,end=datetime.today(),freq="M"):
    month = str(month)
    months[month] = (datetime.strptime(month,'%Y-%m')-start).days
plt.yticks(list(months.values()),months.keys())
plt.xticks(range(0,24*3600,3600),[str(i)+":00" for i in range(24)],rotation=45)
plt.gca().invert_yaxis()
plt.show()

方案1:折线图(统计每小时编码天数)

核心逻辑是统计一天中每个小时区间内,有多少天存在编码会话(避免同一天多次会话重复计数),再用折线图展示分布。

实现代码

import matplotlib.pyplot as plt
import numpy as np

# 初始化24小时的计数数组,每个位置对应小时的编码天数
hour_counts = np.zeros(24, dtype=int)

# 遍历所有日期的会话数据
for date, subsessions in sessions.items():
    # 标记当天涉及的编码小时
    daily_encoded_hours = set()
    for start_sec, duration in subsessions:
        # 计算会话覆盖的小时范围
        start_hour = int(start_sec // 3600)
        end_hour = int((start_sec + duration) // 3600)
        # 把会话涉及的所有小时加入集合
        for hour in range(start_hour, min(end_hour + 1, 24)):
            daily_encoded_hours.add(hour)
    # 更新对应小时的计数
    for hour in daily_encoded_hours:
        hour_counts[hour] += 1

# 绘制折线图
plt.figure(figsize=(12, 6))
hours = np.arange(24)
plt.plot(hours, hour_counts, marker='o', linestyle='-', linewidth=2)
plt.xticks(hours, [f"{h}:00" for h in hours], rotation=45)
plt.xlabel("一天中的时段")
plt.ylabel("编码天数")
plt.title("各时段编码天数统计")
plt.grid(axis='y', alpha=0.3)
plt.tight_layout()
plt.show()

如果需要统计会话总次数而非编码天数,去掉daily_encoded_hours集合,直接在遍历会话时对涉及小时累加计数即可。


方案2:热力图(日期×时段的精细统计)

热力图能直观展示每日各时段的编码分布,颜色深浅可代表编码时长或是否有编码,适合观察长期时段规律。

实现代码

import matplotlib.pyplot as plt
import numpy as np

# 对日期排序,保证时间顺序
sorted_dates = sorted(sessions.keys())
num_days = len(sorted_dates)
# 创建24行(小时)×N列(天数)的矩阵,存储各时段编码时长
heatmap_data = np.zeros((24, num_days))

for day_idx, date in enumerate(sorted_dates):
    subsessions = sessions[date]
    for start_sec, duration in subsessions:
        start_hour = int(start_sec // 3600)
        end_sec = start_sec + duration
        end_hour = int(end_sec // 3600)
        # 计算会话在每个覆盖小时内的实际时长,填充到矩阵
        for hour in range(start_hour, min(end_hour + 1, 24)):
            hour_start = hour * 3600
            hour_end = (hour + 1) * 3600
            overlap_start = max(start_sec, hour_start)
            overlap_end = min(end_sec, hour_end)
            heatmap_data[hour, day_idx] += overlap_end - overlap_start

# 绘制热力图
plt.figure(figsize=(15, 8))
im = plt.imshow(heatmap_data, cmap='YlOrRd', aspect='auto')
plt.yticks(np.arange(24), [f"{h}:00" for h in range(24)])
# 日期过多时,只显示每月第一天的日期
plt.xticks(np.arange(0, num_days, 30), sorted_dates[::30], rotation=45)
plt.xlabel("日期")
plt.ylabel("一天中的时段")
plt.title("每日各时段编码时长热力图")
plt.colorbar(im, label="编码时长(秒)")
plt.tight_layout()
plt.show()

如果只需要标记是否有编码,把heatmap_data[hour, day_idx] += overlap_end - overlap_start改成heatmap_data[hour, day_idx] = 1即可。


内容的提问来源于stack exchange,提问作者hopperelec

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.12 00:30:44