matplotlib tight_layout with annotation 导致图形越来越小

matplotlib tight_layout with annotation causes figure to get smaller and smaller

我有一个 FigureCanvasQTAgg 可以创建图表,用户可以选择要绘制的数据,而 canvas 通过调用 self.fig.clear() 并创建新图表来更新图表。这工作正常,但我 运行 遇到了问题。我设计了一个在轴下带有注释的图,但每次更新图形时,图都会变得越来越小。此代码复制了问题:

import sys
from PyQt5 import QtCore, QtWidgets
import matplotlib.pyplot as plt
from matplotlib.backends.backend_qt5agg import FigureCanvasQTAgg

class MplCanvas(FigureCanvasQTAgg):

    def __init__(self, parent=None, width=5, height=4, dpi=100):

        self.fig, self.axes = plt.subplots(figsize=(width, height), dpi=dpi, tight_layout=True)
        super(MplCanvas, self).__init__(self.fig)


    def make_plot(self, x, y, fmt='.k'):

        self.fig.clear()
        axes = self.fig.subplots()

        axes.plot(x, y, fmt)
        axes.invert_yaxis()
        axes.annotate('I make the plot get smaller and smaller', xy=(0,0), xycoords='figure points', fontsize='x-small', fontstyle='italic', annotation_clip=False)

        self.draw()

class MainWindow(QtWidgets.QMainWindow):

    def __init__(self, *args, **kwargs):
        super(MainWindow, self).__init__(*args, **kwargs)

        #Create a layout with central alignment
        self.layout1 = QtWidgets.QVBoxLayout()
        self.layout1.setAlignment(QtCore.Qt.AlignCenter)

        # Create a placeholder widget to hold our toolbar and canvas.
        self.widget1 = QtWidgets.QWidget()
        self.widget1.setLayout(self.layout1)
        self.setCentralWidget(self.widget1)

        #Create a matplotlib canvas and add it to the layout
        self.sc = MplCanvas(self, width=5, height=4, dpi=100)
        sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Policy.Fixed, QtWidgets.QSizePolicy.Policy.Fixed)
        self.sc.setSizePolicy(sizePolicy)
        self.layout1.addWidget(self.sc)

        # Create a button
        self.button = QtWidgets.QPushButton()
        self.button.setText("Press me")
        self.layout1.addWidget(self.button)

        #Create the connection
        self.button.clicked.connect(self.plot_something)

        self.show()

    def plot_something(self):
        print('plotting')
        x = [0,1,2,3,4]
        y = [10,1,20,3,40]
        self.sc.make_plot(x, y)

app = QtWidgets.QApplication(sys.argv)
w = MainWindow()
app.exec_()

在此示例中,摆弄 xycoords 参数有时可以解决问题,例如使用 xycoords='axes points''data' 似乎可行。但这并不能解决我实际应用中的问题。禁用紧凑布局似乎也可以解决它,但由于各种原因我需要紧凑布局。

轴每次都变得越来越小的事实表明 self.fig.clear() 实际上并没有清除所有内容 - 在绘图迭代之间会记住一些东西。有没有办法完全清除无花果对象并开始一个新对象?或者最好关闭实际的 canvas 并每次创建一个新的?

当艺术家参与 tight_layout(或更好,constrained_layout)时,它会尝试使坐标轴足够小,以免与其他坐标轴重叠。在这种情况下,您在坐标轴上放置注释,但在图形坐标中绘制它。在这种情况下,最好将其从自动布局中取出:

an = axes.annotate('I make the plot get smaller and smaller', 
                   xy=(0,0), xycoords='figure points', 
                   fontsize='x-small', fontstyle='italic',
                   annotation_clip=False)
an.set_in_layout(False)

至于为什么Axes越来越小,tight_layout使用subplots_adjust,设置Figure.subplotpars。 Fig.clear() 上没有将这些归零。你实际上可以打开一个关于那个的错误报告,因为我认为它们应该被重置。

但是,对于您的代码,我可能不会一直清除该数字,因为就 cpu 个周期而言,这会变得很昂贵。如果可能,最好更新坐标区中的数据。