Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

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

Closed
u55 opened this issue Aug 30, 2014 · 8 comments
Closed

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

u55 opened this issue Aug 30, 2014 · 8 comments

Comments

@u55
Copy link
Contributor

u55 commented Aug 30, 2014

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.

@efiring
Copy link
Member

efiring commented Aug 30, 2014

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.

@u55
Copy link
Contributor Author

u55 commented Aug 31, 2014

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.

@tacaswell tacaswell added this to the v1.5.x milestone Sep 1, 2014
@braxtonj
Copy link

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

@u55
Copy link
Contributor Author

u55 commented May 23, 2015

@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.

@tacaswell
Copy link
Member

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

@mgrady3
Copy link

mgrady3 commented Aug 3, 2015

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 ...

@tacaswell tacaswell modified the milestones: Color overhaul, proposed next point release Aug 3, 2015
@tacaswell
Copy link
Member

ping @u55

@mdboom mdboom modified the milestones: Color overhaul, next major release (2.0) Oct 8, 2015
@tacaswell tacaswell self-assigned this Mar 21, 2016
@tacaswell
Copy link
Member

closed by #6197

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

6 participants