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.
@@ -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