Skip to content

Commit dbb34b1

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 eb6e422 commit dbb34b1

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
@@ -25,7 +25,8 @@
2525

2626
from .qt_compat import (QtCore, QtGui, QtWidgets, _getSaveFileName,
2727
__version__, is_pyqt5)
28-
from matplotlib.backends.qt_editor.formsubplottool import UiSubplotTool
28+
from .qt_editor import formlayout
29+
from .qt_editor.formsubplottool import UiSubplotTool
2930

3031
backend_version = __version__
3132

@@ -745,19 +746,19 @@ def save_figure(self, *args):
745746
startpath = matplotlib.rcParams.get('savefig.directory', '')
746747
startpath = os.path.expanduser(startpath)
747748
start = os.path.join(startpath, self.canvas.get_default_filename())
749+
748750
filters = []
749-
selectedFilter = None
751+
selected_filter = None
750752
for name, exts in sorted_filetypes:
751-
exts_list = " ".join(['*.%s' % ext for ext in exts])
752-
filter = '%s (%s)' % (name, exts_list)
753+
filters.append(
754+
'{} ({})'.format(name, ' '.join(map('*.{}'.format, exts))))
753755
if default_filetype in exts:
754-
selectedFilter = filter
755-
filters.append(filter)
756+
selected_filter = filters[-1]
756757
filters = ';;'.join(filters)
757758

758-
fname, filter = _getSaveFileName(self.parent,
759-
"Choose a filename to save to",
760-
start, filters, selectedFilter)
759+
fname, selected_filter = _getSaveFileName(
760+
self.parent, "Choose a filename to save to",
761+
start, filters, selected_filter)
761762
if fname:
762763
if startpath == '':
763764
# explicitly missing key or empty str signals to use cwd
@@ -766,6 +767,25 @@ def save_figure(self, *args):
766767
# save dir for next time
767768
savefig_dir = os.path.dirname(six.text_type(fname))
768769
matplotlib.rcParams['savefig.directory'] = savefig_dir
770+
options = _default_savefig_options
771+
try:
772+
options = (options
773+
+ [None]
774+
+ _extra_savefig_options[
775+
os.path.splitext(fname)[1].lower()])
776+
except KeyError:
777+
pass
778+
fedit_arg = []
779+
for option in options:
780+
if option is None:
781+
fedit_arg.append((None, None))
782+
else:
783+
fedit_arg.append(option.make_fedit_entry())
784+
fedit_res = formlayout.fedit(fedit_arg, "Options")
785+
if not fedit_res:
786+
return
787+
for option, res in zip(filter(None, options), fedit_res):
788+
option.setter(res)
769789
try:
770790
self.canvas.print_figure(six.text_type(fname))
771791
except Exception as e:
@@ -774,6 +794,79 @@ def save_figure(self, *args):
774794
QtWidgets.QMessageBox.Ok, QtWidgets.QMessageBox.NoButton)
775795

776796

797+
class _Option(object):
798+
799+
def __init__(self, name, rc_key=None, getter=None, setter=None):
800+
if rc_key and not (getter or setter):
801+
def make_fedit_entry():
802+
return (name, matplotlib.rcParams[rc_key])
803+
804+
def setter(val):
805+
matplotlib.rcParams[rc_key] = val
806+
807+
elif getter and setter and not rc_key:
808+
def make_fedit_entry():
809+
return (name, getter())
810+
811+
else:
812+
raise ValueError("Invalid entry")
813+
814+
self.name = name
815+
self.make_fedit_entry = make_fedit_entry
816+
self.setter = setter
817+
818+
819+
_default_savefig_options = [
820+
_Option("DPI", "savefig.dpi"),
821+
_Option("Face color", "savefig.facecolor"),
822+
_Option("Edge color", "savefig.edgecolor"),
823+
_Option("Tight bounding box",
824+
getter=lambda: matplotlib.rcParams["savefig.bbox"] == "tight",
825+
setter=lambda val: matplotlib.rcParams.__setitem__(
826+
"savefig.bbox", "tight" if val else "standard")),
827+
_Option("Tight bounding box padding", "savefig.pad_inches"),
828+
_Option("Transparent background", "savefig.transparent")]
829+
830+
831+
_extra_savefig_options = {
832+
".jpg": [
833+
_Option("JPEG quality", "savefig.jpeg_quality")],
834+
".jpeg": [
835+
_Option("JPEG quality", "savefig.jpeg_quality")],
836+
".pdf": [
837+
_Option("PDF compression", "pdf.compression"),
838+
_Option("PDF font type",
839+
getter=lambda:
840+
[str(matplotlib.rcParams["pdf.fonttype"]),
841+
"3", "42"],
842+
setter=lambda val:
843+
matplotlib.rcParams.__setitem__("pdf.fonttype", val))],
844+
".ps": [
845+
_Option("PS paper size",
846+
getter=lambda:
847+
[matplotlib.rcParams["ps.papersize"]]
848+
+ ["auto", "letter", "legal", "ledger"]
849+
+ ["A{}".format(i) for i in range(11)]
850+
+ ["B{}".format(i) for i in range(11)],
851+
setter=lambda val:
852+
matplotlib.rcParams.__setitem__("ps.papersize", val)),
853+
_Option("PS use AFM font", "ps.useafm"),
854+
_Option("PS distiller",
855+
getter=lambda:
856+
[str(matplotlib.rcParams["ps.usedistiller"])]
857+
+ ["None", "ghostscript", "xpdf"],
858+
setter=lambda val:
859+
matplotlib.rcParams.__setitem__("ps.usedistiller", val)),
860+
_Option("PS distiller resolution", "ps.distiller.res"),
861+
_Option("PS font type",
862+
getter=lambda:
863+
[str(matplotlib.rcParams["ps.fonttype"]),
864+
"3", "42"],
865+
setter=lambda val:
866+
matplotlib.rcParams.__setitem__("ps.fonttype", val))]
867+
}
868+
869+
777870
class SubplotToolQt(UiSubplotTool):
778871
def __init__(self, targetfig, parent):
779872
UiSubplotTool.__init__(self, None)

lib/matplotlib/rcsetup.py

Lines changed: 2 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -519,10 +519,8 @@ def update_savefig_format(value):
519519
def validate_ps_distiller(s):
520520
if isinstance(s, six.string_types):
521521
s = s.lower()
522-
if s in ('none', None):
522+
if s in ('none', None, 'false', False):
523523
return None
524-
elif s in ('false', False):
525-
return False
526524
elif s in ('ghostscript', 'xpdf'):
527525
return s
528526
else:
@@ -1349,7 +1347,7 @@ def _validate_linestyle(ls):
13491347
'ps.papersize': ['letter', validate_ps_papersize],
13501348
'ps.useafm': [False, validate_bool], # Set PYTHONINSPECT
13511349
# use ghostscript or xpdf to distill ps output
1352-
'ps.usedistiller': [False, validate_ps_distiller],
1350+
'ps.usedistiller': [None, validate_ps_distiller],
13531351
'ps.distiller.res': [6000, validate_int], # dpi
13541352
'ps.fonttype': [3, validate_fonttype], # 3 (Type3) or 42 (Truetype)
13551353
# 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
@@ -542,12 +542,12 @@ backend : $TEMPLATE_BACKEND
542542
# ps backend params
543543
#ps.papersize : letter # auto, letter, legal, ledger, A0-A10, B0-B10
544544
#ps.useafm : False # use of afm fonts, results in small files
545-
#ps.usedistiller : False # can be: None, ghostscript or xpdf
546-
# Experimental: may produce smaller files.
547-
# xpdf intended for production of publication quality files,
548-
# but requires ghostscript, xpdf and ps2eps
549-
#ps.distiller.res : 6000 # dpi
550-
#ps.fonttype : 3 # Output Type 3 (Type3) or Type 42 (TrueType)
545+
#ps.usedistiller : None # can be: None, ghostscript or xpdf
546+
# Experimental: may produce smaller files.
547+
# xpdf intended for production of publication quality files,
548+
# but requires ghostscript, xpdf and ps2eps
549+
#ps.distiller.res : 6000 # dpi
550+
#ps.fonttype : 3 # Output Type 3 (Type3) or Type 42 (TrueType)
551551

552552
# pdf backend params
553553
#pdf.compression : 6 # integer from 0 to 9

0 commit comments

Comments
 (0)