2017-03-07 106 views
3

python底图有两个内容:多行shapefile(IL_State_ln)和底图范围内的一些随机点的散点图。我的兴趣在于生成一个图例,该图例提供有关shapefile和散点的信息。现在,我只能在图例中包含点而不是shapefile。如何在python底图图例中显示shapefile标签?

检查Basemap API documentation没有提供任何信息,因为函数readshapefile()似乎没有任何标签参数。

您能否帮我在图例中包含shapefile指示器,就像在ArcGIS地图中一样?

这里是我的代码:

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() 

我使用Python 3.5,matplotlib 2.0和1.0.8底图。

回答

8

创建图例条目的想法是将图形绘制为多边形,然后将其添加到图例中。
因此,我们将首先取消drawbounds,m.readshapefile(fn, 'shf', drawbounds = False)。然后,我们可以从shapefile创建一个matplotlib.patches.Polygon,并将其添加到坐标轴plt.gca().add_artist(polygon)

图例然后可以使用这个多边形

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

这里现在是一些代码在作用,这会产生以下的图像被更新。它使用ne_10m_admin_0_countries文件。

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() 

现在,因为我们已经有了形状的多边形,为什么不把传说多一点花哨,由形状直接绘制成传奇。这可以如下完成。

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

我有一个问题。变量* zorder *的用途是什么?或者为什么在这里使用? – SereneWizard

+0

非常好的问题。 'zorder'确定图层的绘制顺序,zorder越高,图层的顶层越高。这就像桌上的纸片 - 最低的一个有最低的zorder。然而,没有理由在这里使用它,并将其留在海岸线后面,这样看起来可能更好。 – ImportanceOfBeingErnest

+0

在我脑海中点击了一个问题。而不是使用* matplotlib.patches.Polygon()*,我们不能在这里使用* shapely.geometry.Polygon()*吗?目的仍然是获取图例中的多边形。 – SereneWizard