Заполните страны базой данных python
Привет. Я пытаюсь построить карту, используя базовую карту pythons, с некоторыми странами, заполненными определенным цветом.
Есть ли быстрое и простое решение там?
Ответы
Ответ 1
Как уже было сказано @unutbu, сообщение Томаса здесь - это именно то, что вы после.
Если вы хотите сделать это с помощью Cartopy, соответствующий код (в версии v.7.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()
![output]()
Ответ 2
Вдохновленный ответом от 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)
Это результат
![example for filling in countries in different colours]()
Вот мой пример, как заполнить Албанию в правильном цвете (не очень элегантный я знаю;)).
#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/