28

Problem

I cannot seem to get savefig() to actually save a PNG file without a transparent figure background.

This is having read and tried all the suggestions previously posted, answered, cursed about and also going through the API docs a bunch of times. I've read it all, but still can't get non-transparent figure faces

Background

I'm using matplotlib and savefig to create a PNG file. (env: macos - latest anaconda modules using PY 3.7).

I am trying this out of jupyter however - so hopefully it's not something completely screwed up with only how ipython in jupyter does it - though I don't see how that could be the case

I did read through the previous many posts about the (confusing as hell) nature of savefig doing it's own thing with backgrounds, and did/tried everything as suggested (and as written in the latest savefig api docs).

In particular, I've tried all the following without sucess:

  • specifying facecolor in the savefig() call (with/without transparency)
  • savefig.facecolor: white in the style mpl file I'm using

When savefig'ing my figure background is always transparent.


Can anyone tell me what the !@#$!# I'm missing here???

Code

Here's what I''m using, which spits out figure with transparent background, regardless of what I do.

In particular the 2nd call below (with savefig(..., transparent=False)) will make the axes not transparent - but the figure itself is still transparent!)

import numpy as np
import matplotlib as mpl
import matplotlib.style as style

a = np.array([-3.2, 0.1, 1.5, 3.3, 8.5])
b = np.array([1.1, 1.8, 1.95, 2.3, 4.3])
labels = ['a', 'bc', 'def', 'g', 'ggghhh']

stylefile = './util/plot_config/aqs_default.mplstyle'
# the file above does contain an entry of:
# savefig.facecolor: white
#
to_res = 1024
dpi = 100
inches = (to_res/dpi, to_res/dpi)

style.use(stylefile)
%matplotlib   

fig = mpl.figure.Figure(figsize=inches, dpi=dpi, facecolor='white')
ax = fig.subplots()

for x, y, l in zip(a,b,labels):
    ax.scatter(x,y,label=l)
ax.legend()
ax.set_xlabel('Some x')
ax.set_ylabel('Attenuation $\mu$ (cm$^{-1}$)')

ax.set_title('blah', y=1.03)
fig.suptitle('Linearity $\mu$')

# for me, _both_ calls below result in the figure having a transparent background:

fig.savefig('a.png', facecolor=fig.get_facecolor(), transparent=True)
fig.savefig('b.png', facecolor=fig.get_facecolor(), transparent=False)
Richard
  • 3,024
  • 2
  • 17
  • 40
  • what errors do you get? did you try absolute path – Arun Kamalanathan Dec 05 '19 at 23:36
  • I don't get any errors at all - there isn't anything wrong in the code. The problem is my output PNG files _always_ have a transparent figure background, regardless of everything I do to make it otherwise (make it white) – Richard Dec 05 '19 at 23:41
  • What does `fig.get_facecolor()` print? – ImportanceOfBeingErnest Dec 05 '19 at 23:41
  • fig.get_facecolor() returns the color set for the figure's facecolor (which get's set when I declare fig about 10 lines up). ...it doesn't print anything. So here it's telling fig.savefig to use the facecolor of the fig object, but querying fig to find out what it's facecolor is set to. – Richard Dec 06 '19 at 00:06
  • 1
    I want to know what `print(fig.get_facecolor())` shows on screen in your case. Best incoorporate that line in your code and report about the result inside the question. – ImportanceOfBeingErnest Dec 06 '19 at 00:08
  • ahh - gotcha - sorry! ...it's 1.0, 1.0, 1.0, 1.0. The last is the alpha right? is 1.0 full transparent, or full opaque? – Richard Dec 06 '19 at 09:42
  • alpha=1.0 is fully opaque. Meaning the correct color is injected into the savefig command. That makes it pretty hard to debug, I'm afraid. I can also not reproduce this behaviour. Are you running this in one single cell? Did you restart the kernel at some point? Which version of matplotlib/IPython/jupyter are you using? – ImportanceOfBeingErnest Dec 06 '19 at 13:18
  • It's mpl 3.1.1. Python 3.7.4, iPython 7.8.0. Jupyter core 4.5.0, notebook 6.0.1. I tried restart jupyter and it's the same behavior. I put the code into a script and ran it outside of jupyter framework, and it's the same. ...I'll try upgrading all my modules and see what happens – Richard Dec 06 '19 at 18:25
  • Updated everything to conda latest and still same behavior. Outside of debugging into MPL itself I don't know what to do. But I can just save as JPG's instead of PNG for my use. Not ideal but works - but it would have been nice to figure out what's up with the MPL savefig(). – Richard Dec 06 '19 at 18:29
  • ...strange you can't reproduce! ...but thanks for trying – Richard Dec 06 '19 at 18:30
  • Just found a clue (not quite a fix for me, as I'm trying to just use mpl) - if I create the figure/axes with pyplot (fig, ax = plt.subplots() in above instead of direct mpl calls) then the background isn't transparent. ...it's only if I skip pyplot, and use mpl directly to create the figure/axes that it screws up. – Richard Dec 06 '19 at 19:56
  • What does `print(mpl.rcParams["backend"], mpl.get_backend(), mpl.rcParams["savefig.facecolor"])` give when put directly before the savefig commands? – ImportanceOfBeingErnest Dec 07 '19 at 15:15
  • Sorry for the delay! I get "MacOSX MacOSX white", for both cases when I create fig, ax only through mpl, or if I use pyplot. However still have the situation where creating via mpl only always gives me transparent background, however creating via plt doesn't. ...weird. Anyway - huge thanks for trying to dig into it! – Richard Dec 09 '19 at 20:05

2 Answers2

48

Unfortunately, it seems that frameon is not supported anymore as of matplotlib 3.3.

I solved the transparency issue by setting facecolor='white', transparent=False options in savefig()

EA304GT
  • 634
  • 8
  • 11
4

FYI for anyone else with a similiar problem.

The cause (and fix) turned out to be because I was creating a figure with frameon set to False. I had actually had this set to False in a style file I was using.

Changing frameon to True fixed the problem.

This was confusing and not very obvious at all from any documentation - here is some background on the issue from the MPL github issues: https://github.com/matplotlib/matplotlib/issues/14339

Richard
  • 3,024
  • 2
  • 17
  • 40
  • 2
    `savefig() got unexpected keyword argument "frameon" which is no longer supported as of 3.3 and will become an error two minor releases later` – EA304GT Oct 29 '20 at 05:32
  • See the answer below, which i updated to be the correct answer with version 3.3 and later – Richard Apr 18 '23 at 17:03