Movatterモバイル変換


[0]ホーム

URL:


Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Sign up
Appearance settings

Commitff262a1

Browse files
Zybulontacaswell
andauthored
Return filename from save_figure (#27766)
---------Co-authored-by: Thomas A Caswell <tcaswell@gmail.com>
1 parent36daea4 commitff262a1

14 files changed

+119
-8
lines changed
Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
``NavigationToolbar2.save_figure`` now returns filepath of saved figure
2+
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
3+
4+
``NavigationToolbar2.save_figure`` function may return the filename of the saved figure.
5+
6+
If a backend implements this functionality it should return `None`
7+
in the case where no figure is actually saved (because the user closed the dialog without saving).
8+
9+
If the backend does not or can not implement this functionality (currently the Gtk4 backends
10+
and webagg backends do not) this method will return ``NavigationToolbar2.UNKNOWN_SAVED_STATUS``.

‎lib/matplotlib/backend_bases.py

Lines changed: 22 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2780,6 +2780,8 @@ class NavigationToolbar2:
27802780
('Save','Save the figure','filesave','save_figure'),
27812781
)
27822782

2783+
UNKNOWN_SAVED_STATUS=object()
2784+
27832785
def__init__(self,canvas):
27842786
self.canvas=canvas
27852787
canvas.toolbar=self
@@ -3194,7 +3196,26 @@ def on_tool_fig_close(e):
31943196
returnself.subplot_tool
31953197

31963198
defsave_figure(self,*args):
3197-
"""Save the current figure."""
3199+
"""
3200+
Save the current figure.
3201+
3202+
Backend implementations may choose to return
3203+
the absolute path of the saved file, if any, as
3204+
a string.
3205+
3206+
If no file is created then `None` is returned.
3207+
3208+
If the backend does not implement this functionality
3209+
then `NavigationToolbar2.UNKNOWN_SAVED_STATUS` is returned.
3210+
3211+
Returns
3212+
-------
3213+
str or `NavigationToolbar2.UNKNOWN_SAVED_STATUS` or `None`
3214+
The filepath of the saved figure.
3215+
Returns `None` if figure is not saved.
3216+
Returns `NavigationToolbar2.UNKNOWN_SAVED_STATUS` when
3217+
the backend does not provide the information.
3218+
"""
31983219
raiseNotImplementedError
31993220

32003221
defupdate(self):

‎lib/matplotlib/backend_bases.pyi

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -402,6 +402,7 @@ class _Mode(str, Enum):
402402

403403
classNavigationToolbar2:
404404
toolitems:tuple[tuple[str, ...]|tuple[None, ...], ...]
405+
UNKNOWN_SAVED_STATUS:object
405406
canvas:FigureCanvasBase
406407
mode:_Mode
407408
def__init__(self,canvas:FigureCanvasBase)->None: ...
@@ -437,7 +438,7 @@ class NavigationToolbar2:
437438
defpush_current(self)->None: ...
438439
subplot_tool:widgets.SubplotTool
439440
defconfigure_subplots(self,*args): ...
440-
defsave_figure(self,*args)->None: ...
441+
defsave_figure(self,*args)->str|None|object: ...
441442
defupdate(self)->None: ...
442443
defset_history_buttons(self)->None: ...
443444

‎lib/matplotlib/backends/_backend_tk.py

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -870,7 +870,7 @@ def save_figure(self, *args):
870870
)
871871

872872
iffnamein ["", ()]:
873-
return
873+
returnNone
874874
# Save dir for next time, unless empty str (i.e., use cwd).
875875
ifinitialdir!="":
876876
mpl.rcParams['savefig.directory']= (
@@ -885,6 +885,7 @@ def save_figure(self, *args):
885885

886886
try:
887887
self.canvas.figure.savefig(fname,format=extension)
888+
returnfname
888889
exceptExceptionase:
889890
tkinter.messagebox.showerror("Error saving file",str(e))
890891

‎lib/matplotlib/backends/backend_gtk3.py

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -339,7 +339,7 @@ def __init__(self, canvas):
339339
defsave_figure(self,*args):
340340
dialog=Gtk.FileChooserDialog(
341341
title="Save the figure",
342-
parent=self.canvas.get_toplevel(),
342+
transient_for=self.canvas.get_toplevel(),
343343
action=Gtk.FileChooserAction.SAVE,
344344
buttons=(Gtk.STOCK_CANCEL,Gtk.ResponseType.CANCEL,
345345
Gtk.STOCK_SAVE,Gtk.ResponseType.OK),
@@ -371,16 +371,17 @@ def on_notify_filter(*args):
371371
fmt=self.canvas.get_supported_filetypes_grouped()[ff.get_name()][0]
372372
dialog.destroy()
373373
ifresponse!=Gtk.ResponseType.OK:
374-
return
374+
returnNone
375375
# Save dir for next time, unless empty str (which means use cwd).
376376
ifmpl.rcParams['savefig.directory']:
377377
mpl.rcParams['savefig.directory']=os.path.dirname(fname)
378378
try:
379379
self.canvas.figure.savefig(fname,format=fmt)
380+
returnfname
380381
exceptExceptionase:
381382
dialog=Gtk.MessageDialog(
382-
parent=self.canvas.get_toplevel(),message_format=str(e),
383-
type=Gtk.MessageType.ERROR,buttons=Gtk.ButtonsType.OK)
383+
transient_for=self.canvas.get_toplevel(),text=str(e),
384+
message_type=Gtk.MessageType.ERROR,buttons=Gtk.ButtonsType.OK)
384385
dialog.run()
385386
dialog.destroy()
386387

‎lib/matplotlib/backends/backend_gtk4.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -393,6 +393,7 @@ def on_response(dialog, response):
393393
msg.show()
394394

395395
dialog.show()
396+
returnself.UNKNOWN_SAVED_STATUS
396397

397398

398399
classToolbarGTK4(ToolContainerBase,Gtk.Box):

‎lib/matplotlib/backends/backend_macosx.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -142,6 +142,7 @@ def save_figure(self, *args):
142142
ifmpl.rcParams['savefig.directory']:
143143
mpl.rcParams['savefig.directory']=os.path.dirname(filename)
144144
self.canvas.figure.savefig(filename)
145+
returnfilename
145146

146147

147148
classFigureManagerMac(_macosx.FigureManager,FigureManagerBase):

‎lib/matplotlib/backends/backend_qt.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -835,6 +835,7 @@ def save_figure(self, *args):
835835
self,"Error saving file",str(e),
836836
QtWidgets.QMessageBox.StandardButton.Ok,
837837
QtWidgets.QMessageBox.StandardButton.NoButton)
838+
returnfname
838839

839840
defset_history_buttons(self):
840841
can_backward=self._nav_stack._pos>0

‎lib/matplotlib/backends/backend_webagg_core.py

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -403,8 +403,9 @@ def remove_rubberband(self):
403403
self.canvas.send_event("rubberband",x0=-1,y0=-1,x1=-1,y1=-1)
404404

405405
defsave_figure(self,*args):
406-
"""Save the current figure"""
406+
"""Save the current figure."""
407407
self.canvas.send_event('save')
408+
returnself.UNKNOWN_SAVED_STATUS
408409

409410
defpan(self):
410411
super().pan()

‎lib/matplotlib/backends/backend_wx.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1143,6 +1143,7 @@ def save_figure(self, *args):
11431143
mpl.rcParams["savefig.directory"]=str(path.parent)
11441144
try:
11451145
self.canvas.figure.savefig(path,format=fmt)
1146+
returnpath
11461147
exceptExceptionase:
11471148
dialog=wx.MessageDialog(
11481149
parent=self.canvas.GetParent(),message=str(e),

‎lib/matplotlib/tests/test_backend_gtk3.py

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,8 @@
1+
importos
12
frommatplotlibimportpyplotasplt
23

34
importpytest
5+
fromunittestimportmock
46

57

68
@pytest.mark.backend("gtk3agg",skip_on_importerror=True)
@@ -46,3 +48,27 @@ def receive(event):
4648
fig.canvas.mpl_connect("draw_event",send)
4749
fig.canvas.mpl_connect("key_press_event",receive)
4850
plt.show()
51+
52+
53+
@pytest.mark.backend("gtk3agg",skip_on_importerror=True)
54+
deftest_save_figure_return():
55+
fromgi.repositoryimportGtk
56+
fig,ax=plt.subplots()
57+
ax.imshow([[1]])
58+
withmock.patch("gi.repository.Gtk.FileFilter")asfileFilter:
59+
filt=fileFilter.return_value
60+
filt.get_name.return_value="Portable Network Graphics"
61+
withmock.patch("gi.repository.Gtk.FileChooserDialog")asdialogChooser:
62+
dialog=dialogChooser.return_value
63+
dialog.get_filter.return_value=filt
64+
dialog.get_filename.return_value="foobar.png"
65+
dialog.run.return_value=Gtk.ResponseType.OK
66+
fname=fig.canvas.manager.toolbar.save_figure()
67+
os.remove("foobar.png")
68+
assertfname=="foobar.png"
69+
70+
withmock.patch("gi.repository.Gtk.MessageDialog"):
71+
dialog.get_filename.return_value=None
72+
dialog.run.return_value=Gtk.ResponseType.OK
73+
fname=fig.canvas.manager.toolbar.save_figure()
74+
assertfnameisNone

‎lib/matplotlib/tests/test_backend_macosx.py

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
importos
22

33
importpytest
4+
fromunittestimportmock
45

56
importmatplotlibasmpl
67
importmatplotlib.pyplotasplt
@@ -50,3 +51,17 @@ def new_choose_save_file(title, directory, filename):
5051
deftest_ipython():
5152
frommatplotlib.testingimportipython_in_subprocess
5253
ipython_in_subprocess("osx", {(8,24):"macosx", (7,0):"MacOSX"})
54+
55+
56+
@pytest.mark.backend('macosx')
57+
deftest_save_figure_return():
58+
fig,ax=plt.subplots()
59+
ax.imshow([[1]])
60+
prop="matplotlib.backends._macosx.choose_save_file"
61+
withmock.patch(prop,return_value="foobar.png"):
62+
fname=fig.canvas.manager.toolbar.save_figure()
63+
os.remove("foobar.png")
64+
assertfname=="foobar.png"
65+
withmock.patch(prop,return_value=None):
66+
fname=fig.canvas.manager.toolbar.save_figure()
67+
assertfnameisNone

‎lib/matplotlib/tests/test_backend_qt.py

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -226,6 +226,20 @@ def test_figureoptions():
226226
fig.canvas.manager.toolbar.edit_parameters()
227227

228228

229+
@pytest.mark.backend('QtAgg',skip_on_importerror=True)
230+
deftest_save_figure_return():
231+
fig,ax=plt.subplots()
232+
ax.imshow([[1]])
233+
prop="matplotlib.backends.qt_compat.QtWidgets.QFileDialog.getSaveFileName"
234+
withmock.patch(prop,return_value=("foobar.png",None)):
235+
fname=fig.canvas.manager.toolbar.save_figure()
236+
os.remove("foobar.png")
237+
assertfname=="foobar.png"
238+
withmock.patch(prop,return_value=(None,None)):
239+
fname=fig.canvas.manager.toolbar.save_figure()
240+
assertfnameisNone
241+
242+
229243
@pytest.mark.backend('QtAgg',skip_on_importerror=True)
230244
deftest_figureoptions_with_datetime_axes():
231245
fig,ax=plt.subplots()

‎lib/matplotlib/tests/test_backend_tk.py

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -196,6 +196,23 @@ class Toolbar(NavigationToolbar2Tk):
196196
print("success")
197197

198198

199+
@_isolated_tk_test(success_count=2)
200+
deftest_save_figure_return():
201+
importmatplotlib.pyplotasplt
202+
fromunittestimportmock
203+
fig=plt.figure()
204+
prop="tkinter.filedialog.asksaveasfilename"
205+
withmock.patch(prop,return_value="foobar.png"):
206+
fname=fig.canvas.manager.toolbar.save_figure()
207+
os.remove("foobar.png")
208+
assertfname=="foobar.png"
209+
print("success")
210+
withmock.patch(prop,return_value=""):
211+
fname=fig.canvas.manager.toolbar.save_figure()
212+
assertfnameisNone
213+
print("success")
214+
215+
199216
@_isolated_tk_test(success_count=1)
200217
deftest_canvas_focus():
201218
importtkinterastk

0 commit comments

Comments
 (0)

[8]ページ先頭

©2009-2025 Movatter.jp