參考Python遙感可視化 — Basemap將地面觀測站點進行空間插值可視化和Python+Matplotlib畫contour圖這兩篇文章
關于空間插值化,也可以直接參考pykrig的github文檔
用到的主要有Matplotlib、Pykrig倆包,首先載入需要的數據文件
from mpl_toolkits.basemap import Basemap
import matplotlib.pyplot as plt
import pandas as pd
import numpy as np
from scipy.interpolate import griddata
import cmaps
# 用來正常顯示中文
plt.rcParams['font.sans-serif'] = ['SimHei']
# 用來正常顯示負號
plt.rcParams['axes.unicode_minus'] = False
# 獲取污染物分布數據,其中包括維度、經度(或者以其他坐標系表示的x和y值),和其他需要圖形展現的污染物數據或者地形高度z值
df = pd.read_csv(r'E:\\xxxxx your pathway and you filename.dat',encoding='gbk')
# 剔除無效值NAN
df = df.dropna(axis=0, how='any')
# 獲取緯度
lat = np.array(df["X"][:])
# 獲取經度
lon = np.array(df["Y"][:])
# 獲取溫度數據,這里也可以是污染物數據或者地形高度z值
Temp = np.array(df["1-2m"][:])
# 創建格網1這種方法我還沒看明白
#grid_x, grid_y = np.meshgrid(lat, lon)
#創建網格,我選擇的是這種方法。linspace(min, max, 區分為多少間隔)間隔取值越大,計算所得的網格越密集
grid_x = np.linspace(502363, 503129,100)
grid_y = np.linspace(3067296, 3067809,60)
讀取數據時可能會遇到一些編碼問題,具體更改encoding可以解決,參考
#使用pykrig進行插值
from pykrige.ok import OrdinaryKriging
import pykrige.kriging_tools as kt
OK1 = OrdinaryKriging(lat, lon, Temp, variogram_model='linear')
# Create ordinary kriging object ignoring curvature:
OK2 = OrdinaryKriging(lat, lon, Temp, variogram_model="linear", verbose=False, enable_plotting=False)
#Execute on grid:
z1, ss1 = OK1.execute('grid', grid_x, grid_y)
z2, ss2 = OK2.execute('grid', grid_x, grid_y)
fig, (ax1, ax2) = plt.subplots(1, 2)
ax1.imshow(z1)
ax1.set_title("geo-coordinates")
ax2.imshow(z2)
ax2.set_title("non geo-coordinates")
plt.show() #兩種方法插值出來的效果很相似
也可以選用matplotlib來生成等值線圖,效果更好看,這里參考Python+Matplotlib畫contour圖,后續我想再研究研究matplotlib中關于顏色的選擇和坐標軸的設置,本土中畫出來的坐標軸只有橫軸是正確的,縱軸出現了問題。
# 生成等高線圖
a = plt.contourf(grid_x, grid_y, z2, 15, cmap=plt.cm.Spectral)
b = plt.contour(grid_x, grid_y, z2, 15, colors='black', linewidths=1, linestyles='solid')
# 添加colorbar,ticks在這里可省略
plt.colorbar(a, ticks=[0, 0.25, 0.5, 0.75, 1])
#添加圖內標簽
plt.clabel(b, inline=True, fontsize=10)
plt.show()
后續:
希望能夠將邊界外的區域填充為白色。
看了很多文章……basemap功能非常強大,類似的有Cartopy,兩個庫都可以直接指定經緯度坐標,做省市的地圖,但是很多參數沒有看懂,比如需要指定坐標投影方法(不能省略),我沒搞懂如何利用自己手上已有的坐標(當地北東坐標)來進行繪圖,所以依然堅持……不使用這倆。
繼續
我找到了 Plotting the geospatial data clipped by coastlines in Python這篇文章
,需求和我完全一致。使用已有地形文件的應該參考這篇文章可以完全解決問題。我沒辦法形成該文中masking的圖形邊界,但顯然看到思路是在原有圖形上加一個填充白色的圖層。
我已有個bln邊界文件,利用surfer另存為shp格式圖形文件后,參考以下幾個問題:#Geopandas Polygon to matplotlib patches Polygon conversion、
Plot shapefile with matplotlib、 Plot shapefile with matplotlib。
利用shapefile和descartes兩個模塊
import shapefile
#導入、形成圖形文件
polys = shapefile.Reader(r'E:\\your shape file.shp')
poly = polys.iterShapes().__next__().__geo_interface__
覆蓋外界不需要的部分為白色
from descartes import PolygonPatch
# 生成等高線圖
fig, ax = plt.subplots(figsize = (10, 5))
a = ax.contourf(grid_x, grid_y, z2, 15, cmap="inferno",alpha=0.6,)
b = ax.contour(grid_x, grid_y, z2, 15, colors='black', linewidths=1, linestyles='solid')
# 添加colorbar,ticks在這里可省略
plt.colorbar(a, ticks=[0, 0.25, 0.5, 0.75, 1])
#添加圖內標簽
#plt.clabel(b, inline=True, fontsize=10)
##屏蔽圖形邊界外側區域
ax.add_patch(PolygonPatch(poly, fc='white', ec='white', alpha=1, zorder=2 ))
ax.axis('scaled')
圖形邊界文件涉及到地圖信息隱私,所以我截取了一個角,能看出來已經滿足了我的需求。
后續還要接著搞縱坐標格式、等值線圖圖形內坐標的標簽。