basemap地图绘制

地图绘制也是数据可视化的一部分,常用的地图绘制库为basemap工具包,其为matplotlib的子包。本篇文章讲解如何利用whl文件在Python3环境下安装basemap;学会使用basemap绘制地图;学会缩放区域和绘制散点图;通过综合案例,巩固basemap的绘制地图方法和技巧。 涉及到的知识点有:

  • basemap安装:学会basemap的安装方法。
  • basemap使用:学会利用basemap绘制简单地图。
  • 缩放区域与绘图:学会通过定位经纬度缩放区域与绘制散点图。
  • 综合案例:通过综合案例,巩固basemap的绘制地图方法和技巧。
  • 1 basemap的使用

    basemap是一个强大的绘制地图工具包。本节将讲解如何安装和使用basemap,结合matplotlib,绘制地图。

    1.1 basemap安装

    在anaconda的python3环境中,通过conda命令安装basemap会导致失败,这里通过该网站( www.lfd.uci.edu/~gohlke/pyt… 图1 Pyproj下载 图2 basemap下载 在anaconda环境中,切换到这两个whl文件的路径下,按顺序通过pip依次安装Pyproj和basemap文件,代码如下,安装Pyproj,如图3所示,代表Pyproj安装成功。

    cd H:\python数据分析\数据 pip install pyproj- 1.9 .5 .1 -cp36-cp36m-win_amd64.whl 图3 Pyproj安装 以同样的方法安装basemap,代码如下,如图4所示,安装basemap。

    cd H:\python数据分析\数据 pip install basemap- 1.1 .0 -cp36-cp36m-win_amd64.whl 图4 basemap安装 如图5所示,通过from mpl_toolkits.basemap import Basemap代码调用该库,发现程序可以运行,代表basemap库安装成功。 图5 安装成功

    1.2 basemap使用

    首先,导入需要的第三方库,通过basemap初始化一个地图对象,通过drawcoastlines绘制海岸线,代码如下。

    import numpy as np
    import pandas as pd
    import matplotlib.pyplot as plt
    from mpl_toolkits.basemap import Basemap
    %matplotlib inline
    map1 = Basemap(projection='ortho', lat_0=90, lon_0=-105,
                  resolution='l', area_thresh=1000.0)      #初始化地图对象
    map1.drawcoastlines()      #绘制海岸线
    

    projection参数是用于定义地图的投影方式;lat_0和lon_0是指定地图的中心坐标,这里的值为美国的中心坐标;resolution参数设置绘制边界的精度,l为低精度;area_thresh参数为阈值,低于该阈值的就不会被绘制。绘制地图如图6所示。 注意:更多参数详情可参考matplotlib.org/basemap/。 图6 基本地图 通过drawcountries方法绘制国家边界,代码如下,如图7所示。

    map1 = Basemap(projection='ortho', lat_0=90, lon_0=-105,
                  resolution='l', area_thresh=1000.0) 
    map1.drawcoastlines()  #绘制海岸线
    map1.drawcountries()   #绘制国家
    图7  绘制国家
    其他常见的绘制方法如下:

    drawmapboundary()   #绘制边界
    drawstates()          #绘制州
    drawcounties()        #绘制县
    

    通过fillcontinents方法为大陆填充颜色,代码如下,如图12.8所示。

    map1 = Basemap(projection='ortho', lat_0=90, lon_0=-105,
                  resolution='l', area_thresh=1000.0) 
    map1.drawcoastlines()  #绘制海岸线
    map1.drawcountries()   #绘制国家
    map1.fillcontinents(color='blue',alpha=0.5)  #填充颜色
    图8  填充大陆颜色
    通过drawmeridians和drawparallels方法绘制经线和纬线,代码如下,如图9所示。

    map1 = Basemap(projection='ortho', lat_0=90, lon_0=-105,
                  resolution='l', area_thresh=1000.0) 
    map1.drawcoastlines()  #绘制海岸线
    map1.drawcountries()   #绘制国家
    map1.drawmapboundary() #绘制边界
    map1.fillcontinents(color='blue',alpha=0.5)  #填充颜色
    map1.drawmeridians(np.arange(0, 360, 30))    #绘制经线
    map1.drawparallels(np.arange(-90, 90, 30))   #绘制纬线
    图9  绘制经度和纬度
    更换projection参数,换为robin坐标,可将图绘制为平面坐标,代码如下,如图10所示。

    map1 = Basemap(projection='robin', lat_0=90, lon_0=-105,
                  resolution='l', area_thresh=1000.0) 
    map1.drawcoastlines()  #绘制海岸线
    map1.drawcountries()   #绘制国家
    map1.drawmapboundary() #绘制边界
    map1.fillcontinents(color='blue',alpha=0.5)  #填充颜色
    map1.drawmeridians(np.arange(0, 360, 30))    #绘制经线
    map1.drawparallels(np.arange(-90, 90, 30))   #绘制纬线
    图10  平面坐标

    1.3 缩放区域与绘图

    在实际案例中,需对特定国家或地区进行绘制地图,这样就需要通过llcrnrlon、llcrnrlat、urcrnrlon和urcrnrlat指定左下角经纬度和右上角经纬度,代码如下,如图11所示。

    map2 = Basemap(projection='stere', lat_0=90, lon_0=-105,
                   llcrnrlon=-118.67, llcrnrlat=23.41,
                   urcrnrlon=-64.5, urcrnrlat=45.44,
                  resolution='l', area_thresh=1000.0) 
    map2.drawcoastlines()  #绘制海岸线
    map2.drawcountries()   #绘制国家
    map2.drawmapboundary() #绘制边界
    map2.drawstates()      #绘制州
    map2.fillcontinents(color='blue',alpha=0.5)  #填充颜色
    map2.drawmeridians(np.arange(0, 360, 30))    #绘制经线
    map2.drawparallels(np.arange(-90, 90, 30))   #绘制纬线
    图11  缩放区域
    通过坐标定位,可以在地图上绘制图形,代码如下,如图12所示。

    map2 = Basemap(projection='stere', lat_0=90, lon_0=-105,
                   llcrnrlon=-118.67, llcrnrlat=23.41,
                   urcrnrlon=-64.5, urcrnrlat=45.44,
                  resolution='l', area_thresh=1000.0) 
    map2.drawcoastlines()  #绘制海岸线
    map2.drawcountries()   #绘制国家
    map2.drawmapboundary() #绘制边界
    map2.drawstates()      #绘制州
    map2.drawmeridians(np.arange(0, 360, 30))    #绘制经线
    map2.drawparallels(np.arange(-90, 90, 30))   #绘制纬线
    lon = -74
    lat = 40.43
    x,y = map2(lon, lat)       #映射坐标
    map2.plot(x, y, 'ro', markersize=8)  #绘制散点图
    图12  绘制散点图
    通过matplotlib库的text方法,为散点加入文本注释。

    map2 = Basemap(projection='stere', lat_0=90, lon_0=-105,
                   llcrnrlon=-118.67, llcrnrlat=23.41,
                   urcrnrlon=-64.5, urcrnrlat=45.44,
                  resolution='l', area_thresh=1000.0) 
    map2.drawcoastlines()  #绘制海岸线
    map2.drawcountries()   #绘制国家
    map2.drawmapboundary() #绘制边界
    map2.drawstates()      #绘制州
    map2.drawmeridians(np.arange(0, 360, 30))    #绘制经线
    map2.drawparallels(np.arange(-90, 90, 30))   #绘制纬线
    lon = -74
    lat = 40.43
    x,y = map2(lon, lat)       #映射坐标
    map2.plot(x, y, 'ro', markersize=8)  #绘制散点图
    plt.text(x,y,'New York')   #文本注释
    图13  文本注释

    2 basemap综合示例

    本节将讲解如何通过basemap绘制区域与全球地图,结合具体案例,讲解地图的绘制方法和技巧。

    2.1 美国人口分布

    通过该网站(github.com/plotly/data… 图14 美国人口数据 通过以下代码,绘制前180个城市的美国人口分布图,如图15所示。

    import numpy as np
    import pandas as pd
    import matplotlib.pyplot as plt
    from mpl_toolkits.basemap import Basemap
    %matplotlib inline
    plt.style.use('ggplot')
    plt.figure(figsize=(10,6))
    map3 = Basemap(projection='stere', lat_0=90, lon_0=-105,
                   llcrnrlon=-118.67, llcrnrlat=23.41,
                   urcrnrlon=-64.5, urcrnrlat=45.44,
                  resolution='l', area_thresh=1000.0) 
    map3.drawcoastlines()  #绘制海岸线
    map3.drawcountries()   #绘制国家
    map3.drawmapboundary() #绘制边界
    map3.drawstates()      #绘制州
    map3.drawcounties()      # 绘制县
    map3.drawmeridians(np.arange(0, 360, 30))    #绘制经线
    map3.drawparallels(np.arange(-90, 90, 30))   #绘制纬线
    lat = np.array(pop_data["lat"][0:180])                        # 获取维度之维度值
    lon = np.array(pop_data["lon"][0:180])                        # 获取经度值
    pop = np.array(pop_data["pop"][0:180],dtype=float)    # 获取人口数,转化为numpy浮点型
    size = (pop/np.max(pop))*1000 # 计算每个点的大小
    x,y = map3(lon,lat)
    map3.scatter(x,y,s=size)
    plt.title('Population distribution in America')     #加标题
    

    代码分析: (1)15行 导入程序需要的库。 (2)78行 设置图表的样式为ggplot,并设置图表的长宽比。 (3)1021行 定义basemap对象,并绘制出美国的地图底图和经纬度。 (4)2329 获取前180个数据,并绘制散点图。 图15 美国人口分布图 注意:人口如果不转化为numpy浮点型,散点图不会显示出大小不一。

    2.2 全球地震可视化

    通过美国地震局官网(earthquake.usgs.gov/earthquakes… 图16 过去一周地震数据下载 读取数据,如图17所示,该数据有很多字段,但本次分析中用到的就是经纬度字段和mag字段(震级)。 图17 地震数据 对这三个字段查看缺失值,如图18所示,mag字段有1个缺失值。 图18 查看缺失值 通过过滤剔除到这个缺失值,如图19所示。 图19 过滤缺失值 通过以下代码,绘制地震分布图,如图20所示。

    plt.style.use('ggplot')
    plt.figure(figsize=(10,6))
    map4 = Basemap(projection='robin', lat_0=39.9, lon_0=116.3,
                  resolution = 'l', area_thresh = 1000.0) 
    map4.drawcoastlines()         #绘制海岸线
    map4.drawcountries()          #绘制国家
    map4.drawmapboundary()      #绘制边界
    map4.drawmeridians(np.arange(0, 360, 30))     #绘制经线
    map4.drawparallels(np.arange(-90, 90, 30))      #绘制纬线
    x,y = map4(list(eq_data['longitude']),list(eq_data['latitude']))
    map4.plot(x, y, 'ro', markersize=6)       #绘制散点图
    图20  全球地震分布图(1)
    根据震级大小,绘制散点不一的地震分布图,如图21所示。

    plt.style.use('ggplot')
    plt.figure(figsize=(10,6))
    map5 = Basemap(projection='robin', lat_0=39.9, lon_0=116.3,
                   resolution = 'l', area_thresh = 1000.0) 
    map5.drawcoastlines()
    map5.drawcountries()
    map5.drawmapboundary()
    map5.drawmeridians(np.arange(0, 360, 30))
    map5.drawparallels(np.arange(-90, 90, 30))
    size = 2    #初始化大小
    for lon, lat, mag in zip(list(eq_data['longitude']), list(eq_data['latitude']), list(eq_data['mag'])):
        x,y = map5(lon, lat)
        msize = mag * size     #不同震级大小不一样
        map5.plot(x, y, 'ro', markersize=msize)
    

    图21 全球地震分布图(2) 通过以下代码,定义一个函数,可通过不同震级绘制颜色不同的地图,如图22所示。

    def get_marker_color(mag):
        if mag < 3.0:
            return ('go')
        elif mag < 5.0:
            return ('yo')
        else:
            return ('ro')      #定义设置颜色函数
    plt.style.use('ggplot')
    plt.figure(figsize=(10,6))
    map6 = Basemap(projection='robin', lat_0=39.9, lon_0=116.3,
                   resolution = 'l', area_thresh = 1000.0) 
    map6.drawcoastlines()
    map6.drawcountries()
    map6.drawmapboundary()
    map6.drawmeridians(np.arange(0, 360, 30))
    map6.drawparallels(np.arange(-90, 90, 30))
    size = 2
    for lon, lat, mag in zip(list(eq_data['longitude']), list(eq_data['latitude']), list(eq_data['mag'])):
        x,y = map6(lon, lat)
        msize = mag * size
        map6.plot(x, y, get_marker_color(mag), markersize=msize)   #调用函数
    plt.title('Earthquakes')
    

    图22 全球地震分布图(3)

    3 pyecharts地图绘制

    pyecharts也可以轻松绘制出美观可交互的地图。本节将讲解如何利用pyecharts绘制不同地区的地图,通过Geo方法在地图上绘制散点图。

    3.1 地图

    利用pyecharts绘制地图,需要下载地图js文件,通过pip进行安装,如图23所示。

    pip install echarts-countries-pypkg        #全球国家地图
    pip install echarts-china-provinces-pypkg  #中国省级地图
    pip install echarts-china-cities-pypkg      #中国市级地图
    图23  安装地图js
    注意:安装好后记得重启jupyter notebook。
    利用Map方法可绘制地图,代码如下。

    value = [155, 78, 23, 65]
    label = ["北京", "上海", "西藏", "广东"]
    map1 = pyecharts.Map("全国地图示例")
    map1.add("",label, value, maptype='china')
    map1.render()   #生成html文件
    

    该add方法的参数如下,maptype设置地图类型,支持china、world、中国省市名称等;is_roam可缩放地图;is_map_symbol_show显示地图红点。

    add(name, attr, value,
        maptype='china',
        is_roam=True,
        is_map_symbol_show=True, **kwargs)
    

    绘制的中国地图如图24所示。 图24 全国地图(1) 设置is_label_show=True,可以显示各省份名称,代码如下,如图25所示。

    value = [155, 78, 23, 65]
    label = ["北京", "上海", "西藏", "广东"]
    map1 = pyecharts.Map("全国地图示例", width=1200, height=600)
    map1.add("",label, value, maptype='china', is_label_show=True)
    map1.render()   #生成html文件
    图25  全国地图(2)
    结合Visualmap可以美化地图,根据值显示不同颜色,代码如下,如图26所示。

    value = [155, 78, 23, 65]
    label = ["北京", "上海", "西藏", "广东"]
    map1 = pyecharts.Map("全国地图示例", width=1200, height=600)
    map1.add("",label, value, maptype='china', is_visualmap=True,
            visual_text_color='#000')
    map1.render()   #生成html文件
    

    图26 全国地图(3)

    修改maptype参数可以绘制省级地图,代码如下,如图27所示。

    value = [233, 102, 41, 82]
    attr = ['武汉市', '咸宁市', '黄冈市', '黄石市']
    map1 = pyecharts.Map("湖北省地图")
    map1.add("", attr, value, maptype='湖北', is_visualmap=True,
            visual_text_color='#000')
    map1.render()
    图27  湖北省地图
    修改maptype参数为world可以绘制世界地图,代码如下,如图28所示。

    value = [46, 54, 45, 82, 45]
    attr= ["China", "Canada", "Brazil", "Russia", "United States"]
    map1 = pyecharts.Map("世界地图", width=1200, height=600)
    map1.add("", attr, value, maptype="world", is_visualmap=True,
            visual_text_color='#000', is_map_symbol_show=False)
    map1.render()
    图28  全球地图

    3.2 地图坐标系

    地图坐标系组件用于地图的绘制,支持在地图上绘制散点图,线集。利用Geo方法可在地图上绘制散点图等,代码如下。

    data = [
        ('上海', 78),('武汉', 56),('长沙', 45),('北京', 65),('苏州', 32),('盐城', 15),
        ('南昌', 87),('青岛', 45),('广州', 78),('拉萨', 12),('桂林', 21),('西安', 42),
        ('济南', 12)]
    geo = pyecharts.Geo("地图绘制案例一",
              title_pos="center", width=1200,
              height=600)
    attr, value = geo.cast(data)
    geo.add("", attr, value, visual_range=[0, 100], visual_text_color="#fff",
            geo_normal_color="#FFFFFF",
            symbol_size=15, is_visualmap=True)
    geo.render()
    

    该add方法的参数如下,type设置图例类型,'scatter', 'effectScatter', 'heatmap'可选;symbol_size为散点图大小;border_color设置地图边界颜色;geo_normal_color为正常情况下地图区域颜色;geo_emphasis_color为高亮下地图区域的颜色。

    add(name, attr, value,
        type="scatter",
        maptype='china',
        symbol_size=12,
        border_color="#111",
        geo_normal_color="#323c48",
        geo_emphasis_color="#2a333d",
        is_roam=True, **kwargs)
    

    绘制的地图如图29所示。 图29 案例一 修改type参数,更改为heatmap,代码如下,如图30所示。

    data = [
        ('上海', 78),('武汉', 56),('长沙', 45),('北京', 65),('苏州', 32),('盐城', 15),
        ('南昌', 87),('青岛', 45),('广州', 78),('拉萨', 12),('桂林', 21),('西安', 42),
        ('济南', 12)]
    geo = pyecharts.Geo("地图绘制案例二",
              title_pos="center", width=1200,
              height=600)
    attr, value = geo.cast(data)
    geo.add("", attr, value, type='heatmap', visual_range=[0, 100], visual_text_color="#fff",
            geo_normal_color="#FFFFFF",
            symbol_size=15, is_visualmap=True)
    geo.render()