【问题标题】:Plot only on continent in matplotlib仅在 matplotlib 中的大陆上绘制
【发布时间】:2012-11-27 14:13:34
【问题描述】:

我正在使用 matplotlib 中的底图绘制地图。数据遍布全球,但我只想把大陆上的数据都保留下来,丢到海里。有没有办法可以过滤数据,或者有没有办法再次绘制海洋来覆盖数据?

【问题讨论】:

    标签: python map matplotlib matplotlib-basemap


    【解决方案1】:

    matplotlib.basemap中有方法:is_land(xpt, ypt)

    如果给定的 x,y 点(在投影坐标中)在陆地上,则返回 True,否则返回 False。土地的定义基于与类实例关联的 GSHHS 海岸线多边形。陆地区域内湖泊上方的点不计为陆地点。

    有关详细信息,请参阅here

    【讨论】:

    • 谢谢,这正是我想要的。但是,当我使用is_land 时,我遇到了问题。这是here
    【解决方案2】:

    is_land() 将循环所有多边形以检查它是否是陆地。对于大数据量,它非常慢。您可以使用 matplotlib 中的 points_inside_poly() 快速检查点数组。这是代码。它不检查lakepolygons,如果你想删除湖中的点,你可以添加你自己。

    在我的电脑上检查 100000 个点需要 2.7 秒。如果您想要更快的速度,您可以将多边形转换为位图,但这样做有点困难。请告诉我以下代码是否对您的数据集不够快。

    from mpl_toolkits.basemap import Basemap
    import numpy as np
    import matplotlib.pyplot as plt
    import matplotlib.nxutils as nx
    
    def points_in_polys(points, polys):
        result = []
        for poly in polys:
            mask = nx.points_inside_poly(points, poly)
            result.extend(points[mask])
            points = points[~mask]
        return np.array(result)
    
    points = np.random.randint(0, 90, size=(100000, 2))
    m = Basemap(projection='moll',lon_0=0,resolution='c')
    m.drawcoastlines()
    m.fillcontinents(color='coral',lake_color='aqua')
    x, y = m(points[:,0], points[:,1])
    loc = np.c_[x, y]
    polys = [p.boundary for p in m.landpolygons]
    land_loc = points_in_polys(loc, polys)
    m.plot(land_loc[:, 0], land_loc[:, 1],'ro')
    plt.show()
    

    【讨论】:

    • 我认为 points_inside_poly(如果我记得整个 nxutils)在 mpl 1.2 中已被贬值,但它也适用于新方法(不记得新方法在时刻,但折旧警告会告诉它)
    【解决方案3】:

    HYRY 的答案不适用于新版本的 matplotlib(nxutils 已弃用)。我制作了一个有效的新版本:

    from mpl_toolkits.basemap import Basemap
    import matplotlib.pyplot as plt
    from matplotlib.path import Path
    import numpy as np
    
    map = Basemap(projection='cyl', resolution='c')
    
    lons = [0., 0., 16., 76.]
    lats = [0., 41., 19., 51.]
    
    x, y = map(lons, lats)
    
    locations = np.c_[x, y]
    
    polygons = [Path(p.boundary) for p in map.landpolygons]
    
    result = np.zeros(len(locations), dtype=bool) 
    
    for polygon in polygons:
    
        result += np.array(polygon.contains_points(locations))
    
    print result
    

    【讨论】:

      【解决方案4】:

      最简单的方法是使用底图的maskoceans

      如果对于每个 lat, lon 你有一个数据并且你想要 使用轮廓: 网格网格和插值后:

      from scipy.interpolate import griddata as gd
      from mpl_toolkits.basemap import Basemap, cm, maskoceans
      xi, yi = np.meshgrid(xi, yi)
      zi = gd((mlon, mlat),
                  scores,
                  (xi, yi),
                  method=grid_interpolation_method)
      #mask points on ocean
      data = maskoceans(xi, yi, zi)
      con = m.contourf(xi, yi, data, cmap=cm.GMT_red2green)
      #note instead of zi we have data now.
      

      更新(比 in_land 或 in_polygon 解决方案快得多):

      如果对于每个 lat, lon 您没有任何数据,并且您只想将点分散在陆地上:

      x, y = m(lons, lats)
      samples = len(lons)
      ocean = maskoceans(lons, lats, datain=np.arange(samples),
                         resolution='i')
      ocean_samples = np.ma.count_masked(ocean)
      print('{0} of {1} points in ocean'.format(ocean_samples, samples))
      m.scatter(x[~ocean.mask], y[~ocean.mask], marker='.', color=colors[~ocean.mask], s=1)
      m.drawcountries()
      m.drawcoastlines(linewidth=0.7)
      plt.savefig('a.png')
      

      【讨论】:

        【解决方案5】:

        我正在回答this question,当时我被告知最好在这里发布我的答案。基本上,我的解决方案提取用于绘制Basemap 实例的海岸线的多边形,并将这些多边形与地图的轮廓相结合,以生成覆盖地图海洋区域的matplotlib.PathPatch

        如果数据是粗略的并且不需要数据插值,这尤其有用。在这种情况下,使用maskoceans 会产生非常粗糙的海岸线轮廓,看起来不太好。

        这是我作为另一个问题的答案发布的相同示例:

        from matplotlib import pyplot as plt
        from mpl_toolkits import basemap as bm
        from matplotlib import colors
        import numpy as np
        import numpy.ma as ma
        from matplotlib.patches import Path, PathPatch
        
        fig, ax = plt.subplots()
        
        lon_0 = 319
        lat_0 = 72
        
        ##some fake data
        lons = np.linspace(lon_0-60,lon_0+60,10)
        lats = np.linspace(lat_0-15,lat_0+15,5)
        lon, lat = np.meshgrid(lons,lats)
        TOPO = np.sin(np.pi*lon/180)*np.exp(lat/90)
        
        m = bm.Basemap(resolution='i',projection='laea', width=1500000, height=2900000, lat_ts=60, lat_0=lat_0, lon_0=lon_0, ax = ax)
        m.drawcoastlines(linewidth=0.5)
        
        x,y = m(lon,lat)
        pcol = ax.pcolormesh(x,y,TOPO)
        
        ##getting the limits of the map:
        x0,x1 = ax.get_xlim()
        y0,y1 = ax.get_ylim()
        map_edges = np.array([[x0,y0],[x1,y0],[x1,y1],[x0,y1]])
        
        ##getting all polygons used to draw the coastlines of the map
        polys = [p.boundary for p in m.landpolygons]
        
        ##combining with map edges
        polys = [map_edges]+polys[:]
        
        ##creating a PathPatch
        codes = [
            [Path.MOVETO] + [Path.LINETO for p in p[1:]]
            for p in polys
        ]
        polys_lin = [v for p in polys for v in p]
        codes_lin = [c for cs in codes for c in cs]
        path = Path(polys_lin, codes_lin)
        patch = PathPatch(path,facecolor='white', lw=0)
        
        ##masking the data:
        ax.add_patch(patch)
        
        plt.show()
        

        这会产生以下情节:

        希望这对某人有帮助:)

        【讨论】:

        • +1 以获得全面的答案。在我的情况下,它完全相反,我想掩盖陆地并显示海洋中的数据。可以进行哪些更改以使其生效?
        • 希望您能提供帮助
        猜你喜欢
        • 2012-08-01
        • 1970-01-01
        • 1970-01-01
        • 2011-07-27
        • 1970-01-01
        • 1970-01-01
        • 2014-11-02
        • 2011-12-25
        相关资源
        最近更新 更多