求助:Matplotlib绘制含分:秒:毫秒Y轴的闪电时间差柱状图
解决Matplotlib柱状图Y轴时间差(分钟:秒:毫秒)显示异常问题
问题背景
我有7个风暴的云内闪电(IC)与云地闪电(GC)的时间差数据,需要绘制X轴为风暴编号、Y轴为「分钟:秒:毫秒」格式的柱状图,但当前代码的Y轴分钟全部显示为0,无法正确展示时间差。
原始数据
Storms (1 2 3 4 5 6 7) time (00:00:00:131.73, 00:00:00:87.57, 00:03:23, 00:00:00:17.13, 00:08:23, 00:07:51, 00:40:41)
现有代码
import matplotlib.pyplot as plt import matplotlib.dates as dates from datetime import datetime, timedelta x = ['1','2','3','4','5','6','7'] y = [00131.73, 087.57, 323, 1713, 823, 751, 4041] fig, ax = plt.subplots(figsize=(8, 5)) plt.gca().yaxis.set_major_formatter(dates.DateFormatter('%M:%S.%f')) plt.bar(x, y) ax.set_title('a) Diferença de tempo entre o primeiro relâmpago IN e NS', fontsize=18) ax.set_ylabel('Tempo (minutos)', fontsize=14) ax.set_xlabel('Tempestades', fontsize=14) plt.gcf().autofmt_xdate() plt.show()
当前问题
Y轴所有刻度的分钟数均显示为0,无法正确反映实际时间差。
问题原因分析
- 数据格式错误:原代码中
y的数值是对时间的错误转换(如把00:03:23转成323),既不是总秒数也不是datetime可识别的数值;dates.DateFormatter是用于格式化日期时间对象,而非纯数字时间差,直接使用会导致解析异常。 - 时间字符串格式不统一:原始时间数据存在两种格式,一种是包含毫秒的
00:00:00:131.73(多余冒号导致无法直接解析),另一种是00:03:23(分:秒格式)。
解决方案
步骤1:统一解析时间字符串为总秒数
针对两种时间格式分别处理,将所有时间转换为总秒数,确保Y轴数值为连续的数值类型。
步骤2:自定义Y轴格式化器
使用FuncFormatter自定义格式化函数,将总秒数转换为「分钟:秒:毫秒」的格式,替代原有的dates.DateFormatter。
完整修正代码
import matplotlib.pyplot as plt from matplotlib.ticker import FuncFormatter from datetime import timedelta # 原始数据 storm_ids = ['1', '2', '3', '4', '5', '6', '7'] time_strings = [ '00:00:00:131.73', '00:00:00:87.57', '00:03:23', '00:00:00:17.13', '00:08:23', '00:07:51', '00:40:41' ] # 解析时间字符串为总秒数 def parse_time(s): if s.count(':') == 3: # 处理带毫秒的格式:拆分小时、分、秒、毫秒 parts = s.split(':') hours = int(parts[0]) mins = int(parts[1]) secs = int(parts[2]) ms = float(parts[3]) total_secs = hours*3600 + mins*60 + secs + ms/1000 else: # 处理分:秒格式 parts = s.split(':') hours = int(parts[0]) mins = int(parts[1]) secs = int(parts[2]) total_secs = hours*3600 + mins*60 + secs return total_secs y_values = [parse_time(t) for t in time_strings] # 自定义Y轴格式化函数:将总秒数转为「分钟:秒:毫秒」格式 def format_time(secs, pos): td = timedelta(seconds=secs) total_seconds = int(td.total_seconds()) mins = total_seconds // 60 secs_remaining = total_seconds % 60 ms = int(td.microseconds // 1000) return f"{mins:02d}:{secs_remaining:02d}:{ms:03d}" # 绘制柱状图 fig, ax = plt.subplots(figsize=(8, 5)) ax.bar(storm_ids, y_values) # 设置Y轴格式化器 ax.yaxis.set_major_formatter(FuncFormatter(format_time)) # 设置标题和标签 ax.set_title('a) Diferença de tempo entre o primeiro relâmpago IN e NS', fontsize=18) ax.set_ylabel('Tempo (minutos:segundos:milissegundos)', fontsize=14) ax.set_xlabel('Tempestades', fontsize=14) plt.tight_layout() plt.show()
关键修正点说明
- 数据解析:针对两种时间格式分别处理,将所有时间转换为总秒数,确保Y轴数值符合Matplotlib的数值要求。
- 自定义格式化器:通过
FuncFormatter实现灵活的时间格式转换,准确展示「两位分钟:两位秒:三位毫秒」的时间差。 - 移除无效代码:删除了不适用的
dates.DateFormatter和autofmt_xdate(后者用于日期X轴旋转,此处X轴为风暴编号,无需使用)。
内容的提问来源于stack exchange,提问作者Sabrina
相关产品推荐
相关产品推荐

