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

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": "&#9654;",
                               "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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.29 06:03:25