小能豆

QScrollWidget 中的 PyQt4 + matplotlib

py

我已经matplotlib嵌入到我正在开发的应用程序中PyQt4。问题是当我动态地向图形中添加子图时,图形会随着每个添加的子图而压缩。我以为可以通过将图形设置为来解决这个问题,QScrollArea但这并不奏效(据我所知)。以下是我认为可行的示例

import os
os.environ['QT_API'] = 'pyside'

from PySide.QtGui   import *
from PySide.QtCore  import *

import matplotlib

from matplotlib.backends.backend_qt4agg import FigureCanvasQTAgg
from matplotlib.figure                  import Figure


class Canvas(FigureCanvasQTAgg):

    def __init__(self, parent=None):
        self.figure = Figure()
        super(Canvas, self).__init__(self.figure)

        ax = self.figure.add_subplot(1,1,1)
        ax.plot([1,2,3])
        self.draw()

    def add_subplot(self, data=[]):
        rows = len(self.figure.axes) + 1
        for index, axes in enumerate(self.figure.axes, start=1):
            axes.change_geometry(rows, 1, index)

        ax = self.figure.add_subplot(rows, 1, index+1)
        ax.plot(data)

        self.draw()

class Main(QWidget):

    def __init__(self, parent=None):
        super(Main, self).__init__(parent)

        self.canvas = QScrollArea(self)
        self.canvas.setWidget(Canvas(self))
        self.canvas.setWidgetResizable(True)

        for x in range(5):
            self.canvas.widget().add_subplot()

        layout = QVBoxLayout(self)
        layout.addWidget(self.canvas)


app = QApplication([])
main = Main()
main.show()
app.exec_()

注意到所有图表是如何组合在一起以在同一个可见空间中显示的吗?我不想滚动查看其他图表。我不确定具体该怎么做。

有人知道该怎么做或者用其他方法做吗?


阅读 20

收藏
2024-12-03

共1个答案

小能豆

您遇到的问题是因为您在动态添加子图时并没有管理图形的大小,导致所有子图被压缩并堆叠在一起。如果您希望每个子图能够显示并且不被压缩,可以考虑以下几种方法:

  1. 使用QScrollArea作为容器,但需要正确管理图表的尺寸。这意味着您需要确保每次添加子图时,容器能够适应所有图形的大小。

  2. 管理子图的布局,例如让子图适应窗口的大小,并且按合适的比例来显示。

解决方法:

您可以通过设置FigureCanvas的大小,确保在添加每个子图时,每个子图有足够的空间来显示,或者使用QVBoxLayout或者QGridLayout来组织子图,而不是仅依赖QScrollArea

解决方案:使用QVBoxLayout管理子图布局

下面是一个示例,其中通过QVBoxLayout来添加多个子图,并调整每个子图的大小:

import os
os.environ['QT_API'] = 'pyside'

from PySide.QtGui   import *
from PySide.QtCore  import *
import matplotlib
from matplotlib.backends.backend_qt4agg import FigureCanvasQTAgg
from matplotlib.figure                  import Figure


class Canvas(FigureCanvasQTAgg):

    def __init__(self, parent=None):
        self.figure = Figure(figsize=(5, 4))  # 设置默认图形大小
        super(Canvas, self).__init__(self.figure)
        self.layout = QVBoxLayout()  # 布局管理器,用来管理子图
        self.setLayout(self.layout)

    def add_subplot(self, data=[]):
        ax = self.figure.add_subplot(len(self.figure.axes)+1, 1, len(self.figure.axes)+1)
        ax.plot(data)
        ax.set_title(f"Subplot {len(self.figure.axes)}")

        # 更新canvas并重新绘制
        self.draw()


class Main(QWidget):

    def __init__(self, parent=None):
        super(Main, self).__init__(parent)

        self.canvas = Canvas(self)

        # 向canvas中添加5个子图
        for x in range(5):
            self.canvas.add_subplot([x, x + 1, x + 2])

        layout = QVBoxLayout(self)
        layout.addWidget(self.canvas)

        self.setLayout(layout)


app = QApplication([])
main = Main()
main.show()
app.exec_()

关键修改点:

  1. Canvas的构造函数:

    • 设置了一个QVBoxLayout来容纳所有的子图。这样,每次添加子图时,都可以将其放在一个垂直布局中。
  2. add_subplot方法:

    • 在添加子图时,计算当前有多少个子图,并将新子图加入到当前的Figure中。然后,自动调用self.draw()来重新渲染图形。
  3. 设置每个子图的标题: 这样可以更容易地知道每个子图的位置,并帮助调试。

结果:

  1. 您将看到多个子图按顺序排列在一个QVBoxLayout中,每个子图的大小是适当的,并且不会被压缩。
  2. 如果您想让子图能够适应更多的空间,可以调整Figure的大小,或者改变QVBoxLayoutFigureCanvas的尺寸。

通过这种方式,您避免了QScrollArea导致的图形压缩问题,同时也确保了每个子图能够正常显示。

2024-12-03