在绘图上添加透明图片

Add transparent picture over plot

我下面的 python 脚本在使用 Basemap 模块生成的地图上添加了一张图片(在这个简单示例中生成了一个矩形)和 GPS 轨迹。
现在我想让两个轨道都变成透明的矩形。通过 alpha kwarg 的曲目没有问题,但我不知道如何为图片做这件事。

import matplotlib.pyplot as plt
from PIL import Image
from matplotlib.offsetbox import AnnotationBbox, OffsetImage
from mpl_toolkits.basemap import Basemap

lats = [ 45, 15  ]
lons = [ 0 , 100 ]

fig = plt.figure( dpi = 300 )
ax  = plt.subplot(111)

myBaseMap = Basemap( projection='ortho', lat_0=lats[-1], lon_0=lons[-1] )
myBaseMap.bluemarble()

planeImg = Image.new('RGB', (600, 300), color = 'red')
planeXY  = myBaseMap( lons[-1], lats[-1] )
x,y      = myBaseMap( lons, lats )

plt.plot( x, y, color='r', alpha=0.5, linewidth=3  )

imagebox = OffsetImage( planeImg , zoom=.4 )

ab = AnnotationBbox( imagebox, myBaseMap( lons[-1], lats[-1] ), xybox=( 0., 0. ), xycoords='data', boxcoords='offset points', frameon=False )
ax.add_artist(ab)
plt.show()

此代码生成下图带有透明线的图片。 现在我想以同样的方式使红色矩形透明。

我尝试在注释框和斧头上使用 set_alpha 方法但没有用。
有任何想法吗 ?

谢谢。

如果在创建 OffsetImage 之前 为图像设置 alpha 值,则结果看起来符合预期。 this answer 中解释了如何设置枕头图像的 alpha 值。注意alpha值必须在0到255之间,而不是0到1。简而言之,你只需要在你的代码中添加一行(注意我改变了图像分辨率):

import matplotlib.pyplot as plt
from PIL import Image
from matplotlib.offsetbox import AnnotationBbox, OffsetImage
from mpl_toolkits.basemap import Basemap

lats = [ 45, 15  ]
lons = [ 0 , 100 ]

fig = plt.figure( dpi = 100 )
ax  = plt.subplot(111)

myBaseMap = Basemap( projection='ortho', lat_0=lats[-1], lon_0=lons[-1] )
myBaseMap.bluemarble()

planeImg = Image.new('RGB', (600, 300), color = 'red')
planeImg.putalpha(128)

planeXY  = myBaseMap( lons[-1], lats[-1] )
x,y      = myBaseMap( lons, lats )

plt.plot( x, y, color='r', alpha=0.5, linewidth=3  )

imagebox = OffsetImage( planeImg , zoom=.4 )

ab = AnnotationBbox( imagebox, myBaseMap( lons[-1], lats[-1] ), xybox=( 0., 0. ), xycoords='data', boxcoords='offset points', frameon=False )
ax.add_artist(ab)
plt.show()

获取如下图片:

除了 Thomas Kühn 的回答:如果我使用他的代码和我的真实图片(这个带有透明区域的 png 红色平面) 而不是红色矩形:我得到下面的图片。

如您所见,png 透明区域被解释为黑色,因此地图上没有只有飞机,而是有一个透明的黑色方块围绕着它。 在 Thomas link 的帮助下,我找到了摆脱它的方法,请参见下面的代码(不要忘记在 运行 之前更改图片路径)。

import matplotlib.pyplot as plt
from PIL import Image
from matplotlib.offsetbox import AnnotationBbox, OffsetImage
from mpl_toolkits.basemap import Basemap

lats = [ 45, 15  ]
lons = [ 0 , 100 ]

fig = plt.figure( dpi = 100 )
ax  = plt.subplot(111)

myBaseMap = Basemap( projection='ortho', lat_0=lats[-1], lon_0=lons[-1] )
myBaseMap.bluemarble()

# /!\ /!\ /!\ CHOOSE A PNG OF YOUR OWN TO RUN THE SCRIPT /!\ /!\ /!\
imgPath  = './avion.png'
planeImg = Image.open( imgPath )
data     = planeImg.getdata()
newData  = []
myAlpha  = 150
# loop through pixels in planeImg
for item in data:
    # item[3] is the current pixel alpha value. When 0: transparent area on png, leave it at 0
    # item[{0, 1, 2}] is pixel {R,G,B} value
    if item[3] == 0:
        newData.append( (item[0], item[1], item[2], 0) )
    # else the current pixel is a part of the plane: set alpha to desired value
    else:
        newData.append( (item[0], item[1], item[2], myAlpha) )
planeImg.putdata( newData )

planeXY  = myBaseMap( lons[-1], lats[-1] )
x,y      = myBaseMap( lons, lats )

plt.plot( x, y, color='r', alpha=0.5, linewidth=3  )

imagebox = OffsetImage( planeImg , zoom=.4 )

ab = AnnotationBbox( imagebox, myBaseMap( lons[-1], lats[-1] ), xybox=( 0., 0. ), xycoords='data', boxcoords='offset points', frameon=False )
ax.add_artist(ab)
plt.show()

此代码生成下面的图片,这正是我要找的。 谢谢 Thomas Kühn。