Skip to content

Neutral landscape models

Simulated landscapes that follow a known rule (complete randomness, a gradient, clustering, fractal roughness) and nothing else: the null models of landscape ecology, to test whether a pattern or a process differs from what chance alone would give. They live in the ls.nlm module. Tutorial: neutral landscapes.

With the same seed every model gives the same landscape as the R package NLMR, value for value: the random number generators of R and of the C++ library NLMR is built with are reproduced, so studies done in R can be repeated and extended here.

import landschaft as ls

r = ls.nlm.random(200, 200, seed=42)             # a DataArray of values in 0-1
habitat = ls.nlm.classify(r, weighting=[0.7, 0.3])

Random and percolation

random

random(
    ncol: int,
    nrow: int,
    resolution: float = 1.0,
    seed: int | None = None,
    rescale: bool = True,
    *,
    n_threads: int | None = None,
) -> DataArray

Spatially random neutral landscape model (NLMR's nlm_random).

Every cell gets an independent uniform value.

Parameters:

Name Type Description Default
ncol int

Columns and rows.

required
nrow int

Columns and rows.

required
resolution float

Cell size.

1
seed int

Seed of R's generator (NLMR's user_seed): the same seed gives the same landscape as NLMR. None draws one, stored in attrs["seed"].

None
rescale bool

Rescale the values to 0-1 (rescale()).

True
n_threads int

Threads (default: all cores but one).

None

Returns:

Type Description
DataArray

float64 values on a grid with origin (0, 0) and the given resolution.

Examples:

>>> import landschaft as ls
>>> r = ls.nlm.random(50, 40, seed=1)
>>> r.shape, float(r.min()), float(r.max())
((40, 50), 0.0, 1.0)

percolation

percolation(
    ncol: int,
    nrow: int,
    resolution: float = 1.0,
    prob: float = 0.5,
    seed: int | None = None,
    *,
    n_threads: int | None = None,
) -> DataArray

Percolation neutral landscape model (NLMR's nlm_percolation).

Each cell is 1 with probability prob (a Bernoulli draw), else 0.

Parameters:

Name Type Description Default
ncol int

Columns and rows.

required
nrow int

Columns and rows.

required
resolution float

Cell size.

1
prob float

Probability of a cell being 1.

0.5
seed int

Seed of R's generator (NLMR's user_seed); None draws one.

None
n_threads int

Threads (default: all cores but one).

None

Returns:

Type Description
DataArray

uint8 0/1 values.

Examples:

>>> import landschaft as ls
>>> p = ls.nlm.percolation(100, 100, prob=0.3, seed=7)
>>> round(float(p.mean()), 2)
0.3

Gradients

planar_gradient

planar_gradient(
    ncol: int,
    nrow: int,
    resolution: float = 1.0,
    direction: float | None = None,
    seed: int | None = None,
    rescale: bool = True,
    *,
    n_threads: int | None = None,
) -> DataArray

Planar gradient neutral landscape model (NLMR's nlm_planargradient).

Values increase linearly in one direction across the landscape.

Parameters:

Name Type Description Default
ncol int

Columns and rows.

required
nrow int

Columns and rows.

required
resolution float

Cell size.

1
direction float

Direction of the gradient in degrees, clockwise from north: the values grow northwards with 0 and eastwards with 90. None draws it with runif(1, 0, 360) after set.seed(seed).

None
seed int

Seed of R's generator, used only when direction is None.

None
rescale bool

Rescale the values to 0-1.

True
n_threads int

Threads (default: all cores but one).

None

Returns:

Type Description
DataArray

float64 values; attrs["direction"] holds the direction used.

Examples:

>>> import landschaft as ls
>>> g = ls.nlm.planar_gradient(5, 4, direction=90)
>>> g.values[0].round(2)
array([0.  , 0.25, 0.5 , 0.75, 1.  ])

edge_gradient

edge_gradient(
    ncol: int,
    nrow: int,
    resolution: float = 1.0,
    direction: float | None = None,
    seed: int | None = None,
    rescale: bool = True,
    *,
    n_threads: int | None = None,
) -> DataArray

Edge gradient neutral landscape model (NLMR's nlm_edgegradient).

A planar gradient folded around its middle: values peak along a central band and fall to both edges (1 - 2 |0.5 - g| of the rescaled planar gradient g).

Parameters:

Name Type Description Default
ncol int

Columns and rows.

required
nrow int

Columns and rows.

required
resolution float

Cell size.

1
direction float

Direction of the gradient in degrees; None draws it with runif(1, 0, 360) after set.seed(seed).

None
seed int

Seed of R's generator, used only when direction is None.

None
rescale bool

Rescale the values to 0-1.

True
n_threads int

Threads (default: all cores but one).

None

Returns:

Type Description
DataArray

float64 values; attrs["direction"] holds the direction used.

Examples:

>>> import landschaft as ls
>>> e = ls.nlm.edge_gradient(5, 3, direction=90)
>>> e.values[0].round(2)
array([0. , 0.5, 1. , 0.5, 0. ])

distance_gradient

distance_gradient(
    ncol: int,
    nrow: int,
    origin,
    resolution: float = 1.0,
    rescale: bool = True,
    nlmr_compat: bool = True,
    *,
    n_threads: int | None = None,
) -> DataArray

Distance gradient neutral landscape model (NLMR's nlm_distancegradient).

The distance of every cell to a rectangular origin.

Parameters:

Name Type Description Default
ncol int

Columns and rows.

required
nrow int

Columns and rows.

required
origin sequence of 4 ints

The origin rectangle, 1-based and inclusive. With nlmr_compat=True as NLMR applies it: (first row, last row, first column, last column) (NLMR documents xmin, xmax, ymin, ymax but indexes the raster as [rows, columns]); otherwise (first column, last column, first row, last row).

required
resolution float

Cell size.

1
rescale bool

Rescale the values to 0-1.

True
nlmr_compat bool

Reproduce NLMR exactly: terra::distance treats a raster of at most 360 x 90 cells as longitude/latitude (terra's default CRS for such an extent) and returns great-circle distances in metres (haversine on a 6378137 m sphere); larger rasters get GDAL's proximity algorithm (in cell units, float32). With False, exact Euclidean distances between cell centres times resolution.

True
n_threads int

Threads (default: all cores but one).

None

Returns:

Type Description
DataArray

float64 distances (rescaled to 0-1 by default).

Examples:

>>> import landschaft as ls
>>> d = ls.nlm.distance_gradient(5, 5, origin=(3, 3, 1, 1), nlmr_compat=False, rescale=False)
>>> d.values[0]
array([2., 1., 0., 1., 2.])

Fractal surfaces and random fields

mpd

mpd(
    ncol: int,
    nrow: int,
    resolution: float = 1.0,
    roughness: float = 0.5,
    rand_dev: float = 1.0,
    seed: int | None = None,
    torus: bool = False,
    rescale: bool = True,
    nlmr_compat: bool = True,
    *,
    n_threads: int | None = None,
) -> DataArray

Midpoint displacement neutral landscape model (NLMR's nlm_mpd).

The diamond-square algorithm: a fractal surface whose spatial autocorrelation is set by roughness (the random deviation shrinks by this factor at every halving of the grid).

Parameters:

Name Type Description Default
ncol int

Columns and rows asked for.

required
nrow int

Columns and rows asked for.

required
resolution float

Cell size.

1
roughness float

Between 0 and 1: low values give smooth, strongly autocorrelated surfaces, high values rough ones.

0.5
rand_dev float

Standard deviation of the displacement at the first step.

1
seed int

Seed of NLMR's std::mt19937 (NLMR's user_seed): the same seed gives NLMR's landscape. None draws one, stored in attrs["seed"].

None
torus bool

Wrap the square steps around the edges (a periodic surface).

False
rescale bool

Rescale the values to 0-1.

True
nlmr_compat bool

Reproduce NLMR: its grid is a square of side max(nrow, ncol) + 1 (made odd) and the result drops one cell on each side, so the raster is square and max(nrow, ncol) - 1 or max(nrow, ncol) cells wide, not nrow x ncol (a warning says so). With False the grid is 2**k + 1 cells wide and cropped to nrow x ncol.

True
n_threads int

Threads (default: all cores but one).

None

Returns:

Type Description
DataArray

float64 values.

Examples:

>>> import landschaft as ls
>>> m = ls.nlm.mpd(65, 65, roughness=0.4, seed=3)
>>> m.shape
(65, 65)
>>> ls.nlm.mpd(100, 80, seed=3, nlmr_compat=False).shape
(80, 100)

fbm

fbm(
    ncol: int,
    nrow: int,
    resolution: float = 1.0,
    fract_dim: float = 1.0,
    seed: int | None = None,
    rescale: bool = True,
    *,
    n_threads: int | None = None,
) -> DataArray

Fractional Brownian motion neutral landscape model (NLMR's nlm_fbm).

A fractal surface from a power-law spectrum |k|^-(fract_dim + 1) with random phases (inverse FFT), centred and scaled to unit standard deviation of the steps between neighbouring cells. fract_dim is the Hurst-like exponent alpha of NLMR (0 < alpha <= 2): small values give rough surfaces, large ones smooth ones; alpha = 2 is a random plane.

NLMR 1.4 disabled nlm_fbm when RandomFields left CRAN and ships this method as its internal simulate_fbm; the results here are that function's, rescaled as NLMR's previous nlm_fbm did.

Parameters:

Name Type Description Default
ncol int

Columns and rows.

required
nrow int

Columns and rows.

required
resolution float

Cell size.

1
fract_dim float

The exponent alpha, in (0, 2].

1
seed int

Seed of R's generator: the same seed gives NLMR's surface. None draws one, stored in attrs["seed"].

None
rescale bool

Rescale the values to 0-1.

True
n_threads int

Threads (default: all cores but one).

None

Returns:

Type Description
DataArray

float64 values.

Examples:

>>> import landschaft as ls
>>> f = ls.nlm.fbm(64, 64, fract_dim=1.5, seed=2)
>>> f.shape, float(f.max())
((64, 64), 1.0)

gaussian_field

gaussian_field(
    ncol: int,
    nrow: int,
    resolution: float = 1.0,
    autocorr_range: float = 10,
    mag_var: float = 5,
    nug: float = 0.2,
    mean: float = 0.5,
    seed: int | None = None,
    rescale: bool = True,
    *,
    n_threads: int | None = None,
) -> DataArray

Gaussian random field neutral landscape model (NLMR's nlm_gaussianfield).

A stationary Gaussian field with an exponential covariance mag_var * exp(-d / autocorr_range), simulated exactly by circulant embedding (FFT on a grid twice as large in each direction), plus a nugget (white noise of variance nug) and a mean.

NLMR 1.4 disabled nlm_gaussianfield when RandomFields left CRAN and ships this method as its internal simulate_gaussian_field; the results here are that function's, rescaled as NLMR's previous nlm_gaussianfield did.

Parameters:

Name Type Description Default
ncol int

Columns and rows.

required
nrow int

Columns and rows.

required
resolution float

Cell size.

1
autocorr_range float

Range of the spatial autocorrelation, in cells.

10
mag_var float

Variance of the autocorrelated part.

5
nug float

Variance of the nugget (uncorrelated noise); 0 for none.

0.2
mean float

Mean of the field.

0.5
seed int

Seed of R's generator: the same seed gives NLMR's field. None draws one, stored in attrs["seed"].

None
rescale bool

Rescale the values to 0-1.

True
n_threads int

Threads (default: all cores but one).

None

Returns:

Type Description
DataArray

float64 values.

Examples:

>>> import landschaft as ls
>>> g = ls.nlm.gaussian_field(80, 60, autocorr_range=15, seed=1)
>>> g.shape, float(g.min()), float(g.max())
((60, 80), 0.0, 1.0)

Mosaics

mosaic_field

mosaic_field(
    ncol: int,
    nrow: int,
    resolution: float = 1.0,
    n: int | None = 20,
    mosaic_mean: float = 0.5,
    mosaic_sd: float = 0.5,
    seed: int | None = None,
    collect: bool = False,
    infinit: bool = False,
    rescale: bool = True,
    nlmr_compat: bool = True,
    *,
    n_threads: int | None = None,
)

Mosaic random field neutral landscape model (NLMR's nlm_mosaicfield, Schlather 1999).

The sum of n mosaic fields: each splits the landscape by a Poisson line tessellation (intensity 4 on the unit square, spatstat's rpoislinetess) and gives every tile a normal value (rMosaicField). As n grows the sum tends to a Gaussian random field; infinit=True also returns that limit, a Gaussian field with exponential covariance (the log intensity of spatstat's rLGCP("exp", 4, var = 1, scale = 0.2)).

Parameters:

Name Type Description Default
ncol int

Columns and rows.

required
nrow int

Columns and rows.

required
resolution float

Cell size.

1
n int or None

Number of mosaic fields summed; None for only the infinit field. With nlmr_compat=True, n = 1 sums three fields as NLMR does (for (i in 2:n) runs over c(2, 1)).

20
mosaic_mean float

Mean and standard deviation of the tile values.

0.5
mosaic_sd float

Mean and standard deviation of the tile values.

0.5
seed int

Seed of R's generator (NLMR's user_seed): the same seed gives NLMR's landscape. None draws one, stored in attrs["seed"].

None
collect bool

Also return every field, the i-th divided by sqrt(i), as NLMR's steps.

False
infinit bool

Also return the limiting Gaussian field.

False
rescale bool

Rescale to 0-1 (the steps together, with the first step's range as NLMR does, unless nlmr_compat=False).

True
nlmr_compat bool

Reproduce NLMR's quirks described above.

True
n_threads int

Threads (default: all cores but one).

None

Returns:

Type Description
DataArray or dict

The summed field; with collect or infinit a dict with the entries "mosaic_field", "steps" (dims step, y, x) and "infinit" that were asked for (a single one is returned as is).

Examples:

>>> import landschaft as ls
>>> m = ls.nlm.mosaic_field(60, 40, n=10, seed=1)
>>> m.shape, float(m.min()), float(m.max())
((40, 60), 0.0, 1.0)
>>> out = ls.nlm.mosaic_field(30, 20, n=4, collect=True, seed=2)
>>> sorted(out), out["steps"].shape
(['mosaic_field', 'steps'], (4, 20, 30))

mosaic_tess

mosaic_tess(
    ncol: int,
    nrow: int,
    germs: int,
    resolution: float = 1.0,
    seed: int | None = None,
    rescale: bool = True,
    nlmr_compat: bool = True,
    *,
    n_threads: int | None = None,
) -> DataArray

Polygonal (Voronoi) mosaic neutral landscape model (NLMR's nlm_mosaictess, Gaucherel 2008).

germs uniform random points split the landscape into Voronoi tiles, each with a uniform random value.

Parameters:

Name Type Description Default
ncol int

Columns and rows.

required
nrow int

Columns and rows.

required
germs int

Number of germs (tiles).

required
resolution float

Cell size.

1
seed int

Seed of R's generator (NLMR's user_seed); None draws one, stored in attrs["seed"].

None
rescale bool

Rescale the values to 0-1.

True
nlmr_compat bool

Reproduce NLMR: the k-th value goes to the k-th tile in the order GEOS returns the Voronoi cells (found with shapely; without it a warning and the other assignment), and values are rounded to float32 as terra::rasterize stores them. With False the k-th germ gets the k-th value, in double precision.

True
n_threads int

Threads (default: all cores but one).

None

Returns:

Type Description
DataArray

float64 values.

Examples:

>>> import landschaft as ls
>>> t = ls.nlm.mosaic_tess(80, 60, germs=40, seed=1)
>>> t.shape, int(len(set(t.values.ravel())))
((60, 80), 40)

mosaic_gibbs

mosaic_gibbs(
    ncol: int,
    nrow: int,
    germs: int,
    R: float,
    patch_classes: int,
    resolution: float = 1.0,
    seed: int | None = None,
    rescale: bool = True,
    nlmr_compat: bool = True,
    *,
    n_threads: int | None = None,
) -> DataArray

Gibbs-process Voronoi mosaic (NLMR's nlm_mosaicgibbs, Gauchel et al. 2008).

germs points from a simple sequential inhibition process (spatstat's rSSI: no two points closer than R) split the landscape into Voronoi tiles; the classes 1..patch_classes, repeated to germs values and shuffled, are given to the tiles.

Parameters:

Name Type Description Default
ncol int

Columns and rows.

required
nrow int

Columns and rows.

required
germs int

Number of germs.

required
R float

Minimum distance between germs, in cells.

required
patch_classes int

Number of classes.

required
resolution float

Cell size.

1
seed int

Seed of R's generator (NLMR's user_seed); None draws one.

None
rescale bool

Rescale the classes to 0-1.

True
nlmr_compat bool

Reproduce NLMR, which gives the k-th germ's class to the k-th Voronoi polygon in GEOS's order (not to the germ's own tile; found with shapely, without it a warning and the other assignment). With False each germ's tile takes its own class.

True
n_threads int

Threads (default: all cores but one).

None

Returns:

Type Description
DataArray

float64 values (classes before rescaling).

Examples:

>>> import landschaft as ls
>>> g = ls.nlm.mosaic_gibbs(80, 60, germs=30, R=6, patch_classes=3, seed=2, rescale=False)
>>> sorted(int(v) for v in set(g.values.ravel()))
[1, 2, 3]

Voronoi mosaics and shapely

NLMR gives the tile values in the order in which GEOS returns the Voronoi cells. Landschaft asks GEOS for that order through shapely (installed with it); without shapely the models warn and give each germ its own value. GEOS 3.11 or later is needed for NLMR's order (older versions return the cells in another order, with a warning).

Clusters

random_cluster

random_cluster(
    ncol: int,
    nrow: int,
    p: float,
    ai: Sequence[float] = (0.5, 0.5),
    neighbourhood: int = 4,
    resolution: float = 1.0,
    seed: int | None = None,
    rescale: bool = True,
    *,
    n_threads: int | None = None,
) -> DataArray

Random cluster neutral landscape model (NLMR's nlm_randomcluster, Saura & Martínez-Millán 2000).

A percolation map with probability p is split into clusters of adjacent cells, each cluster gets a type drawn with the weights ai, and every remaining cell takes the most frequent type among its 8 neighbours (a random one of the tied types; a type drawn with ai when no neighbour has one).

Parameters:

Name Type Description Default
ncol int

Columns and rows.

required
nrow int

Columns and rows.

required
p float

Share of the cells in the initial percolation map (up to 1).

required
ai sequence of float

Weights of the types (their share of the clusters).

(0.5, 0.5)
neighbourhood (4, 8)

Adjacency of the cells of a cluster.

4
resolution float

Cell size.

1
seed int

Seed of R's generator (NLMR's user_seed): the same seed gives NLMR's landscape. None draws one, stored in attrs["seed"].

None
rescale bool

Rescale the types to 0-1; else the types 1, 2, ... as int32.

True
n_threads int

Threads (default: all cores but one).

None

Returns:

Type Description
DataArray

float64 (rescaled) or int32 types.

Examples:

>>> import landschaft as ls
>>> r = ls.nlm.random_cluster(60, 40, p=0.4, ai=[0.25, 0.25, 0.5], seed=4, rescale=False)
>>> sorted(int(v) for v in set(r.values.ravel()))
[1, 2, 3]

neigh

neigh(
    ncol: int,
    nrow: int,
    p_neigh: float,
    p_empty: float,
    resolution: float = 1.0,
    categories: int = 3,
    neighbourhood: int = 4,
    proportions: Sequence[float] | None = None,
    seed: int | None = None,
    rescale: bool = True,
    *,
    n_threads: int | None = None,
) -> DataArray

Neighbourhood-based clusters (NLMR's nlm_neigh, Scherer et al. 2016).

Cells are visited in a random order and take the current category with probability p_neigh when a neighbour already holds one, p_empty otherwise, which grows clusters of adjustable compactness. The edges wrap around.

As in NLMR, categories are filled from categories - 1 down to 0 and "holds one" means a neighbour with a non-zero category.

Parameters:

Name Type Description Default
ncol int

Columns and rows.

required
nrow int

Columns and rows.

required
p_neigh float

Probability of a cell joining the category when a neighbour holds one.

required
p_empty float

Probability when no neighbour does.

required
resolution float

Cell size.

1
categories int

Number of categories (values 0 .. categories - 1).

3
neighbourhood (4, 8)

Neighbours looked at (8 adds the diagonals when the 4 are empty).

4
proportions sequence of float

Share of the cells of each category (summing to 1); by default equal shares, floor(ncol * nrow / categories) cells each (the rest stays 0).

None
seed int

Seed of NLMR's std::mt19937 (NLMR's user_seed); None draws one.

None
rescale bool

Rescale the values to 0-1; else the categories as int32.

True
n_threads int

Threads (default: all cores but one).

None

Returns:

Type Description
DataArray

float64 (rescaled) or int32 categories.

Examples:

>>> import landschaft as ls
>>> n = ls.nlm.neigh(60, 40, p_neigh=0.7, p_empty=0.1, categories=4, seed=2, rescale=False)
>>> sorted(int(v) for v in set(n.values.ravel()))
[0, 1, 2, 3]

random_rectangular_cluster

random_rectangular_cluster(
    ncol: int,
    nrow: int,
    minl: int,
    maxl: int,
    resolution: float = 1.0,
    seed: int | None = None,
    rescale: bool = True,
    *,
    n_threads: int | None = None,
) -> DataArray

Random rectangular clusters (NLMR's nlm_randomrectangularcluster, Gaucherel 2008).

Rectangles with random sides between minl and maxl cells and a random value are laid over each other (wrapping around the edges) until every cell is covered.

Parameters:

Name Type Description Default
ncol int

Columns and rows.

required
nrow int

Columns and rows.

required
minl int

Smallest and largest side of the rectangles, in cells (at most ncol and nrow).

required
maxl int

Smallest and largest side of the rectangles, in cells (at most ncol and nrow).

required
resolution float

Cell size.

1
seed int

Seed of NLMR's std::mt19937 (NLMR's user_seed); None draws one.

None
rescale bool

Rescale the values to 0-1.

True
n_threads int

Threads (default: all cores but one).

None

Returns:

Type Description
DataArray

float64 values.

Examples:

>>> import landschaft as ls
>>> r = ls.nlm.random_rectangular_cluster(50, 30, minl=3, maxl=8, seed=1)
>>> r.shape, float(r.min()), float(r.max())
((30, 50), 0.0, 1.0)

curds

curds(
    curds: Sequence[float],
    recursion_steps: Sequence[int],
    wheyes: Sequence[float] | None = None,
    resolution: float = 1.0,
    seed: int | None = None,
    *,
    n_threads: int | None = None,
) -> DataArray

Hierarchical curdling (NLMR's nlm_curds, Keitt 2000).

Starting from one cell, each step splits every cell into recursion_steps[i] x recursion_steps[i] cells and turns a share 1 - curds[i] of the habitat cells into matrix; with wheyes, a share wheyes[i] of the matrix cells goes back to habitat (the "wheyed curds" model). The raster has prod(recursion_steps) cells a side.

Parameters:

Name Type Description Default
curds sequence of float

Share of the habitat kept at each step.

required
recursion_steps sequence of int

Subdivision of the cells at each step (same length as curds).

required
wheyes sequence of float

Share of the matrix turned back into habitat at each step.

None
resolution float

Cell size.

1
seed int

Seed of R's generator (NLMR's user_seed); None draws one.

None
n_threads int

Threads (default: all cores but one).

None

Returns:

Type Description
DataArray

uint8: 1 habitat (curds), 0 matrix.

Examples:

>>> import landschaft as ls
>>> c = ls.nlm.curds([0.5, 0.3, 0.6], [32, 6, 2], seed=1)
>>> c.shape
(384, 384)

Classification and rescaling

classify

classify(
    x,
    n: int | None = None,
    weighting: Sequence[float] | None = None,
    level_names: Sequence[str] | None = None,
    real_land=None,
    mask_val: float | None = None,
    *,
    n_threads: int | None = None,
)

Classify a continuous landscape into categories (NLMR's landscape_classify).

Three ways, as NLMR:

  • weighting: class proportions (cumulative, relative to their sum; None entries share what is left of 1); the class boundaries are the values at those proportions of the sorted cells, the first class starting at 0 (values below 0 are left out);
  • real_land: the proportions of the classes of a real landscape (after removing mask_val, whose cells are also removed from x);
  • n: Jenks natural breaks into n classes (at most the number of unique values). Jenks' algorithm costs O(n_classes x cells^2): keep it to small maps.

weighting wins over n when both are given.

Parameters:

Name Type Description Default
x DataArray or ndarray

Continuous values (NaN or the nodata value are missing).

required
n int

Number of classes for Jenks' breaks.

None
weighting sequence of float

Class proportions.

None
level_names sequence of str

Class names, stored in attrs["levels"] (class value -> name).

None
real_land DataArray or ndarray

A categorical landscape of the same shape whose class proportions are used.

None
mask_val float

Value of real_land to ignore (and to remove from x).

None
n_threads int

Threads (default: all cores but one).

None

Returns:

Type Description
DataArray or ndarray

int32 classes 1, 2, ...; 0 where x is missing or outside the classes (the DataArray's nodata value).

Examples:

>>> import landschaft as ls
>>> r = ls.nlm.random(20, 20, seed=3)
>>> c = ls.nlm.classify(r, weighting=[0.5, 0.25, 0.25])
>>> [int((c == k).sum()) for k in (1, 2, 3)]
[200, 100, 100]

binarize

binarize(x, breaks: float | Sequence[float], *, n_threads: int | None = None)

Habitat / matrix maps at given habitat shares (landscapetools' util_binarize).

Each break b classifies x with classify() into the proportions 1 - b (class 1, "Matrix", the lowest values) and b (class 2, "Habitat").

Parameters:

Name Type Description Default
x DataArray or ndarray

A continuous landscape.

required
breaks float or sequence of float

Habitat shares, between 0 and 1.

required
n_threads int

Threads (default: all cores but one).

None

Returns:

Type Description
DataArray or ndarray

int32 classes 1 (matrix) and 2 (habitat); with several breaks, stacked along a new first dimension p (the breaks).

Examples:

>>> import landschaft as ls
>>> f = ls.nlm.fbm(100, 100, fract_dim=1.5, seed=4)
>>> h = ls.nlm.binarize(f, [0.2, 0.5])
>>> [int((h.sel(p=b) == 2).sum()) for b in (0.2, 0.5)]
[2000, 5000]

rescale

rescale(x, *, n_threads: int | None = None)

Linearly rescale values to 0-1 (NLMR's util_rescale).

(x - min) / (max - min) over the non-missing cells; a raster whose minimum and maximum are equal within all.equal's tolerance (1.5e-8) becomes 0.

Parameters:

Name Type Description Default
x DataArray or ndarray

Values; NaN (or the DataArray's nodata value) is missing and stays NaN.

required
n_threads int

Threads (default: all cores but one).

None

Returns:

Type Description
DataArray or ndarray

The rescaled values (float64), of the same kind as x.

Examples:

>>> import numpy as np
>>> import landschaft as ls
>>> ls.nlm.rescale(np.array([[2.0, 4.0], [6.0, np.nan]]))
array([[0. , 0.5],
       [1. , nan]])

merge

merge(
    primary,
    secondary,
    scaling: float = 1.0,
    rescale: bool = True,
    *,
    n_threads: int | None = None,
)

Merge neutral landscapes (landscapetools' util_merge).

primary + scaling * sum(secondary): a coarse structure (say a gradient) with finer ones laid over it (say a random field), with scaling setting their weight.

Parameters:

Name Type Description Default
primary DataArray or ndarray

The primary landscape.

required
secondary DataArray, ndarray or sequence of them

One or more landscapes of the same shape.

required
scaling float

Weight of the secondary landscapes.

1
rescale bool

Rescale the result to 0-1.

True
n_threads int

Threads (default: all cores but one).

None

Returns:

Type Description
DataArray or ndarray

The merged landscape, of the same kind as primary.

Examples:

>>> import landschaft as ls
>>> g = ls.nlm.planar_gradient(100, 100, direction=45)
>>> r = ls.nlm.random(100, 100, seed=1)
>>> m = ls.nlm.merge(g, r, scaling=0.5)
>>> float(m.min()), float(m.max())
(0.0, 1.0)