如何在PyQt5应用程序中更改Matplotlib NavigationToolbar的默认文件名?

3
我正在使用Python 3.5和PyQT 5编写一个应用程序。在该应用程序中,我有一个内嵌的matplotlib画布和内嵌的matplotlib NavigationToolbar。该应用程序测量一些数据并将其绘制出来。用户想要在某个时刻将图形导出并将其保存为".png"文件,然后再进行新的测量。
为此,我一直在使用NavigationToolbar上的“保存”图标,它工作得很好。但是,当我单击它时,它会在程序的根文件夹(或最后打开的文件夹)中打开一个对话框,并将保存的图像名称预设为“image.png”。
我想将此预填充的默认名称更改为我的程序自定义名称,例如“measurement_7453243.png”或“2017_01_16_measurement.png”。是否有一种方式可以让我这样做?
想法#1:我找到了使用matplotlib.rcParams ['savefig.directory']选项,并使用它来设置对话框应打开的目录 - 而不是文件名。但我似乎找不到可以更改默认文件名的'savefig.XXXX'属性。
想法#2:我可以在NavigationToolbar之外的我的应用程序中创建一个自定义按钮,以运行带有Qt的自定义文件保存对话框,然后使用savefig()保存该图形。但是,如果已经有一个几乎符合我要求的好按钮,为什么要这样做呢?
非常感谢任何提示和想法,以及带有正确来源的“无法完成此操作”。

1
我曾经也遇到过同样的问题,没有找到快速解决方案后,我实现了您所称的Idea#2。尽管如此,我相信还有其他解决方案。 - ImportanceOfBeingErnest
3个回答

5

我不确定您是否总是可以这样做,但在我的情况下,该图实例有一个画布属性,我可以像Goyo建议的那样进行猴子补丁。

import matplotlib.pyplot as plt
f = plt.figure()
c = f.canvas
my_adventurous_filename = 'figure-III' # irony
c.get_default_filename = lambda : '%s.%s' % (my_adventurous_filename,
                                             c.get_default_filetype())
plt.show()

4

默认文件名由方法FigureCanvasBase.get_default_filename提供。您可以在创建画布后进行猴子打补丁:

canvas = FigureCanvas(fig)
canvas.get_default_filename = lambda: 'new_default_name.png'

我想正确的方法是通过子类化FigureCanvas,重写该方法并可能提供一个API来设置默认文件名。
下面是一个使用猴子补丁的Qt5Agg示例,改编自matplotlib文档:
from PyQt5.QtWidgets import (
    QMainWindow, QApplication, QWidget, QVBoxLayout)

from matplotlib.figure import Figure
from matplotlib.backends.backend_qt5agg import (
    FigureCanvasQTAgg as FigureCanvas,
    NavigationToolbar2QT as NavigationToolbar)


class AppForm(QMainWindow):
    def __init__(self, parent=None):
        QMainWindow.__init__(self, parent)
        main_frame = QWidget()

        fig = Figure((5.0, 4.0), dpi=100)
        ax = fig.add_subplot(111)
        ax.plot([1, 2, 4, 8])

        canvas = FigureCanvas(fig)
        canvas.get_default_filename = lambda: 'new_default_name.png'
        mpl_toolbar = NavigationToolbar(canvas, main_frame)

        vbox = QVBoxLayout()
        vbox.addWidget(canvas)  # the matplotlib canvas
        vbox.addWidget(mpl_toolbar)
        main_frame.setLayout(vbox)
        self.setCentralWidget(main_frame)


app = QApplication(['Test'])
form = AppForm()
form.show()
app.exec_()

谢谢您的回答,我会尝试一下并看看它如何在我的程序中运行 :)。 - erthy
我在我的应用程序中尝试了这个,但无法使其工作。调用成功(即不会抛出异常),但保存图形时没有任何变化。您能否提供一个可行的示例? - erthy
@erthy 我有点困惑。昨天在一个平行宇宙中,fig.set_label 可以用于独立的交互式图形,实现你想要的效果。但现在需要使用 fig.canvas.set_window_title,不过很遗憾这个方法对于嵌入式图形没有任何作用,所以我不得不另寻他法。为了防止我再次被传送到另一个宇宙,我准备了一个 [mcve]。 - Stop harming Monica
我不完全理解这个评论,但希望平行宇宙的问题不是我的错 :)。几个小时前在类似的问题上,我偶然发现了猴子补丁的方法,迫不及待地想试试。甚至比在任何宇宙中使用set_label()看起来更合适。甚至可以值得一试地窃取原始get_default_filename()的代码,只需将 'image' 更改为 'measurement_...',这样即使在冲突时重命名也能保持好处。感谢您的帮助和示例!!在我尝试了应用程序之后,我会回报情况的。 - erthy
运行得非常好,如果我不想要它花哨,它本质上就是一行代码。谢谢您! :) - erthy

0

这在Matplotlib-3文档中提到过,对我有效(Python 3.8.5/TkAgg):

fig, axs = plt.subplots(...)
fig.canvas.set_window_title(my_file_name)

我也设置了:

matplotlib.rcParams['savefig.format'] = 'svg'

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接