python采用Basemap绘制完美中国地图(包括绘制边界框,随机点等)
1. 效果图2. 原理2.1 依赖模块及安装2.2 工程目录2.3 依赖文件latlng.txt 经纬度3 源码参考这篇博客将介绍如何使用basemap绘制简单的地图(包括绘制边界框,随机点等),Basemap基于GEOS的地图二维数据,其底图数据库与GMT相同,封装了大量常用的地图投影、坐标转换功能,利用简洁的Python语法支持绘出多种多样的地理地图。
写这篇博客源于一个博友的提问,绘制地图及经纬度点为这样的效果图:
1. 效果图
左图效果图如下:
右图效果图如下:
2. 原理
2.1 依赖模块及安装
依赖模块如下:安装geos
pyproj
basemap
pip install geospip install pyproj
basemap的wheel文件可在 https://www.lfd.uci.edu/~gohlke/pythonlibs/ 下载,注意需要和python版本以及系统版本对应;
下载完成就可以安装了:
pip install basemap-1.2.2-cp37-cp37m-win_amd64.whl
2.2 工程目录
$ tree.|-- images| `-- latlng.txt ------依赖经纬度值|-- left.png ------------程序运行生成|-- plot_map.py----------程序代码`-- right.png -----------程序运行生成1 directory, 4 files
2.3 依赖文件latlng.txt 经纬度
经纬度是从提问的图片中OCR识别出来的写入了文件,OCR可参考:
另外为了效果图更加明显,随机增加了一些经纬度;
-125 -125.5 48.5 49.0 -125.23 48.79 5 4 7-125 -125.5 48.5 49.0 -125.1 48.9 5 4 7-125 -125.5 48.5 49.0 -125.4 48.6 5 4 7-125 -130.5 48.5 55.0 -128.23 54.79 5 4 7-125 -134.5 35.5 49.0 -134.23 36.79 5 4 7-125 -134.5 35.5 49.0 -130.23 40.79 5 4 7-125 -130.5 45.5 55.0 -128.23 52.79 5 4 7-125 -134.5 45.5 49.0 -134.23 46.79 5 4 7-125 -134.5 45.5 49.0 -130.23 51.79 5 4 7-65.5 -66.0 43 43.5 -65.93 43.33 12 14 7-61.5 -62.0 47 47.5 -61.96 47.39 5 21 16-64.5 -65.0 43.5 44.0 -64.87 43.7 12 2 22-55.5 -56.0 45.5 46.0 -55.75 45.7 10 13 7-66 -66.5 43.5 44.0 -66.41 43.98 12 16 14-53 -53.5 49 49.5 -53.35 49.23 11 3 19-53 -53.5 50 50.5 -53.47 50.29 10 24 11-51 -51.5 45.5 46.0 -51.02 45.6 9 13 16-64 -64.5 49 49.5 -64.37 49.0 5 18 22
3 源码
# 绘制地图数据# 注意:plt.savefig() 依赖 matplotlib.use("Agg")设置# plt.show时,需要注释掉 matplotlib.use("Agg")import osimport numpy as npfrom mpl_toolkits.basemap import Basemap # 地图依赖import matplotlib.pyplot as plt # 绘制效果图及可视化import matplotlib.image as mpimg # 读取图片import matplotlib # 保存图片# 设置此才可保存图片到本地,但同时没法可视化plt.show()了# matplotlib.use("Agg")def left_map():# 边界框,及起点0,0处经纬度map = Basemap(llcrnrlon=-135, llcrnrlat=45, urcrnrlon=-120, urcrnrlat=55,resolution='i', lat_0=45, lon_0=-135)map.drawmapboundary(fill_color='aqua')map.fillcontinents(color='#ddaa66', lake_color='aqua')map.drawcoastlines() # 绘制海岸线图层# drawparalles: 绘制lon# drawmeridians:绘制lat# range(-90,100,5)等差数列,因为range到达不了本身,所以需要大一点# linewidht:线宽# dashes[4,2]: 4绘制大小,2间隔像素# labels[1,0,0,1]:文本位置 分别代表左、右、上、下# color: 字体颜色# zorder:改变线的位置,例如,能够使土地覆盖平行线,或相反. 0:线在土地下方(看不见),1:线在土地上方map.drawparallels(range(45, 57, 2), linewidth=2, dashes=[4, 2], labels=[1, 0, 0, 1], color='r', zorder=0)map.drawmeridians(range(-135, 118, 5), linewidth=2, dashes=[4, 2], labels=[1, 0, 0, 1], color='b', zorder=0)# 获取第5列得到经度lons,获取第5列得到纬度lats# my_data = np.loadtxt('images/latlng.txt')# lons = my_data[:, [4]]# lats = my_data[:, [5]]# 生成随机点lons = np.random.randint(120, 135, (25, 1)).astype(np.float32) * -1lats = np.random.randint(45, 55, (25, 1)).astype(np.float32)x, y = map(lons, lats)# 绘制点 圆点红色# 可参考/stable/api/markers_api.html 找到绘制的样式# 可参考/stable/api/colors_api.html 找到绘制的颜色map.scatter(x, y, marker='.', color='r')plt.show()# plt.savefig('left.png')def right_map():# 边界框,及起点0,0处经纬度map = Basemap(llcrnrlon=-75, llcrnrlat=35, urcrnrlon=-45, urcrnrlat=55,resolution='i', lat_0=35, lon_0=-75)map.drawmapboundary(fill_color='aqua')map.fillcontinents(color='#ddaa66', lake_color='aqua')map.drawcoastlines() # 绘制海岸线图层# drawparalles: 绘制lon# drawmeridians:绘制lat# range(-90,100,5)等差数列# linewidht:线宽# dashes[4,2]: 4绘制大小,2间隔像素# labels[1,0,0,1]:文本位置 分别代表左、右、上、下# color: 字体颜色# zorder:改变线的位置,例如,能够使土地覆盖平行线,或相反. 0:线在土地下方(看不见),1:线在土地上方map.drawparallels(range(-90, 100, 5), linewidth=2, dashes=[4, 2], labels=[1, 0, 0, 1], color='r', zorder=0)map.drawmeridians(range(-75, 0, 10), linewidth=2, dashes=[4, 2], labels=[1, 0, 0, 1], color='b', zorder=0)my_data = np.loadtxt('images/latlng.txt')# print(my_data.shape)# print(my_data)# print('lon: ',my_data[:,[4]])# print('lat: ',my_data[:,[5]])# 获取第5列得到经度lons,获取第5列得到纬度latslons = my_data[:, [4]]lats = my_data[:, [5]]x, y = map(lons, lats)# 绘制点 圆点红色# 可参考/stable/api/markers_api.html 找到绘制的样式# 可参考/stable/api/colors_api.html 找到绘制的颜色map.scatter(x, y, marker='.', color='r')plt.show()# plt.savefig('right.png')left_map()right_map()def mixshow():folder_path = os.getcwd().replace('\\', '/')list = [folder_path + '/left.png', folder_path + '/right.png']for i, j in enumerate(list):print(j)# matplot读出来是RGBimage = mpimg.imread(j)plt.subplot(1, 2, i + 1)plt.imshow(image) # 通过for循环逐个显示图像plt.xticks([]) # 去掉x轴的刻度plt.yticks([]) # 去掉y轴的刻度plt.show()mixshow()