3D中的Basemap

可以使用底图和matplotlib mplot3d工具包创建带有3d元素的地图。

1、创建基本地图

在开始使用3d matplotlib绘图时,必须使用Axes3D类。要向地图添加地理数据,将使用方法add_collection3d:

In [11]:
# %matplotlib inline
# import matplotlib.pyplot as plt
from mpl_toolkits.mplot3d import Axes3D
# from mpl_toolkits.basemap import Basemap

map = Basemap()

fig = plt.figure()
ax = Axes3D(fig)

'''
ax.azim = 270
ax.elev = 90
ax.dist = 5
'''

ax.add_collection3d(map.drawcoastlines(linewidth=0.25))
ax.add_collection3d(map.drawcountries(linewidth=0.35))

plt.show()
  • 在该示例中,ax变量是Axes3D实例。所有的方法都将使用这个实例,所以他们需要支持3D操作。
  • 旋转生成的地图显示已注释的块,这样可以使视图更完美。
  • 要绘制线条,只需使用add_collection3d方法与任何底图方法的输出返回一个matplotlib.patches.LineCollection对象,如drawcountries。

2、填充多边形

不幸的是,底图fillcontinents方法不返回add_collection3d(PolyCollection,LineColleciton,PatchCollection)支持的对象,而是返回一个matplotlib.patches.Polygon对象的列表。

解决方案当然是创建一个PolyCollection的列表:

In [ ]:
# %matplotlib inline
# import matplotlib.pyplot as plt
from mpl_toolkits.mplot3d import Axes3D
# from mpl_toolkits.basemap import Basemap
from matplotlib.collections import PolyCollection

map = Basemap()

fig = plt.figure()
ax = Axes3D(fig)

ax.azim = 270
ax.elev = 50
ax.dist = 8

ax.add_collection3d(map.drawcoastlines(linewidth=0.25))
ax.add_collection3d(map.drawcountries(linewidth=0.35))

polys = []
for polygon in map.landpolygons:
    polys.append(polygon.get_coords())


lc = PolyCollection(polys, edgecolor='black',
                    facecolor='#DDDDDD', closed=False)
# 要创建PolyCollection,需要多边形,但是Basemap对象在领域多边形中有它。 (还有其他的包括多边形,如国家)
# 一旦创建了坐标列表的列表,就可以构建PoilyCollection



ax.add_collection3d(lc)

# PolyCollection使用add_collection3d添加,就像我们对行一样

plt.show()
  • 海岸线和国家的绘制如前面的例子

  • 对于每个多边形,可以使用get_coords方法将坐标作为浮点列表检索。 (它是_geoslib.Polygon对象)

  • 如果使用fillcontinents添加原始多边形,matplotlib会显示没有方法将其转换为3D

3、添加3D条

如果没有绘制3D数据,则创建的3D地图将没有意义。 Axes3D类具有绘制3D条的bar3d方法。它可以使用第三维在地图上添加:

In [ ]:
#%matplotlib inline
#import matplotlib.pyplot as plt
#from mpl_toolkits.mplot3d import Axes3D
#from mpl_toolkits.basemap import Basemap
#from matplotlib.collections import PolyCollection
import numpy as np

map = Basemap(llcrnrlon=-20,llcrnrlat=0,urcrnrlon=15,urcrnrlat=50,)


# 地图被放大以适应Ebola案例数据集的需要
fig = plt.figure()
ax = Axes3D(fig)

ax.set_axis_off()
# 用set_axis_off方法消除轴


ax.azim = 270
ax.dist = 7

polys = []
for polygon in map.landpolygons:
    polys.append(polygon.get_coords())


lc = PolyCollection(polys, edgecolor='black',
                    facecolor='#DDDDDD', closed=False)

ax.add_collection3d(lc)
ax.add_collection3d(map.drawcoastlines(linewidth=0.25))
ax.add_collection3d(map.drawcountries(linewidth=0.35))

lons = np.array([-13.7, -10.8, -13.2, -96.8, -7.99, 7.5, -17.3, -3.7])
lats = np.array([9.6, 6.3, 8.5, 32.7, 12.5, 8.9, 14.7, 40.39])
cases = np.array([1971, 7069, 6073, 4, 6, 20, 1, 1])
deaths = np.array([1192, 2964, 1250, 1, 5, 8, 0, 0])
places = np.array(['Guinea', 'Liberia', 'Sierra Leone','United States', 'Mali', 'Nigeria', 'Senegal', 'Spain'])

x, y = map(lons, lats)

ax.bar3d(x, y, np.zeros(len(x)), 2, 2, deaths, color= 'r', alpha=0.8)
# bar3d需要x,y和z位置,加上delta x,y和z。要正确绘制,z位置必须为0,delta z为最终值


plt.show()

插入定位符

插入定位器是一个很酷的类,它会缩放绘图的一部分,并绘制在绘图本身,才能显示缩放区域。

In [ ]:
#%matplotlib inline
#from mpl_toolkits.basemap import Basemap
#import matplotlib.pyplot as plt
from mpl_toolkits.axes_grid1.inset_locator import zoomed_inset_axes
from mpl_toolkits.axes_grid1.inset_locator import mark_inset
#import numpy as np

fig = plt.figure()
ax = fig.add_subplot(111)

map = Basemap(projection='cyl',
              lat_0=0, lon_0=0)

map.drawmapboundary(fill_color='#7777ff')
map.fillcontinents(color='#ddaa66', lake_color='#7777ff', zorder=0)
map.drawcoastlines()

lons = np.array([-13.7, -10.8, -13.2, -96.8, -7.99, 7.5, -17.3, -3.7])
lats = np.array([9.6, 6.3, 8.5, 32.7, 12.5, 8.9, 14.7, 40.39])
cases = np.array([1971, 7069, 6073, 4, 6, 20, 1, 1])
deaths = np.array([1192, 2964, 1250, 1, 5, 8, 0, 0])
places = np.array(['Guinea', 'Liberia', 'Sierra Leone','United States', 'Mali', 'Nigeria', 'Senegal', 'Spain'])

x, y = map(lons, lats)

map.scatter(x, y, s=cases, c='r', alpha=0.5)

axins = zoomed_inset_axes(ax, 7, loc=1)
axins.set_xlim(-20, 0)
axins.set_ylim(3, 18)

plt.xticks(visible=False)
plt.yticks(visible=False)

map2 = Basemap(llcrnrlon=-20,llcrnrlat=3,urcrnrlon=0,urcrnrlat=18, ax=axins)
map2.drawmapboundary(fill_color='#7777ff')
map2.fillcontinents(color='#ddaa66', lake_color='#7777ff', zorder=0)
map2.drawcoastlines()
map2.drawcountries()

map2.scatter(x, y, s=cases/5., c='r', alpha=0.5)

mark_inset(ax, axins, loc1=2, loc2=4, fc="none", ec="0.5")

plt.show()
  • 基本散点图是一个规则散点图。
  • 插入定位器使用zoomed_inset_axes创建。
  • ax是插入定位器缩放的轴。
  • 7是缩放级别(稍后将被覆盖)。
  • loc是插入定位器的位置(在这种情况下是右上方)。
  • set_xlim和set_ylim将区域更改为由插入定位器覆盖。因为我们使用圆柱投影,经度和纬度可以直接使用,不用任何变换。
  • xticks和yticks设置为false以删除新的轴标签,这在地图上不是必需的。
  • 使用缩放的限制和由zoomed_inset_axes创建的轴创建新的地图。现在,将所有方法将使用到新的缩放地图中,地图将会匹配正确的区域。
  • 使用新的底图实例再次绘制地图,绘制缩放区域。
  • mark_inset绘制显示缩放区域的线。

Basemap实用程序函数

colorbars

在地图的一个边缘绘制颜色图例。使用方法几乎与matplotlib colorbar相同。

colorbar(mappable=None, location=’right’, size=‘5%’, pad=‘2%’, fig=None, ax=None, **kwargs)
  • mappable是最重要的参数。因为地图上的字段要用色标解释。它可以是contourf,pcolormesh,contour等。如果值为None,则表示最后绘制的字段 。
  • 设置绘制颜色标度的地图边界。可以是顶部,右侧,左侧或底部 。
  • size设置颜色条的宽度,以父轴的百分比表示 。
  • pad设置轴和颜色条之间的间距,也以父轴的百分比表示。
  • fig是与colorbar相关联的图。
  • 大多数matplotlib.colorbar参数也将工作,如label。
  • colorbar方法返回一个对象,它也有一些有趣的方法:
  • add_lines添加到颜色栏。

绘制colormesh和轮廓字段,以便能够使用一些高级颜色条属性

  • 第一个颜色条(第27行)显示了颜色条的默认使用。
  • 第二个颜色条使用一些更多的参数 。
  • 位置更改为底部 。
  • 设置标签 。
  • 方法add_lines与轮廓字段一起使用,因此彩条一次性显示pcolormesh和轮廓字段图例 。
  • 刻度设置在随机位置,以显示如何更改它们 。

Drawmapscale

在指定位置绘制地图的比例。

drawmapscale(lon, lat, lon0, lat0, length, barstyle=’simple’, units=’km’, fontsize=9, yoffset=None, labelstyle=’simple’, fontcolor=’k’, fillcolor1=’w’, fillcolor2=’k’, ax=None, format=’%d’, zorder=None)
  • lon和lat表示地图上刻度的位置。所以因为不可能将比例放在地图之外必须使用地理坐标。
  • lon0和lat0表示计算位置比例。
  • 长度是在比例尺中表示的公里数 。
  • barstyle可以是'简单'或'花式',可更改scalebar样式。两个样式都在示例中表示 。
  • units刻度中表示单位,默认为公里 。
  • fontsize可更改绘制在缩放条上的单位字体大小 。
  • fontcolor可设置缩放条上绘制单位的字体颜色 。
  • yoffset控制缩放条的高度。默认为地图高度的0.02倍。它似乎不能在所有版本正常工作。 fillcolor1和fillcolor2可设置条形的当样式是'fancy'时的颜色。
  • format设置比例尺上的数字格式。 注:投影cyl(lat / lon)是默认值,不能使用此方法。

测地线 Gcpoints

计算沿着一个大圆的n点,给定两个坐标。

gcpoints(lon1, lat1, lon2, lat2, npoints)
  • lon1和lat1是初始点的地理坐标。
  • lon2和lat2是最终点的地理坐标 。
  • npoints是要计算的点数。 注:要绘制一个大圆,greatcircle函数可能会更容易使用。此函数可用于获取点值,或由于边缘问题导致大圆失败时绘制大小写。

greatcircle

通过球体中的两个点可以绘制一个最大圆(除当点是对映体时)。

drawgreatcircle(lon1, lat1, lon2, lat2, del_s=100.0, **kwargs)
  • lon1和lat1是起点的经度和纬度。
  • lon2和lat2是终点的经度和纬度。
  • del_s是分隔大圆每个点的公里数。默认值为100 。
  • linewidth参数设置行的宽度。
  • color设置线的颜色。

注:如果圆被地图的边缘切割,即从经度-179开始并在179结束,则该方法不能正确处理它。

In [ ]:
import os




##########################################################################

from mpl_toolkits.basemap import Basemap
import matplotlib.pyplot as plt
from osgeo import gdal
from numpy import linspace
from numpy import meshgrid

map = Basemap(projection='tmerc',
              lat_0=0, lon_0=3,
              llcrnrlon=1.819757266426611,
              llcrnrlat=41.583851612359275,
              urcrnrlon=1.841589961763497,
              urcrnrlat=41.598674173123)

ds = gdal.Open("/gdata/sample_files/dem.tiff")
data = ds.ReadAsArray()

x = linspace(0, map.urcrnrx, data.shape[1])
y = linspace(0, map.urcrnry, data.shape[0])

xx, yy = meshgrid(x, y)

cmap = plt.get_cmap('PiYG')

colormesh = map.pcolormesh(xx, yy, data, vmin = 500, vmax = 1300, cmap=cmap)
contour = map.contour(xx, yy, data, range(500, 1350, 50), colors = 'k', linestyles = 'solid')

map.colorbar(colormesh)
cb = map.colorbar(colormesh, location='bottom', label="contour lines")

cb.add_lines(contour)
cb.set_ticks([600, 760, 1030, 1210])


# plt.show()


plt.show()



from mpl_toolkits.basemap import Basemap
import matplotlib.pyplot as plt

map = Basemap(llcrnrlon=-10.5,llcrnrlat=35,urcrnrlon=4.,urcrnrlat=44.,
             resolution='i', projection='tmerc', lat_0 = 39.5, lon_0 = -3.25)

map.drawmapboundary(fill_color='aqua')
map.fillcontinents(color='#cc9955',lake_color='aqua')
map.drawcoastlines()

map.drawmapscale(-7., 35.8, -3.25, 39.5, 500, barstyle='fancy')

map.drawmapscale(-0., 35.8, -3.25, 39.5, 500, fontsize = 14)
plt.show()
In [ ]: