python中的.nc文件處理 | 04 利用矢量邊界提取NC數據

利用矢量邊界提取.nc數據

import os

import numpy as np
import pandas as pd
import matplotlib.pyplot as plt
import cartopy.crs as ccrs
import cartopy.feature as cfeature
import seaborn as sns
import geopandas as gpd
import earthpy as et
import xarray as xr
# .nc文件的空間切片包
import regionmask


# 繪圖選項
sns.set(font_scale=1.3)
sns.set_style("white")

讀取數據

data_path_monthly='http://thredds.northwestknowledge.net:8080/thredds/dodsC/agg_macav2metdata_tasmax_BNU-ESM_r1i1p1_rcp45_2006_2099_CONUS_monthly.nc'

with xr.open_dataset(data_path_monthly) as file_nc:
    monthly_forecast_temp_xr=file_nc

monthly_forecast_temp_xr

讀取感興趣區的Shapefile文件

# 下載數據
# et.data.get_data(
#     url="https://www.naturalearthdata.com/http//www.naturalearthdata.com/download/50m/cultural/ne_50m_admin_1_states_provinces_lakes.zip")

# 讀取.shp文件
states_path = "ne_50m_admin_1_states_provinces_lakes"
states_path = os.path.join(
    states_path,"ne_50m_admin_1_states_provinces_lakes.shp"
)

states_gdf=gpd.read_file(states_path)
states_gdf.head()

篩選出California州範圍

cali_aoi=states_gdf[states_gdf.name=="California"]
# 獲取其外包絡矩形座標
cali_aoi.total_bounds
array([-124.37165376,   32.53336527, -114.12501824,   42.00076797])

根據外包絡矩形經緯度對nc數據進行切片

  • 利用sel()函數
# 獲取外包絡矩形的左下角和右上角經緯度座標
aoi_lat = [float(cali_aoi.total_bounds[1]), float(cali_aoi.total_bounds[3])]
aoi_lon = [float(cali_aoi.total_bounds[0]), float(cali_aoi.total_bounds[2])]
print(aoi_lat, aoi_lon)
# 將座標轉換爲標準經度,即去掉正負號
aoi_lon[0] = aoi_lon[0] + 360
aoi_lon[1] = aoi_lon[1] + 360
print(aoi_lon)
[32.533365269889316, 42.00076797479207] [-124.3716537616361, -114.12501823892204]
[235.62834623836392, 245.87498176107795]
# 根據指定的時間和空間範圍進行切片
start_date = "2010-01-15"
end_date = "2010-02-15"

two_months_cali = monthly_forecast_temp_xr["air_temperature"].sel(
    time=slice(start_date, end_date),
    lon=slice(aoi_lon[0], aoi_lon[1]),
    lat=slice(aoi_lat[0], aoi_lat[1]))
two_months_cali
# 繪製切片數據分佈的直方圖
two_months_cali.plot()
plt.show()

# 繪製切片數據的空間分佈
two_months_cali.plot(col='time',
                    col_wrap=1)
plt.show()

# 若不指定時間範圍
cali_ts = monthly_forecast_temp_xr["air_temperature"].sel(
    lon=slice(aoi_lon[0], aoi_lon[1]),
    lat=slice(aoi_lat[0], aoi_lat[1]))
cali_ts

提取每個點的每年的最高氣溫

cali_annual_max=cali_ts.groupby('time.year').max(skipna=True)
cali_annual_max

提取每年的最高氣溫

cali_annual_max_val=cali_annual_max.groupby('year').max(["lat","lon"])
cali_annual_max_val

繪製每年的最高溫變化圖

f,ax=plt.subplots(figsize=(12,6))
cali_annual_max_val.plot.line(hue="lat",
                             marker="o",
                             ax=ax,
                             color="grey",
                             markerfacecolor="purple",
                             markeredgecolor="purple")
ax.set(title="Annual Max Temperature (K) in California")
plt.show()

使用Shapefile對nc文件進行切片

在上述的操作中,使用外包絡矩形的座標對nc數據進行了切片,但有時我們希望能得到不規則邊界的數據,此時需要使用到regionmask包創建掩膜

f,ax=plt.subplots()
cali_aoi.plot(ax=ax)
ax.set(title="california AOI Subset")

plt.show()

cali_aoi

根據GeoPandasDataFrame生成掩膜

cali_mask=regionmask.mask_3D_geopandas(cali_aoi,
                                      monthly_forecast_temp_xr.lon,
                                      monthly_forecast_temp_xr.lat)
cali_mask

根據時間和掩膜對數據進行切片

two_months=monthly_forecast_temp_xr.sel(
    time=slice("2099-10-25","2099-12-15"))

two_months=two_months.where(cali_mask)
two_months

繪製掩膜結果

two_months["air_temperature"].plot(col='time',
                                   col_wrap=1,
                                   figsize=(10, 10))
plt.show()

可以看到此時圖中顯示範圍較大,可以通過設置經緯度進一步切片

two_months_masked = monthly_forecast_temp_xr["air_temperature"].sel(time=slice('2099-10-25',
                                                                               '2099-12-15'),
                                                                    lon=slice(aoi_lon[0],
                                                                              aoi_lon[1]),
                                                                    lat=slice(aoi_lat[0],
                                                                              aoi_lat[1])).where(cali_mask)
two_months_masked.dims
('time', 'lat', 'lon', 'region')
two_months_masked.plot(col='time', col_wrap=1)
plt.show()

同時對多個區域進行切片

# 選取多個州
cali_or_wash_nev = states_gdf[states_gdf.name.isin(
    ["California", "Oregon", "Washington", "Nevada"])]
cali_or_wash_nev.plot()
plt.show()

# 根據多個州的範圍進行掩膜的生成
west_mask = regionmask.mask_3D_geopandas(cali_or_wash_nev,
                                         monthly_forecast_temp_xr.lon,
                                         monthly_forecast_temp_xr.lat)
west_mask

幫助生成多個mask的函數

def get_aoi(shp, world=True):
    """Takes a geopandas object and converts it to a lat/ lon
    extent 

    Parameters
    -----------
    shp : geopandas object
    world : boolean

    Returns
    -------
    Dictionary of lat and lon spatial bounds
    """

    lon_lat = {}
    # Get lat min, max
    aoi_lat = [float(shp.total_bounds[1]), float(shp.total_bounds[3])]
    aoi_lon = [float(shp.total_bounds[0]), float(shp.total_bounds[2])]

    if world:
        aoi_lon[0] = aoi_lon[0] + 360
        aoi_lon[1] = aoi_lon[1] + 360
    lon_lat["lon"] = aoi_lon
    lon_lat["lat"] = aoi_lat
    return lon_lat


west_bounds = get_aoi(cali_or_wash_nev)
# 設定提取的起止時間
start_date = "2010-01-15"
end_date = "2010-02-15"

# Subset
two_months_west_coast = monthly_forecast_temp_xr["air_temperature"].sel(
    time=slice(start_date, end_date),
    lon=slice(west_bounds["lon"][0], west_bounds["lon"][1]),
    lat=slice(west_bounds["lat"][0], west_bounds["lat"][1]))
two_months_west_coast
two_months_west_coast.plot(col="region",
                           row="time",
                           sharey=False, sharex=False)
plt.show()

計算每個區域的溫度均值

summary = two_months_west_coast.groupby("time").mean(["lat", "lon"])
summary.to_dataframe()

本節完整代碼

# 提取geopandas對象的外包絡矩形經緯度
def get_aoi(shp, world=True):
    """Takes a geopandas object and converts it to a lat/ lon
    extent """

    lon_lat = {}
    # Get lat min, max
    aoi_lat = [float(shp.total_bounds[1]), float(shp.total_bounds[3])]
    aoi_lon = [float(shp.total_bounds[0]), float(shp.total_bounds[2])]

    # Handle the 0-360 lon values
    if world:
        aoi_lon[0] = aoi_lon[0] + 360
        aoi_lon[1] = aoi_lon[1] + 360
    lon_lat["lon"] = aoi_lon
    lon_lat["lat"] = aoi_lat
    return lon_lat
# 本節完整代碼

# 讀取矢量數據
states_path = "ne_50m_admin_1_states_provinces_lakes"
states_path = os.path.join(
    states_path, "ne_50m_admin_1_states_provinces_lakes.shp")

states_gdf = gpd.read_file(states_path)


# 讀取nc數據
data_path_monthly = 'http://thredds.northwestknowledge.net:8080/thredds/dodsC/agg_macav2metdata_tasmax_BNU-ESM_r1i1p1_rcp45_2006_2099_CONUS_monthly.nc'
with xr.open_dataset(data_path_monthly) as file_nc:
    monthly_forecast_temp_xr = file_nc

# 數據對象
monthly_forecast_temp_xr

# 將geopandas對象轉換成掩膜
states_gdf["name"]

cali_or_wash_nev = states_gdf[states_gdf.name.isin(
    ["California", "Oregon", "Washington", "Nevada"])]

west_mask = regionmask.mask_3D_geopandas(cali_or_wash_nev,
                                         monthly_forecast_temp_xr.lon,
                                         monthly_forecast_temp_xr.lat)
west_mask
west_bounds = get_aoi(cali_or_wash_nev)


# 根據時間、掩膜範圍對數據進行切片 .sel().where()
start_date = "2010-01-15"
end_date = "2020-02-15"

two_months_west_coast = monthly_forecast_temp_xr["air_temperature"].sel(
    time=slice(start_date, end_date),
    lon=slice(west_bounds["lon"][0], west_bounds["lon"][1]),
    lat=slice(west_bounds["lat"][0], west_bounds["lat"][1])).where(west_mask)

# 輸出切片數據
two_months_west_coast

# 直方圖繪製
two_months_west_coast.plot()
plt.show()

# 繪製每個區域的變化
regional_summary = two_months_west_coast.groupby("region").mean(["lat", "lon"])
regional_summary.plot(col="region",
                      marker="o",
                      color="grey",
                      markerfacecolor="purple",
                      markeredgecolor="purple",
                      col_wrap=2)
plt.show()

# 轉換爲dataframe
two_months_west_coast.groupby("region").mean(["lat", "lon"]).to_dataframe()

參考鏈接:

https://www.earthdatascience.org/courses/use-data-open-source-python/hierarchical-data-formats-hdf/summarize-climate-data-by-season/

https://gitee.com/jiangroubao/learning/tree/master/NetCDF4

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章