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.
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.
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()
Ich habe eine Frage. Was nutzt die Variable * zorder *? Oder warum wird es hier benutzt? – SereneWizard
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
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