2017-03-07 5 views
3

In die Python-Grundkarte sind zwei Inhalte eingezeichnet: Eine mehrzeilige Shapefile (IL_State_ln) und ein Streudiagramm einiger zufälliger Punkte innerhalb der Grundkartenausdehnung. Mein Interesse ist es, eine Legende zu generieren, die Informationen über Shapefile und die Streupunkte liefert. Momentan kann ich nur die Punkte in die Legende und nicht das Shapefile einbeziehen.Wie wird Shapefile-Label in der Python-Grundkartenlegende angezeigt?

Die Überprüfung der Basemap API documentation bietet keine Informationen, da die Funktion readshapefile() scheint keine Label Argument zu haben.

Könnten Sie mir bitte helfen, den Shapefile-Indikator in die Legende einzufügen, wie in den ArcGIS-Karten?

Hier ist mein Code:

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

fname = "DATA/GIS/IL_State_ln" 

m = Basemap(llcrnrlon=-92.,llcrnrlat=36.8,urcrnrlon=-86.5,urcrnrlat=43., 
      resolution='i', projection='tmerc', lat_0 = 36.5, lon_0 = -91.8) 

m.readshapefile(fname, 'mygeom') 

x,y = m([-90., -91.2, -88.], [38., 37.7, 42.]) 
m.scatter(x,y, marker='o', label="Points") 

plt.legend(loc=3) 
plt.show() 

ich Python bin mit 3.5, 2.0 und matplotlib basemap 1.0.8.

Antwort

8

Die Idee zum Erstellen eines Legendeneintrags besteht darin, die Formen als Polygone zu zeichnen, die dann zur Legende hinzugefügt werden können.
Deshalb würden wir zunächst drawbounds, m.readshapefile(fn, 'shf', drawbounds = False) deaktivieren. Wir können dann ein matplotlib.patches.Polygon aus dem Shapefile erstellen und es zu den Achsen plt.gca().add_artist(polygon) hinzufügen.

Die Legende kann dann

dieses Polygon aktualisiert werden
handles, labels = plt.gca().get_legend_handles_labels() 
handles.extend([polygon]) 
labels.extend(["Name of the shape"])      
plt.legend(handles=handles, labels=labels) 

Hier jetzt in Aktion einige Code, die die folgenden Bilder erzeugt. Es verwendet die ne_10m_admin_0_countries Datei.

enter image description here

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

m = Basemap(llcrnrlon=-10,llcrnrlat=35,urcrnrlon=35,urcrnrlat=60., 
      resolution='i', projection='tmerc', lat_0 = 48.9, lon_0 = 15.3) 

m.drawcoastlines() 
m.drawcountries(zorder=0, color=(.9,.9,.9), linewidth=1) 

fn = r"ne_10m_admin_0_countries\ne_10m_admin_0_countries" 
m.readshapefile(fn, 'shf', drawbounds = False) 

#Madrid 
x,y = m([-3.703889],[40.4125]) 
m.plot(x,y, marker="o", color="blue", label="Madrid", ls="") 

# some countries 
countries = ['Switzerland', 'Ireland', "Belgium"] 
colors= {'Switzerland':"red", 'Ireland':"orange", 'Belgium' : "purple"} 
shapes = {} 
for info, shape in zip(m.shf_info, m.shf): 
    if info['NAME'] in countries: 
     p= Polygon(np.array(shape), True, facecolor= colors[info['NAME']], 
        edgecolor='none', alpha=0.7, zorder=2) 
     shapes.update({info['NAME'] : p}) 

for country in countries: 
    plt.gca().add_artist(shapes[country]) 


# create legend, by first getting the already present handles, labels 
handles, labels = plt.gca().get_legend_handles_labels() 
# and then adding the new ones 
handles.extend([shapes[c] for c in countries]) 
labels.extend(countries)      
plt.legend(handles=handles, labels=labels, framealpha=1.) 

plt.show() 

Nun, da haben wir schon einen Polygon mit der Form, warum nicht die Legende macht ein bisschen mehr Phantasie, indem sie direkt die Form in die Legende Plotten. Dies kann wie folgt durchgeführt werden.

enter image description here

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

m = Basemap(llcrnrlon=-10,llcrnrlat=35,urcrnrlon=35,urcrnrlat=60., 
      resolution='i', projection='tmerc', lat_0 = 48.9, lon_0 = 15.3) 

m.drawcoastlines() 

fn = r"ne_10m_admin_0_countries\ne_10m_admin_0_countries" 
m.readshapefile(fn, 'shf', drawbounds = False) 

#Madrid 
x,y = m([-3.703889],[40.4125]) 
m.plot(x,y, marker="o", color="blue", label="Madrid", ls="") 

countries = ['Switzerland', 'Ireland', "Belgium"] 
colors= {'Switzerland':"red", 'Ireland':"orange", 'Belgium' : "purple"} 
shapes = {} 
for info, shape in zip(m.shf_info, m.shf): 
    if info['NAME'] in countries: 
     p= Polygon(np.array(shape), True, facecolor= colors[info['NAME']], 
        edgecolor='none', alpha=0.7, zorder=2) 
     shapes.update({info['NAME'] : p}) 

for country in countries: 
    plt.gca().add_artist(shapes[country]) 


class PolygonN(object): 
    def legend_artist(self, legend, orig_handle, fontsize, handlebox): 
     x0, y0 = handlebox.xdescent, handlebox.ydescent 
     width, height = handlebox.width, handlebox.height 
     aspect= height/float(width) 
     verts = orig_handle.get_xy() 
     minx, miny = verts[:,0].min(), verts[:,1].min() 
     maxx, maxy = verts[:,0].max(), verts[:,1].max() 
     aspect= (maxy-miny)/float((maxx-minx)) 
     nvx = (verts[:,0]-minx)*float(height)/aspect/(maxx-minx)-x0 
     nvy = (verts[:,1]-miny)*float(height)/(maxy-miny)-y0 

     p = Polygon(np.c_[nvx, nvy]) 
     p.update_from(orig_handle) 
     p.set_transform(handlebox.get_transform()) 

     handlebox.add_artist(p) 
     return p 

handles, labels = plt.gca().get_legend_handles_labels() 
handles.extend([shapes[c] for c in countries]) 
labels.extend(countries)  
plt.legend(handles=handles, labels=labels, handleheight=3, handlelength=3, framealpha=1., 
      handler_map={Polygon: PolygonN()}) 

plt.show() 
+0

Ich habe eine Frage. Was nutzt die Variable * zorder *? Oder warum wird es hier benutzt? – SereneWizard

+0

Sehr gute Frage. 'zorder' legt die Reihenfolge fest, in der die Ebenen gezeichnet werden, je höher die Zorder sind, desto mehr oben lebt die Ebene. Es ist wie ein Blatt Papier auf dem Schreibtisch - der niedrigste hat die niedrigste Zorder. Es gibt jedoch keinen Grund, es hier zu verwenden und es wegzulassen lässt die Formen hinter den Küsten leben, die besser aussehen könnten. – ImportanceOfBeingErnest

+0

Eine Frage klickte in meinen Gedanken. Statt * matplotlib.patches.Polygon() * könnten wir hier * shapely.geometry.Polygon() * nicht verwenden? Der Zweck ist immer noch das Polygon in der Legende zu bekommen. – SereneWizard

Verwandte Themen