简体   繁体   English

matplotlib 带注释的紧密布局导致图形越来越小

[英]matplotlib tight_layout with annotation causes figure to get smaller and smaller

I have a FigureCanvasQTAgg that creates plots with the user selecting what data to plot, and the canvas updates the plots by calling self.fig.clear() and creating the new plot.我有一个FigureCanvasQTAgg可以创建绘图,用户选择 plot 的数据,canvas 通过调用self.fig.clear()并创建新的 Z32FA6E1B78A9D4028953E605CZ 来更新绘图。 This has worked fine but I ran into a problem.这工作得很好,但我遇到了一个问题。 I have designed a certain plot with an annotation under the axes, but every time the figure is updated, the plot gets smaller and smaller.我设计了一个plot,轴下有注释,但是每次更新图,plot越来越小。 This code replicates the problem:这段代码复制了这个问题:

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_()

In this example, fiddling with the xycoords argument sometimes solves it, for example using xycoords='axes points' or 'data' seems to work.在这个例子中,摆弄xycoords参数有时可以解决它,例如使用xycoords='axes points''data'似乎有效。 But this does not solve the issue in my actual application.但这并不能解决我实际应用中的问题。 Disabling tight layout also seems to solve it, but I need tight layout for various reasons.禁用紧凑布局似乎也可以解决它,但由于各种原因我需要紧凑布局。

The fact that the axes get smaller and smaller each time suggests that self.fig.clear() does not actually clear everything - something is being remembered between iterations of the plot.轴每次都变得越来越小的事实表明self.fig.clear()实际上并没有清除所有内容 - 在 plot 的迭代之间会记住一些东西。 Is there a way I can completely purge the fig object and start a new one?有没有办法完全清除无花果 object 并开始一个新的? Or would it be best to close the actual canvas and create a new one each time?还是最好关闭实际的 canvas 并每次创建一个新的?

When an Artist participates in tight_layout (or better, constrained_layout) it tries to make the axes small enough that it doesn't overlap with other axes.当艺术家参与紧密布局(或更好的约束布局)时,它会尝试使轴足够小,使其不与其他轴重叠。 In this case, you are putting an annotation on the axes, but drawing it in figure co-ordinates.在这种情况下,您在轴上放置注释,但在图形坐标中绘制它。 In which case it would be preferable to take it out of the automatic 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)

As for why the Axes gets smaller and smaller, tight_layout uses subplots_adjust , which set Figure.subplotpars.至于为什么 Axes 越来越小, tight_layout使用了subplots_adjust ,它设置了 Figure.subplotpars。 These are not being zeroed out on Fig.clear() .这些没有在Fig.clear()上归零。 You could actually open a bug report about that, as I think they should be reset.你实际上可以打开一个错误报告,因为我认为它们应该被重置。

However, for your code, I'd probably not keep clearing the figure, as that gets expensive in terms of cpu cycles.但是,对于您的代码,我可能不会继续清除这个数字,因为这在 cpu 周期方面会变得昂贵。 Better would be to update the data in the Axes if possible.如果可能,最好更新轴中的数据。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM