Skip to content

Interactive save should respect 'savefig.facecolor' rcParam. #3437

Closed

Description

@u55

Hi matplotlib developers,

Currently, there is no way to set the figure facecolor when saving a figure interactively via the NavigationToolbar2 graphical save button. All interactive backends, that I have tested, default to a white facecolor while ignoring the 'savefig.facecolor' rcParam. I propose to change this behavior such that every backend will respect the 'savefig.facecolor' rcParam.

One possible option would be to edit the save_figure method of each backend-specific class which inherits from matplotlib.backend_bases.NavigationToolbar2 in every backend. This seems tedious.

Another option would be to edit the print_figure method in matplotlib.backend_bases.FigureCanvasBase, which every backend inherits from. This seems simpler.

For instance, adding the following indicated lines to matplotlib.backend_bases.FigureCanvasBase.print_figure works for me.

def print_figure(self, filename, dpi=None, facecolor=None, edgecolor='w', # <---- facecolor default changed to None
                     orientation='portrait', format=None, **kwargs):

    ...

    if dpi is None:
        dpi = rcParams['savefig.dpi']

    if facecolor is None:  #  <---- added
        facecolor = rcParams['savefig.facecolor']  # <---- added

    origDPI = self.figure.dpi
    origfacecolor = self.figure.get_facecolor()
    origedgecolor = self.figure.get_edgecolor()

    self.figure.dpi = dpi
    self.figure.set_facecolor(facecolor)
    self.figure.set_edgecolor(edgecolor)

    ...

I don't use a custom 'edgecolor' often, but the interactive figure saving functionality should also be changed to use the 'savefig.edgecolor' rcParam.

I would be happy to create a pull request if the developers agree that this change is a good idea.
Thank you.

Activity

  1. efiring commented on Aug 30, 2014

    @efiring
    Member

    Good point; I agree, the rcParams should be respected. I wonder, though, whether what is really needed is a little refactoring. It looks like the correct logic is in Figure.savefig, which also handles the savefig.transparent option. Why do we need both Figure.savefig and backend_bases.print_figure with such similar signatures and docstrings? It is hard to follow the trail of what gets called when a figure is saved; and it seems like saving a figure via the Toolbar should be able to take advantage of the same code that is invoked by explicitly calling Figure.savefig.

  2. u55 commented on Aug 31, 2014

    @u55
    ContributorAuthor

    Hi Eric,

    I'm not sure if your question was directed at me or other developers. The matplotlib.figure.Figure.savefig method ends up calling the backend's print_figure method via the call:

    self.canvas.print_figure(*args, **kwargs)

    So the logic which implements the rcParams could be moved from matplotlib.figure.Figure.savefig to matplotlib.backend_bases.FigureCanvasBase.print_figure. But this will only work if each and every interactive and non-interactive backend uses the matplotlib.backend_bases.FigureCanvasBase.print_figure method that it inherits instead of implementing its own print_figure method. I'm not sure if this is a safe thing to depend on.

  3. added this to the milestone on Sep 1, 2014
  4. braxtonj commented on May 21, 2015

    @braxtonj

    Has anyone found a workaround for this in the meantime? No matter what I try, my interactive plots are saving with a white background which makes all of the labels completely unreadable. Do I have to waste time redesigning my color scheme or can someone point me in the right direction.

    This is what I have thusfar:

    lib_mpl.rcParams['savefig.dpi'] = graphDPI
    lib_mpl.rcParams['savefig.facecolor'] = figbgColor
    lib_mpl.rcParams['savefig.edgecolor'] = figbgColor
    f,ax = lib_plt.subplots(facecolor=figbgColor)

    The dpi works just find but not the savefig.facecolor nor savefig.edgecolor

    Thanks,
    Braxton

  5. u55 commented on May 23, 2015

    @u55
    ContributorAuthor

    @braxtonj, I believe that the only two workarounds are: (1) save the figure programmatically via the savefig method rather than saving interactively, or (2) modify the source code to the file matplotlib.backend_bases.FigureCanvasBase.print_figure as suggested in my first post.

  6. tacaswell commented on May 23, 2015

    @tacaswell
    Member

    @u55 Can you put in a PR with that change?

  7. mgrady3 commented on Aug 3, 2015

    @mgrady3

    Has any further work been done on this PR?

    I know there's a major update to mpl in the works (heard about it in various pycon/scipy talks).
    Will this issue be addressed in the next edition of mpl?

    For GUI programs that are already using the built in mpl toolbar it would be nice to have the savefig button on the toolbar respect rcParams rather than having to manually add another GUI element to place a call programmatically to savefig() for the sole purpose of changing the facecolor of the saved image and thus essentially having a dead item in the built in toolbar ...

  8. modified the milestones: , on Aug 3, 2015
  9. tacaswell commented on Aug 30, 2015

    @tacaswell
    Member

    ping @u55

  10. modified the milestones: , on Oct 8, 2015
  11. self-assigned this
    on Mar 21, 2016
  12. tacaswell commented on Mar 28, 2016

    @tacaswell
    Member

    closed by #6197

  13. self-assigned this
    on Mar 28, 2016
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

Labels

API: consistencyConsistency of the matplotlib API, including naming, behavior, defaults, …API: default changesChanges to default behaviortopic: rcparams

Type

No type

Projects

No projects

    Milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions