Pandas DataFrame中时间轴多循环异常问题排查
问题分析与解决方案
这不是Plotly的bug,而是Plotly对分组(color参数)数据的默认渲染逻辑导致的:当你按short_symbol分组时,Plotly会为每个分组单独处理x轴数据的显示顺序,而非使用全局统一的时间排序刻度。当不同分组的时间数据覆盖范围不同时,就会出现x轴重复循环的现象。
核心原因
- 不设置
color时,Plotly基于全局数据的排序结果生成x轴刻度,因此time_of_day_num呈现单调递增; - 设置
color后,每个short_symbol分组会保留自身数据的顺序,Plotly会依次渲染每个分组的x轴刻度,最终导致多个循环叠加。
解决方案
方案1:使用数值型时间(time_of_day_num)作为x轴,自定义刻度显示为时间格式
直接用已计算的time_of_day_num作为x轴,手动将刻度标签替换为对应的时间字符串,既保证x轴单调递增,又能显示友好的时间格式:
import plotly.express as px # 保留原有的数据处理步骤 df['time_of_day'] = df['entrydate'].dt.time df['time_of_day_num'] = df['time_of_day'].apply(lambda x: x.hour * 3600 + x.minute * 60 + x.second) df.sort_values(by='time_of_day_num', inplace=True) # 获取唯一的时间数值和对应的时间字符串,用于自定义刻度 unique_times = df.drop_duplicates('time_of_day_num').sort_values('time_of_day_num') tick_vals = unique_times['time_of_day_num'].tolist() tick_texts = [t.strftime('%H:%M:%S') for t in unique_times['time_of_day'].tolist()] # 绘图,x用数值型时间,自定义刻度 fig = px.scatter(df, x='time_of_day_num', y='realizedpnl', color='short_symbol', hover_data=['entrydate','realizedpnl']) fig.update_layout( xaxis=dict( tickmode='array', tickvals=tick_vals, ticktext=tick_texts, title='Time of Day' ) ) fig.show()
方案2:将time_of_day转换为可排序的字符串类型
把datetime.time类型转为%H:%M:%S格式的字符串,Plotly会基于字符串的字典序(对应时间顺序)生成全局统一的x轴刻度:
import plotly.express as px df['time_of_day_str'] = df['entrydate'].dt.strftime('%H:%M:%S') df.sort_values(by='time_of_day_str', inplace=True) fig = px.scatter(df, x='time_of_day_str', y='realizedpnl', color='short_symbol', hover_data=['entrydate','realizedpnl']) fig.show()
方案3:使用Plotly Graph Objects手动构建图表(更灵活)
手动创建每个分组的trace,统一设置x轴的全局刻度,完全控制渲染逻辑:
import plotly.graph_objects as go # 数据处理 df['time_of_day'] = df['entrydate'].dt.time df['time_of_day_num'] = df['time_of_day'].apply(lambda x: x.hour * 3600 + x.minute * 60 + x.second) df.sort_values(by='time_of_day_num', inplace=True) # 获取全局唯一的时间列表(排序后) sorted_unique_times = df['time_of_day'].unique().tolist() sorted_unique_times.sort() # 创建图表 fig = go.Figure() # 遍历每个symbol,添加trace for symbol in df['short_symbol'].unique(): subset = df[df['short_symbol'] == symbol] fig.add_trace(go.Scatter( x=subset['time_of_day'], y=subset['realizedpnl'], mode='markers', name=symbol, hovertext=subset.apply(lambda row: f"Entry Date: {row['entrydate']}<br>Realized PnL: {row['realizedpnl']}", axis=1) )) # 设置x轴为全局排序后的时间 fig.update_layout( xaxis=dict( tickmode='array', tickvals=sorted_unique_times, title='Time of Day' ), yaxis=dict(title='Realized PnL') ) fig.show()
内容的提问来源于stack exchange,提问作者greymatter
相关产品推荐
相关产品推荐

