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
相关产品推荐
相关产品推荐

