The actual problem that I have, is that - in the code I'm working on: when I try to save the plot image, I get the plot background in the image as fully transparent, so it looks like this in an image viewer (here eom
, Mate's version of eog
):
I would like to have the background color to be fully opaque white, instead.
This seems to have been a problem often, e.g.:
- Matplotlib figure facecolor alpha while saving (background color, transparency)
- Matplotlib savefig background always transparent
- Set background color behind the image in matplotlib
- https://moonbooks.org/Articles/How-to-change-the-color-background-of-a-matplotlib-figure-/
Anyways, one problem is that I cannot reproduce this with a minimal example. In my code, essentially I have to convert the figure to an image first, then process that image, then finally save it. So I tried making a minimal example, with a conversion to image data first, which is then being saved:
import matplotlib as mpl
print(f"{mpl.__version__}")
import matplotlib.pyplot as plt
import numpy as np
import io
t = np.arange(0.0, 2.0, 0.01)
s = np.sin(2*np.pi*t)
subplotpars = dict(left = 0.05, right=0.99, top=0.89, wspace=0.1)
gss = mpl.gridspec.GridSpec(2,1, height_ratios=(2, 1), **subplotpars),
fig = plt.figure()
gs = gss[0]
ax = fig.add_subplot(gs[0,0])
ax.plot(t, s, color=(0.4, 0.2, 0.6, 0.6))
print(f"{fig.get_facecolor()=}, {fig.get_alpha()=}")
print(f"{fig.patch.get_facecolor()=}, {fig.patch.get_alpha()=}")
with io.BytesIO() as buf:
fig.savefig(buf, dpi=120, format="png")
buf.seek(0)
fig_rgba = plt.imread(buf)
plt.imsave('example_io.png', fig_rgba, dpi=120)
... and this code prints this for me:
3.5.1
fig.get_facecolor()=(1.0, 1.0, 1.0, 1.0), fig.get_alpha()=None
fig.patch.get_facecolor()=(1.0, 1.0, 1.0, 1.0), fig.patch.get_alpha()=None
... and tells me that I have matplotlib 3.5.1, and that the figure background color is defined as RGBA, although with alpha channel set to 1 (opaque). Ultimately, the image that is output by this code, for me, is with fully opaque white background - so this code does not demonstrate the problem.
So, while I cannot reconstruct my problem as a minimal example - I managed to narrow down the problem in my actual code, in this snippet:
# ... time to save as image:
print(f"A {self.fig.get_facecolor()=}, {self.fig.get_alpha()=}")
print(f"A {self.fig.patch.get_facecolor()=}, {self.fig.patch.get_alpha()=}")
orig_figcol = self.fig.get_facecolor()
orig_figpatchcol = self.fig.patch.get_facecolor()
self.fig.set_facecolor( (1.0, 1.0, 1.0, 1.0) ) # calls patch.set_facecolor anyway
self.fig.patch.set_facecolor( (1.0, 1.0, 1.0, 1.0) )
self.fig.canvas.draw()
print(f"B {self.fig.get_facecolor()=}, {self.fig.get_alpha()=}")
print(f"B {self.fig.patch.get_facecolor()=}, {self.fig.patch.get_alpha()=}")
with io.BytesIO() as buf:
# ...
When this section in the code is ran, I get a printout:
A self.fig.get_facecolor()=(1.0, 1.0, 1.0, 0), self.fig.get_alpha()=None
A self.fig.patch.get_facecolor()=(1.0, 1.0, 1.0, 0), self.fig.patch.get_alpha()=0
B self.fig.get_facecolor()=(1.0, 1.0, 1.0, 0), self.fig.get_alpha()=None
B self.fig.patch.get_facecolor()=(1.0, 1.0, 1.0, 0), self.fig.patch.get_alpha()=0
So, unlike the basic example above, the starting background color of the plot, as RGBA, is (1.0, 1.0, 1.0, 0) - that is to say, alpha channel is zero (so no surprise the background is transparent).
However, I do call set_facecolor
right after, with an RGBA color where alpha is 1, and I even call .draw()
, to hopefully trigger a refresh/redraw -- but regardless, when try to get the same facecolor I just previously set, it still returns the old color value, where alpha was 0!
So, essentially, the way I see this is: something does not let me change the Figure background color, right before I want to save the figure as an image.
Under what circumstances would matplotlib not let me change the image background - and ultimately, how can I change the plot figure background color, right before I save the figure as image (or export it as image data, that is, pixels)?