Skip to content

Commit 3652e4a

Browse files
committed
Interactive setting of savefig rcParams (Qt only).
An additional window pops after selecting the filename to allow setting of savefig-related rcParams. For simplicity and consistency, the "ps.usedistiller" rcParam is now normalized to `None` when not set.
1 parent ab98852 commit 3652e4a

File tree

3 files changed

+110
-19
lines changed

3 files changed

+110
-19
lines changed

lib/matplotlib/backends/backend_qt5.py

Lines changed: 102 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,8 @@
2727

2828
from .qt_compat import (QtCore, QtGui, QtWidgets, _getSaveFileName,
2929
__version__, is_pyqt5)
30-
from matplotlib.backends.qt_editor.formsubplottool import UiSubplotTool
30+
from .qt_editor import formlayout
31+
from .qt_editor.formsubplottool import UiSubplotTool
3132

3233
backend_version = __version__
3334

@@ -725,19 +726,19 @@ def save_figure(self, *args):
725726
startpath = matplotlib.rcParams.get('savefig.directory', '')
726727
startpath = os.path.expanduser(startpath)
727728
start = os.path.join(startpath, self.canvas.get_default_filename())
729+
728730
filters = []
729-
selectedFilter = None
731+
selected_filter = None
730732
for name, exts in sorted_filetypes:
731-
exts_list = " ".join(['*.%s' % ext for ext in exts])
732-
filter = '%s (%s)' % (name, exts_list)
733+
filters.append(
734+
'{} ({})'.format(name, ' '.join(map('*.{}'.format, exts))))
733735
if default_filetype in exts:
734-
selectedFilter = filter
735-
filters.append(filter)
736+
selected_filter = filters[-1]
736737
filters = ';;'.join(filters)
737738

738-
fname, filter = _getSaveFileName(self.parent,
739-
"Choose a filename to save to",
740-
start, filters, selectedFilter)
739+
fname, selected_filter = _getSaveFileName(
740+
self.parent, "Choose a filename to save to",
741+
start, filters, selected_filter)
741742
if fname:
742743
if startpath == '':
743744
# explicitly missing key or empty str signals to use cwd
@@ -746,6 +747,25 @@ def save_figure(self, *args):
746747
# save dir for next time
747748
savefig_dir = os.path.dirname(six.text_type(fname))
748749
matplotlib.rcParams['savefig.directory'] = savefig_dir
750+
options = _default_savefig_options
751+
try:
752+
options = (options
753+
+ [None]
754+
+ _extra_savefig_options[
755+
os.path.splitext(fname)[1].lower()])
756+
except KeyError:
757+
pass
758+
fedit_arg = []
759+
for option in options:
760+
if option is None:
761+
fedit_arg.append((None, None))
762+
else:
763+
fedit_arg.append(option.make_fedit_entry())
764+
fedit_res = formlayout.fedit(fedit_arg, "Options")
765+
if not fedit_res:
766+
return
767+
for option, res in zip(filter(None, options), fedit_res):
768+
option.setter(res)
749769
try:
750770
self.canvas.print_figure(six.text_type(fname))
751771
except Exception as e:
@@ -754,6 +774,79 @@ def save_figure(self, *args):
754774
QtWidgets.QMessageBox.Ok, QtWidgets.QMessageBox.NoButton)
755775

756776

777+
class _Option(object):
778+
779+
def __init__(self, name, rc_key=None, getter=None, setter=None):
780+
if rc_key and not (getter or setter):
781+
def make_fedit_entry():
782+
return (name, matplotlib.rcParams[rc_key])
783+
784+
def setter(val):
785+
matplotlib.rcParams[rc_key] = val
786+
787+
elif getter and setter and not rc_key:
788+
def make_fedit_entry():
789+
return (name, getter())
790+
791+
else:
792+
raise ValueError("Invalid entry")
793+
794+
self.name = name
795+
self.make_fedit_entry = make_fedit_entry
796+
self.setter = setter
797+
798+
799+
_default_savefig_options = [
800+
_Option("DPI", "savefig.dpi"),
801+
_Option("Face color", "savefig.facecolor"),
802+
_Option("Edge color", "savefig.edgecolor"),
803+
_Option("Tight bounding box",
804+
getter=lambda: matplotlib.rcParams["savefig.bbox"] == "tight",
805+
setter=lambda val: matplotlib.rcParams.__setitem__(
806+
"savefig.bbox", "tight" if val else "standard")),
807+
_Option("Tight bounding box padding", "savefig.pad_inches"),
808+
_Option("Transparent background", "savefig.transparent")]
809+
810+
811+
_extra_savefig_options = {
812+
".jpg": [
813+
_Option("JPEG quality", "savefig.jpeg_quality")],
814+
".jpeg": [
815+
_Option("JPEG quality", "savefig.jpeg_quality")],
816+
".pdf": [
817+
_Option("PDF compression", "pdf.compression"),
818+
_Option("PDF font type",
819+
getter=lambda:
820+
[str(matplotlib.rcParams["pdf.fonttype"]),
821+
"3", "42"],
822+
setter=lambda val:
823+
matplotlib.rcParams.__setitem__("pdf.fonttype", val))],
824+
".ps": [
825+
_Option("PS paper size",
826+
getter=lambda:
827+
[matplotlib.rcParams["ps.papersize"]]
828+
+ ["auto", "letter", "legal", "ledger"]
829+
+ ["A{}".format(i) for i in range(11)]
830+
+ ["B{}".format(i) for i in range(11)],
831+
setter=lambda val:
832+
matplotlib.rcParams.__setitem__("ps.papersize", val)),
833+
_Option("PS use AFM font", "ps.useafm"),
834+
_Option("PS distiller",
835+
getter=lambda:
836+
[str(matplotlib.rcParams["ps.usedistiller"])]
837+
+ ["None", "ghostscript", "xpdf"],
838+
setter=lambda val:
839+
matplotlib.rcParams.__setitem__("ps.usedistiller", val)),
840+
_Option("PS distiller resolution", "ps.distiller.res"),
841+
_Option("PS font type",
842+
getter=lambda:
843+
[str(matplotlib.rcParams["ps.fonttype"]),
844+
"3", "42"],
845+
setter=lambda val:
846+
matplotlib.rcParams.__setitem__("ps.fonttype", val))]
847+
}
848+
849+
757850
class SubplotToolQt(SubplotTool, UiSubplotTool):
758851
def __init__(self, targetfig, parent):
759852
UiSubplotTool.__init__(self, None)

lib/matplotlib/rcsetup.py

Lines changed: 2 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -504,10 +504,8 @@ def update_savefig_format(value):
504504
def validate_ps_distiller(s):
505505
if isinstance(s, six.string_types):
506506
s = s.lower()
507-
if s in ('none', None):
507+
if s in ('none', None, 'false', False):
508508
return None
509-
elif s in ('false', False):
510-
return False
511509
elif s in ('ghostscript', 'xpdf'):
512510
return s
513511
else:
@@ -1269,7 +1267,7 @@ def validate_animation_writer_path(p):
12691267
'ps.papersize': ['letter', validate_ps_papersize],
12701268
'ps.useafm': [False, validate_bool], # Set PYTHONINSPECT
12711269
# use ghostscript or xpdf to distill ps output
1272-
'ps.usedistiller': [False, validate_ps_distiller],
1270+
'ps.usedistiller': [None, validate_ps_distiller],
12731271
'ps.distiller.res': [6000, validate_int], # dpi
12741272
'ps.fonttype': [3, validate_fonttype], # 3 (Type3) or 42 (Truetype)
12751273
# compression level from 0 to 9; 0 to disable

matplotlibrc.template

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -538,12 +538,12 @@ backend : $TEMPLATE_BACKEND
538538
# ps backend params
539539
#ps.papersize : letter # auto, letter, legal, ledger, A0-A10, B0-B10
540540
#ps.useafm : False # use of afm fonts, results in small files
541-
#ps.usedistiller : False # can be: None, ghostscript or xpdf
542-
# Experimental: may produce smaller files.
543-
# xpdf intended for production of publication quality files,
544-
# but requires ghostscript, xpdf and ps2eps
545-
#ps.distiller.res : 6000 # dpi
546-
#ps.fonttype : 3 # Output Type 3 (Type3) or Type 42 (TrueType)
541+
#ps.usedistiller : None # can be: None, ghostscript or xpdf
542+
# Experimental: may produce smaller files.
543+
# xpdf intended for production of publication quality files,
544+
# but requires ghostscript, xpdf and ps2eps
545+
#ps.distiller.res : 6000 # dpi
546+
#ps.fonttype : 3 # Output Type 3 (Type3) or Type 42 (TrueType)
547547

548548
# pdf backend params
549549
#pdf.compression : 6 # integer from 0 to 9

0 commit comments

Comments
 (0)