Fill countries in python basemap

后端 未结 3 514
佛祖请我去吃肉
佛祖请我去吃肉 2020-11-30 02:23

Hi I am trying to plot a map using pythons basemap with some countries filled in a certain colour.

Is there a quick and easy solution out there??

相关标签:
3条回答
  • 2020-11-30 02:27

    Updating @pelson answer for 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()
    
    0 讨论(0)
  • 2020-11-30 02:32

    Inspired by the answer from pelson, I post the solution I have. I will leave it up to you which works best, so I will not accept any answer at the moment.

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

    This is the result

    example for filling in countries in different colours

    Here is my example how to fill in Albania in the correct colour (not very elegant I know ;)).

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

    It is important that you do this after you have done all the other shapes. Perhaps you can get rid of some part of this code, but as I said it was sufficient for me.

    For my application I coloured contries by name or continent, therefore these lines:

        name = shapedict["name_long"]
        continent = shapedict["continent"]
    

    The data used I got from this website: http://www.naturalearthdata.com/

    0 讨论(0)
  • 2020-11-30 02:44

    As has already been said by @unutbu, Thomas' post here is exactly what you are after.

    Should you want to do this with Cartopy, the corresponding code (in v0.7) can be adapted from http://scitools.org.uk/cartopy/docs/latest/tutorials/using_the_shapereader.html slightly:

    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

    0 讨论(0)
提交回复
热议问题