Utility class for Voronoi tessellation on the surface of a sphere
The Voronoi sites are stored as longitude-latitude pairs, in degrees, with
longitudes in the range [lon_shift - 180, lon_shift + 180) (i.e.,
[-180, 180) by default) and latitudes in the range [-90, 90]. The
tessellation is defined in terms of great-circle distances: each point
on the sphere belongs to the Voronoi cell whose site is nearest in angular
distance. The prior probability of a site position is uniform per unit
area on the sphere, or on the region of interest when polygon is given.
A fixed set of positions onto which the tessellation is repeatedly
interpolated (e.g., the spatial grid used by the forward function) can be
registered through interpolation_positions. In this case, every state
carries in its cache the index of the Voronoi cell associated with each
registered position, kept up to date at every perturbation of the
discretization through exact incremental updates. Forward functions can
then interpolate the tessellation through
get_interpolated_values() (or, at a lower level,
get_nearest_site_indices()), avoiding a nearest-neighbour query of
the full grid at every Markov chain iteration:
Position-dependent priors (see, e.g., the argument position of
bayesbay.prior.UniformPrior) directly associated with this
discretization should be created with spherical_position=True,
so that their positions are interpreted as longitude-latitude pairs
(in degrees) and their hyper parameters are interpolated in terms of
great-circle distances, seamlessly across the +/-180 meridian and
near the poles. A ValueError is raised otherwise.
Parameters:
name (str) – name attributed to the Voronoi tessellation, for display and storing
purposes
perturb_std (Number) – per-axis standard deviation of the local tangent-plane displacement,
expressed in degrees like the site coordinates (the conversion to
radians needed internally is handled by this class). Site perturbations
follow a von Mises–Fisher distribution centered on the current site,
with concentration \(\kappa = 1 / \sigma_{rad}^2\). For small
perturb_std, the total angular displacement is approximately
Rayleigh distributed, with mean \(1.25\sigma\) and standard
deviation \(0.66\sigma\). The proposal density depends only on the
angular distance, so it is symmetric and needs no acceptance correction
polygon (Union[np.ndarray, shapely.geometry.Polygon, shapely.geometry.MultiPolygon], optional) – region of interest delimiting the domain of the discretization;
Voronoi sites outside it are not allowed. The polygon is defined in
the longitude-latitude plane, i.e. its edges are straight lines in an
equirectangular map, consistent with typical GIS boundary data such
as country or continent outlines; a MultiPolygon (e.g. a region
made of disjoint patches) is also accepted. All polygon longitudes
should lie within [lon_shift - 180, lon_shift + 180), and the
polygon should not touch or include the poles
lon_shift (Number, optional) – finite scalar offset that shifts the longitude convention: all site
longitudes are expressed within [lon_shift - 180, lon_shift +
180), i.e. [-180, 180) by default. Use this for regions of interest
crossing the +/-180 meridian: for example, lon_shift=180 expresses
all longitudes within [0, 360), moving the coordinate seam to the
Greenwich meridian
interpolation_positions (np.ndarray of shape (m, 2), optional) – fixed positions (longitude-latitude pairs, in degrees) onto which the
tessellation is interpolated during the sampling; see
set_interpolation_positions(). Configure these positions before
starting the first sampling run
n_dimensions (int, optional) – number of dimensions. None (default) results in a trans-dimensional
discretization, with the dimensionality of the parameter space allowed
to vary in the range n_dimensions_min-n_dimensions_max
n_dimensions_min (Number, optional) – minimum and maximum number of dimensions, by default 2 and 100. These
parameters are ignored if n_dimensions is not None, i.e. if the
discretization is not trans-dimensional
n_dimensions_max (Number, optional) – minimum and maximum number of dimensions, by default 2 and 100. These
parameters are ignored if n_dimensions is not None, i.e. if the
discretization is not trans-dimensional
n_dimensions_init_range (Number, optional) –
percentage of the range n_dimensions_min - n_dimensions_max used to
initialize the number of dimensions (0.3. by default). For example, if
n_dimensions_min = 2, n_dimensions_max = 100, and
n_dimensions_init_range = 0.5,
the maximum number of dimensions at the initialization is:
parameters (List[Prior], optional) – a list of free parameters, by default None
birth_from ({"prior", "neighbour"}, optional) – whether to initialize the free parameters associated with the newborn
Voronoi cell by randomly drawing from their prior or by perturbing the
value found in the nearest Voronoi cell (default)
compute_kdtree (bool) – whether to compute a kd-tree for nearest-neighbour lookup at every
perturbation of the discretization, stored in each state’s cache
under the key "kdtree". The kd-tree is built on the 3-D
Cartesian (unit-vector) representation of the Voronoi sites, for which
nearest neighbours in Euclidean distance coincide with nearest
neighbours in great-circle distance: use lonlat_to_xyz() to
convert longitude-latitude query points before calling kdtree.query.
Access the tree through get_kdtree(), which builds it lazily for
custom, sampled, or nested-birth states that do not yet carry the cache.
Use this when the forward function needs distances, multiple nearest
neighbours, or query points that vary between iterations; when it
only interpolates the tessellation onto a fixed set of points, prefer
interpolation_positions, which is much faster
the list of perturbation functions allowed in the parameter space linked to
the Voronoi discretization. Each function takes in a state (see State)
and returns a new state along with the corresponding partial acceptance
probability,
a list of perturbation weights, corresponding to each of the
perturbation_funcs() that determines the probability of each of them
to be chosen during each step
The weights are not normalized and have the following default values:
creates a new Voronoi cell, initializes all free parameters
associated with it, and returns the pertubed state along with the
log of the corresponding partial acceptance probability,
where \(k\) denotes the number of Voronoi cells, each entry of the
vector \({\bf c}\) corresponds to the position of a Voronoi site,
and each \(i\)th free parameter \({\bf v}\) has the same
dimensionality as \({\bf c}\).
Following [1], \(p({\bf c} \mid k) = \frac{k! \left(N - k \right)!}{N!}\). If we then
assume that \(p(k) = \frac{1}{\Delta k}\), where \(\Delta k = k_{max} - k_{min}\),
the prior ratio reads
where \(p(v_i^{k+1})\) denotes the prior probability of the newly
born \(i\)th parameter, which may be dependent on \({\bf c}\).
The proposal ratio reads
where \(q_{v_i}^{k+1}\) denotes the proposal probability for the
newly born \(i\)th parameter in the new dimension. It is easy to
show that, in the case of a birth from neighbor [1] or a birth from
prior [2] (see birth_from), \(\lvert \mathbf{J} \rvert = 1\)
and \(\alpha_{p} = \frac{p({\bf m'})}{p({\bf m})} \frac{q({\bf m} \mid {\bf m'})}{q({\bf m'} \mid {\bf m})}\).
It follows that
In the case of a birth from neighbor, \(q_{v_i}^{k+1} =
\frac{1}{\theta \sqrt{2 \pi}} \exp \lbrace -\frac{\left( v_i^{k+1} - v_i \right)^2}{2\theta^2} \rbrace\),
where the newly born value, \(v_i^{k+1}\), is generated by perturbing
the original value, \(v_i\), of the \(i\)th parameter. This is
achieved through a random deviate from the normal distribution
\(\mathcal{N}(v_i, \theta)\), with \(\theta\) denoting the
standard deviation of the Gaussian used to carry out the perturbation
(see, for example, bayesbay.prior.UniformPrior.perturb_std) .
The partial acceptance probability is then computed numerically.
Number – log of the partial acceptance probability,
\(log(\alpha_{p}) = \log(\frac{\prod_i p(v_i^{k+1})}{\prod_i{q_{v_i}^{k+1}}})\)
References
Notes
Subclasses with polygonal domains draw the newborn site by rejection
sampling from the position prior restricted to the polygon. Redrawing is
valid here because the birth-position proposal is state independent and
exactly equals that restricted prior; unlike a move proposal centred on
the current site, it introduces no state-dependent normalization.
It is straightforward to show that this equals the reciprocal of
the partial acceptance probability obtained in the case of a birth
perturbation (see birth()), i.e.,
interpolates the values that the given free parameter takes in
each Voronoi cell onto the positions registered through
set_interpolation_positions() (nearest-neighbour interpolation,
i.e., piecewise constant within each Voronoi cell), given the
discretization found in the passed parameter space state
This is equivalent to (but, during the sampling, much faster than)
querying the registered positions against a nearest-neighbour
structure built on the Voronoi sites:
Return the state’s site KD-tree, building it on demand when needed.
The tree uses the coordinates appropriate to the tessellation geometry:
planar coordinates for Voronoi2D and 3-D unit vectors for
Voronoi2DSphere. Spherical longitude-latitude query positions
must therefore be converted with Voronoi2DSphere.lonlat_to_xyz()
before calling query. The accessor supports initialized, sampled,
nested-birth, and user-created parameter-space states.
returns, for each of the positions registered through
set_interpolation_positions(), the index of the Voronoi cell it
belongs to (i.e., of the nearest Voronoi site), given the
discretization found in the passed parameter space state
The indices are read from the cache of the given state, where they
are maintained through exact incremental updates at every
perturbation of the discretization. If they are not present in the
cache (e.g., for a state that was not generated by this class, such
as a user-provided starting state), they are computed from scratch
and stored in it.
Parameters:
ps_state (ParameterSpaceState) – the parameter space state holding the discretization
Returns:
the index of the Voronoi cell each registered position belongs to
get the standard deviation of the Gaussian used to perturb
the parameter at birth, which may be dependent on the position in the
discretization domain
Parameters:
position (Union[Number, np.ndarray], optional) – the position in the discretization domain at which the standard
deviation of the Gaussian used to perturb the parameter at birth
is returned. Default is None
Returns:
standard deviation of the Gaussian used to perturb the parameter at birth,
possibly at the specified position
computes from scratch the nearest-site assignment of the positions
registered through set_interpolation_positions() and stores it
in the cache of the given parameter space state
This is done automatically at the initialization of each Markov chain
and, incrementally, at every perturbation; calling this method is only
needed for states created by other means (e.g. a user-provided
starting state).
Parameters:
ps_state (ParameterSpaceState) – the parameter space state whose cache is to be filled
Returns:
the same instance, with "interp_nearest" and
"interp_affinity" stored in its cache
nearest-neighbour interpolation, in terms of great-circle
distance, based on the Voronoi-site positions and the values
associated with them
Parameters:
voronoi_sites ((n, 2) np.ndarray) – the Voronoi-site positions, i.e. longitude-latitude pairs in degrees
param_values ((n,) np.ndarray) – the parameter values associated with each Voronoi cell
interp_positions ((m, 2) or (m, 3) np.ndarray) – the positions at which the interpolation is performed, either as
longitude-latitude pairs in degrees or as unit vectors (see
lonlat_to_xyz()). When interpolating many tessellations onto
the same positions, pre-converting them to unit vectors once
avoids the conversion at each call
BayesBay implements the grid trick, which calculates the prior
probability of a Voronoi discretization through the combinatorial
formula \({N \choose k}^{-1}\), with k denoting the number of
Voronoi sites and N the number of possible positions allowed for the
sites [3].
displays the Voronoi tessellation on a longitude-latitude
(equirectangular) map, drawing the exact spherical Voronoi cells
(computed through scipy.spatial.SphericalVoronoi) as polygons.
Cells crossing the longitude seam and cells containing a pole are
rendered correctly, enabling global tessellations to be displayed;
the tessellation can also be clipped to an arbitrary region of
interest through clip_polygon
Parameters:
voronoi_sites (np.ndarray of shape (m, 2)) – Voronoi-site positions, i.e. longitude-latitude pairs in degrees
param_values (np.ndarray, optional) – parameter values associated with each Voronoi cell. These could
represent the physical property inferred in each cell of the
discretized medium. If None, only the cell boundaries are drawn
ax (matplotlib.axes.Axes, optional) – an optional Axes object to plot on. This may be a Cartopy
GeoAxes: in that case, pass the appropriate transform
(e.g. transform=cartopy.crs.PlateCarree()) through kwargs
clip_polygon (Union[np.ndarray, shapely.geometry.Polygon, shapely.geometry.MultiPolygon], optional) – region of interest to which the displayed tessellation is
clipped, expressed in the same longitude convention as the
Voronoi sites
lon_bounds (Tuple[Number, Number], optional) – longitude range of the map frame. By default, (-180, 180), or
(0, 360) when the site longitudes exceed 180 degrees (see the
argument lon_shift of this class)
cmap (Union[str, matplotlib.colors.Colormap]) – the Colormap instance or registered colormap name used to map scalar
data to colors
norm (Union[str, matplotlib.colors.Normalize]) – the normalization method used to scale scalar data to the [0, 1]
range before mapping to colors using cmap. By default, a linear
scaling is used, mapping the lowest value to 0 and the highest to 1.
vmin (Number) – minimum and maximum values used to create the colormap. Ignored
when norm is given
vmax (Number) – minimum and maximum values used to create the colormap. Ignored
when norm is given
colorbar (bool) – whether to draw a colorbar, by default True
edgecolor (color) – color of the Voronoi-cell edges, by default black
linewidth (Number) – line width of the Voronoi-cell edges, by default 0.5
voronoi_sites_kwargs (dict, optional) – when given, the Voronoi nuclei are displayed, styled by these
keyword arguments (passed to matplotlib.pyplot.plot). By
default (None), the nuclei are not displayed
At least four non-degenerate sites are required by
scipy.spatial.SphericalVoronoi. Polygon holes are preserved by
the clipping geometry but are not currently rendered by Axes.fill.
Unlike the straight Cartesian edges of Voronoi2D, spherical
edges must be sampled for display. This is handled internally with a
fixed one-degree maximum angular spacing and does not affect the
tessellation geometry.
Returns:
ax (matplotlib.axes.Axes) – The Axes object containing the plot
cbar (Union[Colorbar, None]) – The Colorbar object associated with the tessellation
Display a global Voronoi tessellation on a three-dimensional sphere.
Cell boundaries are the exact geodesic boundaries computed through
scipy.spatial.SphericalVoronoi and sampled internally for
display. When param_values are supplied, cell colours are rendered
on a regular spherical surface mesh; decrease surface_spacing_deg
for a finer representation of the colour transitions.
This method uses Matplotlib’s built-in 3-D toolkit and introduces no
dependency beyond those already required by BayesBay.
Parameters:
voronoi_sites (np.ndarray of shape (m, 2)) – Voronoi-site (longitude,latitude) pairs in degrees. Longitude
is periodic: any finite value is accepted and interpreted modulo
360 degrees. Latitude must lie within [-90, 90] degrees. At least
four non-degenerate sites are required.
param_values (np.ndarray of shape (m,), optional) – Parameter value associated with each cell. If omitted, only the
cell boundaries are drawn.
ax (matplotlib.axes.Axes, optional) – Matplotlib 3-D axes. A new one is created when omitted.
center_lonlat (Tuple[Number, Number], optional) – (longitude,latitude) in degrees to place at the centre of the
initial view. Longitude is periodic and is normalized to
[-180, 180); latitude must lie within [-90, 90]. For example,
(12.5,42.5) centres the globe on Italy. This argument only
sets the initial camera orientation; the globe can still be
rotated interactively. When omitted, the existing orientation of
ax (or Matplotlib’s default for a new axes) is preserved.
surface_spacing_deg (Number, optional) – Approximate angular spacing of the coloured surface mesh. Smaller
values reduce pixelation along colour transitions but increase the
number of surface patches approximately with the inverse square of
the spacing. Default is 2 degrees.
cmap – Matplotlib colour-mapping arguments.
norm – Matplotlib colour-mapping arguments.
vmin – Matplotlib colour-mapping arguments.
vmax – Matplotlib colour-mapping arguments.
colorbar (bool, optional) – Whether to add a colourbar when param_values are supplied.
draws a Voronoi-site position at random from the uniform (per unit
area) distribution on the sphere or, when polygon is given,
on the region of interest it delimits
Rejection sampling within a polygon redraws from a state-independent
uniform-per-area bounding-box proposal. The returned draw is therefore
exactly distributed according to the position prior restricted to the
polygon and can be used for birth proposals without a Hastings
correction.
initialize_func (Callable[["Prior", np.ndarray], np.ndarray]) – The function to use for initialization. This function should take a
Prior instance and optionally an array of positions as input
arguments, and produce an array of values as output.
Examples
defmy_init(param:bb.prior.Prior,position:np.ndarray)->np.ndarray:print("This is my custom init!")returnnp.ones(len(position))my_param.set_custom_initialize(my_init)
registers a fixed set of positions onto which the tessellation is
interpolated during the sampling
Once registered, every parameter space state carries in its cache:
"interp_nearest": the index of the Voronoi site each registered
position belongs to, i.e. the nearest site
"interp_affinity": the affinity between each registered position
and its Voronoi site, i.e. the negative squared Euclidean distance
(Voronoi2D) or the cosine of the angular distance
(Voronoi2DSphere)
Both entries are kept up to date at every perturbation of the
discretization through exact incremental updates (a perturbation only
affects the assignments of the positions within the perturbed Voronoi
cells), which is much faster than a nearest-neighbour query of all
the registered positions at every Markov chain iteration.
Registering a new set of positions increments an internal version;
existing state caches are then recomputed automatically on first use.
Configure the interpolation positions before starting the first
sampling run. Process-based workers receive a serialized copy of the
discretization configuration, so later changes to the original object
do not propagate to workers that are already running.
Parameters:
positions (np.ndarray of shape (m, 2)) – the interpolation positions