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

PyQt6嵌入finplot:实现鼠标悬停显示OHLCV数据的需求

解决方案:Finplot + PyQt6 实现鼠标悬停显示OHLCV

核心思路

嵌入PyQt6后,finplot的hover事件回调不能直接复用非GUI环境的逻辑——需结合Qt的主线程UI更新机制,避免线程安全问题,同时确保回调能正确获取当前显示的股票数据。

具体实现步骤

1. 准备顶部显示控件

在主窗口顶部下拉框旁添加QLabel用于展示OHLCV数据:

from PyQt6.QtWidgets import QMainWindow, QLabel, QHBoxLayout, QWidget
from PyQt6.QtCore import QMetaObject, Q_ARG, Qt

class StockMainWindow(QMainWindow):
    def __init__(self):
        super().__init__()
        # 顶部导航布局(含股票切换下拉框)
        top_bar = QWidget()
        top_layout = QHBoxLayout(top_bar)
        # 股票切换下拉框(你已实现的部分)
        # self.stock_combo = QComboBox()
        # top_layout.addWidget(self.stock_combo)
        # OHLCV显示标签
        self.ohlcv_label = QLabel()
        self.ohlcv_label.setStyleSheet("padding: 4px; border: 1px solid #e0e0e0; min-width: 300px;")
        top_layout.addWidget(self.ohlcv_label)
        self.setMenuBar(top_bar)

2. 绑定finplot hover回调并适配Qt主线程

加载股票数据后,绑定hover回调,通过QMetaObject.invokeMethod确保UI更新在主线程执行:

import finplot as fplt
import pandas as pd

# 全局/实例化变量存储当前显示的股票数据
current_stock_df = None

def load_stock_data(code):
    global current_stock_df
    df = pd.read_csv(f"{code}.csv")
    df['dt'] = pd.to_datetime(df['dt'])
    current_stock_df = df.reset_index(drop=True)  # 重置索引确保hover时索引匹配
    return current_stock_df

def on_hover(x, y, x_text, y_text):
    if x is None or current_stock_df is None:
        update_ohlcv_label("")
        return
    # 获取悬停位置对应行的OHLCV数据
    try:
        row = current_stock_df.iloc[int(x)]
        ohlcv_str = f"O: {row['open']:.2f} | H: {row['high']:.2f} | L: {row['low']:.2f} | C: {row['close']:.2f} | V: {row['volume']:,}"
        update_ohlcv_label(ohlcv_str)
    except IndexError:
        update_ohlcv_label("")

def update_ohlcv_label(text):
    # 强制在Qt主线程更新UI,避免线程冲突
    QMetaObject.invokeMethod(
        main_window.ohlcv_label,
        "setText",
        Qt.ConnectionType.QueuedConnection,
        Q_ARG(str, text)
    )

# 初始化图表并绑定回调
main_window = StockMainWindow()
load_stock_data("600000")
ax, ax_vol = fplt.create_plot("股票K线图", rows=2)
fplt.candlestick_ochl(current_stock_df[['dt','open','close','high','low']], ax=ax)
fplt.volume(current_stock_df[['dt','open','close','volume']], ax=ax_vol)
fplt.set_hover_callback(on_hover)

# 将finplot嵌入PyQt窗口
qt_plot_widget = fplt.get_qt_widget()
main_window.setCentralWidget(qt_plot_widget)

3. 股票切换时的适配逻辑

切换股票时,重新加载数据并刷新图表,确保hover回调能获取最新数据:

def switch_stock(code):
    load_stock_data(code)
    # 清空原有图表并重新绘制
    fplt.clear()
    ax, ax_vol = fplt.create_plot(f"{code} K线图", rows=2)
    fplt.candlestick_ochl(current_stock_df[['dt','open','close','high','low']], ax=ax)
    fplt.volume(current_stock_df[['dt','open','close','volume']], ax=ax_vol)
    fplt.set_hover_callback(on_hover)

常见问题排查

  • 若出现UI更新报错:必须使用QMetaObject.invokeMethod更新标签文本,finplot的hover回调可能在非主线程触发,直接修改UI会引发线程安全问题。
  • 若悬停数据不匹配:确保加载数据时调用reset_index(drop=True),避免因原有索引不连续导致iloc[int(x)]取数错误。
  • 若切换股票后hover无响应:切换时需重新绑定hover回调,确保回调关联最新的current_stock_df。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.14 08:37:09