Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with
or
.
Download ZIP

Loading…

replace cairo.format with savefig.format in rcParams #907

Merged
merged 6 commits into from

3 participants

@mspacek

I stumbled across this post on the mailing list from a while ago about creating an rcParams field that controls the default savefig filetype:

http://www.mail-archive.com/matplotlib-users@lists.sourceforge.net/msg23382.html

It was suggested that cairo.format be deprecated and replaced with a single rcParam that applies to all (relevant) backends. So here's my stab at it. savefig.format is a new key that's loaded by the base backend, and only overridden in backends that didn't default to .png as their hardcoded format (specifically, the PS, PDF, SVG, and EMF backends). Seems pretty straightforward, but I've only really tested this on the Qt4Agg backend, because that's all I use.

I only did this because I wanted to change the default savefig format from .png to .pdf in my matplotlibrc file, and now I can.

This also inadvertently replaced a few stray tabs with spaces in a couple of rc files.

By the way, the if len(be_parts) > 1 clause in __init__.py now raises a ValueError('FIXME: Not sure what to do here'), because I wasn't exactly sure what it was doing wrt cairo.format. But, I'm guessing the whole clause can be deleted. Am I right?

lib/matplotlib/rcsetup.py
@@ -251,9 +251,9 @@ def validate_font_properties(s):
'silent', 'helpful', 'debug', 'debug-annoying',
])
-validate_cairo_format = ValidateInStrings('cairo_format',
- ['png', 'ps', 'pdf', 'svg'],
- ignorecase=True)
+validate_savefig_format = ValidateInStrings('savefig_format',
+ ['png', 'ps', 'pdf', 'svg'],
@pelson Collaborator
pelson added a note

The problem with this, as far as I can see, is that you cannot guarantee what filetypes are valid until you know what backend is being used, and you cannot know what backend is being used until runtime. Therefore, for many of the backends, it would make sense for get_default_filetype to do something like:

def get_default_filetype(self):
    default = rcParams['savefig.format']
    if default in self.get_supported_filetypes().keys():
        return default
    else:
        return 'png'

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
@pelson pelson commented on the diff
lib/matplotlib/backend_bases.py
@@ -2067,7 +2067,7 @@ def print_figure(self, filename, dpi=None, facecolor='w', edgecolor='w',
def get_default_filetype(self):
@pelson Collaborator
pelson added a note

Based on my earlier comment, this method could really do with a docstring (whilst your there, get_supported_filetypes() and get_supported_filetypes_grouped() should get a docstring too, if possible).

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
@pelson pelson commented on the diff
doc/pyplots/matplotlibrc
@@ -266,8 +266,7 @@ figure.figsize : 6, 4 # figure size in inches
#savefig.dpi : 100 # figure dots per inch
#savefig.facecolor : white # figure facecolor when saving
#savefig.edgecolor : white # figure edgecolor when saving
-
-#cairo.format : png # png, ps, pdf, svg
+#savefig.format : png # png, ps, pdf, svg
@pelson Collaborator
pelson added a note

I'm not sure savefig.format falls in the same class of things as dpi, facecolor, edgecolor which applies to the plt.savefig function (I think) whereas format would only apply to GUI save dialogues.

Obviously, this is also breaking backwards compatibility, which at the best should be noted in the doc/api/api_changes.rst.

Would any devs care to suggest appropriate actions (if any) for these issues.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
lib/matplotlib/__init__.py
@@ -943,10 +942,7 @@ def use(arg, warn=True):
be_parts = arg.split('.')
name = validate_backend(be_parts[0])
if len(be_parts) > 1:
- if name == 'cairo':
- rcParams['cairo.format'] = validate_cairo_format(be_parts[1])
- else:
- raise ValueError('Only cairo backend has a format option')
+ raise ValueError('FIXME: Not sure what to do here')
@pelson Collaborator
pelson added a note

I've only just learnt of the matplotlib.use('cairo.pdf') style syntax, and IMHO its pretty ugly.

One of the important things that this is doing is limiting the default format in a Cairo backend to 'png', 'ps', 'pdf', 'svg' (I notice that this doesn't include the Cairo backend supported "svgz"), but, as far as I can see, this validation is handled automatically by the rcParams dictionary.

In which case, other than a few fewer keystrokes, I see no benefit to:

matplotlib.use('cairo.pdf')

over

matplotlib.use('cairo')
rcParams['savefig.format'] = 'pdf'

Therefore I propose that the Cairo backend be brought back into line with the other backends by removing the cariro.<format> syntax in matpltolib.use, by exposing a get_supported_filetypes on the Cairo backend, and by validating the default format at savefig time (as has been proposed for all backends further down this pull request).

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
@mdboom
Owner

I agree with @pelson's comments.

Some history here: the Cairo backend was initially the only backend that supported multiple output types, hence it has a special way of doing it. Much later I added support for saving PDF, PS, SVG etc. directly from any of the GUI backends without having to tinker with switching backends etc. I think the next step of removing Cairo's special way of doing things is probably a good idea. I think it's fine to make this kind of change on master, but it should have a CHANGELOG entry outlining the backward incompatibility.

@mdboom
Owner

Note also the existence of savefig.extension which determines the default filetype when using savefig, but not from the GUI dialog. I think savefig.extension and savefig.format should be merged into a single value -- better than having two values that do almost the save thing. (Or is there any benefit to setting it differently for GUI save dialogs and for calling savefig?)

What I think should happen here is that we deprecate savefig.extension (savefig.format is a better name). So setting savefig.extension raises a DeprecationWarning. If savefig.format is defined, it overrides the value of savefig.extension. If savefig.format is not defined, savefig.extension is used. In the next major release, we go back and remove all references to savefig.extension. All of that magic can be crammed into get_default_filetype. In addition, Figure.savefig should be updated to use get_default_filetype rather than accessing rcParams['savefig.extension'] directly.

@mspacek

@pelson, OK, file format in rcParams is checked at runtime now. I left validate_savefig_format() as is, not sure if that's correct. I added docstrings to get_default_filetype() and get_supported_filetypes(), but I'm not really sure what get_supported_filetypes_grouped does.

@mdboom, I think I've removed support for the cairo.<format> style of backend specificiation. I suppose CHANGELOG entries are added only right before merging? I'll see if I can combine savefig.extension with savefig.format

@mdboom
Owner

Looks good. You can feel free to add a CHANGELOG entry at any time, as long it tracks the current status of the pull request.

lib/matplotlib/backend_bases.py
@@ -2067,7 +2068,16 @@ def print_figure(self, filename, dpi=None, facecolor='w', edgecolor='w',
def get_default_filetype(self):
- raise NotImplementedError
+ """
+ Get the default savefig file format as specified in rcParams.
+ If invalid, use .png. Overridden in backends that only support
@pelson Collaborator
pelson added a note

I think this method's docstring should mention the rcParam that it uses (i.e. explicitly mention savefig.format).

Also, mention that the returning extension does not include the period, and change the If invalid, use .png to If invalid, use "png".

Finally, more at @mdboom, is this the behaviour that we actually want? For instance, if a user specifies "raw" to be the default filetype, shouldn't that be what they get, independent of which backend they are using for their GUI.

@mdboom Owner
mdboom added a note

@pelson: Any of the GUI backends should be able to save to any of the formats (the same doesn't hold true for non-GUI backends), so as per my other comment below, I think the savefig.format parameter should be unrestricted as to what it takes, and then let the backend decide whether it's valid at save time.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
@mspacek

That was a little tricky, but I think I've implemented everything that @mdboom suggested. The deprecation machinery was already there in rcsetup.py and __init__.py, so that's where the magic happens. Haven't examined that machinery much, but it seems to do what was desired.

Sorry about the annoying whitespace changes in api_changes.rst, but my editor replaces tabs with spaces by default, and that's probably something that should be done anyway.

lib/matplotlib/rcsetup.py
@@ -251,9 +251,12 @@ def validate_font_properties(s):
'silent', 'helpful', 'debug', 'debug-annoying',
])
-validate_cairo_format = ValidateInStrings('cairo_format',
- ['png', 'ps', 'pdf', 'svg'],
- ignorecase=True)
+def deprecate_savefig_extension(value):
+ warnings.warn("savefig.extension is deprecated. Use savefig.format instead.")
+
+validate_savefig_format = ValidateInStrings('savefig_format',
+ ['png', 'ps', 'pdf', 'svg'],
+ ignorecase=True)
@mdboom Owner
mdboom added a note

Should we limit ourselves here? As you pointed out, there's no way to know what the complete selection is until a backend has been selected, but it could include other things, such as emf, gif, jpg depending on the backend. I think it best to just make this "any string" and let it be verified by the backend upon saving.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
@mdboom
Owner

@mspacek: get_supported_filetypes_grouped returns a dictionary where each key is a logical filetype and the values are a list of extensions for that filetype. For example, {"Joint Photographic Experts Group": ['jpg', 'jpeg']}. Some GUI frameworks, eg. wx ang qt4, allow this kind of presentation in their save dialog. Others, eg. gtk, don't. So maybe the docstring could be:

Returns a dictionary of supported filetypes where the keys are a file type name, such as 'Joint Photographic Experts Group', and the values are a list of filename extensions used for that filetype, such as ['jpg', 'jpeg'].
@mdboom
Owner

Other than my comment about making the rcParam unrestricted in what it takes, this is really shaping up. Thanks. Would you also mind doing a rebase against current master so it will be automatically mergeable?

mspacek added some commits
@mspacek mspacek replace cairo.format with savefig.format in rcParams, apply to most b…
…ackends

replace some stray tabs with spaces
e58fa07
@mspacek mspacek check validity of savefig.format rcParam at runtime
remove support for 'cairo.pdf' type of backend specification
42002e2
@mspacek mspacek update CHANGELOG and get_default_filetype docstring 6d6da54
@mspacek mspacek replace stray tabs with spaces in api_changes.rst b822c26
@mspacek mspacek deprecate 'savefig.extension' rcParam in favour of 'savefig.format'
remove all mention of cairo.<format>
remove unnecessary check for supported formats in get_default_filetype, rely on check in _get_print_method instead
for uniformity, use get_supported_filetypes instead of directly accessing self.filetypes
8cdc0da
@mspacek mspacek allow any string for rcParams['savefig.format'], leave validity check…
… until runtime

add docstring
bec0a4a
@mspacek

I think the rcParams['savefig.format'] key is now unrestricted. Seems to properly report unsupported file types when calling savefig() or when saving from within the GUI window's save dialog, although I've noticed that for some reason my ipython seems to swallow the popup error dialog box when the format is unsupported. This doesn't happen when I'm running ipython qtconsole or just plain python. Not sure if that's a worry.

Also, I hope I've rebased properly against origin/master. Git stresses me out :)

@mdboom
Owner

This looks good to me. Merging.

@mdboom mdboom merged commit d17dbff into matplotlib:master
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Commits on Jun 3, 2012
  1. @mspacek

    replace cairo.format with savefig.format in rcParams, apply to most b…

    mspacek authored
    …ackends
    
    replace some stray tabs with spaces
  2. @mspacek

    check validity of savefig.format rcParam at runtime

    mspacek authored
    remove support for 'cairo.pdf' type of backend specification
  3. @mspacek
  4. @mspacek
  5. @mspacek

    deprecate 'savefig.extension' rcParam in favour of 'savefig.format'

    mspacek authored
    remove all mention of cairo.<format>
    remove unnecessary check for supported formats in get_default_filetype, rely on check in _get_print_method instead
    for uniformity, use get_supported_filetypes instead of directly accessing self.filetypes
  6. @mspacek

    allow any string for rcParams['savefig.format'], leave validity check…

    mspacek authored
    … until runtime
    
    add docstring
This page is out of date. Refresh to see the latest.
View
4 CHANGELOG
@@ -1,5 +1,9 @@
2012-06-02 Add new Axes method and pyplot function, hist2d. - PO
+2012-05-31 Remove support for 'cairo.<format>' style of backend specification.
+ Deprecate 'cairo.format' and 'savefig.extension' rcParams and
+ replace with 'savefig.format'. - Martin Spacek
+
2012-05-29 pcolormesh now obeys the passed in "edgecolor" kwarg.
To support this, the "shading" argument to pcolormesh now only
takes "flat" or "gouraud". To achieve the old "faceted" behavior,
View
50 doc/api/api_changes.rst
@@ -14,6 +14,10 @@ For new features that were added to matplotlib, please see
Changes in 1.2.x
================
+* The new rc parameter ``savefig.format`` replaces ``cairo.format`` and
+ ``savefig.extension``, and sets the default file format used by
+ :meth:`matplotlib.figure.Figure.savefig`.
+
* In :meth:`~matplotlib.pyplot.pie` and :meth:`~matplotlib.Axes.pie`, one can
now set the radius of the pie; setting the *radius* to 'None' (the default
value), will result in a pie with a radius of 1 as before.
@@ -237,7 +241,7 @@ Changes for 0.98.x
labelsep labelspacing
handlelen handlelength
handlestextsep handletextpad
- axespad borderaxespad
+ axespad borderaxespad
================ ================
@@ -405,51 +409,51 @@ Old method New method
------------------------------------------------------------ ------------------------------------------------------------
:meth:`Bbox.height` :attr:`transforms.Bbox.height`
------------------------------------------------------------ ------------------------------------------------------------
-`Bbox.intervalx().get_bounds()` :attr:`transforms.Bbox.intervalx`
+`Bbox.intervalx().get_bounds()` :attr:`transforms.Bbox.intervalx`
`Bbox.intervalx().set_bounds()` [:attr:`Bbox.intervalx` is now a property.]
------------------------------------------------------------ ------------------------------------------------------------
-`Bbox.intervaly().get_bounds()` :attr:`transforms.Bbox.intervaly`
+`Bbox.intervaly().get_bounds()` :attr:`transforms.Bbox.intervaly`
`Bbox.intervaly().set_bounds()` [:attr:`Bbox.intervaly` is now a property.]
------------------------------------------------------------ ------------------------------------------------------------
-:meth:`Bbox.xmin` :attr:`transforms.Bbox.x0` or
+:meth:`Bbox.xmin` :attr:`transforms.Bbox.x0` or
:attr:`transforms.Bbox.xmin` [1]_
------------------------------------------------------------ ------------------------------------------------------------
-:meth:`Bbox.ymin` :attr:`transforms.Bbox.y0` or
+:meth:`Bbox.ymin` :attr:`transforms.Bbox.y0` or
:attr:`transforms.Bbox.ymin` [1]_
------------------------------------------------------------ ------------------------------------------------------------
-:meth:`Bbox.xmax` :attr:`transforms.Bbox.x1` or
+:meth:`Bbox.xmax` :attr:`transforms.Bbox.x1` or
:attr:`transforms.Bbox.xmax` [1]_
------------------------------------------------------------ ------------------------------------------------------------
-:meth:`Bbox.ymax` :attr:`transforms.Bbox.y1` or
+:meth:`Bbox.ymax` :attr:`transforms.Bbox.y1` or
:attr:`transforms.Bbox.ymax` [1]_
------------------------------------------------------------ ------------------------------------------------------------
-`Bbox.overlaps(bboxes)` `Bbox.count_overlaps(bboxes)`
+`Bbox.overlaps(bboxes)` `Bbox.count_overlaps(bboxes)`
------------------------------------------------------------ ------------------------------------------------------------
-`bbox_all(bboxes)` `Bbox.union(bboxes)`
+`bbox_all(bboxes)` `Bbox.union(bboxes)`
[:meth:`transforms.Bbox.union` is a staticmethod.]
------------------------------------------------------------ ------------------------------------------------------------
-`lbwh_to_bbox(l, b, w, h)` `Bbox.from_bounds(x0, y0, w, h)`
+`lbwh_to_bbox(l, b, w, h)` `Bbox.from_bounds(x0, y0, w, h)`
[:meth:`transforms.Bbox.from_bounds` is a staticmethod.]
------------------------------------------------------------ ------------------------------------------------------------
`inverse_transform_bbox(trans, bbox)` `Bbox.inverse_transformed(trans)`
------------------------------------------------------------ ------------------------------------------------------------
-`Interval.contains_open(v)` `interval_contains_open(tuple, v)`
+`Interval.contains_open(v)` `interval_contains_open(tuple, v)`
------------------------------------------------------------ ------------------------------------------------------------
-`Interval.contains(v)` `interval_contains(tuple, v)`
+`Interval.contains(v)` `interval_contains(tuple, v)`
------------------------------------------------------------ ------------------------------------------------------------
-`identity_transform()` :class:`matplotlib.transforms.IdentityTransform`
+`identity_transform()` :class:`matplotlib.transforms.IdentityTransform`
------------------------------------------------------------ ------------------------------------------------------------
`blend_xy_sep_transform(xtrans, ytrans)` `blended_transform_factory(xtrans, ytrans)`
------------------------------------------------------------ ------------------------------------------------------------
-`scale_transform(xs, ys)` `Affine2D().scale(xs[, ys])`
+`scale_transform(xs, ys)` `Affine2D().scale(xs[, ys])`
------------------------------------------------------------ ------------------------------------------------------------
-`get_bbox_transform(boxin, boxout)` `BboxTransform(boxin, boxout)` or
- `BboxTransformFrom(boxin)` or
- `BboxTransformTo(boxout)`
+`get_bbox_transform(boxin, boxout)` `BboxTransform(boxin, boxout)` or
+ `BboxTransformFrom(boxin)` or
+ `BboxTransformTo(boxout)`
------------------------------------------------------------ ------------------------------------------------------------
-`Transform.seq_xy_tup(points)` `Transform.transform(points)`
+`Transform.seq_xy_tup(points)` `Transform.transform(points)`
------------------------------------------------------------ ------------------------------------------------------------
-`Transform.inverse_xy_tup(points)` `Transform.inverted().transform(points)`
+`Transform.inverse_xy_tup(points)` `Transform.inverted().transform(points)`
============================================================ ============================================================
.. [1] The :class:`~matplotlib.transforms.Bbox` is bound by the points
@@ -492,7 +496,7 @@ The :class:`Polar` class has moved to :mod:`matplotlib.projections.polar`.
============================================================ ============================================================
Old method New method
============================================================ ============================================================
-`Artist.set_clip_path(path)` `Artist.set_clip_path(path, transform)` [5]_
+`Artist.set_clip_path(path)` `Artist.set_clip_path(path, transform)` [5]_
============================================================ ============================================================
.. [5] :meth:`matplotlib.artist.Artist.set_clip_path` now accepts a
@@ -519,7 +523,7 @@ Old method New method
============================================================ ============================================================
Old method New method
============================================================ ============================================================
-`ColorConvertor.to_rgba_list(c)` `ColorConvertor.to_rgba_array(c)`
+`ColorConvertor.to_rgba_list(c)` `ColorConvertor.to_rgba_array(c)`
[:meth:`matplotlib.colors.ColorConvertor.to_rgba_array`
returns an Nx4 Numpy array of RGBA color quadruples.]
============================================================ ============================================================
@@ -530,7 +534,7 @@ Old method New method
============================================================ ============================================================
Old method New method
============================================================ ============================================================
-`Contour._segments` :meth:`matplotlib.contour.Contour.get_paths`` [Returns a
+`Contour._segments` :meth:`matplotlib.contour.Contour.get_paths`` [Returns a
list of :class:`matplotlib.path.Path` instances.]
============================================================ ============================================================
@@ -540,7 +544,7 @@ Old method New method
============================================================ ============================================================
Old method New method
============================================================ ============================================================
-`Figure.dpi.get()` / `Figure.dpi.set()` :attr:`matplotlib.figure.Figure.dpi` *(a property)*
+`Figure.dpi.get()` / `Figure.dpi.set()` :attr:`matplotlib.figure.Figure.dpi` *(a property)*
============================================================ ============================================================
:mod:`matplotlib.patches`
View
25 doc/pyplots/matplotlibrc
@@ -59,10 +59,10 @@ backend : Agg
# circles. See
# http://matplotlib.sourceforge.net/matplotlib.patches.html for more
# information on patch properties
-#patch.linewidth : 1.0 # edge width in points
-#patch.facecolor : blue
-#patch.edgecolor : black
-#patch.antialiased : True # render patches in antialised (no jaggies)
+#patch.linewidth : 1.0 # edge width in points
+#patch.facecolor : blue
+#patch.edgecolor : black
+#patch.antialiased : True # render patches in antialised (no jaggies)
### FONT
#
@@ -152,11 +152,11 @@ backend : Agg
#text.markup : 'plain' # Affects how text, such as titles and labels, are
# interpreted by default.
# 'plain': As plain, unformatted text
- # 'tex': As TeX-like text. Text between $'s will be
- # formatted as a TeX math expression.
- # This setting has no effect when text.usetex is True.
- # In that case, all text will be sent to TeX for
- # processing.
+ # 'tex': As TeX-like text. Text between $'s will be
+ # formatted as a TeX math expression.
+ # This setting has no effect when text.usetex is True.
+ # In that case, all text will be sent to TeX for
+ # processing.
# The following settings allow you to select the fonts in math mode.
# They map from a TeX font name to a fontconfig font pattern.
@@ -170,8 +170,8 @@ backend : Agg
#mathtext.fontset : cm # Should be 'cm' (Computer Modern), 'stix',
# 'stixsans' or 'custom'
#mathtext.fallback_to_cm : True # When True, use symbols from the Computer Modern
- # fonts when a symbol can not be found in one of
- # the custom math fonts.
+ # fonts when a symbol can not be found in one of
+ # the custom math fonts.
### AXES
# default face and edge color, default tick sizes,
@@ -266,8 +266,7 @@ figure.figsize : 6, 4 # figure size in inches
#savefig.dpi : 100 # figure dots per inch
#savefig.facecolor : white # figure facecolor when saving
#savefig.edgecolor : white # figure edgecolor when saving
-
-#cairo.format : png # png, ps, pdf, svg
+#savefig.format : png # png, ps, pdf, svg
@pelson Collaborator
pelson added a note

I'm not sure savefig.format falls in the same class of things as dpi, facecolor, edgecolor which applies to the plt.savefig function (I think) whereas format would only apply to GUI save dialogues.

Obviously, this is also breaking backwards compatibility, which at the best should be noted in the doc/api/api_changes.rst.

Would any devs care to suggest appropriate actions (if any) for these issues.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
# tk backend params
#tk.window_focus : False # Maintain shell focus for TkAgg
View
11 examples/tests/backend_driver.py
@@ -9,11 +9,10 @@
switch, which takes a comma-separated list, or as separate arguments,
e.g.
- python backend_driver.py agg ps cairo.png cairo.ps
+ python backend_driver.py agg ps
-would test the agg and ps backends, and the cairo backend with output
-to png and ps files. If no arguments are given, a default list of
-backends will be tested.
+would test the agg and ps backends. If no arguments are given, a
+default list of backends will be tested.
Interspersed with the backend arguments can be switches for the Python
interpreter executing the tests. If entering such arguments causes an
@@ -27,7 +26,6 @@
from matplotlib.cbook import Bunch, dedent
all_backends = list(rcsetup.all_backends) # to leave the original list alone
-all_backends.extend(['cairo.png', 'cairo.ps', 'cairo.pdf', 'cairo.svg'])
# actual physical directory for each dir
dirs = dict(pylab = os.path.join('..', 'pylab_examples'),
@@ -408,8 +406,7 @@ def parse_options():
help=dedent('''
Run tests only for these backends; comma-separated list of
one or more of: agg, ps, svg, pdf, template, cairo,
- cairo.png, cairo.ps, cairo.pdf, cairo.svg. Default is everything
- except cairo.'''))
+ Default is everything except cairo.'''))
op.add_option('--clean', action='store_true', dest='clean',
help='Remove result directories, run no tests')
op.add_option('-c', '--coverage', action='store_true', dest='coverage',
View
22 lib/matplotlib/__init__.py
@@ -144,8 +144,7 @@ def byte2str(b): return b
from matplotlib.rcsetup import (defaultParams,
validate_backend,
- validate_toolbar,
- validate_cairo_format)
+ validate_toolbar)
major, minor1, minor2, s, tmp = sys.version_info
_python24 = (major == 2 and minor1 >= 4) or major >= 3
@@ -631,7 +630,8 @@ def matplotlib_fname():
'text.fontweight': 'font.weight',
'text.fontsize': 'font.size',
'tick.size' : 'tick.major.size',
- 'svg.embed_char_paths' : 'svg.fonttype'
+ 'svg.embed_char_paths' : 'svg.fonttype',
+ 'savefig.extension' : 'savefig.format'
}
_deprecated_ignore_map = {
@@ -909,13 +909,7 @@ def use(arg, warn=True):
"""
Set the matplotlib backend to one of the known backends.
- The argument is case-insensitive. For the Cairo backend,
- the argument can have an extension to indicate the type of
- output. Example:
-
- use('cairo.pdf')
-
- will specify a default of pdf output generated by Cairo.
+ The argument is case-insensitive.
.. note::
@@ -940,13 +934,7 @@ def use(arg, warn=True):
else:
# Lowercase only non-module backend names (modules are case-sensitive)
arg = arg.lower()
- be_parts = arg.split('.')
- name = validate_backend(be_parts[0])
- if len(be_parts) > 1:
- if name == 'cairo':
- rcParams['cairo.format'] = validate_cairo_format(be_parts[1])
- else:
- raise ValueError('Only cairo backend has a format option')
+ name = validate_backend(arg)
rcParams['backend'] = name
def get_backend():
View
21 lib/matplotlib/backend_bases.py
@@ -1897,9 +1897,14 @@ def print_tif(self, filename_or_obj, *args, **kwargs):
print_tiff = print_tif
def get_supported_filetypes(self):
+ """Return dict of savefig file formats supported by this backend"""
return self.filetypes
def get_supported_filetypes_grouped(self):
+ """Return a dict of savefig file formats supported by this backend,
+ where the keys are a file type name, such as 'Joint Photographic
+ Experts Group', and the values are a list of filename extensions used
+ for that filetype, such as ['jpg', 'jpeg']."""
groupings = {}
for ext, name in self.filetypes.iteritems():
groupings.setdefault(name, []).append(ext)
@@ -1921,10 +1926,9 @@ def _print_method(*args, **kwargs):
return _print_method
- if (format not in self.filetypes or
- not hasattr(self, method_name)):
- formats = self.filetypes.keys()
- formats.sort()
+ formats = self.get_supported_filetypes()
+ if (format not in formats or not hasattr(self, method_name)):
+ formats = sorted(formats)
raise ValueError(
'Format "%s" is not supported.\n'
'Supported formats: '
@@ -1964,7 +1968,6 @@ def print_figure(self, filename, dpi=None, facecolor='w', edgecolor='w',
*format*
when set, forcibly set the file format to save to
-
*bbox_inches*
Bbox in inches. Only the given portion of the figure is
saved. If 'tight', try to figure out the tight bbox of
@@ -1980,6 +1983,7 @@ def print_figure(self, filename, dpi=None, facecolor='w', edgecolor='w',
"""
if format is None:
+ # get format from filename, or from backend's default filetype
if cbook.is_string_like(filename):
format = os.path.splitext(filename)[1][1:]
if format is None or format == '':
@@ -2078,7 +2082,12 @@ def print_figure(self, filename, dpi=None, facecolor='w', edgecolor='w',
def get_default_filetype(self):
@pelson Collaborator
pelson added a note

Based on my earlier comment, this method could really do with a docstring (whilst your there, get_supported_filetypes() and get_supported_filetypes_grouped() should get a docstring too, if possible).

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
- raise NotImplementedError
+ """
+ Get the default savefig file format as specified in rcParam
+ ``savefig.format``. Returned string excludes period. Overridden
+ in backends that only support a single file type.
+ """
+ return rcParams['savefig.format']
def set_window_title(self, title):
"""
View
3  lib/matplotlib/backends/backend_agg.py
@@ -463,9 +463,6 @@ def buffer_rgba(self):
'debug-annoying')
return self.renderer.buffer_rgba()
- def get_default_filetype(self):
- return 'png'
-
def print_raw(self, filename_or_obj, *args, **kwargs):
FigureCanvasAgg.draw(self)
renderer = self.get_renderer()
View
4 lib/matplotlib/backends/backend_cairo.py
@@ -46,7 +46,6 @@ def _fn_name(): return sys._getframe(1).f_code.co_name
from matplotlib.path import Path
from matplotlib.transforms import Bbox, Affine2D
from matplotlib.font_manager import ttfFontProperty
-from matplotlib import rcParams
_debug = False
#_debug = True
@@ -430,9 +429,6 @@ def print_svg(self, fobj, *args, **kwargs):
def print_svgz(self, fobj, *args, **kwargs):
return self._save(fobj, 'svgz', *args, **kwargs)
- def get_default_filetype(self):
- return rcParams['cairo.format']
-
def _save (self, fo, format, **kwargs):
# save PDF/PS/SVG
orientation = kwargs.get('orientation', 'portrait')
View
4 lib/matplotlib/backends/backend_gdk.py
@@ -28,7 +28,6 @@ def fn_name(): return sys._getframe(1).f_code.co_name
from matplotlib.transforms import Affine2D
from matplotlib.backends._backend_gdk import pixbuf_get_pixels_array
-
backend_version = "%d.%d.%d" % gtk.pygtk_version
_debug = False
@@ -465,6 +464,3 @@ def _print_image(self, filename, format, *args, **kwargs):
0, 0, 0, 0, width, height)
pixbuf.save(filename, format)
-
- def get_default_filetype(self):
- return 'png'
View
12 lib/matplotlib/backends/backend_gtk.py
@@ -40,6 +40,7 @@ def fn_name(): return sys._getframe(1).f_code.co_name
from matplotlib import markers
from matplotlib import cbook
from matplotlib import verbose
+from matplotlib import rcParams
backend_version = "%d.%d.%d" % gtk.pygtk_version
@@ -474,9 +475,6 @@ def save_callback(buf, data=None):
else:
raise ValueError("filename must be a path or a file-like object")
- def get_default_filetype(self):
- return 'png'
-
def new_timer(self, *args, **kwargs):
"""
Creates a new backend-specific subclass of :class:`backend_bases.Timer`.
@@ -606,9 +604,9 @@ def full_screen_toggle (self):
def _get_toolbar(self, canvas):
# must be inited after the window, drawingArea and figure
# attrs are set
- if matplotlib.rcParams['toolbar'] == 'classic':
+ if rcParams['toolbar'] == 'classic':
toolbar = NavigationToolbar (canvas, self.window)
- elif matplotlib.rcParams['toolbar'] == 'toolbar2':
+ elif rcParams['toolbar'] == 'toolbar2':
toolbar = NavigationToolbar2GTK (canvas, self.window)
else:
toolbar = None
@@ -698,7 +696,7 @@ def _init_toolbar(self):
def _init_toolbar2_4(self):
- basedir = os.path.join(matplotlib.rcParams['datapath'],'images')
+ basedir = os.path.join(rcParams['datapath'],'images')
if not _new_tooltip_api:
self.tooltips = gtk.Tooltips()
@@ -1257,7 +1255,7 @@ def on_dialog_lineprops_cancelbutton_clicked(self, button):
icon_filename = 'matplotlib.png'
else:
icon_filename = 'matplotlib.svg'
- window_icon = os.path.join(matplotlib.rcParams['datapath'], 'images', icon_filename)
+ window_icon = os.path.join(rcParams['datapath'], 'images', icon_filename)
except:
window_icon = None
verbose.report('Could not load matplotlib icon: %s' % sys.exc_info()[1])
View
12 lib/matplotlib/backends/backend_gtk3.py
@@ -22,6 +22,7 @@ def fn_name(): return sys._getframe(1).f_code.co_name
from matplotlib import lines
from matplotlib import cbook
from matplotlib import verbose
+from matplotlib import rcParams
backend_version = "%s.%s.%s" % (Gtk.get_major_version(), Gtk.get_micro_version(), Gtk.get_minor_version())
@@ -303,9 +304,6 @@ def idle_draw(*args):
if self._idle_draw_id == 0:
self._idle_draw_id = GObject.idle_add(idle_draw)
- def get_default_filetype(self):
- return 'png'
-
def new_timer(self, *args, **kwargs):
"""
Creates a new backend-specific subclass of :class:`backend_bases.Timer`.
@@ -435,9 +433,9 @@ def full_screen_toggle (self):
def _get_toolbar(self, canvas):
# must be inited after the window, drawingArea and figure
# attrs are set
- if matplotlib.rcParams['toolbar'] == 'classic':
+ if rcParams['toolbar'] == 'classic':
toolbar = NavigationToolbar (canvas, self.window)
- elif matplotlib.rcParams['toolbar'] == 'toolbar2':
+ elif rcParams['toolbar'] == 'toolbar2':
toolbar = NavigationToolbar2GTK3 (canvas, self.window)
else:
toolbar = None
@@ -512,7 +510,7 @@ def draw_rubberband(self, event, x0, y0, x1, y1):
def _init_toolbar(self):
self.set_style(Gtk.ToolbarStyle.ICONS)
- basedir = os.path.join(matplotlib.rcParams['datapath'],'images')
+ basedir = os.path.join(rcParams['datapath'],'images')
for text, tooltip_text, image_file, callback in self.toolitems:
if text is None:
@@ -1055,7 +1053,7 @@ def on_dialog_lineprops_cancelbutton_clicked(self, button):
icon_filename = 'matplotlib.png'
else:
icon_filename = 'matplotlib.svg'
- window_icon = os.path.join(matplotlib.rcParams['datapath'], 'images', icon_filename)
+ window_icon = os.path.join(rcParams['datapath'], 'images', icon_filename)
except:
window_icon = None
verbose.report('Could not load matplotlib icon: %s' % sys.exc_info()[1])
View
15 lib/matplotlib/backends/backend_macosx.py
@@ -13,7 +13,7 @@
from matplotlib.path import Path
from matplotlib.mathtext import MathTextParser
from matplotlib.colors import colorConverter
-
+from matplotlib import rcParams
from matplotlib.widgets import SubplotTool
@@ -225,7 +225,7 @@ def draw_if_interactive():
it will be redrawn as soon as the event loop resumes via PyOS_InputHook.
This function should be called after each draw event, even if
matplotlib is not running interactively.
- """
+ """
if matplotlib.is_interactive():
figManager = Gcf.get_active()
if figManager is not None:
@@ -330,9 +330,6 @@ def print_tiff(self, filename, *args, **kwargs):
def print_gif(self, filename, *args, **kwargs):
self._print_bitmap(filename, *args, **kwargs)
- def get_default_filetype(self):
- return 'png'
-
def new_timer(self, *args, **kwargs):
"""
Creates a new backend-specific subclass of :class:`backend_bases.Timer`.
@@ -357,9 +354,9 @@ def __init__(self, canvas, num):
FigureManagerBase.__init__(self, canvas, num)
title = "Figure %d" % num
_macosx.FigureManager.__init__(self, canvas, title)
- if matplotlib.rcParams['toolbar']=='classic':
+ if rcParams['toolbar']=='classic':
self.toolbar = NavigationToolbarMac(canvas)
- elif matplotlib.rcParams['toolbar']=='toolbar2':
+ elif rcParams['toolbar']=='toolbar2':
self.toolbar = NavigationToolbar2Mac(canvas)
else:
self.toolbar = None
@@ -384,7 +381,7 @@ class NavigationToolbarMac(_macosx.NavigationToolbar):
def __init__(self, canvas):
self.canvas = canvas
- basedir = os.path.join(matplotlib.rcParams['datapath'], "images")
+ basedir = os.path.join(rcParams['datapath'], "images")
images = {}
for imagename in ("stock_left",
"stock_right",
@@ -453,7 +450,7 @@ def __init__(self, canvas):
NavigationToolbar2.__init__(self, canvas)
def _init_toolbar(self):
- basedir = os.path.join(matplotlib.rcParams['datapath'], "images")
+ basedir = os.path.join(rcParams['datapath'], "images")
_macosx.NavigationToolbar2.__init__(self, basedir)
def draw_rubberband(self, event, x0, y0, x1, y1):
View
7 lib/matplotlib/backends/backend_wx.py
@@ -1190,9 +1190,6 @@ def _print_image(self, filename, filetype, *args, **kwargs):
self.draw()
self.Refresh()
- def get_default_filetype(self):
- return 'png'
-
def _onPaint(self, evt):
"""
Called when wxPaintEvt is generated
@@ -1513,9 +1510,9 @@ def __init__(self, num, fig):
bind(self, wx.EVT_CLOSE, self._onClose)
def _get_toolbar(self, statbar):
- if matplotlib.rcParams['toolbar']=='classic':
+ if rcParams['toolbar']=='classic':
toolbar = NavigationToolbarWx(self.canvas, True)
- elif matplotlib.rcParams['toolbar']=='toolbar2':
+ elif rcParams['toolbar']=='toolbar2':
toolbar = NavigationToolbar2Wx(self.canvas)
toolbar.set_status_bar(statbar)
else:
View
8 lib/matplotlib/figure.py
@@ -1110,8 +1110,7 @@ def savefig(self, *args, **kwargs):
If *format* is *None* and *fname* is a string, the output
format is deduced from the extension of the filename. If
the filename has no extension, the value of the rc parameter
- ``savefig.extension`` is used. If that value is 'auto',
- the backend determines the extension.
+ ``savefig.format`` is used.
If *fname* is not a string, remember to specify *format* to
ensure that the correct backend is used.
@@ -1163,11 +1162,6 @@ def savefig(self, *args, **kwargs):
kwargs.setdefault('dpi', rcParams['savefig.dpi'])
- extension = rcParams['savefig.extension']
- if args and is_string_like(args[0]) and '.' not in os.path.splitext(args[0])[-1] and extension != 'auto':
- fname = args[0] + '.' + extension
- args = (fname,) + args[1:]
-
transparent = kwargs.pop('transparent', False)
if transparent:
kwargs.setdefault('facecolor', 'none')
View
9 lib/matplotlib/rcsetup.py
@@ -251,9 +251,8 @@ def validate_font_properties(s):
'silent', 'helpful', 'debug', 'debug-annoying',
])
-validate_cairo_format = ValidateInStrings('cairo_format',
- ['png', 'ps', 'pdf', 'svg'],
- ignorecase=True)
+def deprecate_savefig_extension(value):
+ warnings.warn("savefig.extension is deprecated. Use savefig.format instead.")
validate_ps_papersize = ValidateInStrings('ps_papersize',[
'auto', 'letter', 'legal', 'ledger',
@@ -546,9 +545,9 @@ def __call__(self, s):
'savefig.facecolor' : ['w', validate_color], # facecolor; white
'savefig.edgecolor' : ['w', validate_color], # edgecolor; white
'savefig.orientation' : ['portrait', validate_orientation], # edgecolor; white
- 'savefig.extension' : ['auto', str], # what to add to extensionless filenames
+ 'savefig.extension' : ['png', deprecate_savefig_extension], # what to add to extensionless filenames
+ 'savefig.format' : ['png', str], # value checked by backend at runtime
- 'cairo.format' : ['png', validate_cairo_format],
'tk.window_focus' : [False, validate_bool], # Maintain shell focus for TkAgg
'tk.pythoninspect' : [False, validate_tkpythoninspect], # obsolete
'ps.papersize' : ['letter', validate_ps_papersize], # Set the papersize/type
View
8 matplotlibrc.template
@@ -347,9 +347,7 @@ text.hinting_factor : 8 # Specifies the amount of softness for hinting in the
#savefig.dpi : 100 # figure dots per inch
#savefig.facecolor : white # figure facecolor when saving
#savefig.edgecolor : white # figure edgecolor when saving
-#savefig.extension : auto # what extension to use for savefig('foo'), or 'auto'
-
-#cairo.format : png # png, ps, pdf, svg
+#savefig.format : png # png, ps, pdf, svg
# tk backend params
#tk.window_focus : False # Maintain shell focus for TkAgg
@@ -434,8 +432,8 @@ text.hinting_factor : 8 # Specifies the amount of softness for hinting in the
# -1 implies let utility auto-determine
#animation.frame_format: 'png' # Controls frame format used by temp files
#animation.ffmpeg_path: 'ffmpeg' # Path to ffmpeg binary. Without full path
- # $PATH is searched
+ # $PATH is searched
#animation.ffmpeg_args: '' # Additional arugments to pass to mencoder
#animation.mencoder_path: 'ffmpeg' # Path to mencoder binary. Without full path
- # $PATH is searched
+ # $PATH is searched
#animation.mencoder_args: '' # Additional arugments to pass to mencoder
Something went wrong with that request. Please try again.