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

Python Plotly动态散点图:为每一帧设置自定义标题

问题描述

我用Plotly成功创建了动态散点图,现在想给动画的每一帧替换自定义标题。参考相关方案写了代码后,图表显示正常,但每一帧的标题并未更新,求修复。

输入数据:
titles数据:

{'Year': {0: 2021, 1: 2022, 2: 2023}, 'Text': {0: 'Title 1', 1: 'Title 2', 2: 'Title 3'}}

tagged_df数据:

{'Unnamed: 0': {0: 1266, 1: 1289, 2: 1293, 3: 1304, 4: 1305, 5: 1311, 6: 1776, 7: 1790, 8: 1799}, 'LOCATION': {0: 'AUS', 1: 'AUT', 2: 'BEL', 3: 'BEL', 4: 'AUS', 5: 'AUT', 6: 'BEL', 7: 'AUT', 8: 'AUS'}, 'TIME': {0: 2021, 1: 2021, 2: 2021, 3: 2022, 4: 2022, 5: 2022, 6: 2023, 7: 2023, 8: 2023}, 'Value_rates': {0: 0.02833333, 1: -0.5487667, 2: -0.5487667, 3: 0.3415667, 4: 1.636667, 5: 0.3415667, 6: 1.350987085, 7: 1.350987085, 8: 3.580073801}, 'Value_cpi': {0: 2.86391, 1: 2.766667, 2: 2.440248, 3: 9.597511, 4: 6.594097, 5: 8.54687, 6: 2.345248207, 7: 2.382125997, 8: -100.0}, 'Region': {0: 'DM_Other', 1: 'DM_Europe', 2: 'DM_Europe', 3: 'DM_Europe', 4: 'DM_Other', 5: 'DM_Europe', 6: 'DM_Europe', 7: 'DM_Europe', 8: 'DM_Other'}, 'COUNTRY_NAME': {0: 'Australia', 1: 'Austria', 2: 'Belgium', 3: 'Belgium', 4: 'Australia', 5: 'Austria', 6: 'Belgium', 7: 'Austria', 8: 'Australia'}, 'COLOUR_tag': {0: 'purple', 1: 'pink', 2: 'pink', 3: 'pink', 4: 'purple', 5: 'pink', 6: 'pink', 7: 'pink', 8: 'purple'}, 'SIZE_tag': {0: 50, 1: 50, 2: 50, 3: 50, 4: 50, 5: 50, 6: 50, 7: 50, 8: 50}}

当前代码:

#Import Libraries
import pandas as pd
import numpy as np
import os

import matplotlib.pyplot as plt
import plotly.express as px

# Create the scatter plot
fig = px.scatter(tagged_df, x="Value_cpi", y="Value_rates", 
                 animation_frame="TIME", 
                 animation_group="LOCATION",
                 color="COLOUR_tag", 
                 hover_name="COUNTRY_NAME",
                 size=tagged_df['SIZE_tag'].astype(float),  # Convert SIZE_tag to numeric
                 log_x=False, 
                 range_x=[-5, 90], range_y=[-5, 50],
                 title='This Title needs to be replaced',
                 labels={'Value_cpi': 'Inflation Rate', 'Value_rates': 'Nominal Interest Rate (3m T-Bill)'},
                 width=960, height=540,
                 template='plotly_dark',
                 size_max=50,  # Set the maximum dot size
            )

# Iterate through the buttons to set 'redraw': True
for button in fig.layout.updatemenus[0].buttons:
    button['args'][1]['frame']['redraw'] = True

# Update titles for each animation frame
for k in range(len(fig.frames)):
    matching_rows = tagged_df[tagged_df["TIME"].astype(int) == int(fig.frames[k].name)]
    if not matching_rows.empty:
        chart_title = titles[titles['Year'] == int(fig.frames[k].name)]['Text'].values[0]
        fig.frames[k]['layout'].update(title_text=chart_title)

fig.update_traces(
    marker=dict(opacity=0.7), 
    selector=dict(mode='markers')       # Ensure only markers are affected by the update
)

fig.show()
解决方案

问题出在初始布局标题未同步设置,且帧标题的更新路径错误。另外,通过tagged_df匹配年份的步骤可以简化,直接用titles构建映射关系更高效。

修复后的代码如下:

import pandas as pd
import numpy as np
import plotly.express as px

# 将titles转为{年份: 标题}的字典,快速查找对应标题
title_map = titles.set_index('Year')['Text'].to_dict()

# 创建散点图,初始标题设为最早年份的对应标题
fig = px.scatter(tagged_df, x="Value_cpi", y="Value_rates", 
                 animation_frame="TIME", 
                 animation_group="LOCATION",
                 color="COLOUR_tag", 
                 hover_name="COUNTRY_NAME",
                 size='SIZE_tag',  # 直接用列名即可,无需手动转换类型
                 log_x=False, 
                 range_x=[-5, 90], range_y=[-5, 50],
                 title=title_map[tagged_df['TIME'].min()],
                 labels={'Value_cpi': 'Inflation Rate', 'Value_rates': 'Nominal Interest Rate (3m T-Bill)'},
                 width=960, height=540,
                 template='plotly_dark',
                 size_max=50
            )

# 确保动画切换时重绘布局,保证标题更新生效
for button in fig.layout.updatemenus[0].buttons:
    button['args'][1]['frame']['redraw'] = True
    button['args'][1]['transition']['duration'] = 0  # 可选:消除过渡延迟,让标题切换更即时

# 遍历每个帧,更新对应年份的标题
for frame in fig.frames:
    year = int(frame.name)
    frame.layout.title.text = title_map[year]

# 更新标记样式
fig.update_traces(marker=dict(opacity=0.7), selector=dict(mode='markers'))

fig.show()

关键修复点:

  1. 构建标题映射字典:把titles转为字典,避免每次循环都查询DataFrame,提升效率。
  2. 同步初始标题:初始布局的标题要和第一帧一致,否则切换回第一帧时会显示旧标题。
  3. 修正帧标题更新路径:原代码用title_text是错误的,正确路径是frame.layout.title.text。
  4. 可选优化:添加transition['duration']=0可以让标题切换无延迟,体验更流畅。

内容的提问来源于stack exchange,提问作者newquant84

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.12 15:12:08