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

如何在Plotly中实时更新图表而不重复打开新标签页?

解决Plotly图表重复打开新标签页并实现实时更新的方案

问题根源

你每次在while循环里重新创建Figure对象并调用fig.show(),Plotly默认的show()方法每次都会启动独立的浏览器标签页展示新图表,自然无法更新原有页面。要实现实时刷新,需要复用同一个图表容器并动态更新数据,推荐使用Dash(Plotly官方的交互式Web框架)来搭建本地实时更新的图表应用。

解决方案步骤

  1. 安装Dash依赖:
pip install dash
  1. 重构代码,将IB API数据获取与Dash的实时回调结合,核心是用dcc.Interval定时触发数据更新,在回调中修改已有图表的数据而非新建图表。

修改后的完整代码

import ibapi
import pandas as pd
import plotly.graph_objects as go
from ibapi.client import EClient
from ibapi.wrapper import EWrapper
from ibapi.contract import Contract
import threading
import time
from dash import Dash, dcc, html, Input, Output

class IBapi(EWrapper, EClient):
    def __init__(self):
        EClient.__init__(self, self)
        self.data = []  # 存储K线数据
        self.latest_timestamp = 0  # 记录最后一条数据的时间戳,避免重复添加

    def historicalData(self, reqId, bar):
        # 仅添加新的K线数据,避免重复
        if bar.date > self.latest_timestamp:
            print(f'Time: {bar.date} High: {bar.high} Low: {bar.low} Open: {bar.open} Close: {bar.close}')
            self.data.append([bar.date, bar.high, bar.low, bar.open, bar.close])
            self.latest_timestamp = bar.date

def run_loop():
    app_ib.run()

# 初始化IB API连接
app_ib = IBapi()
app_ib.connect('127.0.0.1', 7496, 123)
api_thread = threading.Thread(target=run_loop, daemon=True)
api_thread.start()
time.sleep(1)  # 等待连接建立

# 定义EURUSD合约
eurusd_contract = Contract()
eurusd_contract.symbol = 'EUR'
eurusd_contract.secType = 'CASH'
eurusd_contract.exchange = 'IDEALPRO'
eurusd_contract.currency = 'USD'

# 初始化Dash应用
app_dash = Dash(__name__)
app_dash.layout = html.Div([
    html.H1('EURUSD INTERACTIVE CHART'),
    dcc.Graph(id='live-candlestick'),
    # 每15秒触发一次数据更新(可根据需求调整)
    dcc.Interval(
        id='interval-component',
        interval=15*1000,  # 毫秒
        n_intervals=0
    )
])

# Dash回调函数:定时更新图表
@app_dash.callback(
    Output('live-candlestick', 'figure'),
    Input('interval-component', 'n_intervals')
)
def update_graph(n):
    # 请求最新历史数据
    app_ib.reqHistoricalData(1, eurusd_contract, '', '2 D', '1 hour', 'BID', 1, 2, False, [])
    time.sleep(2)  # 等待数据返回

    # 转换为DataFrame并处理时间格式
    if app_ib.data:
        df = pd.DataFrame(app_ib.data, columns=['DateTime','High', 'Low', 'Open', 'Close'])
        df['DateTime'] = pd.to_datetime(df['DateTime'], unit='s')
        df.to_csv('EURUSD_Hourly.csv')

        # 生成蜡烛图
        fig = go.Figure(data=[go.Candlestick(
            x=df['DateTime'],
            open=df['Open'],
            high=df['High'],
            low=df['Low'],
            close=df['Close']
        )])
        fig.update_layout(yaxis_title=eurusd_contract.symbol)
        return fig
    # 数据为空时返回空图表
    return go.Figure()

if __name__ == '__main__':
    app_dash.run_server(debug=True)

关键优化点

  • 数据去重:新增latest_timestamp变量,只添加比最后一条数据时间戳更新的K线,避免重复存储旧数据。
  • 复用图表容器:通过Dash的dcc.Graph组件作为固定容器,在回调函数中动态更新其figure属性,无需每次新建图表。
  • 定时触发:用dcc.Interval组件定时触发数据更新和图表刷新,替代原有的while循环,更符合Web应用的逻辑。
  • 线程安全:IB API的运行线程与Dash的主线程分离,避免阻塞。

运行说明

执行代码后,会自动在浏览器打开本地地址(默认是http://127.0.0.1:8050/),图表会按照设定的时间间隔自动刷新,无需手动操作或打开新标签页。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.04 19:55:49