Вычисление зональной статистики для массива с нулевыми координатами в поворотно-координатном пространстве - PullRequest
0 голосов
/ 22 марта 2019

BLUF:

У меня проблемы с вычислением зональной статистики с помощью повернутого массива с использованием пакета rasterstats . Я предполагаю, что проблема в моей аффинной матрице, но я не совсем уверен. Ниже приведена матрица аффинного преобразования и вывод:

| 951.79, 0.45, 2999993.57|
| 0.00,-996.15,-1985797.84|
| 0.00, 0.00, 1.00|

enter image description here

Справка:

Я создаю файлы для модели потока подземных вод, и мне нужно вычислить зональную статистику для каждой ячейки сетки модели, используя некоторые данные .csv с веб-портала управления водными ресурсами в Пуэрто-Рико. Эти данные доступны на ежедневном временном шаге для многочисленных параметров (например, ET, tmax, tmin, осадок и т. Д.). Эти файлы не имеют географической привязки, но доступны вспомогательные файлы, в которых указывается lon / lat для каждой ячейки, которую затем можно спроецировать с помощью pyproj:

import pandas as pd
import numpy as np
import pyproj

url_base = 'http://academic.uprm.edu/hdc/GOES-PRWEB_RESULTS'

# Load some data
f = '/'.join([url_base, 'actual_ET', 'actual_ET20090101.csv'])
array = pd.read_csv(f, header=None).values

# Read longitude values
f = '/'.join([url_base, 'NON_TRANSIENT_PARAMETERS', 'LONGITUDE.csv'])
lon = pd.read_csv(f, header=None).values

# Read latitude values
f = '/'.join([url_base, 'NON_TRANSIENT_PARAMETERS', 'LATITUDE.csv'])
lat = np.flipud(pd.read_csv(f, header=None).values)

# Project to x/y coordinates (North America Albers Equal Area Conic)
aea = pyproj.Proj('+init=ESRI:102008')
x, y = aea(lon, lat)

Прежде чем я смогу вычислить зональную статистику, мне нужно создать аффинное преобразование, которое связывает координаты строки / столбца с проецируемыми координатами x / y. Я задаю 6 параметров для создания объекта Affine, используя аффинную библиотеку:

import math
from affine import Affine

length_of_degree_longitude_at_lat_mean = 105754.71  # 18.25 degrees via http://www.csgnetwork.com/degreelenllavcalc.html
length_of_degree_latitude_at_lat_mean = 110683.25   # 18.25 degrees via http://www.csgnetwork.com/degreelenllavcalc.html

# Find the upper left x, y
xul, yul = aea(lon[0][0], lat[0][0])
xll, yll = aea(lon[-1][0], lat[-1][0])
xur, yur = aea(lon[0][-1], lat[0][-1])
xlr, ylr = aea(lon[-1][-1], lat[-1][-1])

# Compute pixel width
a = abs(lon[0][1] - lon[0][0]) * length_of_degree_longitude_at_lat_mean

# Row rotation
adj = abs(xlr - xll)
opp = abs(ylr - yll)
b = math.atan(opp/adj)

# x-coordinate of the upper left corner
c = xul - a / 2

# Compute pixel height
e = -abs(lat[1][0] - lat[0][0]) * length_of_degree_latitude_at_lat_mean

# Column rotation
d = 0

# y-coordinate of the upper left corner
f = yul - e / 2

affine = Affine(a, b, c, d, e, f)

где:

  • a = ширина пикселя
  • b = вращение строки (обычно ноль)
  • c = x-координата левого верхнего угла левого верхнего пикселя
  • d = вращение столбца (обычно ноль)
  • e = высота пикселя (обычно отрицательная)
  • f = y-координата верхнего левого угла верхнего левого пикселя

(из https://www.perrygeo.com/python-affine-transforms.html)

Полученная аффинная матрица выглядит разумно, и я попытался передать вращение строк и столбцов как радианы, так и градусы с небольшим изменением результата. Ссылка на сетку: grid_2km.geojson

import rasterstats
import matplotlib.pyplot as plt

grid_f = 'grid_2km.geojson'
gdf = gpd.read_file(grid_f)

zs = rasterstats.zonal_stats(gdf, 
                             array, 
                             affine=affine,
                             stats=['mean'])

df = pd.DataFrame(zs).fillna(value=np.nan)

fig = plt.figure(figsize=(14, 6))

ax = fig.add_subplot(131, aspect='equal')
ax.pcolormesh(x, y, np.zeros_like(array))
ax.pcolormesh(x, y, array)
ax.set_title('Projected Data')

ax = fig.add_subplot(132, aspect='equal')
gdf.plot(ax=ax)
ax.set_title('Projected Shapefile')

ax = fig.add_subplot(133, aspect='equal')
ax.imshow(df['mean'].values.reshape((gdf.row.max(), gdf.col.max())))
ax.set_title('Zonal Statistics Output')

plt.tight_layout()
plt.show()

enter image description here

Кроме того, существует несоответствие между парами значений x, y, преобразованными с использованием аффинного объекта, и теми, которые получены из собственных значений lon, lat с использованием pyproj:

rr = np.array([np.ones(x.shape[1], dtype=np.int) * i for i in range(x.shape[0])])
cc = np.array([np.arange(x.shape[1]) for i in range(x.shape[0])])
x1, y1 = affine * (cc, rr)

fig = plt.figure(figsize=(14, 6))

ax = fig.add_subplot(111, aspect='equal')
ax.scatter(x, y, s=.2)
ax.scatter(x1, y1, s=.2)

plt.show()

enter image description here

...