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 个周期而言,这会变得很昂贵。如果可能,最好更新坐标区中的数据。
我有一个 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 个周期而言,这会变得很昂贵。如果可能,最好更新坐标区中的数据。