嵌入PyQt5窗口的Matplotlib导航工具栏重置视图崩溃问题
解决Matplotlib 2.1.1嵌入PyQt5时Home按钮重置视图崩溃的问题
我之前也碰到过一模一样的问题,这是因为在PyQt嵌入场景下,直接用plot()绘制日期数据时,Matplotlib没有自动配置日期轴的定位器和格式化器,导致Home按钮重置视图时,试图把无效的数值范围(默认0-1)转换成日期,触发了ValueError: ordinal must be >= 1错误。
核心原因分析
你在独立窗口示例中用的是plot_date(),这个方法会自动识别日期数据并配置对应的轴处理逻辑;但在PyQt嵌入的代码里用了普通的plot(),Matplotlib会把x轴当作普通数值轴处理。当点击Home按钮时,它会试图回到axes的初始空视图范围(0-1),而这个数值转换成日期时,会因为序数小于1而报错。
解决方案
下面提供两种可行的修复方式,选其中一种即可:
方案1:改用plot_date()绘制(推荐)
把绘制代码替换为plot_date(),并设置linestyle='-'来保持折线效果(默认是散点),这样Matplotlib会自动处理日期轴的配置:
# 在plot_basegraph方法中替换原plot代码 for col in stackTSPD.columns: t = stackTSPD.index.to_pydatetime() y = stackTSPD[col].values self.axes.plot_date(t, y, label=col, linestyle='-')
同时别忘了添加日期标签优化和手动触发绘制:
self.axes.legend() self.fig.autofmt_xdate() # 自动旋转日期标签避免重叠 self.canvas.draw() # 确保界面及时更新
方案2:手动配置日期轴
如果你坚持使用plot(),需要在绘图后手动为x轴添加日期定位器和格式化器:
import matplotlib.dates as mdates # 绘图后添加以下代码 self.axes.xaxis.set_major_locator(mdates.AutoDateLocator()) self.axes.xaxis.set_major_formatter(mdates.AutoDateFormatter(mdates.AutoDateLocator())) self.fig.autofmt_xdate() self.canvas.draw()
修改后的完整PyQt代码
这里是用方案1优化后的完整代码:
import matplotlib matplotlib.use("Qt5Agg") import sys from matplotlib.backends.backend_qt5agg import FigureCanvasQTAgg as FigureCanvas from matplotlib.backends.backend_qt5agg import NavigationToolbar2QT as NavigationToolbar from matplotlib.figure import Figure import pandas as pd import numpy as np from PyQt5 import QtWidgets, uic from PyQt5.Qt import QVBoxLayout qtCreatorFile = "window.ui" Ui_MainWindow, QtBaseClass = uic.loadUiType(qtCreatorFile) class PlotSeries(QtWidgets.QMainWindow, Ui_MainWindow): def __init__(self): QtWidgets.QMainWindow.__init__(self) Ui_MainWindow.__init__(self) self.setupUi(self) # 创建绘图组件 self.fig = Figure() self.axes = self.fig.add_subplot(111) self.axes.grid() self.canvas = FigureCanvas(self.fig) self.toolbar = NavigationToolbar(self.canvas, self) # 布局设置 layout = QVBoxLayout() layout.addWidget(self.canvas) layout.addWidget(self.toolbar) self.widgetplot.setLayout(layout) # 绘制初始图形 self.plot_basegraph() def plot_basegraph(self): # 生成时间序列数据 stackTSPD = pd.DataFrame() for i in range(0,5): ts = pd.Series(np.random.randn(2000), index=pd.date_range('1/1/2015', freq='h', periods=2000), name=f"series {i}") stackTSPD = pd.concat([stackTSPD, ts], axis=1) print(matplotlib.__version__) self.axes.clear() self.axes.grid() # 用plot_date绘制日期数据,自动配置日期轴 for col in stackTSPD.columns: t = stackTSPD.index.to_pydatetime() y = stackTSPD[col].values self.axes.plot_date(t, y, label=col, linestyle='-') self.axes.legend() self.fig.autofmt_xdate() self.canvas.draw() if __name__ == "__main__": app = QtWidgets.QApplication(sys.argv) window = PlotSeries() window.show() sys.exit(app.exec_())
这样修改后,Home按钮就能正常重置视图,不会再崩溃了。
内容的提问来源于stack exchange,提问作者Greg
相关产品推荐
相关产品推荐

