Python 使用彩色背景使图形透明

Python 使用彩色背景使图形透明,python,matplotlib,Python,Matplotlib,我有点情况。我需要的是一个黑色背景的情节,在黑色背景上画几个白色圆圈 我使用以下代码成功地做到了这一点: import numpy import matplotlib.pyplot as plt fig = plt.figure() ax = fig.add_subplot(1, 1, 1, aspect = "equal", axisbg = "black") ax.add_artist(plt.Circle((0., 0., .5), color = "white")) plt.x

我有点情况。我需要的是一个黑色背景的情节,在黑色背景上画几个白色圆圈

我使用以下代码成功地做到了这一点:

import numpy
import matplotlib.pyplot as plt

fig = plt.figure()
ax = fig.add_subplot(1, 1, 1, aspect = "equal", axisbg = "black")
ax.add_artist(plt.Circle((0., 0., .5), color =   "white")) 

plt.xlim(-5, 5)
plt.ylim(-5, 5)

fig.savefig("test.png", dpi = 300)

plt.show()
这将产生以下结果:

现在,我想做的是使这个图像透明。所以这意味着只有白色的圆圈应该是透明的。您可能已经能够看到出现的问题,因为如果我设置
transparent=True
。黑色背景自动变为透明,我的身体失去了黑色

我尝试的另一件事是在
savefig
中不设置
transparent=True
,而是在
plt.Circle
中实际设置选项
alpha=0.
。这使得白色圆圈实际上是透明的,这是最终目标。然而,因为它是透明的,我留下了一个完整的黑色背景。有什么办法解决这个问题吗

总结一下我的目标:

我想保存图形的透明版本,其中白色圆圈是透明的,而黑色部分不是

我知道我可以使用不同的程序,如
inkscape
gimp
来创建我想要的。但是,由于我需要执行其他操作,因此我确实需要在python中执行此操作


谢谢大家!

这可能不是您想要的答案,但它提供了您想要的图片!我想你要填充圆圈外的区域!(s) 使用黑色并保持背景透明,而不是相反。计算单个圆的边界并在之间使用
fill\u很简单。在多个圆圈中执行此操作可能更为棘手

import numpy as np
import matplotlib.pyplot as plt

fig = plt.figure()
ax = fig.add_subplot(1, 1, 1, aspect = "equal", )

# A Circle
xy=(1,1); r=3

# more points is smoother
xdata=np.linspace(-5,5,1001)
ydata=np.linspace(-5,5,1001)

# circle edges (top and bottom)
c1=np.sqrt((xy[0]**2-xdata**2)+r**2)+xy[1]
c2=-np.sqrt((xy[0]**2-xdata**2)+r**2)+xy[1]

c1=np.where(np.isnan(c1),xy[0],c1)
c2=np.where(np.isnan(c2),xy[0],c2)

ax.fill_between(xdata,5,c1,color='black')
ax.fill_between(xdata,-5,c2,color='black')

plt.xlim(-5, 5)
plt.ylim(-5, 5)

fig.savefig("test.png", dpi = 300, transparent=True)

用颜色条遮住的圆圈 Colormaps可以有一个alpha通道,因此,如果您的数据位于网格上,其高值和低值显示圆形与非圆形,则其中一组值可以是透明的

这只适用于我以编程方式保存图形时,使用
transparent
关键字;不是从Python图像窗口

从matplotlib库的一个示例开始(在类似gimp的情况下,我可以剪切和粘贴线段,并且透明度正确):

作为另一个图像上的一层。有趣的是,带有alpha通道的颜色栏没有透明度。这看起来像个虫子

编辑3:

经澄清,根本问题是:

如何在
imshow
生成的matplotlib图像前放置“黑色透明”遮罩? 遮罩应来自先前绘制的黑白图

以下代码通过访问和混合地物rgba位图来演示此功能:

import numpy as np
import matplotlib.pyplot as plt

import matplotlib.cm as cm
import matplotlib.mlab as mlab


def get_rgba_bitmap(fig):
    fig.canvas.draw()
    tab = fig.canvas.copy_from_bbox(fig.bbox).to_string_argb()
    ncols, nrows = fig.canvas.get_width_height()
    return np.fromstring(tab, dtype=np.uint8).reshape(nrows, ncols, 4)

def black_white_to_black_transpa(rgba):
    rgba[:, :, 3] = 255 - rgba[:, :, 0]
    rgba[:, :, 0:3] = 0

def over(rgba1, rgba2):
    if rgba1.shape != rgba2.shape:
        raise ValueError("rgba1 and rgba2 shall have same size")
    alpha = np.expand_dims(rgba1[:, :, 3] / 255., 3)
    rgba =  np.array(rgba1 * alpha + rgba2 * (1.-alpha), dtype = np.uint8)
    return rgba[:, :, 0:3]


# fig 1)
fig1 = plt.figure(facecolor = "white")
fig1.set_dpi(300)
ax1 = fig1.add_subplot(1, 1, 1, aspect = "equal", axisbg = "black")
ax1.add_artist(plt.Circle((0., 0., .5), color =   "white")) 
ax1.set_xlim(-5, 5)
ax1.set_ylim(-5, 5)
bitmap_rgba1 = get_rgba_bitmap(fig1)
black_white_to_black_transpa(bitmap_rgba1)

# fig 2
fig2 = plt.figure(facecolor = "white")
fig2.set_dpi(300)
delta = 0.025
ax2 = fig2.add_subplot(1, 1, 1, aspect = "equal", axisbg = "black")
ax2.set_xlim(-5, 5)
ax2.set_ylim(-5, 5)
x = y = np.arange(-3.0, 3.0, delta)
X, Y = np.meshgrid(x, y)
Z1 = mlab.bivariate_normal(X, Y, 1.0, 1.0, 0.0, 0.0)
Z2 = mlab.bivariate_normal(X, Y, 1.5, 0.5, 1, 1)
Z = Z2-Z1  # difference of Gaussians
im = ax2.imshow(Z, interpolation='bilinear', cmap=cm.jet,
                origin='lower', extent=[-5, 5, -5, 5],
                vmax=abs(Z).max(), vmin=-abs(Z).max())
bitmap_rgba2 = get_rgba_bitmap(fig2)    

# now saving the composed figure 
fig = plt.figure()
fig.patch.set_alpha(0.0) 
ax = fig.add_axes([0., 0., 1., 1.])
ax.patch.set_alpha(0.0) 
ax.imshow(over(bitmap_rgba1, bitmap_rgba2))
plt.axis('off')
fig.savefig("test_transpa.png", dpi=300)

plt.show()
给予:

我用你最初的光子测试用例进行了测试,pic的质量似乎还可以

现在,如果您希望图形背景也透明:

  • 将图1背景设置为“白色”,即
    fig1=plt.figure(facecolor='white')
    ,因为白色在传递到
    black\u white\u to\u black\u transpa时将变得透明
  • 将图2背景设置为透明
    fig2.patch。设置alpha(0.0)
    ,因为它将存储在
    bitmap\u rgba2
  • 最后,在混合
    bitmap\u rgba1
    bitmap\u rgba2
    内部
    over
    功能时,注意alpha通道(请参见下面可能的修改)
最后一次(?)编辑: 似乎
返回到_string_argb
的数组与
imshow
所期望的数组(rgb通道的顺序)不一致。一种可能的解决方案是将ax.imshow(在(位图_rgba1,位图_rgba2)上)更改为

over_tab = over(bitmap_rgba1, bitmap_rgba2)
over_tab[:, :, 0:3] = over_tab[:, :, ::-1][:, :, 1:4]
ax.imshow(over_tab)

请将此简化为一个最小的示例。作为一名物理学家,我喜欢这张图片,但是我认为你可以用<10行代码来证明这个问题。如果你能让答案更容易理解你在做什么,你会得到更好的答案。谢谢你的建议,好得多(在我的博士学位中,我研究过干扰系统及其奇怪的声子),这是一个有趣的问题!AGG绘制的方式是,它以附加方式放置图层,如果您希望指定图像的正方向,但指定的是负方向,则该方法效果良好。有很多方法可以让Agg为画布提供RGBA缓冲区,然后你可以修复它并将其作为图像放回画布上,但这似乎太过周而复始,不是一个好的解决方案。非常感谢你提供了悬赏。如果没有它,我可能仍然没有答案。欢迎。这看起来像是一个需要解决的有趣问题。这个问题简化得太多了,OP想要的应用程序是放下~1k个圆来制作光子晶体(参见编辑历史)。好的,我可以看出我的解决方案对应用程序不起作用。有没有理由不在问题中的脚本末尾使用
os.system(“convert test.png-transparent white image\u transparent.png”)
?我知道这不是matplotlib解决方案,但它很简单。对于OP来说,它可能足够好了,但我正在寻找一个纯mpl解决方案;)很公平。但我认为在黑色背景上绘制圆圈不是解决这个问题的方法,以某种方式填补圆圈之间的空白将是一个解决方案。我写一个解决方案,确定1000x1000网格的哪些部分不在一个圆内,并使用
pcolormesh
填充它们,这是否值得?如果你想这样做,你应该从AGG获取RGBA缓冲区(它可以更快地计算圆内/不在圆内的像素)然后将该数组渲染回新画布。您是否确实希望具有透明度的图像在另一个图像@TheDude上搜索?我没有看到问题的原始状态,但在某个地方有一个参考,需要大量的时间
def over(rgba1, rgba2):
    if rgba1.shape != rgba2.shape:
        raise ValueError("rgba1 and rgba2 shall have same size")
    alpha1 = np.expand_dims(rgba1[:, :, 3] / 255., axis=3)
    alpha2 = np.expand_dims(rgba2[:, :, 3] / 255., axis=3)
    alpha = 1. - (1.-alpha1) * (1.-alpha2)
    C1 = rgba1[:, :, 0:3]
    C2 = rgba2[:, :, 0:3]
    C = (alpha1 * C1 + (1-alpha1) * alpha2 * C2) / alpha
    rgba =  np.empty_like(rgba1, dtype = np.uint8)
    rgba[:, :, 0:3] = C
    rgba[:, :, 3] = 255 * alpha[:, :, 0]
    return rgba
over_tab = over(bitmap_rgba1, bitmap_rgba2)
over_tab[:, :, 0:3] = over_tab[:, :, ::-1][:, :, 1:4]
ax.imshow(over_tab)