Skip to content

Commit 7a1395d

Browse files
committed
feature: refactor the tme_analysis folder and prototype the core functions
The tme_analysis module provides comprehensive analysis of tumor microenvironment (TME) interactions, with a primary focus on Tumor-Associated Collagen Signatures (TACS) classification for cancer prognosis. Module purpose: Analyze spatial interactions between cells, collagen fibers, and tumor boundaries to: Classify TACS-1/2/3 patterns (primary use case) Compute prognostic scores for clinical outcomes Quantify cell-fiber interactions Measure TME spatial organization Design Principles: Modular: Each component has clear responsibilities Extensible: Easy to add new detection methods Reusable: Integrates with existing cell/fiber modules Separation of Concerns: Detection → Measurement → Analysis Main module structure/functions: tme_analysis/ ├── config/ │ └── analysis_params.py # Configuration & data models ├── core/ │ ├── interaction_detector.py # 6 interaction detection methods │ ├── region_manager.py # Tumor detection & ROI management │ ├── measurement_engine.py # Feature computation │ └── tme_analyzer.py # Main coordinator ├── measurements/ │ ├── tacs_features.py # TACS-specific features │ └── spatial_features.py # Spatial relationships ├── io/ │ └── exporters.py # CSV, Excel, JSON export └── utils/ └── distance_utils.py # Spatial utilities
1 parent 9f55c91 commit 7a1395d

13 files changed

+2201
-0
lines changed
Lines changed: 54 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,54 @@
1+
"""
2+
Example 1: Cell-based fiber interaction analysis
3+
"""
4+
5+
from tme_quant.tme_analysis import TMEAnalyzer
6+
from tme_quant.tme_analysis.config import (
7+
TMEAnalysisParams,
8+
AnalysisMode,
9+
InteractionStrategy
10+
)
11+
from tme_quant.cell_analysis import CellAnalyzer
12+
from tme_quant.fiber_analysis import FiberAnalyzer
13+
14+
# Segment cells
15+
cell_analyzer = CellAnalyzer()
16+
cell_result = cell_analyzer.segment_cells_2d(cell_image, cell_seg_params)
17+
cells = [
18+
create_cell_object_from_segmentation(c, parent_id="region_1")
19+
for c in cell_result.cells
20+
]
21+
22+
# Extract fibers
23+
fiber_analyzer = FiberAnalyzer()
24+
fiber_result = fiber_analyzer.extract_fibers_2d(fiber_image, fiber_extract_params)
25+
fibers = [
26+
create_fiber_object_from_extraction(f, parent_id="region_1")
27+
for f in fiber_result.fibers
28+
]
29+
30+
# Configure cell-based analysis
31+
params = TMEAnalysisParams(
32+
mode=AnalysisMode.CELL_BASED,
33+
interaction_strategy=InteractionStrategy.RADIUS,
34+
cell_fiber_distance=50.0, # 50 micron radius around each cell
35+
compute_morphology=True,
36+
compute_spatial=True,
37+
compute_orientation=True
38+
)
39+
40+
# Run analysis
41+
tme_analyzer = TMEAnalyzer(verbose=True)
42+
result = tme_analyzer.analyze(
43+
cells=cells,
44+
fibers=fibers,
45+
params=params,
46+
analysis_id="cell_based_001"
47+
)
48+
49+
# Access results
50+
print(f"Found {len(result.interaction_pairs)} cell-fiber interactions")
51+
print(f"Mean distance: {result.spatial_features['mean_interaction_distance']:.2f} µm")
52+
53+
# Export
54+
tme_analyzer.export_results("output/cell_based/", formats=["csv", "json"])
Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
"""
2+
Example 3: Fiber-based cell guidance analysis
3+
"""
4+
5+
params = TMEAnalysisParams(
6+
mode=AnalysisMode.FIBER_BASED,
7+
interaction_strategy=InteractionStrategy.NEAREST, # Find nearest cell
8+
cell_fiber_distance=50.0,
9+
compute_orientation=True,
10+
compute_spatial=True
11+
)
12+
13+
result = tme_analyzer.analyze(
14+
cells=cells,
15+
fibers=fibers,
16+
params=params,
17+
analysis_id="fiber_guidance_001"
18+
)
19+
20+
# Analyze fiber alignment
21+
orientation = result.orientation_features
22+
23+
print(f"Fiber-cell alignment:")
24+
print(f" Parallel: {orientation['parallel_ratio']:.1%}")
25+
print(f" Perpendicular: {orientation['perpendicular_ratio']:.1%}")
26+
print(f" Coherence: {orientation['orientation_coherence']:.3f}")

src/tme_quant/src/examples/integration_of_tmeq_modules.py

Whitespace-only changes.
Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
"""
2+
Example 4: Analysis within custom user-defined ROIs
3+
"""
4+
5+
from shapely.geometry import box
6+
7+
# Define custom ROI (e.g., manually annotated region)
8+
custom_roi = box(100, 100, 500, 500) # Bounding box
9+
10+
custom_rois = [
11+
ROI.from_shapely(custom_roi, roi_id="invasive_front")
12+
]
13+
14+
params = TMEAnalysisParams(
15+
mode=AnalysisMode.ROI_BASED,
16+
interaction_distance=50.0,
17+
compute_tacs=False, # Not tumor-based
18+
compute_morphology=True,
19+
compute_density=True
20+
)
21+
22+
result = tme_analyzer.analyze(
23+
cells=cells,
24+
fibers=fibers,
25+
custom_rois=custom_rois,
26+
params=params,
27+
analysis_id="roi_custom_001"
28+
)
29+
30+
print(f"ROI Analysis:")
31+
print(f" Cell density: {result.density_features['cell_density']:.2f} cells/mm²")
32+
print(f" Fiber density: {result.density_features['fiber_density']:.2f} fibers/mm²")
Lines changed: 156 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,156 @@
1+
"""
2+
Example 2: Tumor-based TACS analysis - Complete workflow
3+
"""
4+
5+
from tme_quant.core.project import TMEProject
6+
from tme_quant.tme_analysis import TMEAnalyzer
7+
from tme_quant.tme_analysis.config import (
8+
TMEAnalysisParams,
9+
TumorDetectionParams,
10+
AnalysisMode,
11+
TumorDetectionMethod
12+
)
13+
14+
# Create project
15+
project = TMEProject(name="TACS_Study")
16+
17+
# Add image
18+
project.add_image(
19+
image_id="patient_001",
20+
image_path="data/patient_001.tif",
21+
channels={'nuclei': 0, 'collagen': 1},
22+
pixel_size=(0.5, 0.5)
23+
)
24+
25+
# Segment cells (using project integration)
26+
from tme_quant.cell_analysis import CellAnalyzer
27+
cell_analyzer = CellAnalyzer()
28+
cell_result = cell_analyzer.segment_cells_2d(
29+
cell_image, seg_params, image_id="patient_001"
30+
)
31+
32+
# Add cells to project
33+
for cell_props in cell_result.cells:
34+
cell_obj = create_cell_object_from_segmentation(
35+
cell_props, parent_id="patient_001"
36+
)
37+
project.add_object(cell_obj)
38+
39+
# Get cells from project
40+
cells = project.get_objects_by_type("cell")
41+
42+
# Detect tumor regions automatically
43+
tme_analyzer = TMEAnalyzer(verbose=True)
44+
45+
tumor_params = TumorDetectionParams(
46+
method=TumorDetectionMethod.CLUSTERING,
47+
dbscan_eps=100.0,
48+
dbscan_min_samples=10,
49+
min_tumor_area=1000.0,
50+
smooth_boundary=True
51+
)
52+
53+
tumor_regions = tme_analyzer.detect_tumor_regions(cells, tumor_params)
54+
55+
print(f"Detected {len(tumor_regions)} tumor regions")
56+
57+
# Add tumor regions to project
58+
for tumor in tumor_regions:
59+
project.add_object(tumor)
60+
61+
# Extract fibers
62+
fiber_result = project.extract_region_fibers(
63+
image_id="patient_001",
64+
region_id=tumor_regions[0].object_id,
65+
params=fiber_extract_params
66+
)
67+
68+
fibers = project.get_fibers_in_region(tumor_regions[0].object_id)
69+
70+
# Configure TACS analysis
71+
tacs_params = TMEAnalysisParams(
72+
mode=AnalysisMode.TUMOR_BASED,
73+
tumor_boundary_distance=100.0, # 100 µm boundary zone
74+
compute_tacs=True,
75+
compute_morphology=True,
76+
compute_spatial=True,
77+
compute_prognostic=True,
78+
generate_zones=True,
79+
invasive_margin_width=50.0,
80+
stroma_width=200.0
81+
)
82+
83+
# Run TACS analysis
84+
tacs_result = tme_analyzer.analyze(
85+
cells=cells,
86+
fibers=fibers,
87+
tumor_regions=tumor_regions,
88+
params=tacs_params,
89+
analysis_id="tacs_patient_001"
90+
)
91+
92+
# Access TACS features
93+
tacs = tacs_result.tacs_features
94+
95+
print("\n=== TACS Analysis Results ===")
96+
print(f"Total boundary fibers: {tacs['total_boundary_fibers']}")
97+
print(f"TACS-1 (Random): {tacs['tacs1_ratio']:.1%} ({tacs['tacs1_count']})")
98+
print(f"TACS-2 (Parallel): {tacs['tacs2_ratio']:.1%} ({tacs['tacs2_count']})")
99+
print(f"TACS-3 (Perpendicular): {tacs['tacs3_ratio']:.1%} ({tacs['tacs3_count']})")
100+
print(f"Dominant TACS: {tacs['dominant_tacs_type']}")
101+
102+
# Access prognostic scores
103+
prog = tacs_result.prognostic_scores
104+
105+
print("\n=== Prognostic Scores ===")
106+
print(f"Collagen Prognostic Score: {prog['collagen_prognostic_score']:.3f}")
107+
print(f"TACS-3 Prognostic: {prog['tacs3_prognostic']:.3f}")
108+
print(f"TME Interaction Score: {prog['tme_interaction_score']:.3f}")
109+
print(f"Invasive Potential: {prog['invasive_potential_score']:.3f}")
110+
print(f"Overall TME Risk: {prog['overall_tme_risk_score']:.3f}")
111+
112+
# Export results
113+
tme_analyzer.export_results(
114+
output_dir="output/tacs_analysis/",
115+
formats=["csv", "excel", "json"]
116+
)
117+
118+
# Visualize in Napari
119+
import napari
120+
121+
viewer = napari.Viewer()
122+
123+
# Add collagen image
124+
viewer.add_image(collagen_image, name='Collagen', colormap='gray')
125+
126+
# Add tumor boundary
127+
tumor_mask = tumor_regions[0].roi.get_mask(collagen_image.shape)
128+
viewer.add_labels(tumor_mask, name='Tumor Boundary')
129+
130+
# Add TACS-classified fibers
131+
tacs_colors = {
132+
'TACS-1': 'blue',
133+
'TACS-2': 'green',
134+
'TACS-3': 'red',
135+
}
136+
137+
fiber_shapes = []
138+
fiber_colors = []
139+
140+
for pair in tacs_result.interaction_pairs:
141+
if pair.target_type == "tumor_boundary":
142+
# Get fiber
143+
fiber = next(f for f in fibers if f.object_id == pair.source_id)
144+
145+
fiber_shapes.append(fiber.centerline)
146+
fiber_colors.append(tacs_colors.get(pair.interaction_type, 'gray'))
147+
148+
viewer.add_shapes(
149+
fiber_shapes,
150+
shape_type='path',
151+
edge_color=fiber_colors,
152+
edge_width=2,
153+
name='TACS Fibers'
154+
)
155+
156+
napari.run()

0 commit comments

Comments
 (0)