如何在Plotly Express中格式化timedelta对象的Y轴
问题:Plotly Express中Timedelta类型Y轴显示格式异常
在Pandas中,timedelta对象可正常显示为0 days 03:00:00这类易读格式,但使用Plotly Express绘图时,Y轴却显示为40T这类难以理解的缩写格式。尝试过将timedelta转为字符串或调整格式化参数,要么格式失效,要么无变化。需求是让Y轴显示易读的时长格式(以小时、分钟为主,超过一天的时长显示为40:xx:xx这类累计小时数的格式)。
用户原始代码如下:
import pandas as pd data = [['tom', 10, "2023-06-21 06:23:55+00:00", "2023-06-21 09:23:55+00:00"], ['nick', 15, "2023-06-20 06:23:55+00:00", "2023-06-21 06:23:55+00:00"], ['juli', 14, "2023-06-21 06:23:50+00:00", "2023-06-21 06:23:55+00:00"]] df = pd.DataFrame(data, columns=['name', 'age', "start", "stop"]) df["start"] = pd.to_datetime(df["start"]) df["stop"] = pd.to_datetime(df["stop"]) df["duration"] = df["stop"] - df["start"] df["duration"] #### output 0 0 days 03:00:00 1 1 days 00:00:00 2 0 days 00:00:05 Name: duration, dtype: timedelta64[ns] import plotly.express as px import plotly.graph_objects as go fig = px.scatter( df, x=df["age"].sort_values(ascending=False), y="duration", # 推测显示的是秒数 #y=pd.to_timedelta(df.duration, unit='h'), # 格式与之前一致 #y=df["duration"].sort_values(ascending=True).dt.to_pytimedelta().astype(str), # 标签固定,但刻度间距与数值差无关 color="name", ) figure = go.Figure(data=fig) # figure.update_layout(yaxis_tickformat='%H:%M:%S') # 会添加大量零 # figure.update_layout(yaxis_tickformat="%H:%M:%S.%f") figure.show()
当前Y轴显示异常效果:
解决方案
核心思路是将timedelta转换为总秒数作为绘图的数值轴(保证刻度间距逻辑正确),再自定义函数将秒数格式化为易读的时长格式,最后手动替换Y轴的刻度标签。
完整修改后代码:
import pandas as pd import plotly.express as px import plotly.graph_objects as go # 数据处理 data = [['tom', 10, "2023-06-21 06:23:55+00:00", "2023-06-21 09:23:55+00:00"], ['nick', 15, "2023-06-20 06:23:55+00:00", "2023-06-21 06:23:55+00:00"], ['juli', 14, "2023-06-21 06:23:50+00:00", "2023-06-21 06:23:55+00:00"]] df = pd.DataFrame(data, columns=['name', 'age', "start", "stop"]) df["start"] = pd.to_datetime(df["start"]) df["stop"] = pd.to_datetime(df["stop"]) df["duration"] = df["stop"] - df["start"] # 将timedelta转换为总秒数,用于维持轴的数值逻辑 df["duration_sec"] = df["duration"].dt.total_seconds() # 自定义时长格式化函数:将秒数转为 小时:分钟:秒 格式,小时数累计(含跨天) def format_timedelta(seconds): hours = int(seconds // 3600) minutes = int((seconds % 3600) // 60) secs = int(seconds % 60) return f"{hours}:{minutes:02d}:{secs:02d}" # 绘制散点图,使用总秒数作为Y轴数值 fig = px.scatter( df, x=df["age"].sort_values(ascending=False), y="duration_sec", color="name", # 自定义hover信息,保留原始timedelta格式提升可读性 hover_data={"duration_sec": False, "duration": True} ) # 获取默认的Y轴刻度值,转换为自定义格式的标签 tick_vals = fig.layout.yaxis.tickvals tick_text = [format_timedelta(val) for val in tick_vals] # 更新Y轴设置,替换刻度标签 fig.update_layout( yaxis=dict( tickmode='array', tickvals=tick_vals, ticktext=tick_text, title="时长" ) ) fig.show()
关键说明
- 转换为总秒数:避免直接使用字符串类型导致Y轴刻度间距混乱,保证轴的数值逻辑正确(比如1天的时长会被识别为86400秒,和3小时的10800秒保持正确比例)
- 自定义格式化函数:自动累计小时数,跨天时长会显示为
24:00:00而非1 days 00:00:00,符合需求中的显示格式 - 保留hover信息:在鼠标悬浮时显示原始timedelta格式,兼顾轴的简洁性和数据的完整性
内容的提问来源于stack exchange,提问作者crazysantaclaus
相关产品推荐
相关产品推荐

