My python script below adds a picture (a generated rectangle on this simple example) and GPS track on a map generated with Basemap module.
Now I would like to make both track an rectangle transparent. No problem for the track via alpha
kwarg but I cannot figure how to do it for the picture.
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()
This code produces the picture below with a transparent line. Now I would like to make the red rectangle transparent in the same fashion.
I tried to use set_alpha
method on the annotation box and ax but didn't work.
Any ideas ?
Thanks.
If you set an alpha value to your image before you create the OffsetImage
, the result looks as expected. How to set the alpha value of a pillow image is explained in this answer. Note that the alpha value has to be between 0 and 255, not 0 and 1. In short, you only need to add one line to your code (note that I changed the image resolution):
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()
to get the following image:
In addition to Thomas Kühn answer: if I use his code with my real picture (this png red plane with transparent areas) instead of a red rectangle: I get the picture below.
As you can see the png transparent areas are interpreted as black so instead of having just the plane on the map I have a transparent black square around it. With the help of Thomas' link I found a way to get rid of this, see code below (don't forget to change the picture path before running it).
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()
This code produces picture below which is what exactly what I was looking for. Thank you Thomas Kühn.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With