四、繪制上海到芝加哥大圓航線
不知道坐過國際航班的你是否也產生過這樣的疑問:為啥國內出發的去美國的飛機不按照地圖上兩點之間直線最短拉一條線段從太平洋上飛而要越過西伯利亞穿過白令海峽在北極圈兜一圈再緩緩繞過加拿大最后抵達美國?
并不是害怕飛機掉海里...(雖然迫降死亡率最高確實在海面,在陸地上還有微乎其微的生還幾率)
這得從地圖的繪制來講。
首先我們要明確... 地球是一個近似球體...
我們日常所見到的世界地圖是基于墨卡托投影的:于是粘一段維基百科,麥卡托投影法(Mercator projection),又稱麥卡托投影法、正軸等角圓柱投影,是一種等角的圓柱形地圖投影法。在以此投影法繪制的地圖上,經線緯線于任何位置皆垂直相交,世界地圖可以繪制在一個長方形上。由于可顯示任兩點間的正確方位,航海用途的海圖、航路圖大都以此方式繪制。在該投影中線型比例尺在圖中任意一點周圍都保持不變,從而可以保持大陸輪廓投影后的角度和形狀不變(即等角投影));但麥卡托投影會使面積產生變形,極點的比例甚至達到了無窮大。
所以我們日常看見的世界地圖南極被拉成了一長條,戰斗民族國家顯得幅員遼闊(雖然國土面積仍然是世界第一但沒有地圖上看起來的那么大)
但其實遵從我們高中所學的(還是大學所學的空間解析幾何?)地球上兩點之間最短的距離并不是在地圖上畫一條連線,而是通過連接球上兩點作出過圓心的大弧~~~
貼一個計算兩點中點經緯度的公式:
哼,求得中點經緯線后喜聞樂見的調用basemap畫出上海到芝加哥的大圓航線:
#把地球看做一個球體,通過地面上任意兩點和地心做一平面,平面與地球表面橡膠看到的圓周就是大圓。
#兩點之間的大圓劣弧線是兩點在地面上的最短距離。沿著這一段大圓弧線航行時的航線稱為大圓航線。
#由于大圓航線是兩點之間的最短航線,故有時稱為最經濟航線。
chilat = 41.52; chilon = -87.37
# 芝加哥經緯度
shlat = 31.22; shlon = 121.48
#上海經緯度
m = Basemap(llcrnrlon=-140.,llcrnrlat=10.,urcrnrlon=140.,urcrnrlat=70.,\
rsphere=(6378137.00,6356752.3142),\
resolution='l',projection='merc',\
lat_0=(chilat+shlat)/2.,lon_0=(chilon+shlon)/2.,lat_ts=0.)
#設置圖像邊界四點經緯度坐標,中心點經緯度參數坐標, 地球半徑,分辨率設置為低
# 麥卡托式地圖投影法設置 projection = 'merc'
# draw great circle route between NY and London
m.drawgreatcircle(shlon,shlat,chilon,chilat,linewidth=2,color='b')
#畫出上海芝加哥兩地間的大圓航線,設置線寬及顏色
m.drawcoastlines()
#海岸線
m.fillcontinents()
#填充大陸
m.drawparallels(np.arange(10,90,20),labels=[1,1,0,1])
# 畫出緯線, 在北緯10度到90度區間內以20度為單位, 緯度標記在圖形左右和下測
m.drawmeridians(np.arange(-180,180,30),labels=[1,1,0,1])
# # 畫出經線, 從西經180度到東經180度區間內以30度為單位, 經度標記在圖形左右和下測
ax.set_title('Great Circle from Chicago to Shanghai')
#圖像命名為芝加哥到上海的大圓航線
plt.show()
這里其實有一個疑惑,我設置的投影中心點沒有按照上文提到的球面中心點計算(因為算了以后生成的地圖視角特別奇怪...主要顯現的是歐洲大陸和南亞次大陸,而且是我們常見世界地圖反轉的...可是我的上下左右經緯度設置沒錯啊...)
五、其他看起來很炫酷的地圖
偷下懶如果沒有新導入的庫,import部分就不寫了。
5.1 微信開始界面的藍色彈珠(Blue Marble)
看起來很高大上其實就加了一行代碼...
plt.figure(figsize=(8, 8))
#設新圖
m = Basemap(projection='ortho', resolution=None, lat_0=30, lon_0=120)
#正射投影,投影原點設在了上海周邊
m.bluemarble(scale=0.5);
#圖像原始分辨率是5400*2700,設置scale = 0.5以后分辨率為2700*1350,如此作圖
#迅速不少也不那么占用內存了
5.2 據說原模型是用來測量儲水量的EPOTO1圖
查了下好像很高大上的樣子...這個模型很能反映地表信息,主要用來看冰層和基巖的。輸入芝加哥經緯度標記下芝加哥的位置
fig = plt.figure(figsize=(8, 8))
m = Basemap(projection='lcc', resolution=None,
width=8E6, height=8E6,
lat_0=45, lon_0=-100,)
#這里投影模式llc是圓錐投影
m.etopo(scale=0.5, alpha=0.5)
#其實也就加了這一句...scale原理同上文bluemarble中的scale,alpha是透明度圖層
# Map (long, lat) to (x, y) for plotting
x, y = m(-87.37, 41.52)
plt.plot(x, y, 'ok', markersize=5)
#這里不是打印ok啊...是設置標記點為黑色圓點
plt.text(x, y, ' Chicago', fontsize=12);
#其實我在想瞄成紅點加一個launched字符是不是更有沖擊力(不帶這么詛咒自己的)
五、繪制即時晨昏線
晨昏圈,又稱晨昏線,或是曙暮光區是一條虛擬的線,它在行星的表面畫出了白天和黑夜的交界線(也稱為灰線)。晨昏圈由晨線和昏線組成,晨線和昏線各是一個半圓弧,晨線的東邊是晝半球,昏線的西邊是夜半球。
其實這個圖沒什么好說的,稍微值得補充的部分都放在代碼的注釋部分,直接上代碼:
import numpy as np
from mpl_toolkits.basemap import Basemap
import matplotlib.pyplot as plt
from datetime import datetime
#python標準庫 日期與時間
from dateutil import tz
#這是一個第三方庫,拓展了標準時間庫,tz = time zone
fig=plt.figure()
ax=fig.add_axes([0.1,0.1,0.8,0.8])
# 新圖對象
map = Basemap(projection='mill',lon_0=180)
#米勒投影法,此投影與墨卡托投影類似,只是極點區域的面積變形不如后者大。向極點靠近時,兩
#條緯線的間距比墨卡托投影的小。這樣就降低了面積變形程度,但這會導致局部形狀和方向發生變形。
map.drawcoastlines()
#畫海岸線
map.drawparallels(np.arange(-90,90,30),labels=[1,0,0,0])
map.drawmeridians(np.arange(map.lonmin,map.lonmax+30,60),labels=[0,0,0,1])
#numpy的作用只是提供了數組
map.drawmapboundary(fill_color='aqua')
#邊界aqua(水)色
map.fillcontinents(color='coral',lake_color='aqua')
#大陸珊瑚色,湖泊水色
date = datetime.now()
#這個是local時間,我所在的芝加哥地區是(CST)central standard time
#如果想取格林尼治時間(Coordinated Universal Time),以上這句改為
#date = datetime.utcnow()即可
CS=map.nightshade(date)
#basemap中的nightshade函數用作將夜晚區域覆蓋作陰影,具體參數不擴展
#有興趣了解搜索basemap.nightshade即可
plt.title('Day/Night Map for %s (CST)' % date.strftime("%d %b %Y %H:%M:%S"))
#設置圖名, datetime格式日/月/年/時/分/秒
plt.show()
把這張圖放在最后也是為了秀一下夜已經深了。
如此python關于basemap的地圖可視化整理告一段落,不排除以后會添加新應用實例或者補充諸如如何釋放內存的解決方案(畫了幾個高級圖遇到了MemoryError,gc.collect()也不好使...容我再研究下)。晚安!