InterSCellar 0.1.0__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- interscellar/__init__.py +22 -0
- interscellar/api/__init__.py +14 -0
- interscellar/api/wrapper_2d.py +176 -0
- interscellar/api/wrapper_3d.py +632 -0
- interscellar/core/__init__.py +80 -0
- interscellar/core/compute_interscellar_volumes_3d.py +2221 -0
- interscellar/core/find_cell_neighbors_2d.py +997 -0
- interscellar/core/find_cell_neighbors_3d.py +1281 -0
- interscellar/visualization/__init__.py +7 -0
- interscellar/visualization/visualize_all_3d.py +177 -0
- interscellar/visualization/visualize_pair_3d.py +333 -0
- interscellar-0.1.0.dist-info/METADATA +136 -0
- interscellar-0.1.0.dist-info/RECORD +17 -0
- interscellar-0.1.0.dist-info/WHEEL +5 -0
- interscellar-0.1.0.dist-info/entry_points.txt +3 -0
- interscellar-0.1.0.dist-info/licenses/LICENSE +21 -0
- interscellar-0.1.0.dist-info/top_level.txt +1 -0
interscellar/__init__.py
ADDED
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
__version__ = "0.1.0"
|
|
2
|
+
|
|
3
|
+
from .api import (
|
|
4
|
+
find_cell_neighbors_2d,
|
|
5
|
+
find_cell_neighbors_3d,
|
|
6
|
+
compute_interscellar_volumes_3d,
|
|
7
|
+
compute_cell_only_volumes_3d
|
|
8
|
+
)
|
|
9
|
+
|
|
10
|
+
from .visualization import (
|
|
11
|
+
visualize_all_3d,
|
|
12
|
+
visualize_pair_3d
|
|
13
|
+
)
|
|
14
|
+
|
|
15
|
+
__all__ = [
|
|
16
|
+
"find_cell_neighbors_2d",
|
|
17
|
+
"find_cell_neighbors_3d",
|
|
18
|
+
"compute_interscellar_volumes_3d",
|
|
19
|
+
"compute_cell_only_volumes_3d",
|
|
20
|
+
"visualize_all_3d",
|
|
21
|
+
"visualize_pair_3d",
|
|
22
|
+
]
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
from .wrapper_2d import find_cell_neighbors_2d
|
|
2
|
+
from .wrapper_3d import (
|
|
3
|
+
find_cell_neighbors_3d,
|
|
4
|
+
compute_interscellar_volumes_3d,
|
|
5
|
+
compute_cell_only_volumes_3d
|
|
6
|
+
)
|
|
7
|
+
|
|
8
|
+
__all__ = [
|
|
9
|
+
"find_cell_neighbors_2d",
|
|
10
|
+
"find_cell_neighbors_3d",
|
|
11
|
+
"compute_interscellar_volumes_3d",
|
|
12
|
+
"compute_cell_only_volumes_3d",
|
|
13
|
+
]
|
|
14
|
+
|
|
@@ -0,0 +1,176 @@
|
|
|
1
|
+
# Import
|
|
2
|
+
|
|
3
|
+
import pandas as pd
|
|
4
|
+
import numpy as np
|
|
5
|
+
from typing import Optional, Tuple
|
|
6
|
+
from tqdm import tqdm
|
|
7
|
+
import time
|
|
8
|
+
import os
|
|
9
|
+
|
|
10
|
+
from ..core.find_cell_neighbors_2d import (
|
|
11
|
+
create_neighbor_edge_table_database_2d,
|
|
12
|
+
find_all_neighbors_by_surface_distance_2d,
|
|
13
|
+
get_cells_dataframe,
|
|
14
|
+
query_cell_type_pairs,
|
|
15
|
+
get_graph_statistics,
|
|
16
|
+
export_to_anndata,
|
|
17
|
+
export_graph_tables,
|
|
18
|
+
build_global_mask_2d,
|
|
19
|
+
build_global_mask_2d_with_mapping
|
|
20
|
+
)
|
|
21
|
+
|
|
22
|
+
try:
|
|
23
|
+
import anndata as ad
|
|
24
|
+
ANNDATA_AVAILABLE = True
|
|
25
|
+
except ImportError:
|
|
26
|
+
ANNDATA_AVAILABLE = False
|
|
27
|
+
|
|
28
|
+
# API: Wrapper functions
|
|
29
|
+
|
|
30
|
+
def find_cell_neighbors_2d(
|
|
31
|
+
polygon_json_path: str,
|
|
32
|
+
metadata_csv_path: str,
|
|
33
|
+
max_distance_um: float = 1.0,
|
|
34
|
+
pixel_size_um: float = 0.1085,
|
|
35
|
+
centroid_prefilter_radius_um: float = 75.0,
|
|
36
|
+
cell_id: str = 'cell_id',
|
|
37
|
+
cell_type: str = 'subclass',
|
|
38
|
+
centroid_x: str = 'X',
|
|
39
|
+
centroid_y: str = 'Y',
|
|
40
|
+
db_path: Optional[str] = None,
|
|
41
|
+
output_csv: Optional[str] = None,
|
|
42
|
+
output_anndata: Optional[str] = None,
|
|
43
|
+
n_jobs: int = 1,
|
|
44
|
+
return_connection: bool = False,
|
|
45
|
+
save_surfaces_pickle: Optional[str] = None,
|
|
46
|
+
load_surfaces_pickle: Optional[str] = None,
|
|
47
|
+
save_graph_state_pickle: Optional[str] = None
|
|
48
|
+
) -> Tuple[Optional[pd.DataFrame], Optional[object], Optional[object]]:
|
|
49
|
+
|
|
50
|
+
print("=" * 60)
|
|
51
|
+
print("InterSCellar: Surface-based Cell Neighbor Detection - 2D")
|
|
52
|
+
print("=" * 60)
|
|
53
|
+
|
|
54
|
+
overall_start_time = time.time()
|
|
55
|
+
|
|
56
|
+
print(f"\n1. Loading metadata from: {metadata_csv_path}...")
|
|
57
|
+
step1_start = time.time()
|
|
58
|
+
try:
|
|
59
|
+
metadata_df = pd.read_csv(metadata_csv_path)
|
|
60
|
+
print(f"Loaded {len(metadata_df)} cells")
|
|
61
|
+
except Exception as e:
|
|
62
|
+
raise ValueError(f"Error loading metadata CSV: {e}")
|
|
63
|
+
|
|
64
|
+
required_cols = [cell_id, cell_type, centroid_x, centroid_y]
|
|
65
|
+
missing_cols = [col for col in required_cols if col not in metadata_df.columns]
|
|
66
|
+
if missing_cols:
|
|
67
|
+
raise ValueError(f"Missing required columns in metadata: {missing_cols}")
|
|
68
|
+
|
|
69
|
+
step1_time = time.time() - step1_start
|
|
70
|
+
print(f"Step 1 completed in {step1_time:.2f} seconds")
|
|
71
|
+
|
|
72
|
+
metadata_dir = os.path.dirname(metadata_csv_path) if os.path.dirname(metadata_csv_path) else "."
|
|
73
|
+
base_name = os.path.splitext(os.path.basename(metadata_csv_path))[0]
|
|
74
|
+
|
|
75
|
+
if db_path is None:
|
|
76
|
+
db_path = os.path.join(metadata_dir, f"{base_name}_neighbor_graph_2d.db")
|
|
77
|
+
print(f"db_path: {db_path}")
|
|
78
|
+
|
|
79
|
+
if output_csv is None:
|
|
80
|
+
output_csv = os.path.join(metadata_dir, f"{base_name}_neighbors_2d.csv")
|
|
81
|
+
print(f"output_csv: {output_csv}")
|
|
82
|
+
|
|
83
|
+
if output_anndata is None:
|
|
84
|
+
output_anndata = os.path.join(metadata_dir, f"{base_name}_neighbors_2d.h5ad")
|
|
85
|
+
print(f"output_anndata: {output_anndata}")
|
|
86
|
+
|
|
87
|
+
print(f"\n2. Validating input file: {polygon_json_path}...")
|
|
88
|
+
step2_start = time.time()
|
|
89
|
+
if not os.path.exists(polygon_json_path):
|
|
90
|
+
raise FileNotFoundError(f"JSON file not found: {polygon_json_path}")
|
|
91
|
+
print(f"JSON file found")
|
|
92
|
+
step2_time = time.time() - step2_start
|
|
93
|
+
print(f"Step 2 completed in {step2_time:.2f} seconds")
|
|
94
|
+
|
|
95
|
+
print(f"\n3. Building neighbor graph...")
|
|
96
|
+
print(f"Parameters: max_distance={max_distance_um}μm, n_jobs={n_jobs}")
|
|
97
|
+
if max_distance_um == 0.0:
|
|
98
|
+
print(f"Mode: Touching cells only")
|
|
99
|
+
else:
|
|
100
|
+
print(f"Mode: Touching cells + near-neighbors")
|
|
101
|
+
|
|
102
|
+
step3_start = time.time()
|
|
103
|
+
|
|
104
|
+
try:
|
|
105
|
+
conn = create_neighbor_edge_table_database_2d(
|
|
106
|
+
polygon_json_path=polygon_json_path,
|
|
107
|
+
metadata_df=metadata_df,
|
|
108
|
+
max_distance_um=max_distance_um,
|
|
109
|
+
pixel_size_um=pixel_size_um,
|
|
110
|
+
centroid_prefilter_radius_um=centroid_prefilter_radius_um,
|
|
111
|
+
db_path=db_path,
|
|
112
|
+
cell_id=cell_id,
|
|
113
|
+
cell_type=cell_type,
|
|
114
|
+
centroid_x=centroid_x,
|
|
115
|
+
centroid_y=centroid_y,
|
|
116
|
+
output_csv=output_csv,
|
|
117
|
+
output_anndata=output_anndata,
|
|
118
|
+
n_jobs=n_jobs,
|
|
119
|
+
save_surfaces_pickle=save_surfaces_pickle,
|
|
120
|
+
load_surfaces_pickle=load_surfaces_pickle,
|
|
121
|
+
save_graph_state_pickle=save_graph_state_pickle
|
|
122
|
+
)
|
|
123
|
+
|
|
124
|
+
step3_time = time.time() - step3_start
|
|
125
|
+
print(f"Neighbor graph created successfully")
|
|
126
|
+
print(f"Step 3 completed in {step3_time:.2f} seconds")
|
|
127
|
+
except Exception as e:
|
|
128
|
+
raise RuntimeError(f"Error in neighbor detection pipeline: {e}")
|
|
129
|
+
|
|
130
|
+
print(f"\n4. Retrieving results...")
|
|
131
|
+
step4_start = time.time()
|
|
132
|
+
|
|
133
|
+
neighbor_table_df = None
|
|
134
|
+
if output_csv:
|
|
135
|
+
try:
|
|
136
|
+
neighbor_table_df = pd.read_sql_query("SELECT * FROM neighbors", conn)
|
|
137
|
+
print(f"Neighbor table: {len(neighbor_table_df)} pairs")
|
|
138
|
+
except Exception as e:
|
|
139
|
+
print(f"Warning: Could not retrieve neighbor table: {e}")
|
|
140
|
+
|
|
141
|
+
adata = None
|
|
142
|
+
if output_anndata:
|
|
143
|
+
try:
|
|
144
|
+
if ANNDATA_AVAILABLE:
|
|
145
|
+
adata = ad.read_h5ad(output_anndata)
|
|
146
|
+
print(f"AnnData object loaded: {adata.shape}")
|
|
147
|
+
else:
|
|
148
|
+
print(f"Warning: AnnData not available (install with: pip install anndata)")
|
|
149
|
+
except Exception as e:
|
|
150
|
+
print(f"Warning: Could not load AnnData object: {e}")
|
|
151
|
+
|
|
152
|
+
try:
|
|
153
|
+
stats = get_graph_statistics(conn)
|
|
154
|
+
print(f"Graph statistics: {stats['total_cells']} cells, {stats['total_edges']} pairs")
|
|
155
|
+
except Exception as e:
|
|
156
|
+
print(f"Warning: Could not retrieve statistics: {e}")
|
|
157
|
+
|
|
158
|
+
step4_time = time.time() - step4_start
|
|
159
|
+
print(f"Step 4 completed in {step4_time:.2f} seconds")
|
|
160
|
+
|
|
161
|
+
overall_time = time.time() - overall_start_time
|
|
162
|
+
print(f"\n5. Pipeline completed successfully!")
|
|
163
|
+
print(f"Total execution time: {overall_time:.2f} seconds")
|
|
164
|
+
print(f"Database: {db_path}")
|
|
165
|
+
if output_csv:
|
|
166
|
+
print(f"CSV output: {output_csv}")
|
|
167
|
+
if output_anndata:
|
|
168
|
+
print(f"AnnData output: {output_anndata}")
|
|
169
|
+
|
|
170
|
+
print("=" * 60)
|
|
171
|
+
|
|
172
|
+
if return_connection:
|
|
173
|
+
return neighbor_table_df, adata, conn
|
|
174
|
+
else:
|
|
175
|
+
conn.close()
|
|
176
|
+
return neighbor_table_df, adata, None
|