【问题标题】:Fill countries in python basemap在 python 底图中填充国家
【发布时间】:2012-11-04 00:33:40
【问题描述】:

您好,我正在尝试使用 python 底图绘制地图,其中一些国家/地区填充了某种颜色。

有没有快速简便的解决方案?

【问题讨论】:

标签: python matplotlib matplotlib-basemap


【解决方案1】:

正如@unutbu 所说,Thomas 的帖子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()

【讨论】:

  • 请注意,您应该在此处或此站点上发布答案的基本部分,否则您的帖子可能会被删除 See the FAQ where it mentions answers that are 'barely more than a link'. 如果您愿意,您仍然可以包含链接,但只能作为“参考'。答案应该是独立的,不需要链接。
  • 谢谢@bluefeet - 我明白为什么会这样。我已经更新了答案以提供一些新信息(不复制原始链接,我不拥有该链接的版权)。干杯,
  • 调用 shpreader.natural_earth 给我一个 http 404 not found 错误,它显然试图下载它?
  • 没错。 Natural Earth 上有数千兆字节的数据可供您使用 - 将它们全部安装是不切实际的。如果您将 cartopy 版本更新到 v0.11.2,NaturalEarth 的 URL 方案的最近更改将被反映,您将不再获得 404。github.com/SciTools/cartopy/pull/472 相关。
【解决方案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)

这是结果

这是我的示例,如何以正确的颜色填写阿尔巴尼亚(我知道不是很优雅;))。

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

【讨论】:

  • 是的,实际上亚美尼亚也是如此。我不得不通过明确填写这两个国家来解决问题。对 naturalearthdata 人员的询问不是结论性的,一旦我为我修好了它,我就没有跟进
  • @red_tiger 我对阿根廷和安哥拉也有同样的问题。你能发布你对“阿尔巴尼亚问题”的解决方案吗? NaturalEarth 的人怎么说?谢谢。
  • @red_tiger 更改 alpha 后会出现阿尔巴尼亚吗?例如lines.set_alpha(0.5)?
  • @tommy.carstensen 查看我对您的第一个问题的更新答案。我在 NaturalEarth 数据论坛 (naturalearthdata.com/forums/topic/armenia-under-water) 上开了一个话题,但还没有定论。在我实施了这个黑客之后,我没有跟进它。对于你的最后一个问题。我还没有尝试过,但请告诉我这是否有积极影响。
【解决方案3】:

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

【讨论】:

  • 我在 Python 3.8 中运行时遇到 TypeError: 'Polygon' object is not iterable 错误,与(此 GitHub 问题)[github.com/SciTools/cartopy/issues/948].我通过将country.geometry 设置为这样的列表来修复它:ax.add_geometries([country.geometry], ccrs.PlateCarree(), ...
  • @dd 可以通过以下调整修复错误:ax.add_geometries([n.geometry], ccrs.PlateCarree()...
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2021-03-03
  • 2018-02-15
  • 1970-01-01
  • 2023-03-22
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多