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

如何用Pandas绘制含日期与车队编号的单图多级X轴柱状图?

问题描述

现有如下格式的车辆行驶数据:

import pandas as pd
import numpy as np
import matplotlib.pyplot as plt

# 固定随机种子
np.random.seed(seed = 123)
dates = pd.date_range(start = "28/05/2024", end = "28/05/2025", freq = "D")
vehicles = np.random.choice(["A", "B", "C", "D", "E", "F"], size = len(dates))
kilometres = np.random.normal(loc = 170, scale = 76, size = len(dates)).round(2)
df = pd.DataFrame({"date":dates, "fleet no":vehicles, "kilometres":kilometres})
# 按月份和车辆分组聚合
df = df.groupby(by = [df["date"].dt.to_period("M"), "fleet no"]).agg({"date":"count", "kilometres":"sum"})\
    .rename(columns = {"date":"days"}).reset_index(level = None)

需要生成一个单图,X轴同时按月份(格式化为%Y-%b)和车辆编号分组,效果类似以下子图代码的合并版:

groups = df.groupby(by = "date")
figure, axes = plt.subplots(nrows = 1, ncols = len(groups), sharey = True, figsize = (16, 5))

for ax, (year, group) in zip(axes, groups):
    group.set_index("fleet no").rename_axis(year)["days"].plot(kind = "bar", ax = ax)
解决方案

可以通过调整数据结构,结合matplotlib手动绘制分组条形并添加多级X轴标签来实现:

import pandas as pd
import numpy as np
import matplotlib.pyplot as plt

# 固定随机种子
np.random.seed(seed = 123)
dates = pd.date_range(start = "28/05/2024", end = "28/05/2025", freq = "D")
vehicles = np.random.choice(["A", "B", "C", "D", "E", "F"], size = len(dates))
kilometres = np.random.normal(loc = 170, scale = 76, size = len(dates)).round(2)
df = pd.DataFrame({"date":dates, "fleet no":vehicles, "kilometres":kilometres})
# 按月份和车辆分组聚合,保留多级索引
df_grouped = df.groupby(by = [df["date"].dt.to_period("M"), "fleet no"]).agg({"date":"count", "kilometres":"sum"})\
    .rename(columns = {"date":"days"})

# 将月份格式化为指定样式
df_grouped.index = df_grouped.index.set_levels(df_grouped.index.levels[0].strftime("%Y-%b"), level=0)

# 获取分组信息
months = df_grouped.index.levels[0]
vehicles = df_grouped.index.levels[1]
n_months = len(months)
n_vehicles = len(vehicles)

# 设置条形宽度和位置
bar_width = 0.8 / n_vehicles
x = np.arange(n_months)

# 创建画布
fig, ax = plt.subplots(figsize=(16, 5))

# 绘制每个车辆的条形
for i, vehicle in enumerate(vehicles):
    # 提取对应车辆的天数数据
    data = df_grouped.xs(vehicle, level="fleet no")["days"]
    ax.bar(x + i * bar_width, data, width=bar_width, label=vehicle)

# 设置X轴主刻度(月份分组)
ax.set_xticks(x + bar_width * (n_vehicles - 1) / 2)
ax.set_xticklabels(months)

# 添加次级X轴标签(车辆编号)
# 计算每个分组内的位置
sub_ticks = []
for month_x in x:
    for i in range(n_vehicles):
        sub_ticks.append(month_x + i * bar_width)
ax.set_xticks(sub_ticks, minor=True)
ax.set_xticklabels([v for _ in months for v in vehicles], minor=True)
# 调整次级标签位置,避免重叠
ax.tick_params(axis='x', which='minor', pad=15)

# 添加图例、标题和标签
ax.legend(title="车辆编号")
ax.set_ylabel("天数")
ax.set_title("各月份车辆行驶天数统计")

# 调整布局,防止标签被截断
plt.tight_layout()
plt.show()

关键步骤说明

  • 保留多级索引并格式化月份标签:将月份周期格式转为%Y-%b样式,方便后续显示
  • 计算条形位置:按月份分组,每个分组内为不同车辆的条形分配位置
  • 双级X轴设置:主刻度为月份分组,次级刻度为车辆编号,通过minor=True实现
  • 布局调整:使用tight_layout()避免标签被截断,调整次级标签的pad参数优化显示

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.13 01:19:58