Distance & restoration¶
Distances to the habitat edge, resistance maps, accumulated costs and least-cost paths, the connectivity gain of restoring a corridor, the zones of influence of habitat objects, and two inputs of restoration plans: the original vegetation of converted land and ecological intactness. Tutorial: distance and restoration.
Distance to the habitat¶
euclidean_distance
¶
euclidean_distance(
data: DataArray | ndarray,
*,
pixel_size: float | tuple[float, float] | None = None,
threads: int = 0,
n_threads: int | None = None,
) -> EuclideanDistanceResult
Euclidean distance to the habitat edge, inside and outside the habitat (GTB's batch_eucldist).
Every foreground pixel gets its straight-line distance to the nearest background pixel (positive), every background pixel its distance to the nearest foreground (negative). The border pixels are replicated so that the map edge does not act as an edge.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
data
|
DataArray | ndarray
|
Map coded 0 missing, 1 background, 2 foreground (DataArray, array or path). |
required |
pixel_size
|
float | tuple[float, float] | None
|
Pixel size (e.g. in metres) for the statistics in map units; read from a georeferenced DataArray when omitted. |
None
|
threads
|
int
|
Threads (0 or |
0
|
n_threads
|
int
|
Threads (0 or |
0
|
Returns:
| Type | Description |
|---|---|
EuclideanDistanceResult
|
|
Examples:
>>> import landschaft as ls
>>> forest = ls.load_raster(ls.example_data("input")) # 0 missing, 1 background, 2 forest
>>> distance = ls.euclidean_distance(forest, pixel_size=25)
>>> round(distance.mean_fg_distance, 2), round(distance.max_bg_distance, 2)
(6.01, 33.54)
>>> distance.stats[["class", "pixel_count", "mean_distance_units"]]
class pixel_count mean_distance_units
0 Foreground (Forest) 428490 150.37
1 Background (Matrix) 571240 125.76
EuclideanDistanceResult
dataclass
¶
EuclideanDistanceResult(
signed_distance: DataArray | ndarray,
byte_map: DataArray | ndarray,
mean_fg_distance: float,
max_fg_distance: float,
mean_bg_distance: float,
max_bg_distance: float,
fg_pixel_count: int,
bg_pixel_count: int,
stats: DataFrame,
pixel_size: float | None = None,
)
Bases: Saveable
Result of euclidean_distance().
Attributes:
| Name | Type | Description |
|---|---|---|
signed_distance |
DataArray | ndarray
|
Distance of every pixel in pixels: positive in the foreground, negative in the background, NaN on missing pixels. |
byte_map |
DataArray | ndarray
|
GTB's |
mean_fg_distance, max_fg_distance |
Mean and maximum distance of the foreground pixels, in pixels. |
|
mean_bg_distance, max_bg_distance |
The same for the background (absolute values). |
|
fg_pixel_count, bg_pixel_count |
Number of foreground and background pixels. |
|
stats |
DataFrame
|
The same statistics as a table, in pixels and in map units. |
pixel_size |
float | None
|
Pixel size used for the map units ( |
Examples:
>>> import landschaft as ls
>>> forest = ls.load_raster(ls.example_data("input")) # 0 missing, 1 background, 2 forest
>>> print(ls.euclidean_distance(forest, pixel_size=25).summary())
================================================================
GuidosToolbox (GTB) - Euclidean Distance Transform
...
distance_to_resistance
¶
Resistance growing with the distance to the foreground (GTB Setup Tools -> Distance -> Resistance).
data is coded 0 missing, 1 background, 2 foreground. Background pixels
get round(distance + 2) capped at 100 (so 3 next to an object),
foreground 2 and missing 0. The distance is IDL's MORPH_DISTANCE as GTB
uses it (quasi-Euclidean; see influence_zones() for the
remaining differences to IDL).
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
data
|
Map coded 0 missing, 1 background, 2 foreground. |
required | |
n_threads
|
int | None
|
Threads (0 or |
None
|
Returns:
| Type | Description |
|---|---|
DataArray or ndarray
|
|
Examples:
Restoration status¶
restoration_status
¶
restoration_status(data: DataArray | ndarray | str | Path) -> RestorationStatusResult
How connected the habitat is and how much reconnecting it could add (GTB's Restoration Status, batch_rss).
The habitat objects (8-connected foreground components) of areas A_i give:
- ECA (equivalent connected area) = sqrt(sum of A_i²), the size of a single object with the same connectivity;
- DOC (degree of coherence) = ECA / total habitat area, in %;
- restoration potential = 100 - DOC;
- RAC (relative area of habitat) = habitat area / valid area, in %;
- APS (average patch size) and CNOA (critical new object area).
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
data
|
DataArray | ndarray | str | Path
|
Map coded 0 missing, 1 background (or resistance 1-100), 2 foreground (DataArray, array or path). |
required |
Returns:
| Type | Description |
|---|---|
RestorationStatusResult
|
|
Examples:
RestorationStatusResult
dataclass
¶
RestorationStatusResult(
data_area: int,
nr_comp: int,
eca_max: int,
larg_obj: int,
aps: float,
cnoa: int,
eca: float,
doc: float,
rest_pot: float,
rac: float,
)
Bases: Saveable
Result of restoration_status().
Attributes:
| Name | Type | Description |
|---|---|---|
data_area |
int
|
Valid pixels (all but the missing ones). |
nr_comp |
int
|
Number of habitat objects (8-connected). |
eca_max |
int
|
Total habitat area, pixels. |
larg_obj |
int
|
Area of the largest object, pixels. |
aps |
float
|
Average patch size, eca_max / nr_comp. |
cnoa |
int
|
Critical new object area (GTB's formula), floor(2 b c² / (b² - c²) + 1) with b = eca_max and c = eca. |
eca |
float
|
Equivalent connected area, sqrt(sum of A_i²), pixels. |
doc |
float
|
Degree of coherence, ECA / eca_max in %. |
rest_pot |
float
|
Restoration potential, 100 - doc. |
rac |
float
|
Relative area of habitat, eca_max / data_area in %. |
Examples:
>>> import landschaft as ls
>>> forest = ls.load_raster(ls.example_data("input")) # 0 missing, 1 background, 2 forest
>>> status = ls.restoration_status(forest)
>>> status.to_dataframe()[["NR_OBJ", "COH[%]", "REST_POT[%]"]]
NR_OBJ COH[%] REST_POT[%]
0 2850 51.64 48.36
to_dataframe
¶
The metrics as one row of GTB's batch_rss spreadsheet.
Returns:
| Type | Description |
|---|---|
DataFrame
|
|
Costs, paths and corridors¶
cost_distance
¶
cost_distance(
resistance: DataArray | ndarray | str | Path,
source_mask: DataArray | ndarray | str | Path,
) -> DataArray | ndarray
Accumulated cost of travelling from the source cells across a resistance surface (8 neighbours).
A step costs the mean resistance of the two cells times the step length (1, or sqrt(2) on the diagonals).
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
resistance
|
DataArray | ndarray | str | Path
|
Resistance surface (1-100; 0 = impassable / NoData): DataArray, array or path. |
required |
source_mask
|
DataArray | ndarray | str | Path
|
Cells > 0 (or |
required |
Returns:
| Type | Description |
|---|---|
DataArray or ndarray
|
Accumulated cost; |
Examples:
>>> import landschaft as ls
>>> forest = ls.load_raster(ls.example_data("input")) # 0 missing, 1 background, 2 forest
>>> import numpy as np
>>> resistance = ls.distance_to_resistance(forest)
>>> objects = ls.accounting(forest) # the two largest forest objects
>>> ids = objects.ids.values
>>> marker = np.zeros(forest.shape, dtype="uint8")
>>> marker[ids == objects.largest[0][0]] = 1 # object A
>>> marker[ids == objects.largest[1][0]] = 2 # object B
>>> marker[forest.values == 0] = 3 # missing: not crossed
>>> cost = ls.cost_distance(resistance, marker == 1)
>>> round(float(cost.values[marker == 2].min()), 1) # cheapest cost to reach B
370.4
least_cost_path
¶
least_cost_path(
resistance: DataArray | ndarray | str | Path,
marker_a: DataArray | ndarray | str | Path,
marker_b: DataArray | ndarray | str | Path,
dist_map: DataArray | ndarray | None = None,
) -> LeastCostPathResult
The least-cost path between two areas A and B.
The costs from A and from B (cost_distance()) are added; the path is
the cells of minimal total cost.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
resistance
|
DataArray | ndarray | str | Path
|
Resistance surface (1-100; 0 = impassable). |
required |
marker_a
|
DataArray | ndarray | str | Path
|
Masks of areas A and B. |
required |
marker_b
|
DataArray | ndarray | str | Path
|
Masks of areas A and B. |
required |
dist_map
|
DataArray | ndarray | None
|
Optional distance map (e.g. |
None
|
Returns:
| Type | Description |
|---|---|
LeastCostPathResult
|
|
Examples:
>>> import landschaft as ls
>>> forest = ls.load_raster(ls.example_data("input")) # 0 missing, 1 background, 2 forest
>>> import numpy as np
>>> resistance = ls.distance_to_resistance(forest)
>>> objects = ls.accounting(forest) # the two largest forest objects
>>> ids = objects.ids.values
>>> marker = np.zeros(forest.shape, dtype="uint8")
>>> marker[ids == objects.largest[0][0]] = 1 # object A
>>> marker[ids == objects.largest[1][0]] = 2 # object B
>>> marker[forest.values == 0] = 3 # missing: not crossed
>>> path = ls.least_cost_path(resistance, marker == 1, marker == 2)
>>> path.path_length, path.rest_pixels, path.expense
(115, 113, 323.0)
LeastCostPathResult
dataclass
¶
LeastCostPathResult(
combined_cost: DataArray | ndarray,
lcp_mask: DataArray | ndarray,
path_length: int,
rest_pixels: int,
expense: float,
avg_distance: float,
)
Bases: Saveable
Result of least_cost_path().
Attributes:
| Name | Type | Description |
|---|---|---|
combined_cost |
DataArray or ndarray
|
Cost from A plus cost from B. |
lcp_mask |
DataArray or ndarray
|
1 on the path, 0 elsewhere. |
path_length |
int
|
Length of the path, pixels. |
rest_pixels |
int
|
Pixels of the path in the background: what would have to be restored. |
expense |
float
|
Total resistance of those pixels. |
avg_distance |
float
|
Mean distance of those pixels (with |
restoration_corridor
¶
restoration_corridor(
data: DataArray | ndarray | str | Path,
resistance: DataArray | ndarray | str | Path,
marker_a: DataArray | ndarray,
marker_b: DataArray | ndarray,
dist_map: DataArray | ndarray | None = None,
) -> RestorationCorridorResult
Connectivity gain of restoring the least-cost corridor between two areas (GTB's Restoration Planner).
The corridor of least_cost_path() is turned into habitat and the
landscape's ECA and degree of coherence (restoration_status()) are
compared before and after.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
data
|
DataArray | ndarray | str | Path
|
Habitat map coded 0 missing, 1 background, 2 foreground. |
required |
resistance
|
DataArray | ndarray | str | Path
|
Resistance surface (1-100; 0 = impassable). |
required |
marker_a
|
DataArray | ndarray
|
Masks of areas A and B. |
required |
marker_b
|
DataArray | ndarray
|
Masks of areas A and B. |
required |
dist_map
|
DataArray | ndarray | None
|
Optional distance map, as in |
None
|
Returns:
| Type | Description |
|---|---|
RestorationCorridorResult
|
|
Examples:
>>> import landschaft as ls
>>> forest = ls.load_raster(ls.example_data("input")) # 0 missing, 1 background, 2 forest
>>> import numpy as np
>>> resistance = ls.distance_to_resistance(forest)
>>> objects = ls.accounting(forest) # the two largest forest objects
>>> ids = objects.ids.values
>>> marker = np.zeros(forest.shape, dtype="uint8")
>>> marker[ids == objects.largest[0][0]] = 1 # object A
>>> marker[ids == objects.largest[1][0]] = 2 # object B
>>> marker[forest.values == 0] = 3 # missing: not crossed
>>> corridor = ls.restoration_corridor(forest, resistance, marker == 1, marker == 2)
>>> corridor.rest_pixels, round(corridor.delta_eca, 2), round(corridor.delta_doc, 2)
(113, 31784.28, 7.41)
RestorationCorridorResult
dataclass
¶
RestorationCorridorResult(
lcp_result: LeastCostPathResult,
size_a: int,
size_b: int,
rest_pixels: int,
expense: float,
efficiency: float,
eca_orig: float,
eca_new: float,
delta_eca: float,
doc_orig: float,
doc_new: float,
delta_doc: float,
)
Bases: Saveable
Result of restoration_corridor().
Attributes:
| Name | Type | Description |
|---|---|---|
lcp_result |
LeastCostPathResult
|
Underlying least-cost path result. |
size_a |
int
|
Pixel area of source component A. |
size_b |
int
|
Pixel area of target component B. |
rest_pixels |
int
|
Number of restored pixels needed to establish the corridor. |
expense |
float
|
Accumulated resistance cost of restored pixels. |
efficiency |
float
|
Restoration efficiency, delta_eca / expense. |
eca_orig |
float
|
Landscape ECA before restoration. |
eca_new |
float
|
Landscape ECA after establishing the corridor. |
delta_eca |
float
|
Net increase in ECA, eca_new - eca_orig. |
doc_orig |
float
|
Landscape Degree of Coherence (%) before restoration. |
doc_new |
float
|
Landscape Degree of Coherence (%) after restoration. |
delta_doc |
float
|
Net increase in Degree of Coherence (% points). |
Examples:
>>> import landschaft as ls
>>> forest = ls.load_raster(ls.example_data("input")) # 0 missing, 1 background, 2 forest
>>> import numpy as np
>>> resistance = ls.distance_to_resistance(forest)
>>> objects = ls.accounting(forest) # the two largest forest objects
>>> ids = objects.ids.values
>>> marker = np.zeros(forest.shape, dtype="uint8")
>>> marker[ids == objects.largest[0][0]] = 1 # object A
>>> marker[ids == objects.largest[1][0]] = 2 # object B
>>> marker[forest.values == 0] = 3 # missing: not crossed
>>> corridor = ls.restoration_corridor(forest, resistance, marker == 1, marker == 2)
>>> corridor.to_dataframe()[["REST_PIX", "COH_ORIG", "COH_NEW"]]
REST_PIX COH_ORIG COH_NEW
0 113 51.64 59.06
to_dataframe
¶
The metrics as one row of GTB's Restoration Planner spreadsheet.
Returns:
| Type | Description |
|---|---|
DataFrame
|
|
isochrone_map
¶
isochrone_map(resistance, marker) -> IsochroneResult
Accumulated cost from object A (GTB Restoration Planner -> Isochrone Map A).
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
resistance
|
|
required | |
marker
|
|
required |
Returns:
| Type | Description |
|---|---|
IsochroneResult
|
|
Examples:
>>> import landschaft as ls
>>> forest = ls.load_raster(ls.example_data("input")) # 0 missing, 1 background, 2 forest
>>> import numpy as np
>>> resistance = ls.distance_to_resistance(forest)
>>> objects = ls.accounting(forest) # the two largest forest objects
>>> ids = objects.ids.values
>>> marker = np.zeros(forest.shape, dtype="uint8")
>>> marker[ids == objects.largest[0][0]] = 1 # object A
>>> marker[ids == objects.largest[1][0]] = 2 # object B
>>> marker[forest.values == 0] = 3 # missing: not crossed
>>> only_a = np.where(marker == 2, 0, marker).astype("uint8")
>>> rings = ls.isochrone_map(resistance, only_a)
>>> rings.min_cost, rings.max_cost
(2, 1166)
isochrone_map_ab
¶
isochrone_map_ab(
resistance, marker, *, n_threads: int | None = None
) -> IsochroneResult
Cheapest route between objects A and B (GTB Restoration Planner -> Isochrone Map AB).
marker holds 1 = object A, 2 = object B (each a single 8-connected
object, not touching each other), 3 = missing, 0 = background; see
isochrone_map() for resistance.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
resistance
|
|
required | |
marker
|
|
required | |
n_threads
|
int | None
|
Threads (0 or |
None
|
Returns:
| Type | Description |
|---|---|
IsochroneResult
|
With the least-cost path in |
Examples:
>>> import landschaft as ls
>>> forest = ls.load_raster(ls.example_data("input")) # 0 missing, 1 background, 2 forest
>>> import numpy as np
>>> resistance = ls.distance_to_resistance(forest)
>>> objects = ls.accounting(forest) # the two largest forest objects
>>> ids = objects.ids.values
>>> marker = np.zeros(forest.shape, dtype="uint8")
>>> marker[ids == objects.largest[0][0]] = 1 # object A
>>> marker[ids == objects.largest[1][0]] = 2 # object B
>>> marker[forest.values == 0] = 3 # missing: not crossed
>>> route = ls.isochrone_map_ab(resistance, marker)
>>> route.min_cost, int(np.asarray(route.lcp).sum())
(210, 215)
IsochroneResult
dataclass
¶
IsochroneResult(
map: DataArray | ndarray,
cost: DataArray | ndarray,
lcp: DataArray | ndarray | None,
min_cost: int,
max_cost: int,
)
Bases: Saveable
Result of isochrone_map() / isochrone_map_ab().
Attributes:
| Name | Type | Description |
|---|---|---|
map |
DataArray | ndarray
|
|
cost |
DataArray | ndarray
|
Accumulated cost as GTB rounds it ( |
lcp |
DataArray | ndarray | None
|
Least-cost path mask (map AB), else |
Zones of influence¶
influence_zones
¶
influence_zones(
data,
min_area: int = 5000,
*,
core_buffer: int = 0,
buffer: int = 0,
n_threads: int = 0,
) -> InfluenceZonesResult
Zones of influence of the foreground objects (GTB Distance -> Influence Zones).
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
data
|
2-D |
required | |
min_area
|
int
|
Minimum object area [pixels] (GTB default 5000). Smaller objects are not objects; they are shown as code 176. |
5000
|
core_buffer
|
int
|
Reduce the objects to their core: drop the foreground within
|
0
|
buffer
|
int
|
Width [pixels] of a background buffer drawn around the objects (0 = none). |
0
|
n_threads
|
int
|
Threads (0 or |
0
|
Returns:
| Type | Description |
|---|---|
InfluenceZonesResult
|
|
Notes
Experimental: the method is GTB's, but its distance transform (IDL's
MORPH_DISTANCE) is not yet reproduced exactly, so zone boundaries can
differ in detail.
Examples:
InfluenceZonesResult
dataclass
¶
InfluenceZonesResult(
classes: DataArray | ndarray,
ids: DataArray | ndarray,
zones: DataArray | ndarray,
object_area: ndarray,
min_area: int,
core_buffer: int,
buffer: int,
)
Bases: Saveable
Result of influence_zones().
Attributes:
| Name | Type | Description |
|---|---|---|
classes |
DataArray | ndarray
|
|
ids |
DataArray | ndarray
|
|
zones |
DataArray | ndarray
|
|
object_area |
ndarray
|
Area of object |
proximity
¶
proximity(
data,
min_area: int = 5000,
*,
core_buffer: int = 0,
prox_max: int = 0,
n_threads: int = 0,
) -> ProximityResult
Proximity between neighbouring objects (GTB Distance -> Proximity).
Parameters are those of influence_zones(), with prox_max: the
watershed lines with a proximity up to prox_max (or the minimum
proximity, if larger) are marked 165 (GTB default 0).
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
data
|
Map coded 0 missing, 1 background, 2 foreground (array, DataArray or path). |
required | |
min_area
|
int
|
Minimum object area in pixels (GTB default 5000). |
5000
|
core_buffer
|
int
|
Reduce the objects to their core first (see |
0
|
prox_max
|
int
|
Watershed lines with a proximity up to this value are marked 165. |
0
|
n_threads
|
int
|
Threads (0 or |
0
|
Returns:
| Type | Description |
|---|---|
ProximityResult
|
|
Notes
Experimental, as influence_zones().
Examples:
ProximityResult
dataclass
¶
ProximityResult(
classes: DataArray | ndarray,
ids: DataArray | ndarray,
zones: DataArray | ndarray,
distance: DataArray | ndarray,
cag: DataArray | ndarray,
object_area: ndarray,
lines: DataFrame,
prox_min: int | None,
prox_min_count: int,
min_area: int,
core_buffer: int,
prox_max: int,
source: str = "",
)
Bases: Saveable
Result of proximity().
Attributes:
| Name | Type | Description |
|---|---|---|
classes, ids, zones, object_area |
As in |
|
distance |
DataArray | ndarray
|
|
cag |
DataArray | ndarray
|
|
lines |
DataFrame
|
One row per watershed pixel between zones (GTB's proximity CSV): 1-based column/row, number of adjacent zones, connector length, CAG and the adjacent zone ids with their object areas. |
prox_min, prox_min_count |
Minimum proximity on the watershed lines and the number of pixels with it. |
Original vegetation¶
original_vegetation
¶
original_vegetation(
land_cover,
natural: Iterable[str],
anthropic: Iterable[str],
*,
past=None,
ecoregions=None,
failsafe: Iterable[str] | None = None,
threshold: float = 0.95,
restore_to: str = "original",
n_threads: int | None = None,
) -> OriginalVegetation
The original vegetation of converted land, and what restoration brings back.
Every pixel holds shares of land-cover classes: natural ones (forest, grassland, wetland...), anthropic ones (crops, pasture...) and others that are neither (water, rock). Restoring a pixel's anthropic share brings back natural vegetation; this function says which, as plangea prepares it for its restoration model (Strassburg et al. 2020):
- the anthropic share is split among the natural classes in the
proportions they had in the pixel in the
past; - where the past has no natural cover, or more than
thresholdof the pixel is anthropic today, in the proportions of the pixel'secoregions(equal proportions without them); - where those are all zero too, in the mean proportions of the
failsafeclasses over the pixels with anthropic land (over all the land withrestore_to="current").
The original cover of a class is then its current share plus its part of the anthropic share.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
land_cover
|
The current share (0 to 1) of every class in each pixel: a
|
required | |
natural
|
Iterable[str]
|
The natural and the anthropic classes. The other layers are ignored. |
required |
anthropic
|
Iterable[str]
|
The natural and the anthropic classes. The other layers are ignored. |
required |
past
|
The past share of every natural class (same forms; NaN counts as 0). By default the current shares. |
None
|
|
ecoregions
|
For every natural class, its proportion in each pixel's ecoregion (same forms). By default equal proportions. |
None
|
|
failsafe
|
Iterable[str] | None
|
The classes the failsafe fills (default: every natural class). |
None
|
threshold
|
float
|
Above this anthropic share, the ecoregion's proportions are used even where there is a past cover. |
0.95
|
restore_to
|
str
|
|
'original'
|
n_threads
|
int | None
|
Threads (default: all cores but one). |
None
|
Returns:
| Type | Description |
|---|---|
OriginalVegetation
|
The original cover, the restored proportions, the source of each pixel's proportions and the anthropic share. |
Notes
The arithmetic is plangea's, bit for bit (harmonize_oa), with two
corrections: without ecoregion maps, plangea gives every natural class
the pixel's total natural share divided by the number of classes instead
of equal proportions (its own comment says "flat among natural types"),
which leaves most of a converted pixel to no class; and pixels the
failsafe fills get 0 for the classes it does not fill, where plangea can
stop with NA.
Examples:
>>> import numpy as np
>>> import xarray as xr
>>> import landschaft as ls
>>> cover = xr.DataArray(np.array([[[0.6, 0.0]], [[0.2, 0.1]], [[0.2, 0.9]]]),
... dims=("band", "y", "x"), coords={"band": ["forest", "savanna", "crops"]})
>>> past = xr.DataArray(np.array([[[0.9, 0.0]], [[0.1, 0.0]]]),
... dims=("band", "y", "x"), coords={"band": ["forest", "savanna"]})
>>> veg = ls.original_vegetation(cover, ["forest", "savanna"], ["crops"], past=past)
>>> veg.original.sel(band="forest").values.round(3)
array([[0.78, 0.45]])
>>> veg.source.values
array([[0., 1.]])
OriginalVegetation
dataclass
¶
OriginalVegetation(
original: DataArray,
restore: DataArray,
source: DataArray,
anthropic: DataArray,
failsafe: dict = dict(),
)
Bases: Saveable
Result of original_vegetation().
Attributes:
| Name | Type | Description |
|---|---|---|
original |
DataArray
|
The share of every natural class in each pixel's original cover
( |
restore |
DataArray
|
The shares of the natural classes that restored land in each pixel becomes (they sum to 1). |
source |
DataArray
|
Where each pixel's proportions come from: 0 its past cover, 1 its
ecoregion, 2 the failsafe (see |
anthropic |
DataArray
|
The anthropic share of each pixel: the land restoration can work on. |
failsafe |
dict
|
The failsafe proportions of the natural classes. |
Ecological intactness¶
intactness
¶
Ecological intactness from the human footprint (Beyer et al. 2020).
A cell's habitat quality is q = exp(-gamma HFI) for its human footprint index HFI, and its
intactness Q_i = sum_j (q_i q_j)^z w_ij / sum_j w_ij: the quality of the cell and of its
surroundings within a radius, weighted by w = exp(beta d) at a distance d (km). The computation and
its parameters follow plangea's multi_calc_it (International Institute for Sustainability;
GPL >= 3), which uses it as a benefit of restoration: restoring a share x of a cell lowers its
footprint by a reduction per unit, and intactness_gradient() gives what that adds to the
total intactness.
References
Beyer, H. L., Venter, O., Grantham, H. S. & Watson, J. E. M. (2020). Substantial losses in ecoregion intactness highlight urgency of globally coordinated action. Conservation Letters 13, e12692. doi:10.1111/conl.12692
intactness
¶
intactness(
hfi,
radius: int = 3,
*,
gamma: float = INTACTNESS_GAMMA,
beta: float = -0.2,
z: float = 0.5,
cell_size=None,
reduction=None,
restored=None,
n_threads: int | None = None,
) -> DataArray
Ecological intactness of every cell from the human footprint (Beyer et al. 2020).
The habitat quality of a cell is q = exp(-gamma HFI), from 1 where people leave no footprint down towards 0; its intactness
.. math:: Q_i = \frac{\sum_j (q_i q_j)^z w_{ij}}{\sum_j w_{ij}}
over the cells j within radius cells of it (itself included), with
weights w = exp(beta d) that fall with the distance d in km: a cell is
intact when it and its surroundings are of high quality.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
hfi
|
The human footprint index (a raster, NaN outside the area). |
required | |
radius
|
int
|
The radius of the neighbourhood, in cells (plangea's |
3
|
gamma
|
float
|
Beyer et al.'s parameters: gamma = -ln(0.2) / 4 (a footprint of 4 gives a quality of 0.2), beta = -0.2 per km, z = 0.5. |
INTACTNESS_GAMMA
|
beta
|
float
|
Beyer et al.'s parameters: gamma = -ln(0.2) / 4 (a footprint of 4 gives a quality of 0.2), beta = -0.2 per km, z = 0.5. |
INTACTNESS_GAMMA
|
z
|
float
|
Beyer et al.'s parameters: gamma = -ln(0.2) / 4 (a footprint of 4 gives a quality of 0.2), beta = -0.2 per km, z = 0.5. |
INTACTNESS_GAMMA
|
cell_size
|
The width (and height) of a cell in km, or |
None
|
|
reduction
|
Restoration: the footprint a cell loses per unit of its area restored (a raster or a number) and the share of each cell restored. The footprint becomes HFI - reduction x restored, at least 0. |
None
|
|
restored
|
Restoration: the footprint a cell loses per unit of its area restored (a raster or a number) and the share of each cell restored. The footprint becomes HFI - reduction x restored, at least 0. |
None
|
|
n_threads
|
int | None
|
Threads (default: all cores but one). |
None
|
Returns:
| Type | Description |
|---|---|
DataArray
|
Q on the footprint's grid, 0 to 1 (NaN where the footprint is). |
Notes
The values are plangea's multi_calc_it (with aggregate = TRUE),
bit for bit, except at the edges: plangea leaves out the cells closer
than the radius to an edge (and one more row and column at the end) and
gives them the mean of the others; here their window is the part inside
the raster, as it is around cells without a footprint.
Examples:
intactness_gradient
¶
intactness_gradient(
hfi,
reduction,
radius: int = 3,
*,
gamma: float = INTACTNESS_GAMMA,
beta: float = -0.2,
z: float = 0.5,
cell_size=None,
restored=None,
n_threads: int | None = None,
) -> DataArray
What restoring each cell adds to the total ecological intactness.
Restoring a share x of a cell lowers its human footprint by
reduction x; this is the derivative of the sum of
intactness() over all cells with respect to x: the cell's own
intactness rises, and so does that of every cell whose neighbourhood
holds it,
.. math:: \frac{\partial \sum_i Q_i}{\partial x_k} = z\,\gamma\,a_k \Big(Q_k + q_k^z \sum_{i} \frac{q_i^z w_{ik}}{W_i}\Big)
(a the reduction, W_i the sum of the weights of i's window), 0 where the footprint is already 0. It is the linear benefit of restoration for intactness in a restoration plan.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
hfi
|
As |
required | |
radius
|
As |
required | |
gamma
|
As |
required | |
beta
|
As |
required | |
z
|
As |
required | |
cell_size
|
As |
required | |
n_threads
|
As |
required | |
reduction
|
The footprint a cell loses per unit of its area restored (a raster
or a number): in plangea, the anthropic classes' shares weighted by
their footprint ( |
required | |
restored
|
Shares already restored (the derivative at that point). |
None
|
Returns:
| Type | Description |
|---|---|
DataArray
|
The derivative on the footprint's grid. |
Notes
plangea's derivative changes only the cell's own factor q_i (by a finite difference), leaving out the cell inside its own window and its effect on its neighbours' intactness; this is the complete one (the derivative of the total intactness).
Examples:
intactness_gradient
¶
intactness_gradient(
hfi,
reduction,
radius: int = 3,
*,
gamma: float = INTACTNESS_GAMMA,
beta: float = -0.2,
z: float = 0.5,
cell_size=None,
restored=None,
n_threads: int | None = None,
) -> DataArray
What restoring each cell adds to the total ecological intactness.
Restoring a share x of a cell lowers its human footprint by
reduction x; this is the derivative of the sum of
intactness() over all cells with respect to x: the cell's own
intactness rises, and so does that of every cell whose neighbourhood
holds it,
.. math:: \frac{\partial \sum_i Q_i}{\partial x_k} = z\,\gamma\,a_k \Big(Q_k + q_k^z \sum_{i} \frac{q_i^z w_{ik}}{W_i}\Big)
(a the reduction, W_i the sum of the weights of i's window), 0 where the footprint is already 0. It is the linear benefit of restoration for intactness in a restoration plan.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
hfi
|
As |
required | |
radius
|
As |
required | |
gamma
|
As |
required | |
beta
|
As |
required | |
z
|
As |
required | |
cell_size
|
As |
required | |
n_threads
|
As |
required | |
reduction
|
The footprint a cell loses per unit of its area restored (a raster
or a number): in plangea, the anthropic classes' shares weighted by
their footprint ( |
required | |
restored
|
Shares already restored (the derivative at that point). |
None
|
Returns:
| Type | Description |
|---|---|
DataArray
|
The derivative on the footprint's grid. |
Notes
plangea's derivative changes only the cell's own factor q_i (by a finite difference), leaving out the cell inside its own window and its effect on its neighbours' intactness; this is the complete one (the derivative of the total intactness).
Examples: