PyQt5集成mplfinance绘图时设置volume=True报错的解决求助
问题说明
在PyQt5窗口中使用mplfinance绘制K线图时,设置volume=True以显示成交量时触发错误:ValueError: volumemust be of typematplotlib.axis.Axes`。仅绘制K线图时功能正常,工具栏与画布联动无问题。
原因分析
当手动向mpf.plot()传入自定义的ax参数时,mplfinance要求volume参数不能是布尔值True,必须指定一个专门用于渲染成交量的Matplotlib Axes对象——因为此时mplfinance不会自动创建成交量子图,需要开发者提前准备好对应的Axes。
解决步骤
- 调整画布的Axes布局:初始化时创建两个Axes,分别用于K线和成交量,通过
gridspec设置上下布局比例。 - 更新绘图方法:每次绘图前清除两个Axes的内容,调用
mpf.plot()时将volume参数指向成交量Axes。 - 确保工具栏同步更新:绘图完成后刷新工具栏,保证导航功能正常。
修改后的完整代码
import sys import pandas as pd import mplfinance as mpf from PyQt5.QtWidgets import QApplication, QWidget, QVBoxLayout, QPushButton from matplotlib.backends.backend_qt5agg import ( FigureCanvasQTAgg as FigureCanvas, NavigationToolbar2QT as NavigationToolbar) import matplotlib.pyplot as plt from matplotlib.gridspec import GridSpec class MyMplCanvas(FigureCanvas): def __init__(self, parent=None, width=5, height=4, dpi=100): self.fig = plt.figure(figsize=(width, height), dpi=dpi) # 创建GridSpec,设置K线图占3份,成交量占1份 gs = GridSpec(2, 1, height_ratios=[3, 1]) self.ax_kline = self.fig.add_subplot(gs[0]) self.ax_volume = self.fig.add_subplot(gs[1], sharex=self.ax_kline) super().__init__(self.fig) self.setParent(parent) class MyDynamicMplCanvas(QWidget): def __init__(self, parent=None): super().__init__(parent) self.plot1_button = QPushButton("Plot 1") self.plot1_button.clicked.connect(self.plot1) self.plot2_button = QPushButton("Plot 2") self.plot2_button.clicked.connect(self.plot2) self.canvas = MyMplCanvas(self, width=5, height=4, dpi=100) self.toolbar = NavigationToolbar(self.canvas, self) vbox = QVBoxLayout() vbox.addWidget(self.toolbar) vbox.addWidget(self.canvas) vbox.addWidget(self.plot1_button) vbox.addWidget(self.plot2_button) self.setLayout(vbox) def getData(self, iisin): if iisin == 'A': pfad = '/path/to/file/Qt/DE000A0DJ6J9_4qs.csv' else: pfad = '/path/to/file/Qt/DE000A0DJ6J9_2qs.csv' data = pd.read_csv(pfad, header=0, sep='|', encoding='utf-8') data.index = pd.to_datetime(data['Datum']) data.rename(columns={'TradesSum': 'Volume'}, inplace=True) return data def plot1(self): # 清除两个Axes的内容 self.canvas.ax_kline.clear() self.canvas.ax_volume.clear() mpf.plot(data=self.getData('A'), ax=self.canvas.ax_kline, volume=self.canvas.ax_volume, type='candle', style='yahoo', mav=(20, 38, 50), returnfig=True) # 重新关联导航工具栏 self.toolbar.update() # 在画布上显示绘图 self.canvas.draw() def plot2(self): # 清除两个Axes的内容 self.canvas.ax_kline.clear() self.canvas.ax_volume.clear() # 从CSV文件加载数据并绘图 data = self.getData('B') mpf.plot(data=data, ax=self.canvas.ax_kline, volume=self.canvas.ax_volume, type='candle', style='yahoo', mav=(20, 38, 50), returnfig=True) # 重新关联导航工具栏 self.toolbar.update() # 在画布上显示绘图 self.canvas.draw() if __name__ == '__main__': app = QApplication(sys.argv) main_window = QWidget() main_layout = QVBoxLayout() main_window.setLayout(main_layout) mpl_widget = MyDynamicMplCanvas() main_layout.addWidget(mpl_widget) main_window.show() sys.exit(app.exec_())
关键修改点说明
- 画布初始化:使用
GridSpec创建两个Axes,设置高度比例为3:1,保证K线图为主视图,成交量为辅助视图,同时通过sharex=self.ax_kline让两个子图共享X轴,联动缩放。 - 绘图参数:将
volume参数从True改为self.canvas.ax_volume,指定成交量的渲染Axes。 - 清除逻辑:每次绘图前同时清除K线和成交量Axes的内容,避免残留旧数据。
内容的提问来源于stack exchange,提问作者finny
相关产品推荐
相关产品推荐

