2

I am trying to export a matplotlib plot with a transparent background as it is a circle and I need to paste onto another canvas (without the corners).

I have followed the example set out here: How to export plots from matplotlib with transparent background?

Sample code:

import matplotlib.pyplot as plt
from PIL import Image, ImageFont, ImageDraw

path = '...'

SomeCanvas1 = Image.new('RGB', (750, 750), '#36454F')

fig, ax = plt.subplots(figsize=(6, 6))
wedgeprops = {'width':0.3, 'edgecolor':'white', 'linewidth':2}
ax.pie([1-0.33,0.33], wedgeprops=wedgeprops, startangle=90, colors=['#BABABA', '#0087AE'])
plt.text(0, 0, '33%', ha='center', va='center', fontsize=42)
fig.savefig(path+'donut1.png', transparent=True)

imgDonut = Image.open(path+'donut1.png')
w,h = imgDonut.size

SomeCanvas1.paste(imgDonut, (int(0.5*(750-w)),int(0.5*(750-h))))
SomeCanvas1.save(path+'test1.png')

and the example set out here: How to set opacity of background colour of graph with Matplotlib

Sample code:

SomeCanvas2 = Image.new('RGB', (750, 750), '#36454F')

fig, ax = plt.subplots(figsize=(6, 6))
fig.patch.set_facecolor('None')
fig.patch.set_alpha(0)
wedgeprops = {'width':0.3, 'edgecolor':'white', 'linewidth':2}
ax.pie([1-0.33,0.33], wedgeprops=wedgeprops, startangle=90, colors=['#BABABA', '#0087AE'])
plt.text(0, 0, '33%', ha='center', va='center', fontsize=42)
fig.savefig(path+'donut2.png', facecolor=fig.get_facecolor(), edgecolor='none')

imgDonut = Image.open(path+'donut2.png')
w,h = imgDonut.size

SomeCanvas2.paste(imgDonut, (int(0.5*(750-w)),int(0.5*(750-h))))
SomeCanvas2.save(path+'test2.png')

as well as the example here: Export plot in .png with transparent background

But it's not working for me. When I paste onto a canvas, I end up with:

enter image description here

I need it tight around the donut, without the square corners.

What is going wrong with my code?

EDIT: I am on Windows 10 and using ATOM IDE. I am not sure whether that makes a difference...

brb
  • 1,123
  • 17
  • 40
  • Does this answer your question? https://stackoverflow.com/a/15858047/2681662 – MSH Aug 02 '21 at 13:32
  • Hi MSH. Thanks. No it does not. I tried that code (and linked in my question). It does not work for me. I do not know why. I am using ATOM IDE. I am not sure whether that would make a difference, but I copied that code exactly and it produced a white background for me. – brb Aug 02 '21 at 14:16
  • isn't it just missing ``ax.patch.set_alpha(0)``? – Karina Aug 02 '21 at 14:47
  • Hi Karina. Thanks,. I understand that ax.patch.set_alpha(0) relates to the background inside the main plot (ie the red/purple part in the second link) and fig.patch.set_alpha(0) relates to the background outside the main plot. At any rate, adding this does not produce a transparent background. – brb Aug 02 '21 at 15:00
  • ``fig.patch.set_alpha(0)`` will do the trick. I just tested it and got a transparent background – Karina Aug 02 '21 at 15:15
  • Hrmm.... I do have that in the above code snippet. Can you please paste your code? Is it in a different spot to me? I will try running in something other than ATOM to see if that is an issue... – brb Aug 02 '21 at 15:19
  • even if it does make any difference, the ``.png`` file would still be the same anyway, right? I can't be 100% sure, but I think it makes no difference. – Karina Aug 02 '21 at 15:43

1 Answers1

2

This works for me:

import matplotlib.pyplot as plt
from PIL import Image, ImageFont, ImageDraw

path = '...'

SomeCanvas1 = Image.new('RGB', (750, 750), '#36454F')

fig, ax = plt.subplots(figsize=(6, 6))
wedgeprops = {'width':0.3, 'edgecolor':'white', 'linewidth':2}
ax.pie([1-0.33,0.33], wedgeprops=wedgeprops, startangle=90, colors=['#BABABA', '#0087AE'])
plt.text(0, 0, '33%', ha='center', va='center', fontsize=42)
fig.savefig(path+'donut1.png', transparent=True)

imgDonut = Image.open(path+'donut1.png')
w,h = imgDonut.size

SomeCanvas1.paste(imgDonut, (int(0.5*(750-w)),int(0.5*(750-h))))
SomeCanvas1.save(path+'test1.png')
fig.patch.set_alpha(0)

The output is (I have black background --> this is screenshot from JupyterLab):

enter image description here

This is your file ...donut1.png (transparent background, my viewer has white background --> this is the actual image file): enter image description here

----edit---

Managed to get it transparent!

import matplotlib.pyplot as plt
from PIL import Image, ImageFont, ImageDraw

path = '...'

SomeCanvas1 = Image.new('RGB', (750, 750), '#36454F')

fig, ax = plt.subplots(figsize=(6, 6))
wedgeprops = {'width':0.3, 'edgecolor':'white', 'linewidth':2}
ax.pie([1-0.33,0.33], wedgeprops=wedgeprops, startangle=90, colors=['#BABABA', '#0087AE'])
plt.text(0, 0, '33%', ha='center', va='center', fontsize=42)
fig.savefig(path+'donut1.png', transparent=True)
fig.patch.set_alpha(0)

SomeCanvas1.save(path+'test1.png')

foreground = path+'donut1.png'
imgfore = Image.open(foreground, 'r')
background = path+'test1.png'
imgback = Image.open(background, 'r')

merged = Image.new('RGBA', (w,h), (0, 0, 0, 0))
merged.paste(imgback, (0,0))
merged.paste(imgfore, (0,0), mask=imgfore)
merged.save((path+"merged.png"), format="png")

In this case you will produce 3 image files. This is the merged file:

enter image description here

Karina
  • 1,252
  • 2
  • 5
  • 16
  • Thanks. I have run in Jupyter now, and I am still getting the same issue... Could it be due to system differences? What operating software are you using? I am on Windows 10. I am not sure if that makes a difference? – brb Aug 02 '21 at 15:46
  • Also running on Windows 10. Are you aware that you produce 2 image files? ``...donut1.png`` and ``...test1.png``? The transparent one is the ``...donut1.png`` – Karina Aug 02 '21 at 15:54
  • Yes. I need to paste donut1 onto another canvas and save as a combined file (test1.png). So I need test1.png not to have the white corners when donut1 is pasted. I'm still getting it... – brb Aug 02 '21 at 15:59
  • Counter question: why do you need to paste donut1 to test1? Isn't it the exact same picture (apart from the size, maybe)? Why not just adjust the ``figsize`` from ``fig, ax = plt.subplots(figsize ... `` to be the final size that you want to have like the one in test1? In this case you will have only 1 image file: ``...donut1.png``, saving some memory and less complicated. – Karina Aug 02 '21 at 16:07
  • Because it's a stylised example. I need to load in another picture (represented here as SomeCanvas, but this will be a .PNG file loaded from disk) and paste donut1 on this picture without the square corners. SomeCanvas serves to show, at least for me, that donut1.png does not have a transparent background, so it's not just my viewer – brb Aug 02 '21 at 16:16
  • I managed to get it transparent! refer to my last edit – Karina Aug 03 '21 at 07:03
  • Thanks. That did work!! Do you know what part of the code change made it work? fig.patch.set_alpha(0) is not necessary, so the first posted link worked. It must be due to creating a canvas with an alpha channel? Is that correct? Or the mask part of the code? If you could post an explanation on these two aspects, it might help. Thanks, appreciate you figuring that out - it was driving me nuts. I will mark as accepted tomorrow. If you are able to add a brief explanation on how this works, that might be useful. – brb Aug 05 '21 at 12:19
  • Yes you are right, alpha(0) is not necessary. I would rather not give any explanation before I explain something not true. I _think_ the key point lies on ``merged.paste(imgback, (0,0))`` and ``merged.paste(imgfore, (0,0), mask=imgfore)``. The masking part is important, if you leave it out from the code, it will not work. However, I'm not sure, since this is also my first time doing it. So as I said before, I'll refrain from explaining. – Karina Aug 05 '21 at 13:55
  • Yes, that is fair enough. I will also research this some more over the weekend. At any rate, I now have a solution that works. Appreciate your help. Thank you. – brb Aug 05 '21 at 16:17