canns 0.13.1__py3-none-any.whl → 0.14.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.
Files changed (99) hide show
  1. canns/analyzer/data/__init__.py +5 -1
  2. canns/analyzer/data/asa/__init__.py +27 -12
  3. canns/analyzer/data/asa/cohospace.py +336 -10
  4. canns/analyzer/data/asa/config.py +3 -0
  5. canns/analyzer/data/asa/embedding.py +48 -45
  6. canns/analyzer/data/asa/path.py +104 -2
  7. canns/analyzer/data/asa/plotting.py +88 -19
  8. canns/analyzer/data/asa/tda.py +11 -4
  9. canns/analyzer/data/cell_classification/__init__.py +97 -0
  10. canns/analyzer/data/cell_classification/core/__init__.py +26 -0
  11. canns/analyzer/data/cell_classification/core/grid_cells.py +633 -0
  12. canns/analyzer/data/cell_classification/core/grid_modules_leiden.py +288 -0
  13. canns/analyzer/data/cell_classification/core/head_direction.py +347 -0
  14. canns/analyzer/data/cell_classification/core/spatial_analysis.py +431 -0
  15. canns/analyzer/data/cell_classification/io/__init__.py +5 -0
  16. canns/analyzer/data/cell_classification/io/matlab_loader.py +417 -0
  17. canns/analyzer/data/cell_classification/utils/__init__.py +39 -0
  18. canns/analyzer/data/cell_classification/utils/circular_stats.py +383 -0
  19. canns/analyzer/data/cell_classification/utils/correlation.py +318 -0
  20. canns/analyzer/data/cell_classification/utils/geometry.py +442 -0
  21. canns/analyzer/data/cell_classification/utils/image_processing.py +416 -0
  22. canns/analyzer/data/cell_classification/visualization/__init__.py +19 -0
  23. canns/analyzer/data/cell_classification/visualization/grid_plots.py +292 -0
  24. canns/analyzer/data/cell_classification/visualization/hd_plots.py +200 -0
  25. canns/analyzer/metrics/__init__.py +2 -1
  26. canns/analyzer/visualization/core/config.py +46 -4
  27. canns/data/__init__.py +6 -1
  28. canns/data/datasets.py +154 -1
  29. canns/data/loaders.py +37 -0
  30. canns/pipeline/__init__.py +13 -9
  31. canns/pipeline/__main__.py +6 -0
  32. canns/pipeline/asa/runner.py +105 -41
  33. canns/pipeline/asa_gui/__init__.py +68 -0
  34. canns/pipeline/asa_gui/__main__.py +6 -0
  35. canns/pipeline/asa_gui/analysis_modes/__init__.py +42 -0
  36. canns/pipeline/asa_gui/analysis_modes/base.py +39 -0
  37. canns/pipeline/asa_gui/analysis_modes/batch_mode.py +21 -0
  38. canns/pipeline/asa_gui/analysis_modes/cohomap_mode.py +56 -0
  39. canns/pipeline/asa_gui/analysis_modes/cohospace_mode.py +194 -0
  40. canns/pipeline/asa_gui/analysis_modes/decode_mode.py +52 -0
  41. canns/pipeline/asa_gui/analysis_modes/fr_mode.py +81 -0
  42. canns/pipeline/asa_gui/analysis_modes/frm_mode.py +92 -0
  43. canns/pipeline/asa_gui/analysis_modes/gridscore_mode.py +123 -0
  44. canns/pipeline/asa_gui/analysis_modes/pathcompare_mode.py +199 -0
  45. canns/pipeline/asa_gui/analysis_modes/tda_mode.py +112 -0
  46. canns/pipeline/asa_gui/app.py +29 -0
  47. canns/pipeline/asa_gui/controllers/__init__.py +6 -0
  48. canns/pipeline/asa_gui/controllers/analysis_controller.py +59 -0
  49. canns/pipeline/asa_gui/controllers/preprocess_controller.py +89 -0
  50. canns/pipeline/asa_gui/core/__init__.py +15 -0
  51. canns/pipeline/asa_gui/core/cache.py +14 -0
  52. canns/pipeline/asa_gui/core/runner.py +1936 -0
  53. canns/pipeline/asa_gui/core/state.py +324 -0
  54. canns/pipeline/asa_gui/core/worker.py +260 -0
  55. canns/pipeline/asa_gui/main_window.py +184 -0
  56. canns/pipeline/asa_gui/models/__init__.py +7 -0
  57. canns/pipeline/asa_gui/models/config.py +14 -0
  58. canns/pipeline/asa_gui/models/job.py +31 -0
  59. canns/pipeline/asa_gui/models/presets.py +21 -0
  60. canns/pipeline/asa_gui/resources/__init__.py +16 -0
  61. canns/pipeline/asa_gui/resources/dark.qss +167 -0
  62. canns/pipeline/asa_gui/resources/light.qss +163 -0
  63. canns/pipeline/asa_gui/resources/styles.qss +130 -0
  64. canns/pipeline/asa_gui/utils/__init__.py +1 -0
  65. canns/pipeline/asa_gui/utils/formatters.py +15 -0
  66. canns/pipeline/asa_gui/utils/io_adapters.py +40 -0
  67. canns/pipeline/asa_gui/utils/validators.py +41 -0
  68. canns/pipeline/asa_gui/views/__init__.py +1 -0
  69. canns/pipeline/asa_gui/views/help_content.py +171 -0
  70. canns/pipeline/asa_gui/views/pages/__init__.py +6 -0
  71. canns/pipeline/asa_gui/views/pages/analysis_page.py +565 -0
  72. canns/pipeline/asa_gui/views/pages/preprocess_page.py +492 -0
  73. canns/pipeline/asa_gui/views/panels/__init__.py +1 -0
  74. canns/pipeline/asa_gui/views/widgets/__init__.py +21 -0
  75. canns/pipeline/asa_gui/views/widgets/artifacts_tab.py +44 -0
  76. canns/pipeline/asa_gui/views/widgets/drop_zone.py +80 -0
  77. canns/pipeline/asa_gui/views/widgets/file_list.py +27 -0
  78. canns/pipeline/asa_gui/views/widgets/gridscore_tab.py +308 -0
  79. canns/pipeline/asa_gui/views/widgets/help_dialog.py +27 -0
  80. canns/pipeline/asa_gui/views/widgets/image_tab.py +50 -0
  81. canns/pipeline/asa_gui/views/widgets/image_viewer.py +97 -0
  82. canns/pipeline/asa_gui/views/widgets/log_box.py +16 -0
  83. canns/pipeline/asa_gui/views/widgets/pathcompare_tab.py +200 -0
  84. canns/pipeline/asa_gui/views/widgets/popup_combo.py +25 -0
  85. canns/pipeline/gallery/__init__.py +15 -5
  86. canns/pipeline/gallery/__main__.py +11 -0
  87. canns/pipeline/gallery/app.py +705 -0
  88. canns/pipeline/gallery/runner.py +790 -0
  89. canns/pipeline/gallery/state.py +51 -0
  90. canns/pipeline/gallery/styles.tcss +123 -0
  91. canns/pipeline/launcher.py +81 -0
  92. {canns-0.13.1.dist-info → canns-0.14.0.dist-info}/METADATA +11 -1
  93. canns-0.14.0.dist-info/RECORD +163 -0
  94. canns-0.14.0.dist-info/entry_points.txt +5 -0
  95. canns/pipeline/_base.py +0 -50
  96. canns-0.13.1.dist-info/RECORD +0 -89
  97. canns-0.13.1.dist-info/entry_points.txt +0 -3
  98. {canns-0.13.1.dist-info → canns-0.14.0.dist-info}/WHEEL +0 -0
  99. {canns-0.13.1.dist-info → canns-0.14.0.dist-info}/licenses/LICENSE +0 -0
@@ -216,7 +216,31 @@ def interp_coords_to_full(idx_map: np.ndarray, coords2: np.ndarray, T_full: int)
216
216
  return np.mod(out, 2 * np.pi)
217
217
 
218
218
 
219
- def align_coords_to_position(
219
+ def interp_coords_to_full_1d(idx_map: np.ndarray, coords1: np.ndarray, T_full: int) -> np.ndarray:
220
+ """Interpolate (K,) circular coords back to full length (T_full,1)."""
221
+ idx_map = np.asarray(idx_map).astype(int).ravel()
222
+ coords1 = np.asarray(coords1, float)
223
+ if coords1.ndim == 2 and coords1.shape[1] == 1:
224
+ coords1 = coords1[:, 0]
225
+ if coords1.ndim != 1:
226
+ raise ValueError(f"coords1 must have shape (K,) or (K,1), got {coords1.shape}")
227
+
228
+ order = np.argsort(idx_map)
229
+ idx_map = idx_map[order]
230
+ coords1 = coords1[order]
231
+
232
+ uniq_idx, uniq_pos = np.unique(idx_map, return_index=True)
233
+ coords1 = coords1[uniq_pos]
234
+ idx_map = uniq_idx
235
+
236
+ ang = np.unwrap(coords1)
237
+ full_i = np.arange(T_full, dtype=float)
238
+ out = np.interp(full_i, idx_map.astype(float), ang)
239
+
240
+ return np.mod(out, 2 * np.pi)[:, None]
241
+
242
+
243
+ def align_coords_to_position_2d(
220
244
  t_full: np.ndarray,
221
245
  x_full: np.ndarray,
222
246
  y_full: np.ndarray,
@@ -248,7 +272,7 @@ def align_coords_to_position(
248
272
 
249
273
  Examples
250
274
  --------
251
- >>> t, x, y, coords2, tag = align_coords_to_position( # doctest: +SKIP
275
+ >>> t, x, y, coords2, tag = align_coords_to_position_2d( # doctest: +SKIP
252
276
  ... t_full, x_full, y_full, coords2,
253
277
  ... use_box=True, times_box=decoding["times_box"], interp_to_full=True
254
278
  ... )
@@ -320,6 +344,84 @@ def align_coords_to_position(
320
344
  )
321
345
 
322
346
 
347
+ def align_coords_to_position_1d(
348
+ t_full: np.ndarray,
349
+ x_full: np.ndarray,
350
+ y_full: np.ndarray,
351
+ coords1: np.ndarray,
352
+ use_box: bool,
353
+ times_box: np.ndarray | None,
354
+ interp_to_full: bool,
355
+ ) -> tuple[np.ndarray, np.ndarray, np.ndarray, np.ndarray, str]:
356
+ """Align 1D decoded coordinates to the original (x, y, t) trajectory."""
357
+ t_full = np.asarray(t_full).ravel()
358
+ x_full = np.asarray(x_full).ravel()
359
+ y_full = np.asarray(y_full).ravel()
360
+ coords1 = np.asarray(coords1, float)
361
+ if coords1.ndim == 2 and coords1.shape[1] == 1:
362
+ coords1 = coords1[:, 0]
363
+ if coords1.ndim != 1:
364
+ raise ValueError(f"coords1 must have shape (T,) or (T,1), got {coords1.shape}")
365
+
366
+ T_full = len(t_full)
367
+
368
+ if not use_box:
369
+ if len(coords1) != T_full:
370
+ raise ValueError(
371
+ f"coords length {len(coords1)} != t length {T_full} "
372
+ f"(set --use-box if you have times_box)"
373
+ )
374
+ return t_full, x_full, y_full, coords1[:, None], "full(no-box)"
375
+
376
+ if times_box is None:
377
+ if len(coords1) == T_full:
378
+ return (
379
+ t_full,
380
+ x_full,
381
+ y_full,
382
+ coords1[:, None],
383
+ "full(use-box but no times_box; treated as full)",
384
+ )
385
+ raise KeyError("use_box=True but times_box not found, and coords is not full-length.")
386
+
387
+ idx_map, kind = parse_times_box_to_indices(times_box, t_full)
388
+
389
+ if len(coords1) == T_full and len(idx_map) == T_full:
390
+ return (
391
+ t_full,
392
+ x_full,
393
+ y_full,
394
+ coords1[:, None],
395
+ f"full(coords already full; times_box kind={kind} ignored)",
396
+ )
397
+
398
+ if len(idx_map) != len(coords1):
399
+ raise ValueError(f"times_box length {len(idx_map)} != coords length {len(coords1)}")
400
+
401
+ order = np.argsort(idx_map)
402
+ idx_map = idx_map[order]
403
+ coords1 = coords1[order]
404
+
405
+ if interp_to_full:
406
+ coords_full = interp_coords_to_full_1d(idx_map, coords1, T_full)
407
+ return (
408
+ t_full,
409
+ x_full,
410
+ y_full,
411
+ coords_full,
412
+ f"interp_to_full(times_box kind={kind}, K={len(idx_map)})",
413
+ )
414
+
415
+ idx_map = np.clip(idx_map, 0, T_full - 1)
416
+ return (
417
+ t_full[idx_map],
418
+ x_full[idx_map],
419
+ y_full[idx_map],
420
+ coords1[:, None],
421
+ f"subset(times_box kind={kind}, K={len(idx_map)})",
422
+ )
423
+
424
+
323
425
  def snake_wrap_trail_in_parallelogram(
324
426
  xy_base: np.ndarray, e1: np.ndarray, e2: np.ndarray
325
427
  ) -> np.ndarray:
@@ -237,7 +237,7 @@ def plot_projection(
237
237
  return fig
238
238
 
239
239
 
240
- def plot_path_compare(
240
+ def plot_path_compare_2d(
241
241
  x: np.ndarray,
242
242
  y: np.ndarray,
243
243
  coords: np.ndarray,
@@ -248,14 +248,14 @@ def plot_path_compare(
248
248
  show: bool = True,
249
249
  save_path: str | None = None,
250
250
  ) -> tuple[plt.Figure, np.ndarray]:
251
- """Plot physical path vs decoded coho-space path side-by-side.
251
+ """Plot physical path vs decoded coho-space path (2D) side-by-side.
252
252
 
253
253
  Parameters
254
254
  ----------
255
255
  x, y : np.ndarray
256
256
  Physical position arrays of shape (T,).
257
257
  coords : np.ndarray
258
- Decoded circular coordinates, shape (T, 1) or (T, 2).
258
+ Decoded circular coordinates, shape (T, 2) or (T, 2+).
259
259
  config : PlotConfig, optional
260
260
  Plot configuration. If None, a default config is created.
261
261
  title, figsize, show, save_path : optional
@@ -268,7 +268,7 @@ def plot_path_compare(
268
268
 
269
269
  Examples
270
270
  --------
271
- >>> fig, axes = plot_path_compare(x, y, coords, show=False) # doctest: +SKIP
271
+ >>> fig, axes = plot_path_compare_2d(x, y, coords, show=False) # doctest: +SKIP
272
272
  """
273
273
  from .path import draw_base_parallelogram, skew_transform, snake_wrap_trail_in_parallelogram
274
274
 
@@ -276,8 +276,8 @@ def plot_path_compare(
276
276
  y = np.asarray(y).ravel()
277
277
  coords = np.asarray(coords)
278
278
 
279
- if coords.ndim != 2 or coords.shape[1] < 1:
280
- raise ValueError(f"coords must be 2D with at least 1 column, got {coords.shape}")
279
+ if coords.ndim != 2 or coords.shape[1] < 2:
280
+ raise ValueError(f"coords must be 2D with at least 2 columns, got {coords.shape}")
281
281
 
282
282
  config = _ensure_plot_config(
283
283
  config,
@@ -314,19 +314,88 @@ def plot_path_compare(
314
314
  ax1.set_aspect("equal", "box")
315
315
  ax1.axis("off")
316
316
 
317
- if coords.shape[1] >= 2:
318
- theta2 = coords[:, :2] % (2 * np.pi)
319
- xy = skew_transform(theta2)
320
- draw_base_parallelogram(ax1)
321
- trail = snake_wrap_trail_in_parallelogram(
322
- xy, np.array([2 * np.pi, 0.0]), np.array([np.pi, np.sqrt(3) * np.pi])
323
- )
324
- ax1.plot(trail[:, 0], trail[:, 1], lw=0.9, alpha=0.9)
325
- else:
326
- th = coords[:, 0] % (2 * np.pi)
327
- ax1.plot(np.cos(th), np.sin(th), lw=0.9, alpha=0.9)
328
- ax1.set_xlim(-1.2, 1.2)
329
- ax1.set_ylim(-1.2, 1.2)
317
+ theta2 = coords[:, :2] % (2 * np.pi)
318
+ xy = skew_transform(theta2)
319
+ draw_base_parallelogram(ax1)
320
+ trail = snake_wrap_trail_in_parallelogram(
321
+ xy, np.array([2 * np.pi, 0.0]), np.array([np.pi, np.sqrt(3) * np.pi])
322
+ )
323
+ ax1.plot(trail[:, 0], trail[:, 1], lw=0.9, alpha=0.9)
324
+
325
+ fig.tight_layout()
326
+ _ensure_parent_dir(config.save_path)
327
+ finalize_figure(fig, config)
328
+ return fig, axes
329
+
330
+
331
+ def plot_path_compare_1d(
332
+ x: np.ndarray,
333
+ y: np.ndarray,
334
+ coords: np.ndarray,
335
+ config: PlotConfig | None = None,
336
+ *,
337
+ title: str = "Path Compare (1D)",
338
+ figsize: tuple[int, int] = (12, 5),
339
+ show: bool = True,
340
+ save_path: str | None = None,
341
+ ) -> tuple[plt.Figure, np.ndarray]:
342
+ """Plot physical path vs decoded coho-space path (1D) side-by-side."""
343
+ x = np.asarray(x).ravel()
344
+ y = np.asarray(y).ravel()
345
+ coords = np.asarray(coords)
346
+ if coords.ndim == 2 and coords.shape[1] == 1:
347
+ coords = coords[:, 0]
348
+ if coords.ndim != 1:
349
+ raise ValueError(f"coords must have shape (T,) or (T, 1), got {coords.shape}")
350
+
351
+ config = _ensure_plot_config(
352
+ config,
353
+ PlotConfig.for_static_plot,
354
+ title=title,
355
+ figsize=figsize,
356
+ save_path=save_path,
357
+ show=show,
358
+ )
359
+
360
+ fig, axes = plt.subplots(1, 2, figsize=config.figsize)
361
+ if config.title:
362
+ fig.suptitle(config.title)
363
+
364
+ ax0 = axes[0]
365
+ ax0.set_title("Physical path (x,y)")
366
+ ax0.set_aspect("equal", "box")
367
+ ax0.plot(x, y, lw=0.9, alpha=0.8)
368
+ ax0.set_xticks([])
369
+ ax0.set_yticks([])
370
+ for spine in ax0.spines.values():
371
+ spine.set_visible(True)
372
+ x_min, x_max = np.min(x), np.max(x)
373
+ y_min, y_max = np.min(y), np.max(y)
374
+ pad_x = (x_max - x_min) * 0.03 if x_max > x_min else 1.0
375
+ pad_y = (y_max - y_min) * 0.03 if y_max > y_min else 1.0
376
+ ax0.set_xlim(x_min - pad_x, x_max + pad_x)
377
+ ax0.set_ylim(y_min - pad_y, y_max + pad_y)
378
+
379
+ ax1 = axes[1]
380
+ ax1.set_title("Decoded coho path (1D)")
381
+ ax1.set_aspect("equal", "box")
382
+ ax1.axis("off")
383
+
384
+ theta = coords % (2 * np.pi)
385
+ x_unit = np.cos(theta)
386
+ y_unit = np.sin(theta)
387
+ sc = ax1.scatter(
388
+ x_unit,
389
+ y_unit,
390
+ c=np.arange(len(theta)),
391
+ cmap="viridis",
392
+ s=4,
393
+ alpha=0.8,
394
+ )
395
+ cbar = plt.colorbar(sc, ax=ax1, fraction=0.046, pad=0.04)
396
+ cbar.set_label("Time")
397
+ ax1.set_xlim(-1.2, 1.2)
398
+ ax1.set_ylim(-1.2, 1.2)
330
399
 
331
400
  fig.tight_layout()
332
401
  _ensure_parent_dir(config.save_path)
@@ -41,7 +41,7 @@ def tda_vis(embed_data: np.ndarray, config: TDAConfig | None = None, **kwargs) -
41
41
  **kwargs : Any
42
42
  Legacy keyword parameters (``dim``, ``num_times``, ``active_times``, ``k``,
43
43
  ``n_points``, ``metric``, ``nbs``, ``maxdim``, ``coeff``, ``show``,
44
- ``do_shuffle``, ``num_shuffles``, ``progress_bar``).
44
+ ``do_shuffle``, ``num_shuffles``, ``progress_bar``, ``standardize``).
45
45
 
46
46
  Returns
47
47
  -------
@@ -77,6 +77,7 @@ def tda_vis(embed_data: np.ndarray, config: TDAConfig | None = None, **kwargs) -
77
77
  do_shuffle=kwargs.get("do_shuffle", False),
78
78
  num_shuffles=kwargs.get("num_shuffles", 1000),
79
79
  progress_bar=kwargs.get("progress_bar", True),
80
+ standardize=kwargs.get("standardize", True),
80
81
  )
81
82
 
82
83
  try:
@@ -120,7 +121,7 @@ def _compute_real_persistence(embed_data: np.ndarray, config: TDAConfig) -> dict
120
121
 
121
122
  # Step 3: PCA dimensionality reduction
122
123
  logging.info("Step 3/5: PCA dimensionality reduction")
123
- dimred = _apply_pca_reduction(embed_data, movetimes, config.dim)
124
+ dimred = _apply_pca_reduction(embed_data, movetimes, config.dim, config.standardize)
124
125
 
125
126
  # Step 4: Point cloud sampling (denoising)
126
127
  logging.info("Step 4/5: Point cloud denoising")
@@ -156,9 +157,15 @@ def _select_active_timepoints(
156
157
  return times_cube[movetimes]
157
158
 
158
159
 
159
- def _apply_pca_reduction(embed_data: np.ndarray, movetimes: np.ndarray, dim: int) -> np.ndarray:
160
+ def _apply_pca_reduction(
161
+ embed_data: np.ndarray, movetimes: np.ndarray, dim: int, standardize: bool
162
+ ) -> np.ndarray:
160
163
  """Apply PCA dimensionality reduction."""
161
- scaled_data = preprocessing.scale(embed_data[movetimes, :])
164
+ subset = embed_data[movetimes, :]
165
+ if standardize:
166
+ scaled_data = preprocessing.scale(subset)
167
+ else:
168
+ scaled_data = np.asarray(subset, dtype=np.float32)
162
169
  dimred, *_ = _pca(scaled_data, dim=dim)
163
170
  return dimred
164
171
 
@@ -0,0 +1,97 @@
1
+ """
2
+ Cell Classification Package
3
+
4
+ Python implementation of grid cell and head direction cell classification algorithms.
5
+
6
+ Based on the MATLAB code from:
7
+ Vollan, Gardner, Moser & Moser (Nature, 2025)
8
+ "Left-right-alternating sweeps in entorhinal-hippocampal maps of space"
9
+ """
10
+
11
+ __version__ = "0.1.0"
12
+
13
+ from .core import ( # noqa: F401
14
+ GridnessAnalyzer,
15
+ GridnessResult,
16
+ HDCellResult,
17
+ HeadDirectionAnalyzer,
18
+ compute_2d_autocorrelation,
19
+ compute_field_statistics,
20
+ compute_grid_spacing,
21
+ compute_rate_map,
22
+ compute_rate_map_from_binned,
23
+ compute_spatial_information,
24
+ identify_grid_modules_and_stats,
25
+ )
26
+ from .io import MATFileLoader, TuningCurve, Unit # noqa: F401
27
+ from .utils import ( # noqa: F401
28
+ autocorrelation_2d,
29
+ cart2pol,
30
+ circ_dist,
31
+ circ_dist2,
32
+ circ_mean,
33
+ circ_r,
34
+ circ_rtest,
35
+ circ_std,
36
+ fit_ellipse,
37
+ label_connected_components,
38
+ normalized_xcorr2,
39
+ pearson_correlation,
40
+ pol2cart,
41
+ polyarea,
42
+ regionprops,
43
+ rotate_image,
44
+ squared_distance,
45
+ wrap_to_pi,
46
+ )
47
+ from .visualization import ( # noqa: F401
48
+ plot_autocorrelogram,
49
+ plot_grid_score_histogram,
50
+ plot_gridness_analysis,
51
+ plot_hd_analysis,
52
+ plot_polar_tuning,
53
+ plot_rate_map,
54
+ plot_temporal_autocorr,
55
+ )
56
+
57
+ __all__ = [
58
+ "GridnessAnalyzer",
59
+ "GridnessResult",
60
+ "HeadDirectionAnalyzer",
61
+ "HDCellResult",
62
+ "compute_2d_autocorrelation",
63
+ "compute_rate_map",
64
+ "compute_rate_map_from_binned",
65
+ "compute_spatial_information",
66
+ "compute_field_statistics",
67
+ "compute_grid_spacing",
68
+ "identify_grid_modules_and_stats",
69
+ "MATFileLoader",
70
+ "TuningCurve",
71
+ "Unit",
72
+ "circ_r",
73
+ "circ_mean",
74
+ "circ_std",
75
+ "circ_dist",
76
+ "circ_dist2",
77
+ "circ_rtest",
78
+ "pearson_correlation",
79
+ "normalized_xcorr2",
80
+ "autocorrelation_2d",
81
+ "fit_ellipse",
82
+ "squared_distance",
83
+ "polyarea",
84
+ "wrap_to_pi",
85
+ "cart2pol",
86
+ "pol2cart",
87
+ "rotate_image",
88
+ "label_connected_components",
89
+ "regionprops",
90
+ "plot_autocorrelogram",
91
+ "plot_gridness_analysis",
92
+ "plot_rate_map",
93
+ "plot_grid_score_histogram",
94
+ "plot_polar_tuning",
95
+ "plot_temporal_autocorr",
96
+ "plot_hd_analysis",
97
+ ]
@@ -0,0 +1,26 @@
1
+ """Core analysis modules."""
2
+
3
+ from .grid_cells import GridnessAnalyzer, GridnessResult, compute_2d_autocorrelation
4
+ from .grid_modules_leiden import identify_grid_modules_and_stats
5
+ from .head_direction import HDCellResult, HeadDirectionAnalyzer
6
+ from .spatial_analysis import (
7
+ compute_field_statistics,
8
+ compute_grid_spacing,
9
+ compute_rate_map,
10
+ compute_rate_map_from_binned,
11
+ compute_spatial_information,
12
+ )
13
+
14
+ __all__ = [
15
+ "GridnessAnalyzer",
16
+ "compute_2d_autocorrelation",
17
+ "GridnessResult",
18
+ "HeadDirectionAnalyzer",
19
+ "HDCellResult",
20
+ "compute_rate_map",
21
+ "compute_rate_map_from_binned",
22
+ "compute_spatial_information",
23
+ "compute_field_statistics",
24
+ "compute_grid_spacing",
25
+ "identify_grid_modules_and_stats",
26
+ ]