Morphology Analysis =================== The morphology module extracts structural features from segmented organelles, including volume, surface area, length, and shape descriptors. These features are fundamental for characterizing subcellular structures across imaging modalities. Overview -------- Morphological analysis quantifies the physical properties of organelles based on their 3D masks or coordinate representations. iPA categorizes organelles into three morphological classes: * **Spherical organelles**: ISGs, vesicles, lipid droplets - characterized by volume and sphericity * **Cylindrical organelles**: Mitochondria - characterized by volume and aspect ratio * **Tubular organelles**: F-actin, microtubules - characterized by total length and network topology The extracted features enable quantitative comparisons of organelle morphology under different conditions (e.g., low vs. high glucose) and across imaging modalities. Core Functions -------------- extract_isg_features ~~~~~~~~~~~~~~~~~~~~ .. autofunction:: ipa.analysis.extract_isg_features Extracts comprehensive morphological features from insulin secretory granule (ISG) masks using watershed-based instance segmentation. **Features Extracted**: - Volume (μm³) - Surface area (μm²) - Sphericity (0-1, where 1 = perfect sphere) - Major/minor axis lengths (nm) - Eccentricity - Solidity (area / convex area) - Equivalent diameter **Algorithm**: 1. Apply distance transform to ISG mask 2. Detect local maxima as seed points 3. Perform watershed segmentation to separate touching ISGs 4. Calculate morphological features for each instance 5. Optionally save results to CSV **Parameters**: - ``img_isg`` (np.ndarray): 3D binary ISG mask - ``min_distance`` (int, optional): Minimum distance between peaks for seed detection. Default: 5 - ``min_size`` (int, optional): Minimum connected component size (voxels). Default: 20 - ``save_csv`` (bool, optional): Whether to save results to CSV. Default: False - ``output_path`` (str, optional): Output CSV file path. Required if ``save_csv=True`` **Returns**: - ``df`` (pd.DataFrame): DataFrame containing morphological features for each ISG instance - ``labels`` (np.ndarray): 3D labeled mask with unique instance IDs **Example**: .. code-block:: python from ipa.analysis import extract_isg_features from ipa.data_loader import UniversalDataLoader # Load ISG mask from SXT data isg_mask = UniversalDataLoader.load_data("isg_segmentation.mrc") # Extract features features_df, labels = extract_isg_features( isg_mask, min_distance=5, min_size=20, save_csv=True, output_path="results/isg_morphology.csv" ) print(f"Found {len(features_df)} ISGs") print(f"Mean volume: {features_df['Vol (unit)'].mean():.3f} μm³") print(f"Mean sphericity: {features_df['Sphericity'].mean():.3f}") calculate_tubular_length ~~~~~~~~~~~~~~~~~~~~~~~~ .. autofunction:: ipa.analysis.calculate_tubular_length Calculates the total length of tubular organelles (e.g., F-actin, microtubules) from skeleton masks by summing distances between adjacent skeleton voxels. **Algorithm**: 1. Extract skeleton voxel coordinates from binary mask 2. Build KDTree for efficient nearest neighbor search 3. Find nearest neighbors for each voxel within a radius threshold 4. Sum unique connections (divided by 2 to avoid double counting) 5. Convert to physical units using voxel size **Parameters**: - ``skeleton_mask`` (np.ndarray): 3D binary skeleton mask - ``voxel_size`` (tuple, optional): Physical voxel size (Z, Y, X) in nm. Default: (1.0, 1.0, 1.0) - ``return_individual`` (bool, optional): Whether to return individual filament lengths. Default: False **Returns**: - If ``return_individual=False``: Total length (float, in nm) - If ``return_individual=True``: Tuple of (total_length, list_of_individual_lengths) **Biological Significance**: Tubular length is a key metric for cytoskeletal networks. Changes in F-actin or microtubule length reflect cellular remodeling during processes like glucose-stimulated insulin secretion (GSIS). **Example**: .. code-block:: python from ipa.analysis import calculate_tubular_length import json import numpy as np # Load actin coordinates from JSON (cryo-ET data) with open("actin_filled_points.json", 'r') as f: actin_data = json.load(f) # Reconstruct skeleton mask from coordinates coords = np.array([pt for filament in actin_data.values() for pt in filament]) skeleton_mask = np.zeros(volume_shape, dtype=np.uint8) for z, y, x in coords.astype(int): skeleton_mask[z, y, x] = 1 # Calculate length (cryo-ET voxel size: 1.34 nm) total_length, individual_lengths = calculate_tubular_length( skeleton_mask, voxel_size=(1.34, 1.34, 1.34), return_individual=True ) print(f"Total F-actin length: {total_length:.2f} nm") print(f"Number of filaments: {len(individual_lengths)}") print(f"Mean filament length: {np.mean(individual_lengths):.2f} nm") actin_to_actin_analysis ~~~~~~~~~~~~~~~~~~~~~~~ .. autofunction:: ipa.analysis.actin_to_actin_analysis Analyzes spatial relationships within actin filament networks, calculating shortest distances between filaments and generating statistical summaries. **Parameters**: - ``data_id`` (str): Dataset identifier for output files - ``mask_file`` (str): Vesicle mask file path (.mrc) - ``actin_file`` (str): Actin coordinates file (.json) - ``config`` (dict): Configuration dictionary with keys: - ``voxel_size_xyz`` (list): Voxel dimensions [nm] - ``shift_bias`` (list): Coordinate offset correction [nm] - ``visualization`` (bool): Enable visualization - ``output_dir`` (str): Output directory **Returns**: - ``results`` (dict): Dictionary containing: - ``distance_stats``: Distance statistics (mean, std, percentiles) - ``contact_sites``: List of contact point coordinates - ``visualization_path``: Path to saved figure (if enabled) **Example**: .. code-block:: python from ipa.analysis import actin_to_actin_analysis config = { 'voxel_size_xyz': [1.34, 1.34, 1.34], # Cryo-ET 'shift_bias': [0.0, 0.0, 0.0], 'visualization': True, 'output_dir': 'results/' } results = actin_to_actin_analysis( data_id="sample_01", mask_file="vesicle_mask.mrc", actin_file="actin_coords.json", config=config ) print(f"Mean inter-filament distance: {results['distance_stats']['mean']:.2f} nm") actin_angle_distance_pair_enhanced_analysis ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ .. autofunction:: ipa.analysis.actin_angle_distance_pair_enhanced_analysis Enhanced analysis of actin angle-distance pair relationships with advanced statistical measures. This function calculates both the distance from actin filaments to reference structures and the angular orientation relative to those structures. **Parameters**: - ``data_id`` (str): Dataset identifier - ``actin_file`` (str): Path to actin coordinates file (.json) - ``vesicle_file`` (str): Path to vesicle mask file (.mrc) - ``config`` (dict): Configuration dictionary **Returns**: - ``results`` (dict): Dictionary with enhanced analysis metrics including angle-distance correlations **Example**: .. code-block:: python from ipa.analysis import actin_angle_distance_pair_enhanced_analysis config = { 'voxel_size_xyz': [1.34, 1.34, 1.34], 'shift_bias': [0.0, 0.0, 0.0], 'visualization': True, 'output_dir': 'results/' } results = actin_angle_distance_pair_enhanced_analysis( data_id="sample_01", actin_file="actin_coords.json", vesicle_file="vesicle_mask.mrc", config=config ) Usage Examples -------------- Complete Morphology Workflow ~~~~~~~~~~~~~~~~~~~~~~~~~~~~ This example demonstrates extracting multiple morphological features from different organelle types: .. code-block:: python from ipa.analysis import extract_isg_features, calculate_tubular_length from ipa.data_loader import UniversalDataLoader import tifffile import json import numpy as np # 1. ISG Morphology (from SXT) print("=== ISG Morphology ===") isg_mask = UniversalDataLoader.load_data("isg_mask.mrc") isg_features, isg_labels = extract_isg_features( isg_mask, min_distance=5, min_size=20, save_csv=True, output_path="results/isg_features.csv" ) print(f"Total ISGs: {len(isg_features)}") print(f"Volume distribution: mean={isg_features['Vol (unit)'].mean():.3f}, " f"std={isg_features['Vol (unit)'].std():.3f}") # 2. F-actin Length (from cryo-ET) print("\n=== F-actin Length ===") with open("actin_points.json", 'r') as f: actin_data = json.load(f) # Reconstruct mask volume_shape = (100, 200, 200) coords = np.array([pt for filament in actin_data.values() for pt in filament]) actin_mask = np.zeros(volume_shape, dtype=np.uint8) for z, y, x in coords.astype(int): actin_mask[z, y, x] = 1 total_length, individual_lengths = calculate_tubular_length( actin_mask, voxel_size=(1.34, 1.34, 1.34), return_individual=True ) print(f"Total length: {total_length:.2f} nm") print(f"Filament count: {len(individual_lengths)}") # 3. Compare across conditions print("\n=== Condition Comparison ===") # Low glucose lg_features, _ = extract_isg_features(lg_isg_mask) # High glucose hg_features, _ = extract_isg_features(hg_isg_mask) print(f"LG mean volume: {lg_features['Vol (unit)'].mean():.3f} μm³") print(f"HG mean volume: {hg_features['Vol (unit)'].mean():.3f} μm³")