Plotly动画水平条形图添加垂直参考线及标签显示优化
问题概述
我使用plotly构建带帧动画的水平分组条形图,通过滑块切换不同Location(点位)的动画帧,展示各点位下不同任务的Date_Existing(原有日期)与Date_New(新日期)对比,同时需要在图中突出标注唯一的“新日期”值。下方提供了完全可复现的代码片段、样例数据集与效果参考图,可直接运行复现当前效果。
待解决技术问题
- 在通过滑块切换点位(动画帧)时,需要为每个唯一的新日期值,在对应水平条形的末端位置添加点状垂直参考线(预期效果为穿过对应日期条形边缘的红色虚线,参考下方第一张效果图),初步考虑是否可通过循环帧调用
add_shape方法实现,也欢迎提供其他突出唯一新日期值的可视化实现思路。 - 如何动态控制数据标签(日期文本)的显示,确保日期标签完整展示在图表区域内?当前输出图表存在标签溢出绘图区的问题(例如下方第二张图中滑块选择“S1”点位时的标签显示异常),约束条件为不能无限制扩大x轴范围到较远的未来日期、预留过多无效空白。
基础数据加载与预处理代码
import pandas as pd from datetime import datetime from plotly import graph_objects as go # 读取样例数据 inputDF = pd.read_csv('https://raw.githubusercontent.com/SauvikDe/Demo/main/Test_Dummy.csv') # 转换为日期格式 inputDF['Date_Existing'] = pd.to_datetime(inputDF['Date_Existing']) inputDF['Date_New'] = pd.to_datetime(inputDF['Date_New']) # 排序优化绘图展示顺序 inputDF.sort_values(by=['Location', 'Date_New', 'Date_Existing'], inplace=True)
样例数据集(前6行)
Location,Task,TaskTimeMins,Date_Existing,Date_New S1,E10,60,7/14/2022,7/14/2022 S1,E12,75,7/21/2022,7/14/2022 S1,SM0,40,7/21/2022,7/28/2022 S1,E16,60,7/28/2022,7/28/2022 S1,SM1,120,7/28/2022,7/28/2022 S1,E18,120,8/4/2022,7/28/2022
当前已实现的动态图表绘制代码
# 为每个点位创建动画帧 frames = [] for s in inputDF['Location'].unique(): t = inputDF.loc[inputDF['Location'] == s] frames.append( go.Frame( name=str(s), data=[ go.Bar(x=t['Date_Existing'], y=t['Task']+":[ "+ t['TaskTimeMins'].astype(str)+" Minutes]", xaxis="x", name="Existing Date", offsetgroup=1, orientation='h', text=t['Date_Existing'].dt.strftime("%d-%m-%y"), textposition='outside', marker_color='#f4af36' ), go.Bar(x=t['Date_New'], y=t['Task']+":[ "+ t['TaskTimeMins'].astype(str)+" Minutes]", xaxis="x2", name='New Date', offsetgroup=2, orientation='h', text=t['Date_New'].dt.strftime("%d-%m-%y"), textposition='outside', marker_color='#38761d' ), ], layout={"xaxis":{"range":[t['Date_Existing'].min() - pd.offsets.DateOffset(1), t['Date_Existing'].max() + pd.offsets.DateOffset(30)], }, "xaxis2":{"range":[t['Date_Existing'].min() - pd.offsets.DateOffset(1), t['Date_Existing'].max() + pd.offsets.DateOffset(30)], }, }, ) ) # 创建画布并初始化轴布局 fig = go.Figure( data=frames[0].data, frames=frames, layout={ "xaxis": { "showticklabels":True, }, "xaxis2": { "showticklabels":True, "overlaying": "x", "side": "top", }, }, ) # 为每个帧更新动态标题 for k in range(len(fig.frames)): fig.frames[k]['layout'].update(title_text= f"<b>Location: {fig.frames[k].name}</b> >> Date comparison:Existing vs New", ) # 配置滑块控件 fig.update_layout( barmode="group", updatemenus=[{"buttons": [{"args": [None, {"frame": {"duration": 2000, "redraw": True}}], "label": "▶", "method": "animate",},], "type": "buttons",}], sliders=[{"steps": [{"args": [[f.name],{"frame": {"duration": 0, "redraw": True}, "mode": "immediate",},], "label": f.name, "method": "animate",} for f in frames ], }], legend=dict(orientation="h", yanchor="bottom", y=-0.5, xanchor="right", x=0.7, ), font_size=12, font_color="blue", title_font_family="Calibri", title_font_color="purple", title_x=0.5, width=950, height=600, ) # 调整播放按钮位置 fig['layout']['updatemenus'][0]['pad']=dict(r=10, t=395) # 调整滑块位置 fig['layout']['sliders'][0]['pad']=dict(r=10, t=50,) # 展示图表 fig.show()
效果参考图


内容的提问来源于stack exchange,提问作者Sauvik De
相关产品推荐
相关产品推荐

