Skip to content

cardiotensor

cardiotensor — 3D cardiomyocyte orientation analysis from volumetric imaging.

from cardiotensor import DataReader, compute_orientation, read_conf_file reader = DataReader("path/to/images") compute_orientation("path/to/images", output_dir="output", sigma=1.0, rho=3.0)

Sub-module imports

For tractography::

from cardiotensor.tractography import (
    generate_streamlines_from_vector_field,
    generate_streamlines_from_params,
)

For I/O utilities::

from cardiotensor.utils import (
    read_conf_file,
    load_npz_streamlines,
    load_trk_streamlines,
    write_spatialgraph_am,
    export_vector_field_to_vtk,
)

For analysis::

from cardiotensor.analysis import calculate_intensities, find_end_points

For visualization (requires a display)::

from cardiotensor.visualization import visualize_streamlines, visualize_vector_field

Modules:

Functions:

calculate_intensities

calculate_intensities(img_helix: ndarray, start_point: tuple[int, int], end_point: tuple[int, int], angle_range: float = 5, N_line: int = 10, max_value: float | None = None, min_value: float | None = None) -> list[ndarray]

Calculate intensity profiles along multiple lines.

Parameters: img_helix (np.ndarray): The image array. start_point (Tuple[int, int]): The starting point of the line. end_point (Tuple[int, int]): The ending point of the line. angle_range (float, optional): The range of angles to consider in degrees. Default is 5. N_line (int, optional): The number of lines to generate. Default is 10. max_value (Optional[float], optional): Maximum value for intensity normalization. Default is None. min_value (Optional[float], optional): Minimum value for intensity normalization. Default is None.

Returns: List[np.ndarray]: List of intensity profiles for each line.

calculate_structure_tensor

calculate_structure_tensor(volume: ndarray, sigma: float, rho: float, truncate: float = 4.0, devices: list[str] | None = None, block_size: int = 200, use_gpu: bool = False, dtype: type = float32, return_eigenvalues: bool = True, memmap_dir: str | PathLike[str] | None = None) -> tuple[ndarray | None, ndarray]

Calculates the structure tensor of a volume.

Parameters:

  • volume

    (ndarray) –

    The 3D volume data.

  • sigma

    (float) –

    sigma value for Gaussian smoothing.

  • rho

    (float) –

    rho value for Gaussian smoothing.

  • devices

    (Optional[list[str]], default: None ) –

    List of devices for parallel processing (e.g., ['cpu', 'cuda:0']).

  • block_size

    (int, default: 200 ) –

    Size of the blocks for processing. Default is 200.

  • use_gpu

    (bool, default: False ) –

    If True, uses GPU for calculations. Default is False.

  • dtype

    (type, default: float32 ) –

    Output dtype for eigenvalues and eigenvectors.

  • return_eigenvalues

    (bool, default: True ) –

    If False, do not allocate the eigenvalue volume.

  • memmap_dir

    (str | PathLike[str] | None, default: None ) –

    Optional scratch directory for disk-backed tensor outputs.

Returns:

  • ndarray | None

    tuple[np.ndarray | None, np.ndarray]: Eigenvalues, when requested, and

  • ndarray

    eigenvectors of the structure tensor.

compute_azimuth_and_elevation

compute_azimuth_and_elevation(vector_field_2d: ndarray) -> tuple[ndarray, ndarray]

Azimuth = angle in XY plane from +X toward +Y, in degrees [-180, 180] Elevation = unsigned angle from XY plane toward +Z, in degrees [0, 90]

compute_fraction_anisotropy

compute_fraction_anisotropy(eigenvalues_2d: ndarray) -> ndarray

Computes Fractional Anisotropy (FA) from eigenvalues of a structure tensor.

Parameters:

Returns:

  • ndarray

    np.ndarray: Fractional Anisotropy values.

compute_helical_and_intrusion_angles

compute_helical_and_intrusion_angles(vector_field_2d: ndarray, center_point: tuple[int, int, int], projected: bool = False) -> tuple[ndarray, ndarray]

Computes helical and intrusion angles from a 2D vector field.

By default, both angles use the full local vector. The helical angle retains radial contribution instead of first projecting into the circumferential/ longitudinal plane, and the intrusion angle retains longitudinal contribution instead of first projecting into the radial/circumferential plane.

Set projected=True to return the legacy projected helical angle and projected intrusion angle for comparison with projection-based literature.

Parameters:

  • vector_field_2d

    (ndarray) –

    2D orientation vector field.

  • center_point

    (Tuple[int, int, int]) –

    Coordinates of the center point.

  • projected

    (bool, default: False ) –

    If True, compute projected helical/intrusion angles. Defaults to False for unprojected 3D helical/intrusion angles.

Returns:

  • tuple[ndarray, ndarray]

    Tuple[np.ndarray, np.ndarray]: Helical and intrusion angle arrays.

compute_orientation

compute_orientation(volume_path: str, mask_path: str | None = None, output_dir: str = './output', output_format: str = 'jp2', output_type: str = '8bit', sigma: float = 1.0, rho: float = 3.0, truncate: float = 4.0, axis_points: ndarray | None = None, vertical_padding: float | None = None, write_vectors: bool = False, angle_mode: str = 'ha_ia', write_angles: bool = True, use_gpu: bool = True, is_test: bool = False, n_slice_test: int | None = None, show_quiver: bool = True, start_index: int = 0, end_index: int | None = None, colormap: str | None = None, colormap_angle1: str | None = None, colormap_angle2: str | None = None, projected: bool = False, vector_format: str = 'zarr', low_memory: bool = False, low_memory_dir: str | PathLike[str] | None = None) -> None

Compute the orientation for a volume dataset.

Parameters:

  • volume_path

    (str) –

    Path to the 3D volume.

  • mask_path

    (str | None, default: None ) –

    Optional binary mask path.

  • output_dir

    (str, default: './output' ) –

    Output directory for results.

  • output_format

    (str, default: 'jp2' ) –

    Image format for results.

  • output_type

    (str, default: '8bit' ) –

    Image type ("8bit" or "rgb").

  • sigma

    (float, default: 1.0 ) –

    Noise scale for structure tensor.

  • rho

    (float, default: 3.0 ) –

    Integration scale for structure tensor.

  • truncate

    (float, default: 4.0 ) –

    Gaussian kernel truncation.

  • axis_points

    (ndarray | None, default: None ) –

    3D points defining LV axis for cylindrical coordinates.

  • vertical_padding

    (float | None, default: None ) –

    Padding slices for tensor computation.

  • write_vectors

    (bool, default: False ) –

    Whether to save eigenvectors. Ignored in test mode.

  • vector_format

    (str, default: 'zarr' ) –

    Vector storage backend, either "npy" or "zarr".

  • low_memory

    (bool, default: False ) –

    Store temporary tensor outputs as memory-mapped files.

  • low_memory_dir

    (str | PathLike[str] | None, default: None ) –

    Optional scratch root. Defaults to OUTPUT_PATH/.cardiotensor_scratch, never the system /tmp directory.

  • write_angles

    (bool, default: True ) –

    Whether to save HA/IA/FA maps.

  • projected

    (bool, default: False ) –

    If True in ha_ia mode, write projected HA/IA legacy maps.

  • use_gpu

    (bool, default: True ) –

    Use GPU acceleration for tensor computation.

  • is_test

    (bool, default: False ) –

    If True, runs in test mode and outputs plots.

  • n_slice_test

    (int | None, default: None ) –

    Number of slices to process in test mode.

  • show_quiver

    (bool, default: True ) –

    If True, overlay the vector field on the test-slice figure.

  • start_index

    (int, default: 0 ) –

    Start slice index.

  • end_index

    (int | None, default: None ) –

    End slice index (None = last slice).

  • colormap

    (str | None, default: None ) –

    Shared colormap name for RGB angle outputs.

  • colormap_angle1

    (str | None, default: None ) –

    Colormap name for the first angle output.

  • colormap_angle2

    (str | None, default: None ) –

    Colormap name for the second angle output.

convert_to_8bit

convert_to_8bit(img: ndarray, perc_min: int = 0, perc_max: int = 100, min_value: float | None = None, max_value: float | None = None) -> ndarray

Converts a NumPy array to an 8-bit image.

Parameters:

  • img

    (ndarray) –

    Input image array.

  • perc_min

    (int, default: 0 ) –

    Minimum percentile for normalization. Default is 0.

  • perc_max

    (int, default: 100 ) –

    Maximum percentile for normalization. Default is 100.

  • min_value

    (Optional[float], default: None ) –

    Optional explicit minimum value.

  • max_value

    (Optional[float], default: None ) –

    Optional explicit maximum value.

Returns:

  • ndarray

    np.ndarray: 8-bit converted image.

find_end_points

find_end_points(start_point: tuple[float, float], end_point: tuple[float, float], angle_range: float, N_line: int) -> ndarray

Find the end points for lines at different angles within a range.

Parameters: start_point (Tuple[int, int]): The starting point of the main line. end_point (Tuple[int, int]): The ending point of the main line. angle_range (float): The range of angles to consider in degrees. N_line (int): The number of lines to generate within the range.

Returns: np.ndarray: Array of end points for the generated lines.

generate_streamlines_from_params

generate_streamlines_from_params(vector_field_dir: str | Path, output_dir: str | Path, fa_dir: str | Path, angle_dir: str | Path, mask_path: str | Path | None = None, start_xyz: tuple[int, int, int] = (0, 0, 0), end_xyz: tuple[int | None, int | None, int | None] = (None, None, None), bin_factor: int = 1, num_seeds: int = 20000, fa_seed_min: float = 0.4, fa_threshold: float = 0.1, step_length: float = 0.5, max_steps: int | None = 1000, angle_threshold: float = 60.0, min_length_pts: int = 10, bidirectional: bool = True, voxel_sizes_zyx: tuple[float, float, float] = (1.0, 1.0, 1.0), save_trk_file: bool = True, angle_mode: str = 'ha_ia', random_seed: int = 0) -> None

Generate streamlines from the eigenvector field, then export: - .trk with all discovered per-point angle fields - .am with all per-edge mean angle scalars

Angle discovery follows angle_mode: - "ha_ia" includes HA and IA only. - "az_el" includes AZ and EL only. If angle_dir is one of the selected angle folders, discover selected siblings next to it. If angle_dir is a parent, include selected subfolders below it. If none are found, treat angle_dir as a single custom angle and include it.

load_npz_streamlines

load_npz_streamlines(p: Path) -> tuple[list[ndarray], dict[str, list[ndarray]]]

Load streamlines from a .npz file saved as object arrays. Expects 'streamlines' in (z, y, x). Converts to (x, y, z). Collects any per-point arrays whose keys end with '_values' and exposes them as uppercase names without the suffix, e.g. 'ha_values' -> 'HA'.

Returns:

  • streamlines_xyz ( list[ndarray] ) –

    list[np.ndarray], each (N_i, 3) in (x, y, z)

  • per_point ( dict[str, list[ndarray]] ) –

    dict[str, list[np.ndarray]] keyed by field, each list aligned to streamlines

load_trk_streamlines

load_trk_streamlines(p: Path, include_per_streamline: bool = False)

Load streamlines and all per-point fields from a TrackVis .trk file. Returns streamlines in (x, y, z) voxel/world space (as stored in the TRK), and a dict of per-point fields, one list per field aligned with streamlines.

plot_intensity

plot_intensity(intensity_profiles: list[ndarray], label_y: str = '', x_max_lim: float | None = None, x_min_lim: float | None = None, y_max_lim: float | None = None, y_min_lim: float | None = None) -> None

Plot intensity profiles with mean and percentile shading.

Parameters: intensity_profiles (List[np.ndarray]): List of intensity profiles. label_y (str, optional): Label for the y-axis. Default is an empty string. x_max_lim (Optional[float], optional): Maximum x-axis limit. Default is None. x_min_lim (Optional[float], optional): Minimum x-axis limit. Default is None. y_max_lim (Optional[float], optional): Maximum y-axis limit. Default is None. y_min_lim (Optional[float], optional): Minimum y-axis limit. Default is None.

read_conf_file

read_conf_file(file_path: str) -> dict[str, Any]

Reads and parses a configuration file into a dictionary.

Parameters:

Returns:

  • dict[str, Any]

    Dict[str, Any]: Parsed configuration parameters.

Raises:

  • FileNotFoundError

    If the configuration file does not exist.

  • ValueError

    If expected numerical or array values are incorrectly formatted.

save_intensity

save_intensity(intensity_profiles: list[ndarray], save_path: str) -> None

Save intensity profiles to a CSV file.

Parameters: intensity_profiles (List[np.ndarray]): List of intensity profiles. save_path (str): Path to save the CSV file.

Returns: None

write_spatialgraph_am

write_spatialgraph_am(out_path: str | Path, streamlines_xyz: list[ndarray], point_thickness: Sequence[ndarray] | ndarray | None = None, edge_scalar: Sequence[float] | ndarray | Mapping[str, Sequence[float] | ndarray] | None = None, edge_scalar_name: str | None = None) -> None

Minimal Amira SpatialGraph writer with optional EDGE scalar blocks.

Writes blocks

@1 VERTEX float[3] @2 EDGE int[2] @3 EDGE int NumEdgePoints @4 POINT float[3] EdgePointCoordinates @5 POINT float thickness @6.. EDGE float one or more per-edge scalars

Parameters

out_path : str | Path Output .am path. streamlines_xyz : list[np.ndarray] List of polylines (x, y, z). Each array shape = (Ni, 3), Ni >= 2. point_thickness : np.ndarray | list[np.ndarray], optional Per-point thickness. Either a flat array of length sum(Ni) or a list aligned to streamlines with lengths Ni. edge_scalar : array-like | dict[str, array-like], optional - If a 1D array-like: one scalar per edge, use edge_scalar_name. - If a dict: multiple scalars, each value must be 1D, length = n_edges. Keys become field names. edge_scalar_name : str, optional Name for the single-scalar case. If edge_scalar is a dict, this is ignored.

Notes

  • Field names are lightly validated for Amira compatibility.
  • Values are written as ASCII floats with 6 decimal places.

DataReader

Classes:

DataReader

DataReader(path: str | Path)

Initializes the DataReader with a path to the volume.

Parameters:

  • path

    (str | Path) –

    Path to the volume directory or file.

Methods:

  • check_memory_requirement

    Check if the dataset can fit in available memory.

  • load_region

    Load a Z/Y/X region, using direct chunk reads for Zarr vectors.

  • load_volume

    Loads the volume and resizes it to unbinned_shape if provided, using fast

Attributes:

  • dtype (dtype) –

    Returns the data type of the volume.

  • shape (tuple[int, ...]) –

    Returns the shape of the volume as (Z, Y, X) or (Z, Y, X, C).

  • volume_size_gb (float) –

    Returns the total size of the volume in GB.

dtype property

dtype: dtype

Returns the data type of the volume.

shape property

shape: tuple[int, ...]

Returns the shape of the volume as (Z, Y, X) or (Z, Y, X, C).

volume_size_gb property

volume_size_gb: float

Returns the total size of the volume in GB.

check_memory_requirement

check_memory_requirement(shape, dtype, safety_factor=0.8, verbose=True)

Check if the dataset can fit in available memory.

Parameters:

  • shape
    (tuple[int]) –

    Shape of the array.

  • dtype
    (dtype) –

    NumPy dtype of the array.

  • safety_factor
    (float, default: 0.8 ) –

    Fraction of available memory allowed to be used.

load_region

load_region(start_index: int = 0, end_index: int | None = None, start_y: int = 0, end_y: int | None = None, start_x: int = 0, end_x: int | None = None) -> ndarray

Load a Z/Y/X region, using direct chunk reads for Zarr vectors.

load_volume

load_volume(start_index: int = 0, end_index: int | None = None, unbinned_shape: tuple[int, int, int] | None = None, show_progress: bool = True) -> ndarray

Loads the volume and resizes it to unbinned_shape if provided, using fast integer-only resampling: - np.repeat for upsampling - block_reduce (max) for downsampling

Parameters:

  • start_index
    (int, default: 0 ) –

    Start index for slicing (for stacks).

  • end_index
    (int, default: None ) –

    End index for slicing (for stacks). If None, loads the entire stack.

  • unbinned_shape
    (tuple, default: None ) –

    Desired shape (Z, Y, X). If None, no resizing is done.

  • show_progress
    (bool, default: True ) –

    Display the stack-loading progress bar.

Returns:

  • ndarray

    np.ndarray: Loaded volume.

analysis

Public analysis API.

Modules:

Functions:

calculate_intensities

calculate_intensities(img_helix: ndarray, start_point: tuple[int, int], end_point: tuple[int, int], angle_range: float = 5, N_line: int = 10, max_value: float | None = None, min_value: float | None = None) -> list[ndarray]

Calculate intensity profiles along multiple lines.

Parameters: img_helix (np.ndarray): The image array. start_point (Tuple[int, int]): The starting point of the line. end_point (Tuple[int, int]): The ending point of the line. angle_range (float, optional): The range of angles to consider in degrees. Default is 5. N_line (int, optional): The number of lines to generate. Default is 10. max_value (Optional[float], optional): Maximum value for intensity normalization. Default is None. min_value (Optional[float], optional): Minimum value for intensity normalization. Default is None.

Returns: List[np.ndarray]: List of intensity profiles for each line.

find_end_points

find_end_points(start_point: tuple[float, float], end_point: tuple[float, float], angle_range: float, N_line: int) -> ndarray

Find the end points for lines at different angles within a range.

Parameters: start_point (Tuple[int, int]): The starting point of the main line. end_point (Tuple[int, int]): The ending point of the main line. angle_range (float): The range of angles to consider in degrees. N_line (int): The number of lines to generate within the range.

Returns: np.ndarray: Array of end points for the generated lines.

plot_intensity

plot_intensity(intensity_profiles: list[ndarray], label_y: str = '', x_max_lim: float | None = None, x_min_lim: float | None = None, y_max_lim: float | None = None, y_min_lim: float | None = None) -> None

Plot intensity profiles with mean and percentile shading.

Parameters: intensity_profiles (List[np.ndarray]): List of intensity profiles. label_y (str, optional): Label for the y-axis. Default is an empty string. x_max_lim (Optional[float], optional): Maximum x-axis limit. Default is None. x_min_lim (Optional[float], optional): Minimum x-axis limit. Default is None. y_max_lim (Optional[float], optional): Maximum y-axis limit. Default is None. y_min_lim (Optional[float], optional): Minimum y-axis limit. Default is None.

save_intensity

save_intensity(intensity_profiles: list[ndarray], save_path: str) -> None

Save intensity profiles to a CSV file.

Parameters: intensity_profiles (List[np.ndarray]): List of intensity profiles. save_path (str): Path to save the CSV file.

Returns: None

analysis_functions

Functions:

calculate_intensities

calculate_intensities(img_helix: ndarray, start_point: tuple[int, int], end_point: tuple[int, int], angle_range: float = 5, N_line: int = 10, max_value: float | None = None, min_value: float | None = None) -> list[ndarray]

Calculate intensity profiles along multiple lines.

Parameters: img_helix (np.ndarray): The image array. start_point (Tuple[int, int]): The starting point of the line. end_point (Tuple[int, int]): The ending point of the line. angle_range (float, optional): The range of angles to consider in degrees. Default is 5. N_line (int, optional): The number of lines to generate. Default is 10. max_value (Optional[float], optional): Maximum value for intensity normalization. Default is None. min_value (Optional[float], optional): Minimum value for intensity normalization. Default is None.

Returns: List[np.ndarray]: List of intensity profiles for each line.

find_end_points

find_end_points(start_point: tuple[float, float], end_point: tuple[float, float], angle_range: float, N_line: int) -> ndarray

Find the end points for lines at different angles within a range.

Parameters: start_point (Tuple[int, int]): The starting point of the main line. end_point (Tuple[int, int]): The ending point of the main line. angle_range (float): The range of angles to consider in degrees. N_line (int): The number of lines to generate within the range.

Returns: np.ndarray: Array of end points for the generated lines.

plot_intensity

plot_intensity(intensity_profiles: list[ndarray], label_y: str = '', x_max_lim: float | None = None, x_min_lim: float | None = None, y_max_lim: float | None = None, y_min_lim: float | None = None) -> None

Plot intensity profiles with mean and percentile shading.

Parameters: intensity_profiles (List[np.ndarray]): List of intensity profiles. label_y (str, optional): Label for the y-axis. Default is an empty string. x_max_lim (Optional[float], optional): Maximum x-axis limit. Default is None. x_min_lim (Optional[float], optional): Minimum x-axis limit. Default is None. y_max_lim (Optional[float], optional): Maximum y-axis limit. Default is None. y_min_lim (Optional[float], optional): Minimum y-axis limit. Default is None.

save_intensity

save_intensity(intensity_profiles: list[ndarray], save_path: str) -> None

Save intensity profiles to a CSV file.

Parameters: intensity_profiles (List[np.ndarray]): List of intensity profiles. save_path (str): Path to save the CSV file.

Returns: None

gui_analysis_tool

Functions:

  • convert_slice_for_display

    Return normalized float slice for display, in the mode's physical domain, then min-max to 0..1.

  • discover_modes

    Return list of available subfolders among HA, IA, AZ, EL, FA, in a stable order.

convert_slice_for_display

convert_slice_for_display(slice2d: ndarray, mode: str) -> ndarray

Return normalized float slice for display, in the mode's physical domain, then min-max to 0..1.

discover_modes

discover_modes(base: Path) -> list[str]

Return list of available subfolders among HA, IA, AZ, EL, FA, in a stable order.

launcher

Modules:

slurm_launcher

Functions:

  • is_chunk_done

    Return True when every requested output exists for [start, end).

  • monitor_job_output

    Monitor every requested output for the requested index range.

  • slurm_launcher

    Launch SLURM array jobs for a subset [start_index, end_index) of the volume.

  • submit_job_to_slurm

    Submit a SLURM array job for a contiguous index window [start_index, end_index_exclusive).

is_chunk_done

is_chunk_done(output_dir: str, start: int, end: int, output_format: str = 'jp2', angle_mode: str = 'ha_ia', write_angles: bool = True, write_vectors: bool = False, vector_format: str = 'zarr', projected: bool = False) -> bool

Return True when every requested output exists for [start, end).

monitor_job_output

monitor_job_output(output_directory: str, start_index: int, end_index_exclusive: int, output_format: str = 'jp2', angle_mode: str = 'ha_ia', write_angles: bool = True, write_vectors: bool = False, vector_format: str = 'zarr', poll_interval_sec: int = 60, projected: bool = False) -> None

Monitor every requested output for the requested index range.

Completion requires both angle outputs, FA, and vectors when enabled.

slurm_launcher

slurm_launcher(conf_file_path: str, start_index: int = 0, end_index: int | None = None, chunk_size: int | None = None, partition: str | None = None, time_limit: str | None = None, cpus_per_task: int | None = None, mem_gb: int | None = None, array_parallel: int | None = None, log_dir: str | None = None, submit_dir: str | None = None, monitor: bool = True, dry_run: bool = False) -> None

Launch SLURM array jobs for a subset [start_index, end_index) of the volume.

Parameters

conf_file_path : str Path to cardiotensor configuration file. start_index : int Global start index (inclusive). end_index : int | None Global end index (exclusive). If None, process until the last slice. monitor : bool If True, wait and monitor outputs after submission. dry_run : bool If True, generate scripts but do not submit jobs.

submit_job_to_slurm

submit_job_to_slurm(conf_file_path: str, start_index: int, end_index_exclusive: int, chunk_size: int, *, partition: str | None, time_limit: str, cpus_per_task: int, mem_gb: int, array_parallel: int, log_dir: str, submit_dir: str, dry_run: bool = False) -> int | None

Submit a SLURM array job for a contiguous index window [start_index, end_index_exclusive).

orientation

Public orientation API.

Modules:

Functions:

calculate_structure_tensor

calculate_structure_tensor(volume: ndarray, sigma: float, rho: float, truncate: float = 4.0, devices: list[str] | None = None, block_size: int = 200, use_gpu: bool = False, dtype: type = float32, return_eigenvalues: bool = True, memmap_dir: str | PathLike[str] | None = None) -> tuple[ndarray | None, ndarray]

Calculates the structure tensor of a volume.

Parameters:

  • volume

    (ndarray) –

    The 3D volume data.

  • sigma

    (float) –

    sigma value for Gaussian smoothing.

  • rho

    (float) –

    rho value for Gaussian smoothing.

  • devices

    (Optional[list[str]], default: None ) –

    List of devices for parallel processing (e.g., ['cpu', 'cuda:0']).

  • block_size

    (int, default: 200 ) –

    Size of the blocks for processing. Default is 200.

  • use_gpu

    (bool, default: False ) –

    If True, uses GPU for calculations. Default is False.

  • dtype

    (type, default: float32 ) –

    Output dtype for eigenvalues and eigenvectors.

  • return_eigenvalues

    (bool, default: True ) –

    If False, do not allocate the eigenvalue volume.

  • memmap_dir

    (str | PathLike[str] | None, default: None ) –

    Optional scratch directory for disk-backed tensor outputs.

Returns:

  • ndarray | None

    tuple[np.ndarray | None, np.ndarray]: Eigenvalues, when requested, and

  • ndarray

    eigenvectors of the structure tensor.

compute_azimuth_and_elevation

compute_azimuth_and_elevation(vector_field_2d: ndarray) -> tuple[ndarray, ndarray]

Azimuth = angle in XY plane from +X toward +Y, in degrees [-180, 180] Elevation = unsigned angle from XY plane toward +Z, in degrees [0, 90]

compute_fraction_anisotropy

compute_fraction_anisotropy(eigenvalues_2d: ndarray) -> ndarray

Computes Fractional Anisotropy (FA) from eigenvalues of a structure tensor.

Parameters:

Returns:

  • ndarray

    np.ndarray: Fractional Anisotropy values.

compute_helical_and_intrusion_angles

compute_helical_and_intrusion_angles(vector_field_2d: ndarray, center_point: tuple[int, int, int], projected: bool = False) -> tuple[ndarray, ndarray]

Computes helical and intrusion angles from a 2D vector field.

By default, both angles use the full local vector. The helical angle retains radial contribution instead of first projecting into the circumferential/ longitudinal plane, and the intrusion angle retains longitudinal contribution instead of first projecting into the radial/circumferential plane.

Set projected=True to return the legacy projected helical angle and projected intrusion angle for comparison with projection-based literature.

Parameters:

  • vector_field_2d

    (ndarray) –

    2D orientation vector field.

  • center_point

    (Tuple[int, int, int]) –

    Coordinates of the center point.

  • projected

    (bool, default: False ) –

    If True, compute projected helical/intrusion angles. Defaults to False for unprojected 3D helical/intrusion angles.

Returns:

  • tuple[ndarray, ndarray]

    Tuple[np.ndarray, np.ndarray]: Helical and intrusion angle arrays.

compute_orientation

compute_orientation(volume_path: str, mask_path: str | None = None, output_dir: str = './output', output_format: str = 'jp2', output_type: str = '8bit', sigma: float = 1.0, rho: float = 3.0, truncate: float = 4.0, axis_points: ndarray | None = None, vertical_padding: float | None = None, write_vectors: bool = False, angle_mode: str = 'ha_ia', write_angles: bool = True, use_gpu: bool = True, is_test: bool = False, n_slice_test: int | None = None, show_quiver: bool = True, start_index: int = 0, end_index: int | None = None, colormap: str | None = None, colormap_angle1: str | None = None, colormap_angle2: str | None = None, projected: bool = False, vector_format: str = 'zarr', low_memory: bool = False, low_memory_dir: str | PathLike[str] | None = None) -> None

Compute the orientation for a volume dataset.

Parameters:

  • volume_path

    (str) –

    Path to the 3D volume.

  • mask_path

    (str | None, default: None ) –

    Optional binary mask path.

  • output_dir

    (str, default: './output' ) –

    Output directory for results.

  • output_format

    (str, default: 'jp2' ) –

    Image format for results.

  • output_type

    (str, default: '8bit' ) –

    Image type ("8bit" or "rgb").

  • sigma

    (float, default: 1.0 ) –

    Noise scale for structure tensor.

  • rho

    (float, default: 3.0 ) –

    Integration scale for structure tensor.

  • truncate

    (float, default: 4.0 ) –

    Gaussian kernel truncation.

  • axis_points

    (ndarray | None, default: None ) –

    3D points defining LV axis for cylindrical coordinates.

  • vertical_padding

    (float | None, default: None ) –

    Padding slices for tensor computation.

  • write_vectors

    (bool, default: False ) –

    Whether to save eigenvectors. Ignored in test mode.

  • vector_format

    (str, default: 'zarr' ) –

    Vector storage backend, either "npy" or "zarr".

  • low_memory

    (bool, default: False ) –

    Store temporary tensor outputs as memory-mapped files.

  • low_memory_dir

    (str | PathLike[str] | None, default: None ) –

    Optional scratch root. Defaults to OUTPUT_PATH/.cardiotensor_scratch, never the system /tmp directory.

  • write_angles

    (bool, default: True ) –

    Whether to save HA/IA/FA maps.

  • projected

    (bool, default: False ) –

    If True in ha_ia mode, write projected HA/IA legacy maps.

  • use_gpu

    (bool, default: True ) –

    Use GPU acceleration for tensor computation.

  • is_test

    (bool, default: False ) –

    If True, runs in test mode and outputs plots.

  • n_slice_test

    (int | None, default: None ) –

    Number of slices to process in test mode.

  • show_quiver

    (bool, default: True ) –

    If True, overlay the vector field on the test-slice figure.

  • start_index

    (int, default: 0 ) –

    Start slice index.

  • end_index

    (int | None, default: None ) –

    End slice index (None = last slice).

  • colormap

    (str | None, default: None ) –

    Shared colormap name for RGB angle outputs.

  • colormap_angle1

    (str | None, default: None ) –

    Colormap name for the first angle output.

  • colormap_angle2

    (str | None, default: None ) –

    Colormap name for the second angle output.

orient_vectors_z_positive

orient_vectors_z_positive(vector_field_slice: ndarray) -> ndarray

Flip unoriented vectors so their local Z component is non-negative.

This is useful for azimuth/elevation maps when the desired elevation is an unsigned angle above the local XY plane. Structure-tensor eigenvectors are axes, so v and -v represent the same local orientation.

rotate_vectors_to_new_axis

rotate_vectors_to_new_axis(vector_field_slice: ndarray, new_axis_vec: ndarray) -> ndarray

Rotate vectors into a local frame where new_axis_vec is aligned to +Z.

Parameters:

Returns:

  • ndarray

    np.ndarray: Rotated vectors with the same shape as input.

orientation_computation_functions

Functions:

adjust_start_end_index

adjust_start_end_index(start_index: int, end_index: int, N_img: int, padding_start: int = 0, padding_end: int = 0, is_test: bool = False, n_slice: int = 0) -> tuple[int, int]

Adjusts start and end indices for image processing, considering padding and test mode.

Parameters:

Returns:

  • tuple[int, int]

    Tuple[int, int]: Adjusted start and end indices.

calculate_center_vector

calculate_center_vector(points: ndarray) -> ndarray

Compute the linear regression vector for a given set of 3D points.

Parameters:

  • points
    (ndarray) –

    An Nx3 array of (x, y, z) coordinates representing the curved line.

Returns:

  • ndarray

    np.ndarray: A single 3D unit vector representing the direction of the best-fit line.

calculate_structure_tensor

calculate_structure_tensor(volume: ndarray, sigma: float, rho: float, truncate: float = 4.0, devices: list[str] | None = None, block_size: int = 200, use_gpu: bool = False, dtype: type = float32, return_eigenvalues: bool = True, memmap_dir: str | PathLike[str] | None = None) -> tuple[ndarray | None, ndarray]

Calculates the structure tensor of a volume.

Parameters:

  • volume
    (ndarray) –

    The 3D volume data.

  • sigma
    (float) –

    sigma value for Gaussian smoothing.

  • rho
    (float) –

    rho value for Gaussian smoothing.

  • devices
    (Optional[list[str]], default: None ) –

    List of devices for parallel processing (e.g., ['cpu', 'cuda:0']).

  • block_size
    (int, default: 200 ) –

    Size of the blocks for processing. Default is 200.

  • use_gpu
    (bool, default: False ) –

    If True, uses GPU for calculations. Default is False.

  • dtype
    (type, default: float32 ) –

    Output dtype for eigenvalues and eigenvectors.

  • return_eigenvalues
    (bool, default: True ) –

    If False, do not allocate the eigenvalue volume.

  • memmap_dir
    (str | PathLike[str] | None, default: None ) –

    Optional scratch directory for disk-backed tensor outputs.

Returns:

  • ndarray | None

    tuple[np.ndarray | None, np.ndarray]: Eigenvalues, when requested, and

  • ndarray

    eigenvectors of the structure tensor.

compute_azimuth_and_elevation

compute_azimuth_and_elevation(vector_field_2d: ndarray) -> tuple[ndarray, ndarray]

Azimuth = angle in XY plane from +X toward +Y, in degrees [-180, 180] Elevation = unsigned angle from XY plane toward +Z, in degrees [0, 90]

compute_fraction_anisotropy

compute_fraction_anisotropy(eigenvalues_2d: ndarray) -> ndarray

Computes Fractional Anisotropy (FA) from eigenvalues of a structure tensor.

Parameters:

Returns:

  • ndarray

    np.ndarray: Fractional Anisotropy values.

compute_helical_and_intrusion_angles

compute_helical_and_intrusion_angles(vector_field_2d: ndarray, center_point: tuple[int, int, int], projected: bool = False) -> tuple[ndarray, ndarray]

Computes helical and intrusion angles from a 2D vector field.

By default, both angles use the full local vector. The helical angle retains radial contribution instead of first projecting into the circumferential/ longitudinal plane, and the intrusion angle retains longitudinal contribution instead of first projecting into the radial/circumferential plane.

Set projected=True to return the legacy projected helical angle and projected intrusion angle for comparison with projection-based literature.

Parameters:

  • vector_field_2d
    (ndarray) –

    2D orientation vector field.

  • center_point
    (Tuple[int, int, int]) –

    Coordinates of the center point.

  • projected
    (bool, default: False ) –

    If True, compute projected helical/intrusion angles. Defaults to False for unprojected 3D helical/intrusion angles.

Returns:

  • tuple[ndarray, ndarray]

    Tuple[np.ndarray, np.ndarray]: Helical and intrusion angle arrays.

interpolate_points

interpolate_points(points: list[tuple[float, float, float]], N_img: int) -> ndarray

Generates interpolated points using cubic spline interpolation for a given set of 3D points.

Parameters:

  • points
    (list[tuple[float, float, float]]) –

    A list of (x, y, z) points.

  • N_img
    (int) –

    The number of slices in the z-dimension.

Returns:

  • ndarray

    np.ndarray: Array of interpolated points.

orient_vectors_y_positive

orient_vectors_y_positive(vector_field_slice: ndarray) -> ndarray

Flip unoriented vectors so their local Y component is non-negative.

Structure-tensor eigenvectors are axes: v and -v represent the same local fiber direction. This helper chooses a deterministic polarity after vectors have been rotated into the analysis frame.

orient_vectors_z_positive

orient_vectors_z_positive(vector_field_slice: ndarray) -> ndarray

Flip unoriented vectors so their local Z component is non-negative.

This is useful for azimuth/elevation maps when the desired elevation is an unsigned angle above the local XY plane. Structure-tensor eigenvectors are axes, so v and -v represent the same local orientation.

plot_images

plot_images(img: ndarray, img_angle1: ndarray, img_angle2: ndarray, img_FA: ndarray, center_point: tuple[int, int, int], vector_field_slice: ndarray | None = None, colormap_angle=None, colormap_angle2=None, colormap_FA=None, angle1_title: str = 'Helical Angle', angle2_title: str = 'Intrusion Angle', angle_ranges: tuple[tuple[float, float], tuple[float, float]] | None = None, save_path: str | None = None, show: bool = True, quiver_step: int | None = None, quiver_length: float | None = None, quiver_color: str = 'cyan', overlay_scalar_map: ndarray | None = None) -> None

Render a 2x2 figure of source, angle1, angle2, FA for a single slice.

Parameters

img : np.ndarray 2D grayscale slice of the anatomical image. img_angle1 : np.ndarray 2D float map for the first angle, for example HA or AZ, in degrees. img_angle2 : np.ndarray 2D float map for the second angle, for example IA or EL, in degrees. img_FA : np.ndarray 2D float map of fractional anisotropy in [0, 1]. center_point : tuple[int, int, int] Voxel coordinates (x, y, z) of the centerline point on this slice. Only (x, y) is used here for the marker. vector_field_slice : np.ndarray, optional Slice of the vector field with shape (3, Y, X). When provided, a subsampled arrow overlay is drawn on the source image. colormap_angle : matplotlib colormap, optional Colormap for the first angle. Defaults to helix_angle_cmap if None. colormap_angle2 : matplotlib colormap, optional Colormap for the second angle. Defaults to colormap_angle if None. colormap_FA : matplotlib colormap, optional Colormap for FA. Defaults to plt.cm.magma if None. angle1_title : str Title for the first angle panel. angle2_title : str Title for the second angle panel. angle_ranges : tuple[(float, float), (float, float)], optional Fixed display range for angle1 and angle2. save_path : str, optional If provided, save the figure to this location. show : bool If True, display the figure interactively. Useful to disable in tests. quiver_step : int, optional Spatial subsampling step for the arrow overlay. quiver_length : float, optional Arrow length in pixel units for the overlay. quiver_color : str Arrow color for the vector overlay. overlay_scalar_map : np.ndarray, optional Optional scalar map used to color the quiver arrows, typically the first angle image (HA or AZ).

Notes

This function shows the centerline marker on the source panel and can optionally overlay the in-plane vector direction.

remove_padding

remove_padding(volume: ndarray, val: ndarray, vec: ndarray, padding_start: int, padding_end: int, *, copy: bool = False) -> tuple[ndarray, ndarray, ndarray]

Removes padding from the volume, eigenvalues, and eigenvectors.

Parameters:

  • volume
    (ndarray) –

    The 3D volume data.

  • val
    (ndarray) –

    The eigenvalues.

  • vec
    (ndarray) –

    The eigenvectors.

  • padding_start
    (int) –

    Padding at the start to remove.

  • padding_end
    (int) –

    Padding at the end to remove.

  • copy
    (bool, default: False ) –

    Return compact copies instead of views into the padded arrays.

Returns:

  • tuple[ndarray, ndarray, ndarray]

    Tuple[np.ndarray, np.ndarray, np.ndarray]: Adjusted data without padding.

rotate_vectors_to_new_axis

rotate_vectors_to_new_axis(vector_field_slice: ndarray, new_axis_vec: ndarray) -> ndarray

Rotate vectors into a local frame where new_axis_vec is aligned to +Z.

Parameters:

Returns:

  • ndarray

    np.ndarray: Rotated vectors with the same shape as input.

write_images

write_images(img_angle1: ndarray, img_angle2: ndarray, img_FA: ndarray, start_index: int, output_dir: str, output_format: str, output_type: str, z: int, colormap_angle=None, colormap_angle2=None, colormap_FA=None, angle_names: tuple[str, str] = ('HA', 'IA'), angle_ranges: tuple[tuple[float, float], tuple[float, float]] = ((-90, 90), (-90, 90))) -> None

Write per-slice angle1, angle2, and FA images to disk with flexible naming and ranges.

Parameters

img_angle1 : np.ndarray 2D float array for the first angle, for example HA or AZ, in degrees. img_angle2 : np.ndarray 2D float array for the second angle, for example IA or EL, in degrees. img_FA : np.ndarray 2D float array for FA in [0, 1]. start_index : int Global starting index for z numbering in filenames. output_dir : str Base output directory. Subfolders angle_names[0], angle_names[1], and FA are created. output_format : {"jp2", "tif"} Output file format. Uses glymur for jp2 and tifffile for tif. output_type : {"8bit", "rgb"} Write mode. "8bit" writes single channel uint8, "rgb" writes colormapped RGB. z : int Current z offset used to compute the running index in filenames. colormap_angle : matplotlib colormap, optional Colormap for the first angle in "rgb" mode. Defaults to helix_angle_cmap if None. colormap_angle2 : matplotlib colormap, optional Colormap for the second angle in "rgb" mode. Defaults to colormap_angle if None. colormap_FA : matplotlib colormap, optional Colormap for FA in "rgb" mode. Defaults to plt.cm.magma if None. angle_names : tuple[str, str] Names used for subfolders and file prefixes, for example ("HA", "IA") or ("AZ", "EL"). angle_ranges : tuple[(float, float), (float, float)] Min and max for normalization of angle1 and angle2. For example HA and IA use (-90, 90), AZ uses (-180, 180) and EL uses (0, 90).

Raises

RuntimeError If required IO backends are missing for the chosen format. ValueError If output_format or output_type is unsupported.

Notes

The function creates subdirectories and writes files named like: {output_dir}/{name}/{name}{index:06d}.{ext} and {output_dir}/FA/FA}.{ext

write_img_rgb

write_img_rgb(img: ndarray, out_path: str, vmin: float, vmax: float, colormap: object | None = None, output_format: str = 'jp2') -> None

Write a single 2D float image as an RGB file using a matplotlib colormap.

Parameters

img : np.ndarray 2D float array to color map. out_path : str Full output path without extension handling. vmin : float Minimum for normalization. vmax : float Maximum for normalization. colormap : matplotlib colormap, optional Colormap to apply. If None, use helix_angle_cmap. output_format : {"jp2", "tif"} Output format. Uses glymur for jp2 and tifffile for tif.

Notes

The function normalizes to [0, 1], applies the colormap, then writes uint8 RGB.

orientation_computation_pipeline

Functions:

check_already_processed

check_already_processed(output_dir: str, start_index: int, end_index: int, write_vectors: bool, write_angles: bool, output_format: str, vector_format: str = 'zarr', zarr_store: ZarrVectorFieldStore | None = None, angle_names: tuple[str, str] = ('HA', 'IA'), fa_name: str = 'FA', extra_expected: Sequence[str] | None = None) -> bool

Check whether all required output files already exist for every slice index.

Parameters

output_dir : str Base output directory. start_index : int First global slice index to check (inclusive). end_index : int Last global slice index to check (exclusive). write_vectors : bool If True, expect completed vector output in the selected backend. write_angles : bool If True, expect angle images for angle_names[0], angle_names[1], and FA. output_format : str Image format/extension for angles, for example "jp2" or "tif". angle_names : tuple[str, str], optional Names of the two angle outputs, e.g. ("HA", "IA") or ("AZ", "EL"). fa_name : str, optional Name of the FA subfolder, default "FA". extra_expected : sequence of str, optional Additional per-slice path templates to check. Each template must contain "{idx}" which will be formatted as a zero-padded integer (06d), and may also contain "{ext}" for the image extension.

Returns

bool True if all expected files for all indices exist (and pass the quick corruption filter), False otherwise.

compute_orientation

compute_orientation(volume_path: str, mask_path: str | None = None, output_dir: str = './output', output_format: str = 'jp2', output_type: str = '8bit', sigma: float = 1.0, rho: float = 3.0, truncate: float = 4.0, axis_points: ndarray | None = None, vertical_padding: float | None = None, write_vectors: bool = False, angle_mode: str = 'ha_ia', write_angles: bool = True, use_gpu: bool = True, is_test: bool = False, n_slice_test: int | None = None, show_quiver: bool = True, start_index: int = 0, end_index: int | None = None, colormap: str | None = None, colormap_angle1: str | None = None, colormap_angle2: str | None = None, projected: bool = False, vector_format: str = 'zarr', low_memory: bool = False, low_memory_dir: str | PathLike[str] | None = None) -> None

Compute the orientation for a volume dataset.

Parameters:

  • volume_path
    (str) –

    Path to the 3D volume.

  • mask_path
    (str | None, default: None ) –

    Optional binary mask path.

  • output_dir
    (str, default: './output' ) –

    Output directory for results.

  • output_format
    (str, default: 'jp2' ) –

    Image format for results.

  • output_type
    (str, default: '8bit' ) –

    Image type ("8bit" or "rgb").

  • sigma
    (float, default: 1.0 ) –

    Noise scale for structure tensor.

  • rho
    (float, default: 3.0 ) –

    Integration scale for structure tensor.

  • truncate
    (float, default: 4.0 ) –

    Gaussian kernel truncation.

  • axis_points
    (ndarray | None, default: None ) –

    3D points defining LV axis for cylindrical coordinates.

  • vertical_padding
    (float | None, default: None ) –

    Padding slices for tensor computation.

  • write_vectors
    (bool, default: False ) –

    Whether to save eigenvectors. Ignored in test mode.

  • vector_format
    (str, default: 'zarr' ) –

    Vector storage backend, either "npy" or "zarr".

  • low_memory
    (bool, default: False ) –

    Store temporary tensor outputs as memory-mapped files.

  • low_memory_dir
    (str | PathLike[str] | None, default: None ) –

    Optional scratch root. Defaults to OUTPUT_PATH/.cardiotensor_scratch, never the system /tmp directory.

  • write_angles
    (bool, default: True ) –

    Whether to save HA/IA/FA maps.

  • projected
    (bool, default: False ) –

    If True in ha_ia mode, write projected HA/IA legacy maps.

  • use_gpu
    (bool, default: True ) –

    Use GPU acceleration for tensor computation.

  • is_test
    (bool, default: False ) –

    If True, runs in test mode and outputs plots.

  • n_slice_test
    (int | None, default: None ) –

    Number of slices to process in test mode.

  • show_quiver
    (bool, default: True ) –

    If True, overlay the vector field on the test-slice figure.

  • start_index
    (int, default: 0 ) –

    Start slice index.

  • end_index
    (int | None, default: None ) –

    End slice index (None = last slice).

  • colormap
    (str | None, default: None ) –

    Shared colormap name for RGB angle outputs.

  • colormap_angle1
    (str | None, default: None ) –

    Colormap name for the first angle output.

  • colormap_angle2
    (str | None, default: None ) –

    Colormap name for the second angle output.

compute_slice_angles_and_anisotropy

compute_slice_angles_and_anisotropy(z: int, vector_field_slice: ndarray, img_slice: ndarray | None, center_point: ndarray, eigen_val_slice: ndarray | None, center_line: ndarray, output_dir: str, output_format: str = 'jp2', output_type: str = '8bit', start_index: int = 0, write_vectors: bool = False, write_angles: bool = True, is_test: bool = False, show_quiver: bool = True, angle_mode: str = 'ha_ia', colormap: str | None = None, colormap_angle1: str | None = None, colormap_angle2: str | None = None, projected: bool = False, global_slice_idx: int | None = None, invalid_mask_slice: ndarray | None = None, vector_format: str = 'zarr', zarr_store: ZarrVectorFieldStore | None = None, vector_already_written: bool = False) -> tuple[float, float, bool]

Compute either HA/IA or Azimuth/Elevation plus FA for a single slice, then plot and/or write outputs depending on flags.

tractography

Public tractography API.

Modules:

Functions:

generate_streamlines_from_params

generate_streamlines_from_params(vector_field_dir: str | Path, output_dir: str | Path, fa_dir: str | Path, angle_dir: str | Path, mask_path: str | Path | None = None, start_xyz: tuple[int, int, int] = (0, 0, 0), end_xyz: tuple[int | None, int | None, int | None] = (None, None, None), bin_factor: int = 1, num_seeds: int = 20000, fa_seed_min: float = 0.4, fa_threshold: float = 0.1, step_length: float = 0.5, max_steps: int | None = 1000, angle_threshold: float = 60.0, min_length_pts: int = 10, bidirectional: bool = True, voxel_sizes_zyx: tuple[float, float, float] = (1.0, 1.0, 1.0), save_trk_file: bool = True, angle_mode: str = 'ha_ia', random_seed: int = 0) -> None

Generate streamlines from the eigenvector field, then export: - .trk with all discovered per-point angle fields - .am with all per-edge mean angle scalars

Angle discovery follows angle_mode: - "ha_ia" includes HA and IA only. - "az_el" includes AZ and EL only. If angle_dir is one of the selected angle folders, discover selected siblings next to it. If angle_dir is a parent, include selected subfolders below it. If none are found, treat angle_dir as a single custom angle and include it.

generate_streamlines

Functions:

generate_streamlines_from_params

generate_streamlines_from_params(vector_field_dir: str | Path, output_dir: str | Path, fa_dir: str | Path, angle_dir: str | Path, mask_path: str | Path | None = None, start_xyz: tuple[int, int, int] = (0, 0, 0), end_xyz: tuple[int | None, int | None, int | None] = (None, None, None), bin_factor: int = 1, num_seeds: int = 20000, fa_seed_min: float = 0.4, fa_threshold: float = 0.1, step_length: float = 0.5, max_steps: int | None = 1000, angle_threshold: float = 60.0, min_length_pts: int = 10, bidirectional: bool = True, voxel_sizes_zyx: tuple[float, float, float] = (1.0, 1.0, 1.0), save_trk_file: bool = True, angle_mode: str = 'ha_ia', random_seed: int = 0) -> None

Generate streamlines from the eigenvector field, then export: - .trk with all discovered per-point angle fields - .am with all per-edge mean angle scalars

Angle discovery follows angle_mode: - "ha_ia" includes HA and IA only. - "az_el" includes AZ and EL only. If angle_dir is one of the selected angle folders, discover selected siblings next to it. If angle_dir is a parent, include selected subfolders below it. If none are found, treat angle_dir as a single custom angle and include it.

save_trk_dipy_from_vox_zyx

save_trk_dipy_from_vox_zyx(streamlines_zyx: list[list[tuple[float, float, float]]], out_path: str | Path, vol_shape_zyx: tuple[int, int, int], voxel_sizes_zyx: tuple[float, float, float] = (1.0, 1.0, 1.0), data_values: list[ndarray] | None = None, data_name: str | None = None)

Save streamlines given in voxel indices (z,y,x) as TrackVis .trk using DIPY. Optionally attach one per-point scalar list under data_name.

save_trk_dipy_from_vox_zyx_multi

save_trk_dipy_from_vox_zyx_multi(streamlines_zyx: list[list[tuple[float, float, float]]], out_path: str | Path, vol_shape_zyx: tuple[int, int, int], voxel_sizes_zyx: tuple[float, float, float] = (1.0, 1.0, 1.0), data_per_point: dict[str, list[ndarray]] | None = None) -> None

Save streamlines in voxel indices (z,y,x) as TrackVis .trk using DIPY. Accepts multiple per-point scalar lists via data_per_point dict, with keys like "HA", "IA", "AZ", "EL". Each list must align with streamlines.

trilinear_interpolate_scalar

trilinear_interpolate_scalar(volume: ndarray, zf: float, yf: float, xf: float) -> float

Trilinearly interpolate a scalar volume at fractional point (z, y, x). Clamps to valid range.

trilinear_interpolate_vector

trilinear_interpolate_vector(vector_field: ndarray, pt: tuple[float, float, float], reference_vector: ndarray | None = None) -> ndarray

Given a fractional (z,y,x), returns the trilinearly‐interpolated 3‐vector from vector_field (shape = (3, Z, Y, X)). Clamps to nearest voxel if out‐of‐bounds.

Spatial indexing is (z, y, x), but vector components are stored as (x, y, z): vector_field[0] is the x component, vector_field[1] is y, and vector_field[2] is z.

If reference_vector is provided, the eight corner vectors are first flipped so they point into the same half-space as the reference. This treats structure-tensor eigenvectors as unoriented axes and avoids cancellation when neighboring voxels store equivalent vectors with opposite signs.

utils

Public utility API.

Modules:

Functions:

convert_to_8bit

convert_to_8bit(img: ndarray, perc_min: int = 0, perc_max: int = 100, min_value: float | None = None, max_value: float | None = None) -> ndarray

Converts a NumPy array to an 8-bit image.

Parameters:

  • img

    (ndarray) –

    Input image array.

  • perc_min

    (int, default: 0 ) –

    Minimum percentile for normalization. Default is 0.

  • perc_max

    (int, default: 100 ) –

    Maximum percentile for normalization. Default is 100.

  • min_value

    (Optional[float], default: None ) –

    Optional explicit minimum value.

  • max_value

    (Optional[float], default: None ) –

    Optional explicit maximum value.

Returns:

  • ndarray

    np.ndarray: 8-bit converted image.

load_npz_streamlines

load_npz_streamlines(p: Path) -> tuple[list[ndarray], dict[str, list[ndarray]]]

Load streamlines from a .npz file saved as object arrays. Expects 'streamlines' in (z, y, x). Converts to (x, y, z). Collects any per-point arrays whose keys end with '_values' and exposes them as uppercase names without the suffix, e.g. 'ha_values' -> 'HA'.

Returns:

  • streamlines_xyz ( list[ndarray] ) –

    list[np.ndarray], each (N_i, 3) in (x, y, z)

  • per_point ( dict[str, list[ndarray]] ) –

    dict[str, list[np.ndarray]] keyed by field, each list aligned to streamlines

load_trk_streamlines

load_trk_streamlines(p: Path, include_per_streamline: bool = False)

Load streamlines and all per-point fields from a TrackVis .trk file. Returns streamlines in (x, y, z) voxel/world space (as stored in the TRK), and a dict of per-point fields, one list per field aligned with streamlines.

read_conf_file

read_conf_file(file_path: str) -> dict[str, Any]

Reads and parses a configuration file into a dictionary.

Parameters:

Returns:

  • dict[str, Any]

    Dict[str, Any]: Parsed configuration parameters.

Raises:

  • FileNotFoundError

    If the configuration file does not exist.

  • ValueError

    If expected numerical or array values are incorrectly formatted.

write_spatialgraph_am

write_spatialgraph_am(out_path: str | Path, streamlines_xyz: list[ndarray], point_thickness: Sequence[ndarray] | ndarray | None = None, edge_scalar: Sequence[float] | ndarray | Mapping[str, Sequence[float] | ndarray] | None = None, edge_scalar_name: str | None = None) -> None

Minimal Amira SpatialGraph writer with optional EDGE scalar blocks.

Writes blocks

@1 VERTEX float[3] @2 EDGE int[2] @3 EDGE int NumEdgePoints @4 POINT float[3] EdgePointCoordinates @5 POINT float thickness @6.. EDGE float one or more per-edge scalars

Parameters

out_path : str | Path Output .am path. streamlines_xyz : list[np.ndarray] List of polylines (x, y, z). Each array shape = (Ni, 3), Ni >= 2. point_thickness : np.ndarray | list[np.ndarray], optional Per-point thickness. Either a flat array of length sum(Ni) or a list aligned to streamlines with lengths Ni. edge_scalar : array-like | dict[str, array-like], optional - If a 1D array-like: one scalar per edge, use edge_scalar_name. - If a dict: multiple scalars, each value must be 1D, length = n_edges. Keys become field names. edge_scalar_name : str, optional Name for the single-scalar case. If edge_scalar is a dict, this is ignored.

Notes
  • Field names are lightly validated for Amira compatibility.
  • Values are written as ASCII floats with 6 decimal places.

DataReader

Classes:

DataReader

DataReader(path: str | Path)

Initializes the DataReader with a path to the volume.

Parameters:

  • path
    (str | Path) –

    Path to the volume directory or file.

Methods:

  • check_memory_requirement

    Check if the dataset can fit in available memory.

  • load_region

    Load a Z/Y/X region, using direct chunk reads for Zarr vectors.

  • load_volume

    Loads the volume and resizes it to unbinned_shape if provided, using fast

Attributes:

  • dtype (dtype) –

    Returns the data type of the volume.

  • shape (tuple[int, ...]) –

    Returns the shape of the volume as (Z, Y, X) or (Z, Y, X, C).

  • volume_size_gb (float) –

    Returns the total size of the volume in GB.

dtype property
dtype: dtype

Returns the data type of the volume.

shape property
shape: tuple[int, ...]

Returns the shape of the volume as (Z, Y, X) or (Z, Y, X, C).

volume_size_gb property
volume_size_gb: float

Returns the total size of the volume in GB.

check_memory_requirement
check_memory_requirement(shape, dtype, safety_factor=0.8, verbose=True)

Check if the dataset can fit in available memory.

Parameters:

  • shape
    (tuple[int]) –

    Shape of the array.

  • dtype
    (dtype) –

    NumPy dtype of the array.

  • safety_factor
    (float, default: 0.8 ) –

    Fraction of available memory allowed to be used.

load_region
load_region(start_index: int = 0, end_index: int | None = None, start_y: int = 0, end_y: int | None = None, start_x: int = 0, end_x: int | None = None) -> ndarray

Load a Z/Y/X region, using direct chunk reads for Zarr vectors.

load_volume
load_volume(start_index: int = 0, end_index: int | None = None, unbinned_shape: tuple[int, int, int] | None = None, show_progress: bool = True) -> ndarray

Loads the volume and resizes it to unbinned_shape if provided, using fast integer-only resampling: - np.repeat for upsampling - block_reduce (max) for downsampling

Parameters:

  • start_index
    (int, default: 0 ) –

    Start index for slicing (for stacks).

  • end_index
    (int, default: None ) –

    End index for slicing (for stacks). If None, loads the entire stack.

  • unbinned_shape
    (tuple, default: None ) –

    Desired shape (Z, Y, X). If None, no resizing is done.

  • show_progress
    (bool, default: True ) –

    Display the stack-loading progress bar.

Returns:

  • ndarray

    np.ndarray: Loaded volume.

am_utils

Functions:

write_spatialgraph_am

write_spatialgraph_am(out_path: str | Path, streamlines_xyz: list[ndarray], point_thickness: Sequence[ndarray] | ndarray | None = None, edge_scalar: Sequence[float] | ndarray | Mapping[str, Sequence[float] | ndarray] | None = None, edge_scalar_name: str | None = None) -> None

Minimal Amira SpatialGraph writer with optional EDGE scalar blocks.

Writes blocks

@1 VERTEX float[3] @2 EDGE int[2] @3 EDGE int NumEdgePoints @4 POINT float[3] EdgePointCoordinates @5 POINT float thickness @6.. EDGE float one or more per-edge scalars

Parameters

out_path : str | Path Output .am path. streamlines_xyz : list[np.ndarray] List of polylines (x, y, z). Each array shape = (Ni, 3), Ni >= 2. point_thickness : np.ndarray | list[np.ndarray], optional Per-point thickness. Either a flat array of length sum(Ni) or a list aligned to streamlines with lengths Ni. edge_scalar : array-like | dict[str, array-like], optional - If a 1D array-like: one scalar per edge, use edge_scalar_name. - If a dict: multiple scalars, each value must be 1D, length = n_edges. Keys become field names. edge_scalar_name : str, optional Name for the single-scalar case. If edge_scalar is a dict, this is ignored.

Notes
  • Field names are lightly validated for Amira compatibility.
  • Values are written as ASCII floats with 6 decimal places.

downsampling

Functions:

downsample_vector_volume

downsample_vector_volume(input_npy: Path, bin_factor: int, output_dir: Path, mask_path: str | Path | None = None) -> Path

Downsamples a vector volume using a thread pool.

Parameters:

  • input_npy
    (Path) –

    Path to the directory containing numpy files.

  • bin_factor
    (int) –

    Binning factor for downsampling.

  • output_dir
    (Path) –

    Path to the output directory.

  • mask_path
    (str | Path | None, default: None ) –

    Optional mask applied before vector downsampling.

downsample_volume

downsample_volume(input_path: Path, bin_factor: int, output_dir: Path, subfolder: str = 'HA', out_ext: str = 'tif', min_value: float = 0, max_value: float = 255) -> None

Downsamples a 3D image volume along the Z and XY axes and saves as 8-bit images.

This function reads a volumetric image dataset (e.g. TIFF stack) using DataReader, performs block averaging along the Z-axis and spatial downsampling in XY, then saves each resulting slice in a specified output directory as 8-bit images.

Parameters:

  • input_path
    (Path) –

    Path to the directory containing the image stack.

  • bin_factor
    (int) –

    Factor to downsample in XY and the number of Z-slices to average per output slice.

  • output_dir
    (Path) –

    Path to the output root directory.

  • subfolder
    (str, default: 'HA' ) –

    Subdirectory name under binX/ to place results (default: "HA").

  • out_ext
    (str, default: 'tif' ) –

    Output image format extension (e.g., 'tif', 'png').

  • min_value
    (float, default: 0 ) –

    Minimum value for intensity normalization to 8-bit.

  • max_value
    (float, default: 255 ) –

    Maximum value for intensity normalization to 8-bit.

Returns:

  • None

    None

process_image_block

process_image_block(file_list, block_idx, bin_factor, h, w, out_file, min_value, max_value)

Process a Z-block of images by averaging along the Z axis, downsampling in XY, converting to 8-bit, and writing to disk.

Parameters:

  • file_list
    (list) –

    List of file paths (entire volume stack).

  • bin_factor
    (int) –

    Binning factor for XY downsampling.

  • h
    (int) –

    Input image height.

  • w
    (int) –

    Input image width.

  • out_file
    (Path) –

    Output file path for the downsampled image.

  • min_value
    (float) –

    Minimum intensity for 8-bit scaling.

  • max_value
    (float) –

    Maximum intensity for 8-bit scaling.

process_vector_block

process_vector_block(block: list[Path], bin_factor: int, h: int, w: int, output_dir: Path, idx: int) -> None

Processes a single block of numpy files and saves the downsampled output.

Parameters:

  • block
    (List[Path]) –

    List of file paths to the numpy files in the block.

  • bin_factor
    (int) –

    Binning factor for downsampling.

  • h
    (int) –

    Height of the data block.

  • w
    (int) –

    Width of the data block.

  • output_dir
    (Path) –

    Path to the output directory.

  • idx
    (int) –

    Index of the current block.

image_io

Classes:

Functions:

ZarrVectorFieldStore dataclass

ZarrVectorFieldStore(path: Path, vectors: Any, completed: Any)

Open arrays belonging to one Cardiotensor Zarr vector field.

initialize_zarr_vector_field

initialize_zarr_vector_field(output_dir: str | Path, volume_shape: tuple[int, int, int]) -> ZarrVectorFieldStore

Create or validate the sharded Zarr vector field for a full volume.

normalize_vector_format

normalize_vector_format(vector_format: str) -> str

Validate and normalize a vector output format.

open_zarr_vector_field

open_zarr_vector_field(output_dir: str | Path, mode: str = 'r') -> ZarrVectorFieldStore

Open an existing Cardiotensor Zarr vector field.

read_image_file

read_image_file(file_path: str | Path) -> ndarray

Read one image file to a NumPy array using the preferred backend.

vector_field_path

vector_field_path(output_dir: str | Path, vector_format: str) -> Path

Return the vector-field path for one configured storage format.

write_atomic

write_atomic(out_path: str | Path, writer: Callable[[str], None]) -> None

Write to a temporary file first, then replace the final output.

write_image

write_image(out_path: str | Path, data: ndarray) -> None

Write an image using the backend selected from the output extension.

write_vector_field

write_vector_field(vector_field_slice: ndarray, start_index: int, output_dir: str, slice_idx: int, vector_format: str = 'npy', zarr_store: ZarrVectorFieldStore | None = None) -> None

Save one vector field slice using the configured vector backend.

streamlines_io_utils

Functions:

compute_elevation_angles

compute_elevation_angles(streamlines_xyz: list[ndarray]) -> list[ndarray]

Compute per-vertex elevation angle from streamline geometry: elevation = arcsin(z-component of unit tangent) in degrees. The last vertex copies the previous value to keep lengths aligned.

ha_to_degrees_per_streamline

ha_to_degrees_per_streamline(ha_list: list[ndarray]) -> list[ndarray]

Convert HA values that might be byte-scaled (0..255) to degrees (-90..90). Leaves values unchanged if they already look like degrees.

load_npz_streamlines

load_npz_streamlines(p: Path) -> tuple[list[ndarray], dict[str, list[ndarray]]]

Load streamlines from a .npz file saved as object arrays. Expects 'streamlines' in (z, y, x). Converts to (x, y, z). Collects any per-point arrays whose keys end with '_values' and exposes them as uppercase names without the suffix, e.g. 'ha_values' -> 'HA'.

Returns:

  • streamlines_xyz ( list[ndarray] ) –

    list[np.ndarray], each (N_i, 3) in (x, y, z)

  • per_point ( dict[str, list[ndarray]] ) –

    dict[str, list[np.ndarray]] keyed by field, each list aligned to streamlines

load_trk_streamlines

load_trk_streamlines(p: Path, include_per_streamline: bool = False)

Load streamlines and all per-point fields from a TrackVis .trk file. Returns streamlines in (x, y, z) voxel/world space (as stored in the TRK), and a dict of per-point fields, one list per field aligned with streamlines.

normalize_attrs_to_degrees

normalize_attrs_to_degrees(attrs: dict | None) -> dict[str, list[ndarray]]

Normalize HA, IA, AZ, EL fields to degrees if stored as 0–255. If already in degrees or unit vectors, returns unchanged except cast to float32.

Input

attrs: dict[str, list[np.ndarray]] from TRK (e.g., {"HA":[...], "IA":[...], ...})

Returns:

  • normalized ( dict[str, list[ndarray]] ) –

    same keys, each entry = list of np.ndarray (float32) in degrees.

reduce_per_edge

reduce_per_edge(values_per_point: list[ndarray], how: str = 'mean') -> ndarray

Reduce per-point values along each streamline to a single scalar per edge.

utils

Functions:

convert_to_8bit

convert_to_8bit(img: ndarray, perc_min: int = 0, perc_max: int = 100, min_value: float | None = None, max_value: float | None = None) -> ndarray

Converts a NumPy array to an 8-bit image.

Parameters:

  • img
    (ndarray) –

    Input image array.

  • perc_min
    (int, default: 0 ) –

    Minimum percentile for normalization. Default is 0.

  • perc_max
    (int, default: 100 ) –

    Maximum percentile for normalization. Default is 100.

  • min_value
    (Optional[float], default: None ) –

    Optional explicit minimum value.

  • max_value
    (Optional[float], default: None ) –

    Optional explicit maximum value.

Returns:

  • ndarray

    np.ndarray: 8-bit converted image.

get_available_cpu_count

get_available_cpu_count(default: int = 1) -> int

Return the CPU count available to this process, respecting SLURM limits.

get_available_memory_bytes

get_available_memory_bytes() -> int

Return free memory visible to this process, respecting job limits.

get_gpu_count

get_gpu_count() -> int

Return the number of visible NVIDIA GPUs, or 0 if none are detected.

read_conf_file

read_conf_file(file_path: str) -> dict[str, Any]

Reads and parses a configuration file into a dictionary.

Parameters:

Returns:

  • dict[str, Any]

    Dict[str, Any]: Parsed configuration parameters.

Raises:

  • FileNotFoundError

    If the configuration file does not exist.

  • ValueError

    If expected numerical or array values are incorrectly formatted.

visualization

Public visualization API.

Modules:

Functions:

visualize_streamlines

visualize_streamlines(streamlines_file: str | Path, color_by: str = 'ha', line_width: float = 4.0, subsample_factor: int = 1, filter_min_len: int | None = None, downsample_factor: int = 1, max_streamlines: int | None = None, top_clusters: int | None = None, crop_bounds: tuple | None = None, interactive: bool = True, screenshot_path: str | None = None, video_path: str | None = None, video_fps: int = 30, video_frames: int = 120, window_size: tuple[int, int] = (800, 800), colormap=None, spline_subdiv: int = 2, backend: str = 'fury', mode: str = 'tube', background_color: str | tuple[float, float, float] | None = None, tube_sides: int = 9, pyvista_opacity: float = 1.0, pyvista_show_axes: bool = True, pyvista_show_bounds: bool = False, pyvista_shadows: bool = False, random_seed: int | None = None, session_path: str | Path | None = None, restore_session: bool = True, session_settings: dict | None = None, fury_quality: str = 'interactive')

Visualize .trk streamlines with per-point angle-based coloring.

Parameters

backend Rendering backend: "fury" for tractography-oriented interaction or "pyvista" for polished scientific plots and screenshots. mode "tube" for explicit tube geometry or "line" for faster line rendering.

visualize_vector_field

visualize_vector_field(vector_field_path: str | Path, color_volume_path: str | Path | None = None, mask_path: str | Path | None = None, downsample: int = 10, bin_factor: int = 1, size: float = 1.0, radius: float = 0.5, start: int | None = None, end: int | None = None, save_path: str | Path | None = None, voxel_size: float = 1.0, is_vtk: bool = False, mode: str = 'arrow', colormap=None)

High-level visualization of a 3D vector field using FURY for interactive visualization or optional VTK export for ParaView.

This function loads a 3D vector field, optionally applies a mask and a scalar volume for coloring, downsamples the data for visualization, and displays it in FURY as arrows or cylinders. The user can also save a snapshot or export the vector field to a VTK file.

Parameters

vector_field_path : str or Path Path to the 3D vector field (directory or file). The vector field must be stored as (3, Z, Y, X) or (Z, Y, X, 3) numpy arrays. color_volume_path : str or Path, optional Path to a scalar volume used to color the vectors (e.g., helical angles). If RGB, the channels will be averaged to a single scalar map. mask_path : str or Path, optional Path to a binary mask volume. Vectors outside the mask are set to NaN and ignored in visualization. downsample : int, optional Display one vector every downsample voxels in each dimension. Default is 10. bin_factor : int, optional Spatial downsampling factor applied before visualization. Useful for large volumes. Default is 1 (no binning). size : float, optional Global scaling factor for arrow or cylinder lengths. Default is 1.0. radius : float, optional Radius of cylinders if mode="cylinder". Ignored in arrow mode. Default is 0.5. start : int, optional Starting Z slice index to visualize. Default is 0. end : int, optional Ending Z slice index (exclusive). Default is the last slice. save_path : str or Path, optional If provided, saves a rendered screenshot to this path instead of opening an interactive window. voxel_size : float, optional Physical voxel size used for scaling coordinates and lengths in 3D space. Default is 1.0. is_vtk : bool, optional If True, exports the vector field to a VTK file (paraview.vtk) for visualization in ParaView. mode : str, optional Visualization mode, either: - "arrow" : draws 3D arrows - "cylinder" : draws cylinders aligned with vector directions Default is "arrow". colormap : matplotlib colormap, optional Colormap used for coloring the vectors based on color_volume. Accepts any Matplotlib colormap (e.g., plt.cm.turbo) or your custom helix_angle_cmap. Default is helix_angle_cmap.

Returns

None Displays the 3D vector field interactively or saves a screenshot/VK file.

fury_plotting_streamlines

Classes:

StreamlineViewer

StreamlineViewer(streamlines_xyz, color_values, mode, line_width, window_size, lut, background_color='black', spline_subdiv=16, tube_sides: int = 9, color_range: tuple[float, float] | None = None, color_label: str = 'Angle', flat_values: ndarray | None = None, session_path: str | Path | None = None, restore_session: bool = True, session_settings: dict | None = None, streamlines_file: str | Path | None = None, opacity: float = 1.0, quality: str = 'interactive')

fury_plotting_vectors

Functions:

matplotlib_cmap_to_fury_lut

matplotlib_cmap_to_fury_lut(cmap, value_range: tuple[float, float], n_colors: int = 256) -> vtkLookupTable

Convert a Matplotlib colormap to a VTK lookup table for FURY scalar bars.

plot_vector_field_fury

plot_vector_field_fury(vector_field: ndarray, size: float = 1.0, radius: float = 0.5, color_volume: ndarray = None, downsample: int = 10, voxel_size: float = 1.0, mode: str = 'arrow', save_path: str = None, colormap=None)

Visualize a 3D vector field using FURY as arrows or cylinders.

Parameters

vector_field : np.ndarray 4D array (Z, Y, X, 3) of vectors. size : float Scaling factor for arrow/cylinder lengths. radius : float Radius of the cylinders (ignored in arrow mode). color_volume : np.ndarray, optional 3D array (Z, Y, X) of scalar values for coloring. downsample : int Display one vector every downsample voxels in Z, Y, and X. voxel_size : float Physical voxel size for proper scaling. mode : str Visualization mode: "arrow" or "cylinder". save_path : Path or str, optional If provided, save the screenshot to this path. colormap : matplotlib colormap, optional Colormap to use for coloring the vectors. Default is helix_angle_cmap.

streamlines

Functions:

visualize_streamlines

visualize_streamlines(streamlines_file: str | Path, color_by: str = 'ha', line_width: float = 4.0, subsample_factor: int = 1, filter_min_len: int | None = None, downsample_factor: int = 1, max_streamlines: int | None = None, top_clusters: int | None = None, crop_bounds: tuple | None = None, interactive: bool = True, screenshot_path: str | None = None, video_path: str | None = None, video_fps: int = 30, video_frames: int = 120, window_size: tuple[int, int] = (800, 800), colormap=None, spline_subdiv: int = 2, backend: str = 'fury', mode: str = 'tube', background_color: str | tuple[float, float, float] | None = None, tube_sides: int = 9, pyvista_opacity: float = 1.0, pyvista_show_axes: bool = True, pyvista_show_bounds: bool = False, pyvista_shadows: bool = False, random_seed: int | None = None, session_path: str | Path | None = None, restore_session: bool = True, session_settings: dict | None = None, fury_quality: str = 'interactive')

Visualize .trk streamlines with per-point angle-based coloring.

Parameters

backend Rendering backend: "fury" for tractography-oriented interaction or "pyvista" for polished scientific plots and screenshots. mode "tube" for explicit tube geometry or "line" for faster line rendering.

vector_field

vector_field.py

High-level functions for loading, processing, and visualizing 3D vector fields using FURY or exporting to VTK.

Functions:

visualize_vector_field

visualize_vector_field(vector_field_path: str | Path, color_volume_path: str | Path | None = None, mask_path: str | Path | None = None, downsample: int = 10, bin_factor: int = 1, size: float = 1.0, radius: float = 0.5, start: int | None = None, end: int | None = None, save_path: str | Path | None = None, voxel_size: float = 1.0, is_vtk: bool = False, mode: str = 'arrow', colormap=None)

High-level visualization of a 3D vector field using FURY for interactive visualization or optional VTK export for ParaView.

This function loads a 3D vector field, optionally applies a mask and a scalar volume for coloring, downsamples the data for visualization, and displays it in FURY as arrows or cylinders. The user can also save a snapshot or export the vector field to a VTK file.

Parameters

vector_field_path : str or Path Path to the 3D vector field (directory or file). The vector field must be stored as (3, Z, Y, X) or (Z, Y, X, 3) numpy arrays. color_volume_path : str or Path, optional Path to a scalar volume used to color the vectors (e.g., helical angles). If RGB, the channels will be averaged to a single scalar map. mask_path : str or Path, optional Path to a binary mask volume. Vectors outside the mask are set to NaN and ignored in visualization. downsample : int, optional Display one vector every downsample voxels in each dimension. Default is 10. bin_factor : int, optional Spatial downsampling factor applied before visualization. Useful for large volumes. Default is 1 (no binning). size : float, optional Global scaling factor for arrow or cylinder lengths. Default is 1.0. radius : float, optional Radius of cylinders if mode="cylinder". Ignored in arrow mode. Default is 0.5. start : int, optional Starting Z slice index to visualize. Default is 0. end : int, optional Ending Z slice index (exclusive). Default is the last slice. save_path : str or Path, optional If provided, saves a rendered screenshot to this path instead of opening an interactive window. voxel_size : float, optional Physical voxel size used for scaling coordinates and lengths in 3D space. Default is 1.0. is_vtk : bool, optional If True, exports the vector field to a VTK file (paraview.vtk) for visualization in ParaView. mode : str, optional Visualization mode, either: - "arrow" : draws 3D arrows - "cylinder" : draws cylinders aligned with vector directions Default is "arrow". colormap : matplotlib colormap, optional Colormap used for coloring the vectors based on color_volume. Accepts any Matplotlib colormap (e.g., plt.cm.turbo) or your custom helix_angle_cmap. Default is helix_angle_cmap.

Returns

None Displays the 3D vector field interactively or saves a screenshot/VK file.