muspan.domain#

Overview#

A muspan.domain represents a container for spatial data in MuSpAn. It acts as the central object in which geometric objects, labels, and spatial relationships are defined, updated, and queried throughout an analysis.

A domain is responsible for:

  • defining the spatial extent of an analysis,

  • storing pointclouds, shapeclouds, and associated labels,

  • managing derived spatial structures such as boundaries and object groupings,

  • maintaining visualisation attributes and other analysis state required by downstream workflows.

In typical workflows, a domain is created once at the start of an analysis, populated with geometric data, and then progressively updated as spatial relationships and derived structures are computed.

This page documents the public API of the muspan.domain class. The method summaries below provide a structured index of common domain operations, grouped by their role in the analysis workflow. Each summary entry links directly to its full documentation in the class reference section.

Adding data to the domain#

domain.add_points

Adds points to this domain.

domain.add_lines

Adds lines to this domain.

domain.add_shapes

Adds shapes to this domain.

domain.add_shapes_with_internal_holes

Adds shapes to this domain that contain internal holes.

domain.add_labels

Add labels to objects in the domain.

Updating domain properties#

domain.estimate_boundary

Estimate the boundary of the domain using the specified method.

domain.add_objects_to_collection

Add objects to a specified collection.

domain.simplify_shape_boundaries

Simplify the boundaries of a set of shapes by removing vertices, using the Visvalingam-Whyatt algorithm.

domain.update_colors

Update the colors for labels, objects, or collections.

domain.convert_objects

Convert objects in the population to a specified type using a specified method.

Inspecting domain contents#

domain.print_labels

Print a table of labels of objects in the domain.

domain.print_collections

Print a table of collections in the domain.

Removing data and derived structures#

domain.delete_distances

Delete distance matrix stored within the domain.

domain.delete_network

Delete a network stored within the domain.

domain.delete_labels

Delete labels stored within the domain.

domain.delete_objects

Delete objects from the domain.

Class reference#

class domain(name, unit_of_length='units')#

The basic container for all MuSpAn analysis. A domain keeps track of which pointclouds / shapeclouds, labels, and metadata are within the domain. The default domain is a unit cube in n-dimensions, with default units of length being “units”.

Parameters:
namestr

The name of the domain.

unit_of_lengthstr, optional

The unit of length for the domain. Default is ‘units’.

Attributes:
unit_of_lengthstr

The unit of length for the domain.

dimensionint

The number of dimensions of the domain.

n_collectionsint

Number of collections in the domain.

n_objectsint

Number of objects in the domain.

n_verticesint

Number of vertices in the domain.

max_IDint

Maximum ID of objects in the domain.

collectionsdict

Dictionary to store collections.

int_to_collectiondict

Dictionary to map collection integers to collection names.

objectsdict

Dictionary to store objects.

nd_componentsdict

Dictionary to store n-dimensional components.

colorsdict

Dictionary to store colors for collections, objects, and labels.

verticesnp.ndarray

Array to store vertices.

boundaryShape

Boundary shape of the domain.

labelsdict

Dictionary to store labels associated with objects.

networksdict

Dictionary to store network information.

distancesdict

Dictionary to store distance matrices.

Examples

Minimal example for initialising an empty domain:

import muspan as ms

# initialise a muspan domain with the name 'example domain'
example_domain = ms.domain('example domain')

# print the domain information
print(example_domain)
add_labels(label_name, labels, add_labels_to=None, label_type=None, cmap=None, bypass_checks=False)#

Add labels to objects in the domain.

Parameters:
label_namestr

The name of the label to be added.

labelslist or np.ndarray

The labels to be added. Must be the same length as the number of objects specified.

add_labels_tostr, query-like, list, np.ndarray, or None, optional

Specifies which objects to add labels to. Can be: - A string representing the name of a collection. - A query-like object to filter objects. - A list or 1D numpy array of object indices. - None, to apply labels to all objects in the domain. Default is None.

label_typestr, optional

The type of the label. Can be ‘categorical’ or ‘continuous’. Default is ‘categorical’.

cmapstr, optional

The colormap to use for labels. If None, a default colormap is used. Default is None.

Raises:
ValueError

If add_labels_to is not a valid collection name, query-like object, or list of object indices. If the length of labels does not match the number of objects specified. If label_type is not ‘categorical’ or ‘continuous’.

Notes

  • If label_name already exists, the function updates the existing labels with the new ones.

  • Colormaps defined using Matplotlib’s colormaps, for example, ‘tab10’, ‘tab20’, ‘viridis’, etc.

  • For categorical labels, the function assigns colors based on the specified or default colormap.

  • For continuous labels, the function uses the ‘plasma’ colormap by default.

Examples

Minimal example adding categorical labels to objects in a domain:

import muspan as ms
import numpy as np

# x,y coordinates of a set of points
points = np.array([[0.0, 0.0],
                [1.0, 0.0],
                [1.0, 1.0],
                [0.0, 1.0]])

# categorical labels for the points - must be in the same order as the points
labels_categorical = ['A', 'B', 'C', 'D']

#initialise a muspan domain
example_domain = ms.domain('example domain')

# add points to the domain
example_domain.add_points(points,collection_name='some points')

# add categorical labels to the points  
example_domain.add_labels(label_name='Demo categorical labels',
                        labels=labels_categorical,
                        add_labels_to=('collection','some points'))

# visualise the domain
ms.visualise.visualise(example_domain,color_by='Demo categorical labels')

Minimal example adding continuous (numeric) labels to objects in a domain:

import muspan as ms
import numpy as np

# x,y coordinates of a set of points
points = np.array([[0.0, 0.0],
                [1.0, 0.0],
                [1.0, 1.0],
                [0.0, 1.0]])

# categorical labels for the points - must be in the same order as the points
labels_continuous= np.array([0.0, 
                            1.5, 
                            7.2, 
                            10.0])

#initialise a muspan domain
example_domain = ms.domain('example domain')

# add points to the domain
example_domain.add_points(points,collection_name='some points')

# add categorical labels to the points  
example_domain.add_labels(label_name='Demo continuous labels',
                        labels=labels_continuous,
                        add_labels_to=('collection','some points'))

# visualise the domain
ms.visualise.visualise(example_domain,color_by='Demo continuous labels')
add_lines(lines, collection_name=None, zorder=20, return_IDs=False)#

Adds lines to this domain.

Parameters:
lineslist of array-like

List of m (n x d) arrays of d-dimensional points.

collection_namestr, optional

Name of a collection to add these objects to.

zorderint, optional

Z-order for plotting, by default 20.

return_IDsbool, optional

If True, the IDs of newly created objects will be returned as an array.

add_objects_to_collection(add_collection_to=None, collection_name=None)#

Add objects to a specified collection.

Parameters:
add_collection_toint, list, np.ndarray, or query-like

The IDs of the objects to be added to the collection. It can be a single integer ID, a list or numpy array of IDs, or a query that returns object IDs.

collection_namestr or None

The name of the collection to which the objects will be added. If None, a default collection name ‘default_collection’ will be used.

Raises:
ValueError

If any of the provided object IDs do not exist in self.objects, or if the type of objectIDs is unrecognized.

add_points(points, collection_name=None, zorder=30, return_IDs=False)#

Adds points to this domain.

Parameters:
pointsarray-like, shape (n, d)

Array of d-dimensional points.

collection_namestr, optional

Name of a collection to add these objects to.

zorderint, optional

Z-order for plotting, by default 30.

return_IDsbool, optional

If True, the IDs of newly created objects will be returned as an array.

Notes

Example data input:

points = [
          [x1,y2],
          [x2,y2],
          ...
          ]

Examples

Minimal example adding points to an empty domain:

import muspan as ms
import numpy as np

# x,y coordinates of a set of points
points = np.array([[0.0, 0.0],
                [1.0, 0.0],
                [1.0, 1.0],
                [0.0, 1.0]])

#initialise a muspan domain
example_domain = ms.domain('example domain')

# add points to the domain
example_domain.add_points(points,collection_name='some points')

# visualise the domain
ms.visualise.visualise(example_domain)
add_shapes(shapes, collection_name=None, zorder=10, return_IDs=False)#

Adds shapes to this domain.

Parameters:
shapeslist of array-like

List of m (n x d) arrays of d-dimensional points defining the outer boundary of the polygon or outer_shape.

collection_namestr, optional

Name of a collection to add these objects to.

zorderint, optional

Z-order for plotting, by default 10.

return_IDsbool, optional

If True, the IDs of newly created objects will be returned as an array.

Notes

Each shape is defined by a set of vertices in clock-wise order describing its outer boundary.

Example data input:

shapes = [
          outer_shape_1,
          outer_shape_2,
          ...
          ]

Examples

Minimal example adding shapes to an empty domain:

import muspan as ms
import numpy as np

# x,y coordinates of two squares
right_square_big = np.array([[1,-2],[5,-2],[5,2],[1,2]])
left_square_big = np.array([[-5,-2],[-1,-2],[-1,2],[-5,2]])

# create a list of shapes
list_of_shapes = [left_square_big, right_square_big]

# initialise a muspan domain
example_domain = ms.domain('example domain')

# add the shapes to the domain
example_domain.add_shapes(list_of_shapes, 'some squares')

# visualise the domain
ms.visualise.visualise(example_domain)
add_shapes_with_internal_holes(shapes_and_holes, collection_name=None, zorder=10, return_IDs=False)#

Adds shapes to this domain that contain internal holes.

Parameters:
shapes_and_holeslist of tuples

A list where each element is a tuple of the form (outer_shape, holes). outer_shape is an array of shape (n, d) containing the coordinates of the vertices defining the outer boundary of the polygon. holes is a list of arrays, where each array has shape (n_hole, d) and defines the vertices of a single interior hole.

collection_namestr, optional

Name of a collection to add these objects to.

zorderint, optional

Z-order for plotting, by default 10.

return_IDsbool, optional

If True, the IDs of newly created objects will be returned as an array.

Notes

This method is used when a shape is not simply a closed exterior boundary, but includes one or more interior voids (holes). Each shape is defined by a set of vertices describing its outer boundary, together with one or more sets of vertices describing the holes inside it.

Example data input:

shapes_and_holes = [
                    (outer_shape_1, [hole1_1, hole1_2]),
                    (outer_shape_2, [hole2_1]),
                    ...
                    ]

Examples

Minimal example adding shapes with holes to an empty domain:

import muspan as ms
import numpy as np

# x,y coordinates of two squares - one square contained within the other
right_square_big = np.array([[1,-2],[5,-2],[5,2],[1,2]])
right_square_small = np.array([[2,-1],[4,-1],[4,1],[2,1]]) 

# x,y coordinates of two squares - one square contained within the other
left_square_big = np.array([[-5,-2],[-1,-2],[-1,2],[-5,2]])
left_square_small = np.array([[-4,-1],[-2,-1],[-2,1],[-4,1]]) 

# create shapes with holes - each shape is a list where the first element is the outer boundary
shape_1 = [left_square_big,[left_square_small]]
shape_2 = [right_square_big,[right_square_small]]

# create a list of shapes with holes
list_of_shapes_with_holes = [shape_1, shape_2]

# initialise a muspan domain
example_domain = ms.domain('example domain')

# add the shapes with holes to the domain
example_domain.add_shapes_with_internal_holes(list_of_shapes_with_holes, 'holey squares')

# visualise the domain
ms.visualise.visualise(example_domain)
convert_objects(population=None, collection_name='converted objects', object_type='point', conversion_method='centroid', conversion_method_kwargs={}, remove_parent_objects=False, inherit_collections=False, return_IDs=False, zorder=10)#

Convert objects in the population to a specified type using a specified method.

This function allows for the conversion of objects in the domain to either point or shape types, using various conversion methods. If the conversion is injective (e.g., shapes to centroids), the labels will be inherited from the parent objects.

Parameters:
populationquery-like, optional

Query-like specifying the population of objects to analysis. Can be a list or array of object indices, a muspan query, or None to include all objects. Default is None.

collection_namestr, optional

Name of the collection to which the converted objects will be added. Default is ‘converted objects’.

object_typestr, optional

Type of objects to convert to. Options are ‘point’ or ‘shape’. Default is ‘point’.

conversion_methodstr, optional

Method to use for conversion. For ‘point’, options are ‘centroid’, ‘centroids’, ‘vertices’. For ‘shape’, options are ‘alpha shape’, ‘convex hull’, ‘boundary’, ‘voronoi’. Default is ‘centroid’.

conversion_method_kwargsdict, optional

Additional keyword arguments for the conversion method. Default is an empty dictionary.

remove_parent_objectsbool, optional

If True, parent objects will be removed after conversion. Default is False.

inherit_collectionsbool, optional

If True, the converted objects will inherit collections from their parent objects. Default is False.

return_IDsbool, optional

If True, the function will return the IDs of the new objects. Default is False.

zorderint, optional

Z-order for the new objects. Default is 10.

Returns:
new_object_idslist, optional

List of IDs of the new objects, if return_IDs is True.

Raises:
ValueError

If an invalid object_type or conversion_method is provided.

Notes

For object_type ‘point’, the conversion methods are:

  • ‘centroid’: Converts each object to a single point at its centroid.

  • ‘centroids’: Converts each object to a point at its centroid, inheriting labels.

  • ‘vertices’: Converts each object to points at its vertices, inheriting labels.

For object_type ‘shape’, the conversion methods are:

  • ‘alpha shape’: Converts the objects to an alpha shape, using the ‘alpha’ key in conversion_method_kwargs to specify the alpha value. If only outer polygon is required, set ‘internal_boundaries’ key to False in conversion_method_kwargs.

  • ‘convex hull’: Converts the objects to their convex hull.

  • ‘boundary’: Converts the objects to their boundary shape. This assumes the objects in the population are ordered to from a closed shape.

  • ‘voronoi’: Converts the objects to Voronoi cells based on their centroids, inheriting labels.

delete_distances(distance_metric=None)#

Delete distance matrix stored within the domain.

Parameters:
distance_metricstr, optional

The key for the distance matrix to be deleted. Default is None.

Raises:
Warning

If no distance matrix is stored with the specified key.

delete_labels(label_name=None)#

Delete labels stored within the domain.

Parameters:
label_namestr, optional

The name of the label to delete. Default is None.

Raises:
Warning

If no label is stored with the specified name.

delete_network(network_name=None)#

Delete a network stored within the domain.

Parameters:
network_namestr, optional

The name of the network to delete. Default is None.

Raises:
Warning

If no network is stored with the specified name.

delete_objects(objects_to_delete)#

Delete objects from the domain.

This function performs the relevant bookkeeping of removing any object associated with labels, distances, and networks stored within the domain.

Parameters:
objects_to_deletequery, list, tuple, array, or int

The objects to delete. This can be a query, a list/tuple of indices, or a single integer.

Raises:
ValueError

If objects_to_delete is not of the correct type. Potential types are query, list, tuple, array, or int.

estimate_boundary(method='rectangle', alpha_shape_kwargs={}, specify_boundary_coords=None)#

Estimate the boundary of the domain using the specified method.

Parameters:
methodstr, optional

The method to use for boundary estimation. Options are ‘convex hull’, ‘rectangle’, ‘alpha shape’, and ‘specify’. If ‘specify’, pass a set of coordinates that will define the boundary. Default is ‘rectangle’.

alpha_shape_kwargsdict, optional

Keyword arguments to pass to the alpha shape function. Default is an empty dictionary.

specify_boundary_coordsarray-like, optional

An array of coordinates to specify the boundary. specify_boundary_coords must be a (nx2) array. Required if method is ‘specify’.

Raises:
ValueError

If the specified method is not one of the available options.

Notes

  • If no objects are present in the domain, the initial vertices (excluding the first four) are used.

  • The boundary is created as a new shape but is not added to the domain’s objects list.

  • Alpha shape only return the exterior vertices to construct the boundary shape, i.e., boundaries will not contain holes.

  • The boundary shape is assigned an object_ID of -1 to indicate it is not a real object within the domain objects list.

Examples

Minimal example estimating the boundary of a domain using the convex hull method:

import muspan as ms

# load example domain
example_domain = ms.datasets.load_example_domain('Xenium-Healthy-Colon')

# estimate and visualize the boundary using the convex hull method
example_domain.estimate_boundary(method='convex hull')

# visualise the domain with estimated boundary
ms.visualise.visualise(example_domain,marker_size=1,show_boundary=True)

Minimal example estimating the boundary of a domain using the alpha shape method:

import muspan as ms

# load example domain
example_domain = ms.datasets.load_example_domain('Xenium-Healthy-Colon')

# estimate and visualize the boundary using the alpha method
example_domain.estimate_boundary(method='alpha shape',alpha_shape_kwargs={'alpha':20})

# visualise the domain with estimated boundary
ms.visualise.visualise(example_domain,marker_size=1,show_boundary=True)
print_collections()#

Print a table of collections in the domain.

This method creates a DataFrame where each column represents a collection, and each row represents an object. The DataFrame indicates whether each object belongs to each collection.

Returns:
None

Notes

Collections with names starting with ‘__’ are ignored as they represent internal objects.

print_labels(label_name=None)#

Print a table of labels of objects in the domain.

Parameters:
label_namestr, optional

The name of the label to print. If None, all labels are printed. Default is None.

Returns:
None
Raises:
ValueError

If the specified label_name is not found in the available labels.

Notes

The DataFrame’s index is named ‘object_id’.

simplify_shape_boundaries(shape_indices, delete_original_boundary=True, algorithm='Visvalingam-Whyatt', epsilon=30, collection_name='Simplified boundaries', protect_boundary_vertices=False, return_IDs=False)#

Simplify the boundaries of a set of shapes by removing vertices, using the Visvalingam-Whyatt algorithm.

Parameters:
shape_indicesint or query-like

Indices of the shapes which are to be simplified.

delete_original_boundarybool, optional

Use this boundary as the new shape, deleting the former shape boundary, by default True. If False, the new shape will be added to the domain as a new object.

algorithmstr, optional

Choice of boundary simplification algorithm to use, by default ‘Visvalingam-Whyatt’. Options are ‘Visvalingam-Whyatt’.

epsilonfloat, optional

Choice of epsilon algorithm - under the Visvalingam-Whyatt algorithm, increasing epsilon will lead to simpler shapes.

collection_namestr, optional

Name of the collection to which the simplified shapes will be added. Default is ‘Simplified boundaries’.

protect_boundary_verticesbool, optional

If True, prevent any vertices on the domain boundary from moving. Default is False.

return_IDsbool, optional

If True, the function will return the IDs of the new simplified shapes. Default is False.

References

See Visvalingam, M.; Whyatt, J. D. (1993). “Line generalisation by repeated elimination of points”. The Cartographic Journal. 30 (1): 46–51. doi:10.1179/000870493786962263.

update_colors(new_colors, colors_to_update='labels', label_name=None)#

Update the colors for labels, objects, or collections.

Parameters:
new_colorsdict, str

For categorical classes, a dictionary where keys are the names of the items to update and values are the new colors. For continuous labels, the name of a matplotlib colormap (or a Colormap object). To update the null color for a label, use {‘NULL_COLOR’:color} as the dictionary (for both categorical and continuous labels). For continuous labels, any other entries in the dictionary will be ignored.

colors_to_updatestr, optional

Specifies what type of colors to update. Must be one of ‘labels’, ‘objects’, or ‘collections’. Default is ‘labels’.

label_namestr, optional

The name of the label to update. Required if colors_to_update is ‘labels’.

Raises:
ValueError

If colors_to_update is not one of ‘labels’, ‘objects’, or ‘collections’. If colors_to_update is ‘labels’ and label_name is not specified or invalid. If any value in new_colors cannot be interpreted as a color. If any key in new_colors is not found in the specified colors_to_update category.

Notes

This function allows updating of colors for labels, objects, or collections. It validates the input colors and ensures that the specified keys exist in the current color mappings. Any labels or collections not specified in new_colors will retain their current colors. Any labels or collections not stored in the domain will be ignored.