from collections import Counter
import numpy as np
import xarray as xr
funcs = {
'max': np.max,
'mean': np.mean,
'median': np.median,
'min': np.min,
'std': np.std,
'sum': np.sum,
}
[docs]def cell_stats(raster, data_vars=None, func='sum'):
"""
Calculates statistics of raster dataset on a cell-by-cell basis.
Parameters
----------
raster : xarray.Dataset
2D or 3D labelled array.
data_vars : list of string
Variable name list.
func : string, default=sum
Statistic type. The supported types are max, mean, median,
min, std, and sum.
Returns
-------
final_arr : xarray.DataArray
References
----------
- https://desktop.arcgis.com/en/arcmap/10.3/tools/spatial-analyst-toolbox/cell-statistics.htm # noqa
"""
if not isinstance(raster, xr.Dataset):
raise TypeError(
"Expected raster to be a 'xarray.Dataset'. "
f"Received '{type(raster).__name__}' instead."
)
if func not in funcs:
raise ValueError(
f'{func} is not supported. '
f"The supported types are '{list(funcs.keys())}'."
)
if data_vars:
if (
not isinstance(data_vars, list) or
not all([isinstance(var, str) for var in data_vars])
):
raise TypeError('Expected data_vars to be a list of string.')
if not set(data_vars).issubset(raster.data_vars):
raise ValueError(
"raster must contain all the variables of data_vars. "
f"The variables available are '{list(raster.data_vars)}'."
)
else:
data_vars = list(raster.data_vars)
iter_list = []
for comb in np.nditer([raster[var].data for var in data_vars]):
iter_list.append(tuple(items.item() for items in comb))
out = []
for comb in iter_list:
out.append(funcs[func](comb))
final_arr = np.array(out)
final_arr = np.reshape(final_arr, (-1, raster[data_vars[0]].data.shape[1]))
final_arr = xr.DataArray(final_arr)
return final_arr
[docs]def combine(raster, data_vars=None):
"""
Combines raster dataset, a unique output value is assigned to each
unique combination of raster values.
Parameters
----------
raster : xarray.Dataset
2D or 3D labelled array.
data_vars : list of string
Variable name list.
Returns
-------
final_arr : xarray.DataArray
References
----------
- https://desktop.arcgis.com/en/arcmap/10.3/tools/spatial-analyst-toolbox/combine.htm # noqa
"""
if not isinstance(raster, xr.Dataset):
raise TypeError(
"Expected raster to be a 'xarray.Dataset'. "
f"Received '{type(raster).__name__}' instead."
)
if data_vars:
if (
not isinstance(data_vars, list) or
not all([isinstance(var, str) for var in data_vars])
):
raise TypeError('Expected data_vars to be a list of string.')
if not set(data_vars).issubset(raster.data_vars):
raise ValueError(
"raster must contain all the variables of data_vars. "
f"The variables available are '{list(raster.data_vars)}'."
)
else:
data_vars = list(raster.data_vars)
iter_list = []
for comb in np.nditer([raster[var].data for var in data_vars]):
iter_list.append(tuple(items.item() for items in comb))
unique_comb = {}
unique_values = {}
all_comb = []
all_values = []
value = 1
for comb in iter_list:
if np.isnan(comb).any():
all_values.append(np.nan)
all_comb.append('NAN')
continue
if comb in unique_comb.keys():
all_comb.append(comb)
all_values.append(0)
else:
unique_comb[comb] = value
unique_values[value] = comb
all_comb.append(comb)
all_values.append(value)
value += 1
k = 0
for value in all_values:
if value == 0:
comb = all_comb[k]
all_values[k] = [unique_comb[comb]][0]
k += 1
final_arr = np.array(all_values)
final_arr = np.reshape(final_arr, (-1, raster[data_vars[0]].data.shape[1]))
final_arr = xr.DataArray(
data=final_arr,
attrs=dict(key=unique_values)
)
return final_arr
[docs]def lesser_frequency(raster, ref_var, data_vars=None):
"""
Calculates the number of times the raster dataset has a lesser
frequency on a cell-by-cell basis.
Parameters
----------
raster : xarray.Dataset
2D or 3D labelled array.
ref_var : string
The reference variable name.
data_vars : list of string
Variable name list.
Returns
-------
final_arr : xarray.DataArray
References
----------
- https://desktop.arcgis.com/en/arcmap/10.3/tools/spatial-analyst-toolbox/less-than-frequency.htm # noqa
"""
if not isinstance(raster, xr.Dataset):
raise TypeError(
"Expected raster to be a 'xarray.Dataset'. "
f"Received '{type(raster).__name__}' instead."
)
if not isinstance(ref_var, str):
raise TypeError(
"Expected ref_var to be a 'str'. "
f"Received '{type(ref_var).__name__}' instead."
)
if ref_var not in list(raster.data_vars):
raise ValueError('raster must contain ref_var.')
if data_vars:
if (
not isinstance(data_vars, list) or
not all([isinstance(var, str) for var in data_vars])
):
raise TypeError('Expected data_vars to be a list of string.')
if not set(data_vars).issubset(raster.data_vars):
raise ValueError(
"raster must contain all the variables of data_vars. "
f"The variables available are '{list(raster.data_vars)}'."
)
if ref_var in data_vars:
raise ValueError('ref_var must not be an element of data_vars.')
else:
data_vars = list(raster.data_vars)
data_vars.remove(ref_var)
iter_list = []
for comb in np.nditer([raster[var].data for var in data_vars]):
iter_list.append(tuple(items.item() for items in comb))
out = []
ref_list = [item for arr in raster[ref_var].data for item in arr]
for ref, comb in zip(ref_list, iter_list):
count = 0
if np.isnan(comb).any():
out.append(np.nan)
continue
for item in comb:
if ref > item:
count += 1
out.append(count)
final_arr = np.array(out)
final_arr = np.reshape(final_arr, (-1, raster[data_vars[0]].data.shape[1]))
final_arr = xr.DataArray(final_arr)
return final_arr
[docs]def equal_frequency(raster, ref_var, data_vars=None):
"""
Calculates the number of times the raster dataset has a equal
frequency on a cell-by-cell basis.
Parameters
----------
raster : xarray.Dataset
2D or 3D labelled array.
ref_var : string
The reference variable name.
data_vars : list of string
Variable name list.
Returns
-------
final_arr : xarray.DataArray
References
----------
- https://desktop.arcgis.com/en/arcmap/10.3/tools/spatial-analyst-toolbox/equal-to-frequency.htm # noqa
"""
if not isinstance(raster, xr.Dataset):
raise TypeError(
"Expected raster to be a 'xarray.Dataset'. "
f"Received '{type(raster).__name__}' instead."
)
if not isinstance(ref_var, str):
raise TypeError(
"Expected ref_var to be a 'str'. "
f"Received '{type(ref_var).__name__}' instead."
)
if ref_var not in list(raster.data_vars):
raise ValueError('raster must contain ref_var.')
if data_vars:
if (
not isinstance(data_vars, list) or
not all([isinstance(var, str) for var in data_vars])
):
raise TypeError('Expected data_vars to be a list of string.')
if not set(data_vars).issubset(raster.data_vars):
raise ValueError(
"raster must contain all the variables of data_vars. "
f"The variables available are '{list(raster.data_vars)}'."
)
if ref_var in data_vars:
raise ValueError('ref_var must not be an element of data_vars.')
else:
data_vars = list(raster.data_vars)
data_vars.remove(ref_var)
iter_list = []
for comb in np.nditer([raster[var].data for var in data_vars]):
iter_list.append(tuple(items.item() for items in comb))
out = []
ref_list = [item for arr in raster[ref_var].data for item in arr]
for ref, comb in zip(ref_list, iter_list):
count = 0
if np.isnan(comb).any():
out.append(np.nan)
continue
for item in comb:
if ref == item:
count += 1
out.append(count)
final_arr = np.array(out)
final_arr = np.reshape(final_arr, (-1, raster[data_vars[0]].data.shape[1]))
final_arr = xr.DataArray(final_arr)
return final_arr
[docs]def greater_frequency(raster, ref_var, data_vars=None):
"""
Calculates the number of times the raster dataset has a greater
frequency on a cell-by-cell basis.
Parameters
----------
raster : xarray.Dataset
2D or 3D labelled array.
ref_var : string
The reference variable name.
data_vars : list of string
Variable name list.
Returns
-------
final_arr : xarray.DataArray
References
----------
- https://desktop.arcgis.com/en/arcmap/10.3/tools/spatial-analyst-toolbox/greater-than-frequency.htm # noqa
"""
if not isinstance(raster, xr.Dataset):
raise TypeError(
"Expected raster to be a 'xarray.Dataset'. "
f"Received '{type(raster).__name__}' instead."
)
if not isinstance(ref_var, str):
raise TypeError(
"Expected ref_var to be a 'str'. "
f"Received '{type(ref_var).__name__}' instead."
)
if ref_var not in list(raster.data_vars):
raise ValueError('raster must contain ref_var.')
if data_vars:
if (
not isinstance(data_vars, list) or
not all([isinstance(var, str) for var in data_vars])
):
raise TypeError('Expected data_vars to be a list of string.')
if not set(data_vars).issubset(raster.data_vars):
raise ValueError(
"raster must contain all the variables of data_vars. "
f"The variables available are '{list(raster.data_vars)}'."
)
if ref_var in data_vars:
raise ValueError('ref_var must not be an element of data_vars.')
else:
data_vars = list(raster.data_vars)
data_vars.remove(ref_var)
iter_list = []
for comb in np.nditer([raster[var].data for var in data_vars]):
iter_list.append(tuple(items.item() for items in comb))
out = []
ref_list = [item for arr in raster[ref_var].data for item in arr]
for ref, comb in zip(ref_list, iter_list):
count = 0
if np.isnan(comb).any():
out.append(np.nan)
continue
for item in comb:
if ref < item:
count += 1
out.append(count)
final_arr = np.array(out)
final_arr = np.reshape(final_arr, (-1, raster[data_vars[0]].data.shape[1]))
final_arr = xr.DataArray(final_arr)
return final_arr
[docs]def lowest_position(raster, data_vars=None):
"""
Calculates the data variable index of the lowest value on a
cell-by-cell basis.
Parameters
----------
raster : xarray.Dataset
2D or 3D labelled array.
data_vars : list of string
Variable name list.
Returns
-------
final_arr : xarray.DataArray
References
----------
- https://desktop.arcgis.com/en/arcmap/10.3/tools/spatial-analyst-toolbox/lowest-position.htm # noqa
"""
if not isinstance(raster, xr.Dataset):
raise TypeError(
"Expected raster to be a 'xarray.Dataset'. "
f"Received '{type(raster).__name__}' instead."
)
if data_vars:
if (
not isinstance(data_vars, list) or
not all([isinstance(var, str) for var in data_vars])
):
raise TypeError('Expected data_vars to be a list of string.')
if not set(data_vars).issubset(raster.data_vars):
raise ValueError(
"raster must contain all the variables of data_vars. "
f"The variables available are '{list(raster.data_vars)}'."
)
else:
data_vars = list(raster.data_vars)
iter_list = []
for comb in np.nditer([raster[var].data for var in data_vars]):
iter_list.append(tuple(items.item() for items in comb))
out = []
for comb in iter_list:
if np.isnan(comb).any():
out.append(np.nan)
continue
min_value = min(comb)
min_index = comb.index(min_value) + 1
out.append(min_index)
final_arr = np.array(out)
final_arr = np.reshape(final_arr, (-1, raster[data_vars[0]].data.shape[1]))
final_arr = xr.DataArray(final_arr)
return final_arr
[docs]def highest_position(raster, data_vars=None):
"""
Calculates the data variable index of the highest value on a
cell-by-cell basis.
Parameters
----------
raster : xarray.Dataset
2D or 3D labelled array.
data_vars : list of string
Variable name list.
Returns
-------
final_arr : xarray.DataArray
References
----------
- https://desktop.arcgis.com/en/arcmap/10.3/tools/spatial-analyst-toolbox/highest-position.htm # noqa
"""
if not isinstance(raster, xr.Dataset):
raise TypeError(
"Expected raster to be a 'xarray.Dataset'. "
f"Received '{type(raster).__name__}' instead."
)
if data_vars:
if (
not isinstance(data_vars, list) or
not all([isinstance(var, str) for var in data_vars])
):
raise TypeError('Expected data_vars to be a list of string.')
if not set(data_vars).issubset(raster.data_vars):
raise ValueError(
"raster must contain all the variables of data_vars. "
f"The variables available are '{list(raster.data_vars)}'."
)
else:
data_vars = list(raster.data_vars)
iter_list = []
for comb in np.nditer([raster[var].data for var in data_vars]):
iter_list.append(tuple(items.item() for items in comb))
out = []
for comb in iter_list:
if np.isnan(comb).any():
out.append(np.nan)
continue
max_value = max(comb)
max_index = comb.index(max_value) + 1
out.append(max_index)
final_arr = np.array(out)
final_arr = np.reshape(final_arr, (-1, raster[data_vars[0]].data.shape[1]))
final_arr = xr.DataArray(final_arr)
return final_arr
[docs]def popularity(raster, ref_var, data_vars=None):
"""
Calculates the popularity, the number of occurrences of each value,
of raster dataset on a cell-by-cell basis. The output value is
assigned based on the reference data variable nth most popular.
Parameters
----------
raster : xarray.Dataset
2D or 3D labelled array.
ref_var : string
The reference variable name.
data_vars : list of string
Variable name list.
Returns
-------
final_arr : xarray.DataArray
References
----------
- https://desktop.arcgis.com/en/arcmap/10.3/tools/spatial-analyst-toolbox/popularity.htm # noqa
"""
if not isinstance(raster, xr.Dataset):
raise TypeError(
"Expected raster to be a 'xarray.Dataset'. "
f"Received '{type(raster).__name__}' instead."
)
if not isinstance(ref_var, str):
raise TypeError(
"Expected ref_var to be a 'str'. "
f"Received '{type(ref_var).__name__}' instead."
)
if ref_var not in list(raster.data_vars):
raise ValueError('raster must contain ref_var.')
if data_vars:
if (
not isinstance(data_vars, list) or
not all([isinstance(var, str) for var in data_vars])
):
raise TypeError('Expected data_vars to be a list of string.')
if not set(data_vars).issubset(raster.data_vars):
raise ValueError(
"raster must contain all the variables of data_vars. "
f"The variables available are '{list(raster.data_vars)}'."
)
if ref_var in data_vars:
raise ValueError('ref_var must not be an element of data_vars.')
else:
data_vars = list(raster.data_vars)
data_vars.remove(ref_var)
iter_list = []
for comb in np.nditer([raster[var].data for var in data_vars]):
iter_list.append(tuple(items.item() for items in comb))
out = []
ref_list = [item for arr in raster[ref_var].data for item in arr]
for ref, comb in zip(ref_list, iter_list):
comb = np.array(comb)
comb_ref = ref - 1
comb_counts = sorted(list(dict(Counter(comb)).keys()))
if (np.isnan(comb).any() or len(comb_counts) >= len(comb)):
out.append(np.nan)
continue
elif len(comb_counts) == 1:
out.append(comb_counts[0])
else:
if comb_ref >= len(comb_counts):
out.append(np.nan)
continue
out.append(comb_counts[comb_ref])
final_arr = np.array(out)
final_arr = np.reshape(final_arr, (-1, raster[data_vars[0]].data.shape[1]))
final_arr = xr.DataArray(final_arr)
return final_arr
[docs]def rank(raster, ref_var, data_vars=None):
"""
Calculates the rank of raster dataset on a cell-by-cell basis.
The output value is assigned based on the reference data variable
rank.
Parameters
----------
raster : xarray.Dataset
2D or 3D labelled array.
ref_var : string
The reference variable name.
data_vars : list of string
Variable name list.
Returns
-------
final_arr : xarray.DataArray
References
----------
- https://desktop.arcgis.com/en/arcmap/10.3/tools/spatial-analyst-toolbox/rank.htm # noqa
"""
if not isinstance(raster, xr.Dataset):
raise TypeError(
"Expected raster to be a 'xarray.Dataset'. "
f"Received '{type(raster).__name__}' instead."
)
if not isinstance(ref_var, str):
raise TypeError(
"Expected ref_var to be a 'str'. "
f"Received '{type(ref_var).__name__}' instead."
)
if ref_var not in list(raster.data_vars):
raise ValueError('raster must contain ref_var.')
if data_vars:
if (
not isinstance(data_vars, list) or
not all([isinstance(var, str) for var in data_vars])
):
raise TypeError('Expected data_vars to be a list of string.')
if not set(data_vars).issubset(raster.data_vars):
raise ValueError(
"raster must contain all the variables of data_vars. "
f"The variables available are '{list(raster.data_vars)}'."
)
if ref_var in data_vars:
raise ValueError('ref_var must not be an element of data_vars.')
else:
data_vars = list(raster.data_vars)
data_vars.remove(ref_var)
iter_list = []
for comb in np.nditer([raster[var].data for var in data_vars]):
iter_list.append(list(items.item() for items in comb))
out = []
ref_list = [item for arr in raster[ref_var].data for item in arr]
for ref, comb in zip(ref_list, iter_list):
comb_ref = ref - 1
comb.sort()
if np.isnan(comb).any() or comb_ref >= len(comb):
out.append(np.nan)
continue
out.append(comb[comb_ref])
final_arr = np.array(out)
final_arr = np.reshape(final_arr, (-1, raster[data_vars[0]].data.shape[1]))
final_arr = xr.DataArray(final_arr)
return final_arr