Заполните страны на базовой карте Python

Привет, я пытаюсь построить карту, используя базовую карту питонов, где некоторые страны залиты определенным цветом.

Есть ли быстрое и простое решение??


person red_tiger    schedule 15.11.2012    source источник
comment
Может быть полезно: geophysique.be/2011/ 27.01.   -  person unutbu    schedule 15.11.2012
comment
Я считаю, что это помогает: >matplotlib.1069221.n5.nabble.com/   -  person Fran Borcic    schedule 15.11.2012
comment
Спасибо за эти комментарии, они были наиболее полезными. Я также нашел сайт с бесплатными данными о странах, и это было именно то, что я искал: http://www.naturalearthdata.com/   -  person red_tiger    schedule 16.11.2012
comment
@red_tiger - вы могли бы ответить на свой вопрос небольшим фрагментом кода и выводом?   -  person pelson    schedule 04.01.2013


Ответы (3)


Как уже было сказано @unutbu, пост Томаса вот именно то, что вам нужно.

Если вы хотите сделать это с помощью Cartopy, соответствующий код (в версии 0.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()

выход

person pelson    schedule 08.05.2013
comment
Обратите внимание, что вы должны опубликовать основные части ответа здесь, на этом сайте, иначе ваше сообщение может быть удалено см. FAQ, где упоминаются ответы, которые являются «чуть больше, чем ссылкой». Вы все равно можете включить ссылку, если хотите, но только как «ссылку». Ответ должен стоять сам по себе, без ссылки. - person Taryn; 09.05.2013
comment
Спасибо @bluefeet - я понимаю, почему это так. Я обновил ответ, чтобы дать новую информацию (без дублирования исходной ссылки, авторские права на которую мне не принадлежат). Ваше здоровье, - person pelson; 09.05.2013
comment
Вызов shpreader.natural_earth дает мне ошибку http 404 not found, он, видимо, пытается его загрузить? - person Leo; 05.12.2014
comment
Вот так. Вам доступны гигабайты данных на Natural Earth — было бы нецелесообразно устанавливать их все. Если вы обновите версию cartopy до версии 0.11.2, будут отражены недавние изменения в схеме URL-адресов NaturalEarth, и вы больше не будете получать ошибку 404. github.com/SciTools/cartopy/pull/472 относится. - person pelson; 05.12.2014

Вдохновленный ответом Пелсона, я публикую решение, которое у меня есть. Я оставлю это на ваше усмотрение, что работает лучше всего, поэтому в данный момент я не приму никаких ответов.

#! /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/

person red_tiger    schedule 15.05.2013
comment
Да, собственно то же самое происходит и с Арменией. Мне пришлось поработать, явно заполнив эти две страны впоследствии. Запрос с людьми из naturalearthdata не был окончательным, и я не стал следить за этим, как только исправил его для себя. - person red_tiger; 15.05.2013
comment
@red_tiger У меня такая же проблема с Аргентиной и Анголой. Можете ли вы опубликовать свое решение албанской проблемы? Что сказали ребята из NaturalEarth? Спасибо. - person tommy.carstensen; 14.01.2016
comment
@red_tiger Появляется ли Албания, если вы меняете альфу? Например lines.set_alpha(0.5)? - person tommy.carstensen; 15.01.2016
comment
@tommy.carstensen смотрите мой обновленный ответ на ваш первый вопрос. Я открыл тему на форуме данных NaturalEarth (naturalearthdata.com/forums/topic /armenia-under-water), но это не было окончательным. И я не следил за этим после того, как реализовал этот хак. И на ваш последний вопрос. Я не пробовал это, но дайте мне знать, если это имеет положительный эффект. - person red_tiger; 15.01.2016

Обновление ответа @pelson для Python 3:

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()
person user1718097    schedule 18.06.2018
comment
Я получил ошибку TypeError: 'Polygon' object is not iterable в Python 3.8, которая соответствовала (этой проблеме GitHub)[github. com/SciTools/cartopy/issues/948]. Я исправил это, превратив country.geometry в такой список: ax.add_geometries([country.geometry], ccrs.PlateCarree(), ... - person dd.; 05.05.2020
comment
@dd Ошибку можно исправить следующей настройкой: ax.add_geometries([n.geometry], ccrs.PlateCarree()... - person Jan Bodnar; 12.05.2020