Python Matplotlib Fond de carte de superposition de l'image de petite sur la carte de la parcelle

je trace les données d'un avion sur une carte et je voudrais insérer cette image 75px par 29px PNG d'un avion aux coordonnées du dernier point de données sur la carte.

avion http://i45.tinypic.com/mslr86.jpg

pour autant Que je sais et que vous avez lu, pyplot.imshow() est le meilleur moyen pour y parvenir. Cependant, je m'accroche à l'étape 1, Obtenir l'image à même l'affichage. En utilisant un tracé normal au lieu de Basemap, il est assez facile de faire apparaître l'image en utilisant imshow, mais en utilisant Basemap, Je ne peux pas le faire apparaître du tout. Consultez l'exemple de code.

si je peux obtenir l'image à afficher sur la carte, je suppose que je peux, par essai et erreur, définir sa position et quelques dimensions appropriées pour elle en utilisant le extent l'attribut imshow(), avec l'intrigue coordonnées converties à partir des coordonnées de carte x,y = m(lons,lats).

Voici l'exemple de code (à l'essayez, vous pouvez télécharger l'image de l'avion surtout.)

from matplotlib import pyplot as plt
from mpl_toolkits.basemap import Basemap
import Image
from numpy import arange

lats = arange(26,29,0.5)
lons = arange(-90,-87,0.5)

m = Basemap(projection='cyl',llcrnrlon=min(lons)-2,llcrnrlat=min(lats)-2,
            urcrnrlon=max(lons)+2,urcrnrlat=max(lats)+2,resolution='i')

x,y = m(lons,lats)
u,v, = arange(0,51,10),arange(0,51,10)
barbs = m.barbs(x,y,u,v)
m.drawcoastlines(); m.drawcountries(); m.drawstates()

img = Image.open('c130j_75px.png')
im = plt.imshow(img, extent=(x[-1],x[-1]+50000,y[-1],y[-1]+50000))
plt.show()

Voici l'image résultante, qui ne contient aucune trace de l'avion. J'ai essayé plusieurs tailles différentes en utilisant extent, en pensant que je l'ai peut-être fait trop petit, mais sans succès. J'ai aussi essayé la configuration de zorder=10, mais aussi sans chance. Toute aide serait appréciée.

résultat http://i45.tinypic.com/35mgnev.jpg

mise à jour: je peux maintenant faire apparaître l'image au moins en utilisant m.imshow au lieu de plt.imshow, puisque le premier passe dans l'instance axes de la carte, mais le extent argument semble n'avoir aucun effet sur les dimensions de l'image, car il remplit toujours l'ensemble de l'intrigue, peu importe comment petit je fais extent dimensions, même si je les mets à zéro. Comment puis-je dimensionner l'image de l'avion de façon appropriée et la positionner près du dernier point de données?

im = m.imshow(img, extent=(x[-1],x[-1]+5,y[-1],y[-1]+2))

result2 http://i50.tinypic.com/2ntdy0o.jpg

24
demandé sur bmu 2012-07-15 02:17:25

2 réponses

en fait, pour cela vous voulez utiliser une fonctionnalité un peu non documentée de matplotlib: le matplotlib.offsetbox module. Voici un exemple:http://matplotlib.sourceforge.net/trunk-docs/examples/pylab_examples/demo_annotation_box.html

Dans votre cas, vous feriez quelque chose comme ceci:

import matplotlib.pyplot as plt
import numpy as np
import Image

from mpl_toolkits.basemap import Basemap
from matplotlib.offsetbox import OffsetImage, AnnotationBbox

# Set up the basemap and plot the markers.
lats = np.arange(26, 29, 0.5)
lons = np.arange(-90, -87, 0.5)

m = Basemap(projection='cyl',
            llcrnrlon=min(lons) - 2, llcrnrlat=min(lats) - 2,
            urcrnrlon=max(lons) + 2, urcrnrlat=max(lats) + 2,
            resolution='i')

x,y = m(lons,lats)
u,v, = np.arange(0,51,10), np.arange(0,51,10)
barbs = m.barbs(x,y,u,v)

m.drawcoastlines()
m.drawcountries()
m.drawstates()

# Add the plane marker at the last point.
plane = np.array(Image.open('plane.jpg'))
im = OffsetImage(plane, zoom=1)
ab = AnnotationBbox(im, (x[-1],y[-1]), xycoords='data', frameon=False)

# Get the axes object from the basemap and add the AnnotationBbox artist
m._check_ax().add_artist(ab)

plt.show()

enter image description here

l'avantage de ceci est que le plan est en coordonnées d'axes et restera de la même taille par rapport à la taille de la figure lors d'un zoom.

22
répondu Joe Kington 2012-07-16 03:43:58

avec basemap, vous pouvez généralement juste utiliser les commandes de style normal de typlot si vous traduisez vos coordonnées en utilisant d'abord l'instance map. Dans ce cas, vous pouvez simplement transformer l'étendue en coordonnées uv avec:

x0, y0 = m(x[-1], y[-1])
x1, y1 = m(x[-1] + 0.5, y[-1] + 0.5)

Et puis par la suite, vous serez en mesure de faire:

im = plt.imshow(img, extent=(x0, x1, y0, y1))

Ma solution à ce ressemble:

import matplotlib.pyplot as plt
from mpl_toolkits.basemap import Basemap
import numpy as np


lats = np.arange(26, 29, 0.5)
lons = np.arange(-90, -87, 0.5)

m = Basemap(projection='cyl', llcrnrlon=min(lons)-2, llcrnrlat=min(lats)-2,
            urcrnrlon=max(lons)+2, urcrnrlat=max(lats)+2, resolution='h')

x, y = m(lons,lats)
u, v = np.arange(0, 51, 10), np.arange(0, 51, 10)
barbs = m.barbs(x, y, u, v)

m.drawcoastlines()
m.fillcontinents()

x_size, y_size = 0.8, 0.4
x0, y0 = m(x[-1] - x_size/2., y[-1] - y_size/2.)
x1, y1 = m(x[-1] + x_size/2., y[-1] + y_size/2.)
im = plt.imshow(plt.imread('mslr86.png'), extent=(x0, x1, y0, y1))

plt.show()

Qui produit une image qui ressemble àenter image description here

mise à Jour: si vous voulez que l'image reste un taille fixe, indépendamment du zoom, voir la réponse de Joe.

14
répondu pelson 2012-07-16 13:29:31