pointstools module
- class clabtoolkit.pointstools.PointCloud(points=None, affine=None, color='#BFBDBD', alpha=1.0, name='default')[source]
Bases:
objectA class to represent and manipulate point clouds.
- coords
An array of shape (N, 3) representing the 3D coordinates of points.
- Type:
np.ndarray
- affine
Affine transformation matrix for the points.
- Type:
np.ndarray
- colortables
A dictionary to store colortable information for visualization.
- Type:
Dict
- point_data
A dictionary to store scalar data associated with each point.
- Type:
Dict
- __init__(points=None, affine=None, color='#BFBDBD', alpha=1.0, name='default')[source]
Initializes the PointCloud object.
Parameters:
- points (np.ndarray or pd.DataFrame, optional):
An array of shape (N, 3) representing the 3D coordinates of points, or a DataFrame with columns [‘X’, ‘Y’, ‘Z’].
- affine (np.ndarray, optional):
Affine transformation matrix for the points. Default is identity matrix.
- color (str or np.ndarray, optional):
Color for the point cloud. Can be a hex string or RGB array. Default is “#BFBDBD”.
- alpha (float, optional):
Opacity value for the point cloud (0-1). Default is 1.0.
- name (str, optional):
Name of the point cloud. Default is “default”.
- copy()[source]
Creates a deep copy of the PointCloud object.
Returns:
PointCloud: A new PointCloud instance with copied data.
- add_point_data(data, name, dtype=None)[source]
Adds scalar data associated with each point.
Parameters:
- data (np.ndarray):
Array of data values, one per point.
- name (str):
Name for this data attribute.
- dtype (type, optional):
Data type to cast the array to. If None, keeps original dtype.
Raises:
- ValueError:
If data length doesn’t match number of points.
- transform(affine, inplace=True)[source]
Applies an affine transformation to the point coordinates.
Parameters:
- affine (np.ndarray):
A 4x4 affine transformation matrix.
- inplace (bool):
If True, modifies the current object. If False, returns a new object. Default is True.
Returns:
- PointCloud or None:
If inplace=False, returns a new transformed PointCloud. If inplace=True, returns None.
- filter_by_bounds(x_range=None, y_range=None, z_range=None, inplace=True)[source]
Filters points based on spatial bounds.
Parameters:
- x_range (tuple, optional):
(min, max) range for X coordinates.
- y_range (tuple, optional):
(min, max) range for Y coordinates.
- z_range (tuple, optional):
(min, max) range for Z coordinates.
- inplace (bool):
If True, modifies the current object. If False, returns a new object. Default is True.
Returns:
- PointCloud or None:
If inplace=False, returns a new filtered PointCloud. If inplace=True, returns None.
- get_bounds()[source]
Computes the bounding box of the point cloud.
Returns:
- dict:
Dictionary with ‘x’, ‘y’, ‘z’ keys, each containing (min, max) tuples.
- get_centroid()[source]
Computes the centroid (geometric center) of the point cloud.
Returns:
- np.ndarray:
Array of shape (3,) with the centroid coordinates [x, y, z].
- filter(condition, inplace=True, **kwargs)[source]
Filters points based on coordinate values or point_data attributes.
Parameters:
- condition (str):
Condition string to filter points. Supported formats: - ‘X > value’: Keep points where X coordinate is greater than value. - ‘Y < value’: Keep points where Y coordinate is less than value. - ‘Z >= value’: Keep points where Z coordinate is greater than or equal to value. - ‘intensity > value’: Keep points where intensity attribute is greater than value. - ‘min_value <= attribute <= max_value’: Keep points within range.
Available attributes: X, Y, Z (coordinates) or any key in point_data.
- inplace (bool):
If True, modifies the current object. If False, returns a new filtered object. Default is True.
- **kwargs:
Additional keyword arguments passed to the condition parser.
Returns:
- PointCloud or None:
If inplace=False, returns a new filtered PointCloud. If inplace=True, returns None.
Raises:
- ValueError:
If the specified attribute doesn’t exist in coordinates or point_data, or if no points match the condition.
Examples:
>>> pc = PointCloud(points=np.random.rand(1000, 3) * 100) >>> pc.add_point_data(np.random.rand(1000), name="intensity")
>>> # Filter by coordinate >>> pc.filter_points('X > 50') # Keep points with X > 50
>>> # Filter by point_data attribute >>> pc.filter_points('intensity > 0.5') # Keep high intensity points
>>> # Filter by range >>> pc.filter_points('20 <= Z <= 80') # Keep points in Z range
>>> # Create new filtered point cloud >>> pc_filtered = pc.filter_points('Y < 30', inplace=False)
- to_dataframe(include_data=True, include_colortable=False, colortable_name='default')[source]
Converts the point cloud to a pandas DataFrame.
Parameters:
- include_data (bool):
If True, includes all point_data attributes as columns. Default is True.
- include_colortable (bool):
If True, includes index, name, and color columns from the colortable. Default is False.
- colortable_name (str):
Name of the colortable to use for color information. Default is “default”.
Returns:
- pd.DataFrame:
DataFrame with columns in order: index, name, color (if include_colortable=True), X, Y, Z, and optionally additional data columns.
Raises:
- ValueError:
If include_colortable is True but the specified colortable doesn’t exist or the corresponding point_data key is missing.
Examples:
>>> pc = PointCloud(points=np.random.rand(100, 3)) >>> df = pc.to_dataframe() # Basic: X, Y, Z columns
>>> df = pc.to_dataframe(include_colortable=True) >>> # Returns: index, name, color, X, Y, Z columns
- save(filename, format='npy', include_colortable=False, colortable_name='default')[source]
Saves the point cloud to a file.
Parameters:
- filename (str or Path):
Output filename.
- format (str):
File format. Options: ‘npy’, ‘csv’, ‘txt’. Default is ‘npy’.
- include_colortable (bool):
If True and format is ‘csv’ or ‘txt’, includes colortable information (index, name, color columns). Only applies to text formats. Default is False.
- colortable_name (str):
Name of the colortable to use when include_colortable=True. Default is “default”.
Raises:
- ValueError:
If format is not supported or if the point cloud is empty.
- classmethod load(filename, format='npy')[source]
Loads a point cloud from a file.
Parameters:
- filename (str or Path):
Input filename.
- format (str):
File format. Options: ‘npy’, ‘csv’, ‘txt’. Default is ‘npy’.
Returns:
- PointCloud:
Loaded PointCloud object.
Raises:
- ValueError:
If format is not supported.
- FileNotFoundError:
If file does not exist.
- load_colortable(lut_file, map_name='default', opacity=1.0, lut_type='lut')[source]
Loads a colortable from a file and associates it with a specified map name.
Parameters:
- lut_file (str or Path):
Path to the colortable file.
- map_name (str):
Name of the map to associate with the loaded colortable. Default is “default”.
- opacity (float, int, or np.ndarray):
Opacity value(s) for the colortable. Can be a single value (applied to all entries) or an array of values. Default is 1.0.
- lut_type (str):
Type of lookup table to load. Currently only “lut” is supported. Default is “lut”.
Returns:
None
Raises:
- FileNotFoundError:
If the specified colortable file does not exist.
- ValueError:
If the colortable does not cover all IDs in the data or if lut_type is not supported.
- append(other, inplace=True, fill_value=np.nan, handle_colortable_conflicts='warn')[source]
Appends another PointCloud to this one by concatenating coordinates and data.
Parameters:
- other (PointCloud):
The PointCloud object to append.
- inplace (bool):
If True, modifies the current object. If False, returns a new object. Default is True.
- fill_value (float):
Value to use when filling missing point_data keys. Default is np.nan.
- handle_colortable_conflicts (str):
How to handle colortable name conflicts. Options: - ‘warn’: Keep first colortable and warn (default) - ‘overwrite’: Use the new colortable - ‘rename’: Rename the new colortable as ‘name_2’ - ‘skip’: Skip the new colortable silently
Returns:
- PointCloud or None:
If inplace=False, returns a new concatenated PointCloud. If inplace=True, returns None.
Raises:
- ValueError:
If other is not a PointCloud object or if both point clouds are empty.
Notes:
If point_data keys don’t match, missing values are filled with fill_value
Affine matrices are compared; a warning is issued if they differ
The name of the resulting point cloud is kept from self
Examples:
>>> pc1 = PointCloud(points=np.random.rand(100, 3), name="cloud1") >>> pc2 = PointCloud(points=np.random.rand(50, 3), name="cloud2") >>> pc1.append(pc2) # pc1 now has 150 points
>>> # Or create a new combined cloud >>> pc3 = pc1.append(pc2, inplace=False)
- explore_pointcloud()[source]
Display comprehensive information about the point cloud.
Provides a formatted overview of the point cloud including point count, spatial transformations, bounding box, scalar data properties, and available colortables. Useful for quick inspection and validation of point cloud data.
- The method displays:
Basic point cloud identification and point count
Affine transformation matrix for spatial mapping
Bounding box information (spatial extent)
Centroid coordinates
Scalar data per point (with min/max statistics)
Available colortables for visualization
- Returns:
Prints formatted information to stdout.
- Return type:
None
Notes
This method performs no modifications to the point cloud data. It only displays information for inspection purposes.
Examples
>>> pc = PointCloud(points=np.random.rand(10000, 3)) >>> pc.add_point_data(np.random.rand(10000), name="intensity") >>> pc.explore_pointcloud() ╔════════════════════════════════════════════════════════════════╗ ║ POINT CLOUD EXPLORATION ║ ╠════════════════════════════════════════════════════════════════╣ ║ Name: default ║ ║ Points: 10,000 ║ ╠════════════════════════════════════════════════════════════════╣ ║ AFFINE TRANSFORMATION MATRIX ║ ║ [[ 1.00 0.00 0.00 0.00] ║ ║ [ 0.00 1.00 0.00 0.00] ║ ║ [ 0.00 0.00 1.00 0.00] ║ ║ [ 0.00 0.00 0.00 1.00]] ║ ╠════════════════════════════════════════════════════════════════╣ ║ SPATIAL INFORMATION ║ ║ Bounding Box: ║ ║ X: 0.0012 to 0.9998 (range: 0.9986) ║ ║ Y: 0.0034 to 0.9987 (range: 0.9953) ║ ║ Z: 0.0009 to 0.9995 (range: 0.9986) ║ ║ Centroid: [0.5023, 0.4989, 0.5012] ║ ╠════════════════════════════════════════════════════════════════╣ ║ SCALAR DATA PER POINT (2 maps) ║ ║ default Min: 1.0000 Max: 1.0000 ║ ║ intensity Min: 0.0001 Max: 0.9999 ║ ╠════════════════════════════════════════════════════════════════╣ ║ COLORTABLES (1 available) ║ ║ • default ║ ╚════════════════════════════════════════════════════════════════╝
- get_pointwise_colors(overlay_name='default', colormap='viridis', vmin=None, vmax=None, range_min=None, range_max=None, range_color=(128, 128, 128, 255))[source]
Compute streamlines colors for visualization based on the specified overlay.
This method processes the overlay data and creates appropiate point colors for visualization, handling both scalar data (with colormaps) and categorical data (with discrete color tables).
- Parameters:
overlay_name (str, optional) – Name of the overlay to visualize. If None, the first available overlay is used.
colormap (str, optional) – Colormap to use for scalar overlays. If None, uses parcellation color table for categorical data or ‘viridis’ for scalar data.
vmin (np.float64, optional) – Minimum value for scaling the colormap. If None, uses the minimum value of the overlay
vmax (np.float64, optional) – Maximum value for scaling the colormap. If None, uses the maximum value of the overlay
None (If both vmin and vmax are)
values. (the colormap will be applied to the full range of the overlay)
provided (If both are)
colormap. (they will be used to scale the)
range_min (np.float64, optional) – Minimum threshold for the overlay values. Values below this will be colored with range_color. If None, no minimum threshold is applied.
range_max (np.float64, optional) – Maximum threshold for the overlay values. Values above this will be colored with range_color. If None, no maximum threshold is applied.
range_color (List[int, int, int, int], optional) – RGBA color to use for values outside the specified range (range_min, range_max). Default is gray [128, 128, 128].
- Returns:
point_colors – Array of RGBA colors for each point in the tractogram.
- Return type:
ArraySequence
- Raises:
ValueError – If the specified overlay is not found in the mesh point data
ValueError – If no overlays are available
Notes
This method sets the vertices colors based on the specified overlay.
Examples
>>> # Prepare colors for a parcellation (uses discrete colors) >>> tractogram.get_vertexwise_colors(overlay_name="aparc") >>> >>> # Prepare colors for scalar data with custom colormap >>> tractogram.get_vertexwise_colors(overlay_name="thickness", colormap="hot") >>> >>> # Prepare colors for the tractogram overlay >>> tractogram.get_vertexwise_colors()
- list_maps()[source]
Lists all available scalar maps in the point cloud.
Returns:
- maps_per_point (set or None):
Set of scalar map names stored per point. None if no maps are available.
Examples:
>>> points = PointCloud(points) >>> maps = points.list_maps() >>> print("Available maps per point:", maps)
- plot(overlay_name='default', cmap='viridis', vmin=None, vmax=None, range_min=None, range_max=None, range_color=(128, 128, 128, 255), views=['lateral'], hemi='lh', use_opacity=True, notebook=False, show_colorbar=False, colorbar_title=None, colorbar_position='bottom', save_path=None, config=None)[source]
Plot the point cloud with specified overlay and visualization parameters.
Renders the tractogram with optional overlays using PyVista, supporting multiple camera views, custom colormaps, and interactive or static output. Handles both categorical parcellation data and continuous scalar overlays.
- Parameters:
overlay_name (str, default "default") – Name of the overlay to visualize from the tractogram’s point data.
cmap (str, optional) – Colormap for scalar data. If None, uses parcellation colors for categorical data or ‘viridis’ for scalar data.
vmin (float, optional) – Minimum value for colormap scaling. If None, uses data minimum.
vmax (float, optional) – Maximum value for colormap scaling. If None, uses data maximum.
views (str or List[str], default ["lateral"]) – Camera view(s): ‘lateral’, ‘medial’, ‘dorsal’, ‘ventral’, ‘anterior’, ‘posterior’, or multiple views like [‘lateral’, ‘medial’]. Also supports preset layouts: ‘4_views’, ‘6_views’, ‘8_views’ with optional orientation.
hemi (str, default "lh") – Hemisphere to visualize: ‘lh’ (left) or ‘rh’ (right).
use_opacity (bool, default True) – Whether to use opacity settings from the tractogram overlays.
plot_style (str, default "tube") – Style for rendering streamlines: ‘tube’ or ‘line’.
vis_percentage (float, default 100) – Percentage of streamlines to visualize (0-100). Reduces number for faster rendering if less than 100.
force_reduction (bool, default True) – Whether to force reduction of streamlines when vis_percentage < 100.
notebook (bool, default False) – Whether to display in Jupyter notebook. If False, opens interactive window.
show_colorbar (bool, default False) – Whether to display colorbar. Automatically determined if None.
colorbar_title (str, optional) – Title for the colorbar. Uses overlay name if None.
colorbar_position (str, default "bottom") – Colorbar position: ‘bottom’, ‘top’, ‘left’, or ‘right’.
save_path (str, optional) – Path to save plot as image. If None, displays interactively.
config (str, Path or Dict, optional) – Configuration for visualization settings. Can be a file path or dictionary.
- Returns:
PyVista plotter object for further customization.
- Return type:
Plotter
- Raises:
ValueError – If overlay not found or invalid view parameter.
Examples
>>> tractogram.plot(overlay_name="fa") >>> tractogram.plot(overlay_name="fa", cmap="hot", views="medial", show_colorbar=True)
- clabtoolkit.pointstools.merge_pointclouds(tractograms, color_table=None, map_name='point_id')[source]
Merges multiple point clouds into a single tractogram.
It combines all points and associated data from the input point clouds into a new Point object. Each point cloud’s points are assigned unique IDs in the merged object, and a color table is created to differentiate them.
- color_tabledict, optional
A dictionary defining the color table for the merged tractogram. If None, a default color table will be created.
- The dictionary should contain:
‘tractograms_names’: List of names for each tractogram.
‘color_table’: numpy.ndarray of shape (n_tractograms, 5) with RGBA colors and values.
‘lookup_table’: Optional, can be None.
- map_namestr, optional
Name of the map to store tract IDs in the merged tractogram. Default is ‘tract_id’.
Returns:
- merged_tractogramTractogram
A new Tractogram object containing all streamlines and associated data from the input tractograms.
Raises:
ValueError: If the input list is empty or contains non-Tractogram objects.
Examples:
>>> tract1 = Tractogram('tract1.trk') >>> tract2 = Tractogram('tract2.trk') >>> merged_tract = merge_tractograms([tract1, tract2]) >>> print(f"Merged tractogram has {len(merged_tract.tracts)} streamlines")
- clabtoolkit.pointstools.smooth_curve_coordinates(points, sigma=1.0, iterations=1, window_size=5)[source]
Smooth a 3D curve using Gaussian-weighted neighborhood averaging.
- Parameters:
points (ndarray, shape (N, 3)) – Array of 3D coordinates forming an ordered curve.
sigma (float, optional) – Standard deviation for Gaussian weighting. Default is 1.0.
iterations (int, optional) – Number of smoothing iterations. Default is 1.
window_size (int, optional) – Size of the neighborhood window (must be odd). Default is 5.
- Returns:
smoothed – Smoothed 3D coordinates.
- Return type:
ndarray, shape (N, 3)
The pointstools module provides point cloud representation and manipulation, with per-point scalar data, spatial filtering, affine transformation and 3D visualization.
Key Features
Point cloud construction from coordinate arrays or files
Per-point scalar data with named maps
Affine transformation and spatial (bounding box) filtering
Colortable support for categorical point data
Conversion to pandas DataFrames and multi-format saving
Merging of multiple point clouds
3D rendering via PyVista
Main Classes
PointCloud
The core class for representing and manipulating point clouds.
Key Methods:
- load(): Load a point cloud from a file (class method)
- save(): Save the point cloud to a file
- copy(): Create a deep copy of the point cloud
- add_point_data(): Attach named scalar data to each point
- transform(): Apply an affine transformation to the coordinates
- filter_by_bounds(): Filter points by spatial bounds
- filter(): Filter points by coordinate values or point data attributes
- get_bounds(): Compute the bounding box
- get_centroid(): Compute the geometric center
- append(): Append another PointCloud to this one
- load_colortable(): Attach a colortable to a named map
- get_pointwise_colors(): Compute per-point colors for an overlay
- list_maps(): List the available scalar maps
- to_dataframe(): Convert the point cloud to a pandas DataFrame
- explore_pointcloud(): Print a comprehensive summary
- plot(): Render the point cloud with an optional overlay
Main Functions
merge_pointclouds(): Merge multiple point clouds into onesmooth_curve_coordinates(): Smooth a 3D curve with Gaussian-weighted neighborhood averaging
Common Usage Examples
Basic construction and inspection:
import numpy as np
from clabtoolkit.pointstools import PointCloud
# Build a point cloud from an Nx3 coordinate array
coords = np.random.rand(100, 3) * 50
pc = PointCloud(points=coords, name="seeds")
# Print a full summary
pc.explore_pointcloud()
# Geometry
bounds = pc.get_bounds()
centroid = pc.get_centroid()
Attaching and using scalar data:
# Attach a named scalar map to the points
pc.add_point_data(np.random.rand(100), name="fa")
# List available maps
pc.list_maps()
# Filter by a point data attribute or by coordinates
high_fa = pc.filter("fa > 0.5", inplace=False)
Spatial operations:
# Restrict to a bounding box
pc.filter_by_bounds(x_range=(0, 25), y_range=(0, 25), z_range=None)
# Apply an affine transformation
affine = np.eye(4)
pc.transform(affine, inplace=True)
Colortables and visualization:
# Attach a colortable to a categorical map and render
pc.load_colortable("/path/to/lookup_table.lut", map_name="region")
pc.plot(overlay_name="fa", cmap="viridis")
Export and merging:
from clabtoolkit.pointstools import merge_pointclouds
# Convert to a DataFrame for downstream analysis
df = pc.to_dataframe(include_data=True)
# Save to file
pc.save("/path/to/points.tsv")
# Reload later
pc_reloaded = PointCloud.load("/path/to/points.tsv")
# Merge several point clouds
merged = merge_pointclouds([pc_a, pc_b])
# Or append in place
pc_a.append(pc_b, inplace=True)