您好我正在尝试使用pythons底图绘制地图,其中一些国家/地区填充了某种颜色。
那里有一个快速简便的解决方案吗?
答案 0 :(得分:14)
正如@unutbu已经说过的那样,托马斯的帖子here正是你所追求的。
如果你想用Cartopy做这个,相应的代码(在v0.7中)可以稍微改编自http://scitools.org.uk/cartopy/docs/latest/tutorials/using_the_shapereader.html:
import cartopy.crs as ccrs
import matplotlib.pyplot as plt
import cartopy.io.shapereader as shpreader
import itertools
import numpy as np
shapename = 'admin_0_countries'
countries_shp = shpreader.natural_earth(resolution='110m',
category='cultural', name=shapename)
# some nice "earthy" colors
earth_colors = np.array([(199, 233, 192),
(161, 217, 155),
(116, 196, 118),
(65, 171, 93),
(35, 139, 69),
]) / 255.
earth_colors = itertools.cycle(earth_colors)
ax = plt.axes(projection=ccrs.PlateCarree())
for country in shpreader.Reader(countries_shp).records():
print country.attributes['name_long'], earth_colors.next()
ax.add_geometries(country.geometry, ccrs.PlateCarree(),
facecolor=earth_colors.next(),
label=country.attributes['name_long'])
plt.show()
答案 1 :(得分:9)
受到pelson答案的启发,我发布了我的解决方案。我会把它留给你最好的,所以我现在不接受任何答案。
#! /usr/bin/env python
import sys
import os
from pylab import *
from mpl_toolkits.basemap import Basemap
import matplotlib as mp
from shapelib import ShapeFile
import dbflib
from matplotlib.collections import LineCollection
from matplotlib import cm
def get_shapeData(shp,dbf):
for npoly in range(shp.info()[0]):
shpsegs = []
shpinfo = []
shp_object = shp.read_object(npoly)
verts = shp_object.vertices()
rings = len(verts)
for ring in range(rings):
if ring == 0:
shapedict = dbf.read_record(npoly)
name = shapedict["name_long"]
continent = shapedict["continent"]
lons, lats = zip(*verts[ring])
if max(lons) > 721. or min(lons) < -721. or max(lats) > 91. or min(lats) < -91:
raise ValueError,msg
x, y = m(lons, lats)
shpsegs.append(zip(x,y))
shapedict['RINGNUM'] = ring+1
shapedict['SHAPENUM'] = npoly+1
shpinfo.append(shapedict)
lines = LineCollection(shpsegs,antialiaseds=(1,))
lines.set_facecolors(cm.jet(np.random.rand(1)))
lines.set_edgecolors('k')
lines.set_linewidth(0.3)
ax.add_collection(lines)
if __name__=='__main__':
f=figure(figsize=(10,10))
ax = plt.subplot(111)
m = Basemap(projection='merc',llcrnrlat=30,urcrnrlat=72,\
llcrnrlon=-40,urcrnrlon=50,resolution='c')
m.drawcountries(linewidth=0.1,color='w')
sfile = 'ne_10m_admin_0_countries'
shp = ShapeFile(sfile)
dbf = dbflib.open(sfile)
get_shapeData(shp,dbf)
show()
sys.exit(0)
这是结果
以下是我如何以正确的颜色填充阿尔巴尼亚的例子(我知道这不是很优雅;)。
#HACK for Albania
shpsegs = []
shpinfo = []
shp_object = shp.read_object(9)
verts = shp_object.vertices()
rings = len(verts)
for ring in range(rings):
if ring == 0:
shapedict = dbf.read_record(9)
name = shapedict["name_long"]
continent = shapedict["continent"]
lons, lats = zip(*verts[ring])
if max(lons) > 721. or min(lons) < -721. or max(lats) > 91. or min(lats) < -91:
raise ValueError,msg
x, y = m(lons, lats)
shpsegs.append(zip(x,y))
shapedict['RINGNUM'] = ring+1
shapedict['SHAPENUM'] = npoly+1
shpinfo.append(shapedict)
lines = LineCollection(shpsegs,antialiaseds=(1,))
if name == 'Albania':
lines.set_facecolors('w')
lines.set_edgecolors('k')
lines.set_linewidth(0.3)
ax.add_collection(lines)
完成所有其他形状后,执行此操作非常重要。也许你可以摆脱这部分代码,但正如我所说,这对我来说已经足够了。
对于我的申请,我按名称或大陆着色,因此这些行:
name = shapedict["name_long"]
continent = shapedict["continent"]
我从这个网站获得的数据:http://www.naturalearthdata.com/
答案 2 :(得分:2)
更新Python 3的@pelson答案:
import cartopy.crs as ccrs
import matplotlib.pyplot as plt
import cartopy.io.shapereader as shpreader
import itertools
import numpy as np
shapename = 'admin_0_countries'
countries_shp = shpreader.natural_earth(resolution='110m',
category='cultural', name=shapename)
print(countries_shp)
# some nice "earthy" colors
earth_colors = np.array([(199, 233, 192),
(161, 217, 155),
(116, 196, 118),
(65, 171, 93),
(35, 139, 69),
]) / 255
earth_colors = itertools.cycle(earth_colors)
ax = plt.axes(projection=ccrs.PlateCarree())
for country in shpreader.Reader(countries_shp).records():
print(country.attributes['NAME_LONG'], next(earth_colors))
ax.add_geometries(country.geometry, ccrs.PlateCarree(),
facecolor=next(earth_colors),
label=country.attributes['NAME_LONG'])
plt.show()