canns 0.14.3__py3-none-any.whl → 0.15.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 (28) hide show
  1. canns/analyzer/data/asa/__init__.py +77 -21
  2. canns/analyzer/data/asa/coho.py +97 -0
  3. canns/analyzer/data/asa/cohomap.py +408 -0
  4. canns/analyzer/data/asa/cohomap_scatter.py +10 -0
  5. canns/analyzer/data/asa/cohomap_vectors.py +311 -0
  6. canns/analyzer/data/asa/cohospace.py +173 -1153
  7. canns/analyzer/data/asa/cohospace_phase_centers.py +137 -0
  8. canns/analyzer/data/asa/cohospace_scatter.py +1220 -0
  9. canns/analyzer/data/asa/embedding.py +3 -4
  10. canns/analyzer/data/asa/plotting.py +4 -4
  11. canns/analyzer/data/cell_classification/__init__.py +10 -0
  12. canns/analyzer/data/cell_classification/core/__init__.py +4 -0
  13. canns/analyzer/data/cell_classification/core/btn.py +272 -0
  14. canns/analyzer/data/cell_classification/visualization/__init__.py +3 -0
  15. canns/analyzer/data/cell_classification/visualization/btn_plots.py +258 -0
  16. canns/analyzer/visualization/__init__.py +2 -0
  17. canns/analyzer/visualization/core/config.py +20 -0
  18. canns/analyzer/visualization/theta_sweep_plots.py +142 -0
  19. canns/pipeline/asa/runner.py +19 -19
  20. canns/pipeline/asa_gui/__init__.py +5 -3
  21. canns/pipeline/asa_gui/analysis_modes/pathcompare_mode.py +3 -1
  22. canns/pipeline/asa_gui/core/runner.py +23 -23
  23. canns/pipeline/asa_gui/views/pages/preprocess_page.py +7 -12
  24. {canns-0.14.3.dist-info → canns-0.15.0.dist-info}/METADATA +1 -1
  25. {canns-0.14.3.dist-info → canns-0.15.0.dist-info}/RECORD +28 -20
  26. {canns-0.14.3.dist-info → canns-0.15.0.dist-info}/WHEEL +0 -0
  27. {canns-0.14.3.dist-info → canns-0.15.0.dist-info}/entry_points.txt +0 -0
  28. {canns-0.14.3.dist-info → canns-0.15.0.dist-info}/licenses/LICENSE +0 -0
@@ -760,6 +760,148 @@ def plot_grid_cell_manifold(
760
760
  raise e
761
761
 
762
762
 
763
+ def plot_internal_position_trajectory(
764
+ internal_position: np.ndarray,
765
+ position: np.ndarray,
766
+ max_activity: np.ndarray | None = None,
767
+ env_size: float | tuple[float, float] | tuple[float, float, float, float] | None = None,
768
+ config: PlotConfig | None = None,
769
+ ax: plt.Axes | None = None,
770
+ # Backward compatibility parameters
771
+ title: str = "Internal Position (GC bump) vs. Real Trajectory",
772
+ figsize: tuple[int, int] = (6, 4),
773
+ cmap: str = "cool",
774
+ show: bool = True,
775
+ save_path: str | None = None,
776
+ **kwargs,
777
+ ) -> tuple[plt.Figure, plt.Axes]:
778
+ """Plot internal position (GC bump) against the real trajectory.
779
+
780
+ Args:
781
+ internal_position: Internal decoded positions ``(T, 2)``.
782
+ position: Real positions ``(T, 2)``.
783
+ max_activity: Optional per-time max activity to color the internal position.
784
+ env_size: Environment size. If float, uses ``[0, env_size]`` for both axes.
785
+ If a tuple of 2, treats as ``(width, height)``. If a tuple of 4, treats as
786
+ ``(xmin, xmax, ymin, ymax)``.
787
+ config: PlotConfig object for unified configuration.
788
+ ax: Optional axis to draw on instead of creating a new figure.
789
+ **kwargs: Additional parameters for backward compatibility.
790
+
791
+ Returns:
792
+ tuple: ``(figure, axis)`` objects.
793
+ """
794
+ if internal_position.ndim != 2 or internal_position.shape[1] != 2:
795
+ raise ValueError(
796
+ f"internal_position must be (T, 2), got shape {internal_position.shape}"
797
+ )
798
+ if position.ndim != 2 or position.shape[1] != 2:
799
+ raise ValueError(f"position must be (T, 2), got shape {position.shape}")
800
+ if internal_position.shape[0] != position.shape[0]:
801
+ raise ValueError(
802
+ "internal_position and position must have the same length: "
803
+ f"{internal_position.shape[0]} != {position.shape[0]}"
804
+ )
805
+ if max_activity is not None and max_activity.shape[0] != internal_position.shape[0]:
806
+ raise ValueError(
807
+ "max_activity must have same length as internal_position: "
808
+ f"{max_activity.shape[0]} != {internal_position.shape[0]}"
809
+ )
810
+
811
+ if config is None:
812
+ config = PlotConfig(
813
+ title=title,
814
+ figsize=figsize,
815
+ show=show,
816
+ save_path=save_path,
817
+ kwargs={"cmap": cmap, **kwargs},
818
+ )
819
+
820
+ plot_kwargs = config.to_matplotlib_kwargs()
821
+ trajectory_color = plot_kwargs.pop("trajectory_color", "black")
822
+ trajectory_linewidth = plot_kwargs.pop("trajectory_linewidth", 1.0)
823
+ scatter_size = plot_kwargs.pop("scatter_size", 4)
824
+ scatter_alpha = plot_kwargs.pop("scatter_alpha", 0.9)
825
+ add_colorbar = bool(plot_kwargs.pop("add_colorbar", True))
826
+ colorbar_options = plot_kwargs.pop("colorbar", {}) if add_colorbar else {}
827
+ if "cmap" not in plot_kwargs:
828
+ plot_kwargs["cmap"] = "cool"
829
+
830
+ if max_activity is None:
831
+ add_colorbar = False
832
+
833
+ axis_provided = ax is not None
834
+ if not axis_provided:
835
+ fig, ax = plt.subplots(figsize=config.figsize)
836
+ else:
837
+ fig = ax.figure
838
+
839
+ try:
840
+ scatter = ax.scatter(
841
+ internal_position[:, 0],
842
+ internal_position[:, 1],
843
+ c=max_activity,
844
+ s=scatter_size,
845
+ alpha=scatter_alpha,
846
+ **plot_kwargs,
847
+ )
848
+ ax.plot(position[:, 0], position[:, 1], color=trajectory_color, lw=trajectory_linewidth)
849
+
850
+ ax.set_aspect("equal", adjustable="box")
851
+ if config.title:
852
+ ax.set_title(config.title, fontsize=14, fontweight="bold")
853
+
854
+ if env_size is not None:
855
+ if isinstance(env_size, (tuple, list, np.ndarray)):
856
+ if len(env_size) == 2:
857
+ ax.set_xlim(0, env_size[0])
858
+ ax.set_ylim(0, env_size[1])
859
+ elif len(env_size) == 4:
860
+ ax.set_xlim(env_size[0], env_size[1])
861
+ ax.set_ylim(env_size[2], env_size[3])
862
+ else:
863
+ raise ValueError("env_size tuple must be length 2 or 4.")
864
+ else:
865
+ ax.set_xlim(0, env_size)
866
+ ax.set_ylim(0, env_size)
867
+
868
+ sns.despine(ax=ax)
869
+
870
+ if add_colorbar:
871
+ default_cbar_opts = {"pad": 0.15, "size": "5%", "label": "Max GC activity"}
872
+ if isinstance(colorbar_options, dict):
873
+ extra_cbar_kwargs = colorbar_options.get("kwargs", {})
874
+ for key in ("pad", "size", "label"):
875
+ if key in colorbar_options:
876
+ default_cbar_opts[key] = colorbar_options[key]
877
+ else:
878
+ extra_cbar_kwargs = {}
879
+
880
+ divider = make_axes_locatable(ax)
881
+ cax = divider.append_axes(
882
+ "right", size=default_cbar_opts["size"], pad=default_cbar_opts["pad"]
883
+ )
884
+ cbar = fig.colorbar(scatter, cax=cax, **extra_cbar_kwargs)
885
+ if default_cbar_opts["label"]:
886
+ cbar.set_label(default_cbar_opts["label"], fontsize=12)
887
+
888
+ if not axis_provided:
889
+ fig.tight_layout()
890
+
891
+ show_flag = config.show and not axis_provided
892
+ finalize_figure(
893
+ fig,
894
+ replace(config, show=show_flag),
895
+ rasterize_artists=[scatter] if config.rasterized else None,
896
+ always_close=not show_flag,
897
+ )
898
+ return fig, ax
899
+
900
+ except Exception as e:
901
+ plt.close(fig)
902
+ raise e
903
+
904
+
763
905
  @dataclass(slots=True)
764
906
  class _PlaceCellAnimationData:
765
907
  """Immutable container for place cell animation arrays."""
@@ -628,7 +628,7 @@ class PipelineRunner:
628
628
  self, asa_data: dict[str, Any], state: WorkflowState, log_callback
629
629
  ) -> dict[str, Path]:
630
630
  """Run CohoMap analysis (TDA + decode + plotting)."""
631
- from canns.analyzer.data.asa import plot_cohomap_multi
631
+ from canns.analyzer.data.asa import plot_cohomap_scatter_multi
632
632
  from canns.analyzer.visualization import PlotConfigs
633
633
 
634
634
  tda_dir = self._results_dir(state) / "TDA"
@@ -661,7 +661,7 @@ class PipelineRunner:
661
661
  log_callback("Generating cohomology map...")
662
662
  pos = self._aligned_pos if self._aligned_pos is not None else asa_data
663
663
  config = PlotConfigs.cohomap(show=False, save_path=str(cohomap_path))
664
- plot_cohomap_multi(
664
+ plot_cohomap_scatter_multi(
665
665
  decoding_result=decode_result,
666
666
  position_data={"x": pos["x"], "y": pos["y"]},
667
667
  config=config,
@@ -838,16 +838,16 @@ class PipelineRunner:
838
838
  ) -> dict[str, Path]:
839
839
  """Run cohomology space visualization."""
840
840
  from canns.analyzer.data.asa import (
841
- plot_cohospace_neuron_1d,
842
- plot_cohospace_neuron_2d,
843
- plot_cohospace_population_1d,
844
- plot_cohospace_population_2d,
845
- plot_cohospace_trajectory_1d,
846
- plot_cohospace_trajectory_2d,
841
+ plot_cohospace_scatter_neuron_1d,
842
+ plot_cohospace_scatter_neuron_2d,
843
+ plot_cohospace_scatter_population_1d,
844
+ plot_cohospace_scatter_population_2d,
845
+ plot_cohospace_scatter_trajectory_1d,
846
+ plot_cohospace_scatter_trajectory_2d,
847
847
  )
848
- from canns.analyzer.data.asa.cohospace import (
849
- plot_cohospace_neuron_skewed,
850
- plot_cohospace_population_skewed,
848
+ from canns.analyzer.data.asa.cohospace_scatter import (
849
+ plot_cohospace_scatter_neuron_skewed,
850
+ plot_cohospace_scatter_population_skewed,
851
851
  )
852
852
  from canns.analyzer.visualization import PlotConfigs
853
853
 
@@ -937,7 +937,7 @@ class PipelineRunner:
937
937
  traj_path = out_dir / "cohospace_trajectory.png"
938
938
  if dim_mode == "1d":
939
939
  traj_cfg = PlotConfigs.cohospace_trajectory_1d(show=False, save_path=str(traj_path))
940
- plot_cohospace_trajectory_1d(
940
+ plot_cohospace_scatter_trajectory_1d(
941
941
  coords=coords2,
942
942
  times=None,
943
943
  subsample=subsample,
@@ -945,7 +945,7 @@ class PipelineRunner:
945
945
  )
946
946
  else:
947
947
  traj_cfg = PlotConfigs.cohospace_trajectory_2d(show=False, save_path=str(traj_path))
948
- plot_cohospace_trajectory_2d(
948
+ plot_cohospace_scatter_trajectory_2d(
949
949
  coords=coords2,
950
950
  times=None,
951
951
  subsample=subsample,
@@ -958,7 +958,7 @@ class PipelineRunner:
958
958
  log_callback(f"Plotting neuron {neuron_id}...")
959
959
  neuron_path = out_dir / f"cohospace_neuron_{neuron_id}.png"
960
960
  if unfold == "skew" and dim_mode != "1d":
961
- plot_cohospace_neuron_skewed(
961
+ plot_cohospace_scatter_neuron_skewed(
962
962
  coords=coordsbox2,
963
963
  activity=activity,
964
964
  neuron_id=int(neuron_id),
@@ -974,7 +974,7 @@ class PipelineRunner:
974
974
  neuron_cfg = PlotConfigs.cohospace_neuron_1d(
975
975
  show=False, save_path=str(neuron_path)
976
976
  )
977
- plot_cohospace_neuron_1d(
977
+ plot_cohospace_scatter_neuron_1d(
978
978
  coords=coordsbox2,
979
979
  activity=activity,
980
980
  neuron_id=int(neuron_id),
@@ -986,7 +986,7 @@ class PipelineRunner:
986
986
  neuron_cfg = PlotConfigs.cohospace_neuron_2d(
987
987
  show=False, save_path=str(neuron_path)
988
988
  )
989
- plot_cohospace_neuron_2d(
989
+ plot_cohospace_scatter_neuron_2d(
990
990
  coords=coordsbox2,
991
991
  activity=activity,
992
992
  neuron_id=int(neuron_id),
@@ -1001,7 +1001,7 @@ class PipelineRunner:
1001
1001
  pop_path = out_dir / "cohospace_population.png"
1002
1002
  neuron_ids = list(range(activity.shape[1]))
1003
1003
  if unfold == "skew" and dim_mode != "1d":
1004
- plot_cohospace_population_skewed(
1004
+ plot_cohospace_scatter_population_skewed(
1005
1005
  coords=coords2,
1006
1006
  activity=activity,
1007
1007
  neuron_ids=neuron_ids,
@@ -1017,7 +1017,7 @@ class PipelineRunner:
1017
1017
  pop_cfg = PlotConfigs.cohospace_population_1d(
1018
1018
  show=False, save_path=str(pop_path)
1019
1019
  )
1020
- plot_cohospace_population_1d(
1020
+ plot_cohospace_scatter_population_1d(
1021
1021
  coords=coords2,
1022
1022
  activity=activity,
1023
1023
  neuron_ids=neuron_ids,
@@ -1029,7 +1029,7 @@ class PipelineRunner:
1029
1029
  pop_cfg = PlotConfigs.cohospace_population_2d(
1030
1030
  show=False, save_path=str(pop_path)
1031
1031
  )
1032
- plot_cohospace_population_2d(
1032
+ plot_cohospace_scatter_population_2d(
1033
1033
  coords=coords2,
1034
1034
  activity=activity,
1035
1035
  neuron_ids=neuron_ids,
@@ -2,9 +2,9 @@
2
2
 
3
3
  from __future__ import annotations
4
4
 
5
- import sys
6
- import os
7
5
  import importlib.util
6
+ import os
7
+ import sys
8
8
 
9
9
  __all__ = ["main", "ASAGuiApp"]
10
10
 
@@ -14,7 +14,9 @@ if _pyside6_missing:
14
14
  try: # pragma: no cover - only used in CI/test runs
15
15
  import pytest
16
16
 
17
- pytest.skip("PySide6 is not installed; skipping asa_gui module.", allow_module_level=True)
17
+ pytest.skip(
18
+ "PySide6 is not installed; skipping asa_gui module.", allow_module_level=True
19
+ )
18
20
  except Exception:
19
21
  pass
20
22
 
@@ -250,7 +250,9 @@ class PathCompareMode(AbstractAnalysisMode):
250
250
  self.dim.setToolTip("1D decoded dimension index.")
251
251
  self.dim1.setToolTip("2D decoded dimension 1.")
252
252
  self.dim2.setToolTip("2D decoded dimension 2.")
253
- self.use_box.setToolTip("Use coordsbox/times_box alignment (recommended with speed_filter).")
253
+ self.use_box.setToolTip(
254
+ "Use coordsbox/times_box alignment (recommended with speed_filter)."
255
+ )
254
256
  self.interp_full.setToolTip("Interpolate back to full trajectory.")
255
257
  self.coords_key.setToolTip("Optional decode coords key (default coords/coordsbox).")
256
258
  self.times_key.setToolTip("Optional times_box key.")
@@ -651,7 +651,7 @@ class PipelineRunner:
651
651
  def _run_cohomap(
652
652
  self, asa_data: dict[str, Any], state: WorkflowState, log_callback
653
653
  ) -> dict[str, Path]:
654
- from canns.analyzer.data.asa import plot_cohomap_multi
654
+ from canns.analyzer.data.asa import plot_cohomap_scatter_multi
655
655
  from canns.analyzer.visualization import PlotConfigs
656
656
 
657
657
  tda_dir = self._results_dir(state) / "TDA"
@@ -684,7 +684,7 @@ class PipelineRunner:
684
684
  log_callback("Generating cohomology map...")
685
685
  pos = self._aligned_pos if self._aligned_pos is not None else asa_data
686
686
  config = PlotConfigs.cohomap(show=False, save_path=str(cohomap_path))
687
- plot_cohomap_multi(
687
+ plot_cohomap_scatter_multi(
688
688
  decoding_result=decode_result,
689
689
  position_data={"x": pos["x"], "y": pos["y"]},
690
690
  config=config,
@@ -1175,18 +1175,18 @@ class PipelineRunner:
1175
1175
  self, asa_data: dict[str, Any], state: WorkflowState, log_callback
1176
1176
  ) -> dict[str, Path]:
1177
1177
  from canns.analyzer.data.asa import (
1178
- plot_cohospace_neuron_1d,
1179
- plot_cohospace_neuron_2d,
1180
- plot_cohospace_population_1d,
1181
- plot_cohospace_population_2d,
1182
- plot_cohospace_trajectory_1d,
1183
- plot_cohospace_trajectory_2d,
1178
+ plot_cohospace_scatter_neuron_1d,
1179
+ plot_cohospace_scatter_neuron_2d,
1180
+ plot_cohospace_scatter_population_1d,
1181
+ plot_cohospace_scatter_population_2d,
1182
+ plot_cohospace_scatter_trajectory_1d,
1183
+ plot_cohospace_scatter_trajectory_2d,
1184
1184
  )
1185
- from canns.analyzer.data.asa.cohospace import (
1186
- compute_cohoscore_1d,
1187
- compute_cohoscore_2d,
1188
- plot_cohospace_neuron_skewed,
1189
- plot_cohospace_population_skewed,
1185
+ from canns.analyzer.data.asa.cohospace_scatter import (
1186
+ compute_cohoscore_scatter_1d,
1187
+ compute_cohoscore_scatter_2d,
1188
+ plot_cohospace_scatter_neuron_skewed,
1189
+ plot_cohospace_scatter_population_skewed,
1190
1190
  )
1191
1191
  from canns.analyzer.visualization import PlotConfigs
1192
1192
 
@@ -1254,11 +1254,11 @@ class PipelineRunner:
1254
1254
  if enable_score:
1255
1255
  try:
1256
1256
  if dim_mode == "1d":
1257
- scores = compute_cohoscore_1d(
1257
+ scores = compute_cohoscore_scatter_1d(
1258
1258
  coords2, activity, top_percent=top_percent, times=times
1259
1259
  )
1260
1260
  else:
1261
- scores = compute_cohoscore_2d(
1261
+ scores = compute_cohoscore_scatter_2d(
1262
1262
  coords2, activity, top_percent=top_percent, times=times
1263
1263
  )
1264
1264
  cohoscore_path = out_dir / "cohoscore.npy"
@@ -1314,7 +1314,7 @@ class PipelineRunner:
1314
1314
  traj_path = out_dir / "cohospace_trajectory.png"
1315
1315
  if dim_mode == "1d":
1316
1316
  traj_cfg = PlotConfigs.cohospace_trajectory_1d(show=False, save_path=str(traj_path))
1317
- plot_cohospace_trajectory_1d(
1317
+ plot_cohospace_scatter_trajectory_1d(
1318
1318
  coords=coords2,
1319
1319
  times=None,
1320
1320
  subsample=subsample,
@@ -1322,7 +1322,7 @@ class PipelineRunner:
1322
1322
  )
1323
1323
  else:
1324
1324
  traj_cfg = PlotConfigs.cohospace_trajectory_2d(show=False, save_path=str(traj_path))
1325
- plot_cohospace_trajectory_2d(
1325
+ plot_cohospace_scatter_trajectory_2d(
1326
1326
  coords=coords2,
1327
1327
  times=None,
1328
1328
  subsample=subsample,
@@ -1334,7 +1334,7 @@ class PipelineRunner:
1334
1334
  log_callback(f"Plotting neuron {neuron_id}...")
1335
1335
  neuron_path = out_dir / f"cohospace_neuron_{neuron_id}.png"
1336
1336
  if unfold == "skew" and dim_mode != "1d":
1337
- plot_cohospace_neuron_skewed(
1337
+ plot_cohospace_scatter_neuron_skewed(
1338
1338
  coords=coordsbox2,
1339
1339
  activity=activity,
1340
1340
  neuron_id=int(neuron_id),
@@ -1351,7 +1351,7 @@ class PipelineRunner:
1351
1351
  neuron_cfg = PlotConfigs.cohospace_neuron_1d(
1352
1352
  show=False, save_path=str(neuron_path)
1353
1353
  )
1354
- plot_cohospace_neuron_1d(
1354
+ plot_cohospace_scatter_neuron_1d(
1355
1355
  coords=coordsbox2,
1356
1356
  activity=activity,
1357
1357
  neuron_id=int(neuron_id),
@@ -1364,7 +1364,7 @@ class PipelineRunner:
1364
1364
  neuron_cfg = PlotConfigs.cohospace_neuron_2d(
1365
1365
  show=False, save_path=str(neuron_path)
1366
1366
  )
1367
- plot_cohospace_neuron_2d(
1367
+ plot_cohospace_scatter_neuron_2d(
1368
1368
  coords=coordsbox2,
1369
1369
  activity=activity,
1370
1370
  neuron_id=int(neuron_id),
@@ -1384,7 +1384,7 @@ class PipelineRunner:
1384
1384
  else:
1385
1385
  neuron_ids = list(range(activity.shape[1]))
1386
1386
  if unfold == "skew" and dim_mode != "1d":
1387
- plot_cohospace_population_skewed(
1387
+ plot_cohospace_scatter_population_skewed(
1388
1388
  coords=coords2,
1389
1389
  activity=activity,
1390
1390
  neuron_ids=neuron_ids,
@@ -1401,7 +1401,7 @@ class PipelineRunner:
1401
1401
  pop_cfg = PlotConfigs.cohospace_population_1d(
1402
1402
  show=False, save_path=str(pop_path)
1403
1403
  )
1404
- plot_cohospace_population_1d(
1404
+ plot_cohospace_scatter_population_1d(
1405
1405
  coords=coords2,
1406
1406
  activity=activity,
1407
1407
  neuron_ids=neuron_ids,
@@ -1414,7 +1414,7 @@ class PipelineRunner:
1414
1414
  pop_cfg = PlotConfigs.cohospace_population_2d(
1415
1415
  show=False, save_path=str(pop_path)
1416
1416
  )
1417
- plot_cohospace_population_2d(
1417
+ plot_cohospace_scatter_population_2d(
1418
1418
  coords=coords2,
1419
1419
  activity=activity,
1420
1420
  neuron_ids=neuron_ids,
@@ -5,7 +5,6 @@ from __future__ import annotations
5
5
  from pathlib import Path
6
6
 
7
7
  import numpy as np
8
-
9
8
  from PySide6.QtCore import QSettings, Qt, Signal
10
9
  from PySide6.QtGui import QColor
11
10
  from PySide6.QtWidgets import (
@@ -388,9 +387,7 @@ class PreprocessPage(QWidget):
388
387
  if is_zh
389
388
  else "Choose local file, built-in dataset, or URL."
390
389
  )
391
- self.dataset_key.setToolTip(
392
- "选择内置数据集" if is_zh else "Select a built-in dataset."
393
- )
390
+ self.dataset_key.setToolTip("选择内置数据集" if is_zh else "Select a built-in dataset.")
394
391
  self.dataset_session.setToolTip(
395
392
  "Left-Right 数据集的会话 id。" if is_zh else "Session id for Left-Right dataset."
396
393
  )
@@ -410,7 +407,9 @@ class PreprocessPage(QWidget):
410
407
  else "Embedding builds a dense spike matrix for TDA/FR."
411
408
  )
412
409
  self.embed_res.setToolTip(
413
- "时间分箱分辨率(与 t 单位一致)。" if is_zh else "Time bin resolution (same unit as t)."
410
+ "时间分箱分辨率(与 t 单位一致)。"
411
+ if is_zh
412
+ else "Time bin resolution (same unit as t)."
414
413
  )
415
414
  self.embed_dt.setToolTip(
416
415
  "时间步长(与 t 单位一致)。" if is_zh else "Time step (same unit as t)."
@@ -425,9 +424,7 @@ class PreprocessPage(QWidget):
425
424
  else "Remove low-speed samples (common for grid data)."
426
425
  )
427
426
  self.embed_min_speed.setToolTip(
428
- "速度阈值(与 t/x/y 单位一致)。"
429
- if is_zh
430
- else "Speed threshold (same unit as t/x/y)."
427
+ "速度阈值(与 t/x/y 单位一致)。" if is_zh else "Speed threshold (same unit as t/x/y)."
431
428
  )
432
429
 
433
430
  self.dataset_session.setPlaceholderText("例如 26034_3" if is_zh else "e.g. 26034_3")
@@ -527,9 +524,7 @@ class PreprocessPage(QWidget):
527
524
  except Exception:
528
525
  hint = ""
529
526
  if is_left_right:
530
- hint = (
531
- (hint + "\n") if hint else ""
532
- ) + (
527
+ hint = ((hint + "\n") if hint else "") + (
533
528
  "左/右数据集需要 session id 和文件名。"
534
529
  if is_zh
535
530
  else "Left-right dataset requires session id + filename."
@@ -612,8 +607,8 @@ class PreprocessPage(QWidget):
612
607
  key = self.dataset_key.currentData() or self.dataset_key.currentText()
613
608
  label = self._slugify(str(key))
614
609
  try:
615
- from canns.data import loaders as _loaders
616
610
  from canns.data import datasets as _datasets
611
+ from canns.data import loaders as _loaders
617
612
 
618
613
  if key == "roi_data":
619
614
  data = _loaders.load_roi_data()
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: canns
3
- Version: 0.14.3
3
+ Version: 0.15.0
4
4
  Summary: A Python Library for Continuous Attractor Neural Networks
5
5
  Project-URL: Repository, https://github.com/routhleck/canns
6
6
  Author-email: Sichao He <sichaohe@outlook.com>
@@ -3,19 +3,26 @@ canns/_version.py,sha256=zIvJPOGBFvo4VV6f586rlO_bvhuFp1fsxjf6xhsqkJY,1547
3
3
  canns/py.typed,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
4
4
  canns/analyzer/__init__.py,sha256=EQ02fYHkpMADp-ojpVCVtapuSPkl6j5WVfdPy0mOTs4,506
5
5
  canns/analyzer/data/__init__.py,sha256=RfS8vwApLkNF05Y_lfPaJpN_bRv-mOA_uFziaduDHgI,354
6
- canns/analyzer/data/asa/__init__.py,sha256=w1RC5QbCXh9UH1PrrBXdclopH86jAJyxNw-nCymGgA8,2312
7
- canns/analyzer/data/asa/cohospace.py,sha256=wiTu03IqxnkJeSRzlJpcN31OZRG3jfgq4TG8mVvs3R0,37246
6
+ canns/analyzer/data/asa/__init__.py,sha256=nXaRd49ePAnrjJaUO-FNkN_RlldEkC55e9jszEhmYKM,3897
7
+ canns/analyzer/data/asa/coho.py,sha256=rYKb0ae2ZK7PX_XkDd7JOVNmPRStG6ZLCKvUsseoK1g,2884
8
+ canns/analyzer/data/asa/cohomap.py,sha256=EmlG13f948de1O7Sm9e0YACtjbp9lEoFWeG3-hWRu6M,13437
9
+ canns/analyzer/data/asa/cohomap_scatter.py,sha256=qu5F9UBCG-JuRrQL0Ag0ACAM61bzAGXEYpPgZ-Oqciw,231
10
+ canns/analyzer/data/asa/cohomap_vectors.py,sha256=krzLr-MSw4Az8VD0AZruXHkv6G9i6VOE6AgavDJCGIw,9113
11
+ canns/analyzer/data/asa/cohospace.py,sha256=dQ_HDNW6xGy6RRBUD8zK3FnQksjiupd84ORIwy6NKCE,7668
12
+ canns/analyzer/data/asa/cohospace_phase_centers.py,sha256=JqgDH_SJZOln5wFhnNJ_qnPTlsTBFWb3M5VZX5b0Wrk,4113
13
+ canns/analyzer/data/asa/cohospace_scatter.py,sha256=z13lLFdYkODmjKeOYildM5TgvT2QxmFSh7q8BYS5WjA,37163
8
14
  canns/analyzer/data/asa/config.py,sha256=qm0k0nt0xuDUK5t63MG7ii7fgs2XbxyLxKOaOKJuB_s,6398
9
15
  canns/analyzer/data/asa/decode.py,sha256=NG8vVx2cPG7uSJDovnC2vzk0dsqU8oR4jaNPxxrvCc0,16501
10
- canns/analyzer/data/asa/embedding.py,sha256=fa1wEH2puMw8HiZIYCufas51uvnlduxwNMUPpwkbdoc,9643
16
+ canns/analyzer/data/asa/embedding.py,sha256=CupBvkqZJ7zDMQWH-aIfqrOPTdUfv6wfTtZrI4tj0f0,9623
11
17
  canns/analyzer/data/asa/filters.py,sha256=D-1mDVn4hBEAphKUgx1gQEUfgbghKcNQhZmr4xEExQA,7146
12
18
  canns/analyzer/data/asa/fly_roi.py,sha256=_scBOd-4t9yv_1tHk7wbXJwPieU-L-QtFJY6fhHpxDI,38031
13
19
  canns/analyzer/data/asa/fr.py,sha256=jt99H50e1RRAQgMIdkfK0rBbembZJEr9SMrxK-ZI_LA,13449
14
20
  canns/analyzer/data/asa/path.py,sha256=dL6hsqBoPFfC4ZrHDVFDWprbRfJAAYpiq4tIkZ6NvHY,15540
15
- canns/analyzer/data/asa/plotting.py,sha256=o0fErGzDtbERiZK7uzyQN6Jd7Hm6jXZFg4aGZ100BQU,42766
21
+ canns/analyzer/data/asa/plotting.py,sha256=lpQfN55Sy8B5P1YSQhch_wc0e6SIEVCw9Wch7wHw04o,42798
16
22
  canns/analyzer/data/asa/tda.py,sha256=7IdxhBNEE99qenG6Zi4B5tv_L9K6gAW6HHxYGiErx4c,30574
17
- canns/analyzer/data/cell_classification/__init__.py,sha256=ho8yYcBf0Do_M3V1l0Li26gLDi_DIS4F-Pr5IMLcJ5A,2221
18
- canns/analyzer/data/cell_classification/core/__init__.py,sha256=Lv1zkGI3UnFT4yGkj351Jj-KEVtZlmRUM37SDby1bIE,761
23
+ canns/analyzer/data/cell_classification/__init__.py,sha256=Ri0VJYn2OI3ygC4m-Xc9rjFvgPLaEykc-D94VxmUclQ,2447
24
+ canns/analyzer/data/cell_classification/core/__init__.py,sha256=J9uqjx2wTK-uh3OWFqP8BkY_ySz3rU_VWRNQ_1t3EbM,865
25
+ canns/analyzer/data/cell_classification/core/btn.py,sha256=rgZdEoMgqgOPah5KHEQAx7pNWDsWBzZ2pNQ5BstTYFM,8546
19
26
  canns/analyzer/data/cell_classification/core/grid_cells.py,sha256=fRFixjvPVJy0QF9MygGqpIk1lnTToMZvvbGubM5woRk,21547
20
27
  canns/analyzer/data/cell_classification/core/grid_modules_leiden.py,sha256=xWrbL51BeU9pIaCzak54upFBeSUtnx_V_naILjzzExk,9032
21
28
  canns/analyzer/data/cell_classification/core/head_direction.py,sha256=CQKyon9pb3K5SBkesuqkBTU-QXx_-g0FBa0bblWDPOw,12060
@@ -27,7 +34,8 @@ canns/analyzer/data/cell_classification/utils/circular_stats.py,sha256=fQ1PNBiF_
27
34
  canns/analyzer/data/cell_classification/utils/correlation.py,sha256=57Ckn8OQGLipT7qZIGl6wgooQ_8gwp01g9lVc8I3Cs0,10354
28
35
  canns/analyzer/data/cell_classification/utils/geometry.py,sha256=jOLh3GeO-riR5a7r7Q7uON3HU_bYOZZJLbokU5bjCOQ,12683
29
36
  canns/analyzer/data/cell_classification/utils/image_processing.py,sha256=o9bLT4ycJ_IF7SKBe2RqSWIQwNcpi9v4AI-N5vpm_jM,12805
30
- canns/analyzer/data/cell_classification/visualization/__init__.py,sha256=HJy71bZuvvfFxrd4PTj3AUon68FBjZjtmjgky20oo5o,450
37
+ canns/analyzer/data/cell_classification/visualization/__init__.py,sha256=fmEHZBcurW6y6FwySLoq65b6CH2kNUB02NCVw2ou6Nc,590
38
+ canns/analyzer/data/cell_classification/visualization/btn_plots.py,sha256=nl29Ihe-gayCu_poJIWLN9oT6Srg1yjC-okPZ0IeRjo,7702
31
39
  canns/analyzer/data/cell_classification/visualization/grid_plots.py,sha256=NFtyYOe2Szt0EOIwQmZradwEvvRjjm7mm6VnnGThDQ0,7914
32
40
  canns/analyzer/data/cell_classification/visualization/hd_plots.py,sha256=nzw1jck3VHvAFsJAGelhrJf1q27A5PI0r3NKVgeea8U,5670
33
41
  canns/analyzer/metrics/__init__.py,sha256=DTsrv1HW133_RgvhWzz7Gx-bP2hOZbPO2unCPPyf9gs,178
@@ -41,16 +49,16 @@ canns/analyzer/slow_points/checkpoint.py,sha256=s4_-5HZJvmnyFqpK1O9WWYkhAhZj1i5j
41
49
  canns/analyzer/slow_points/finder.py,sha256=y-YKg-LI7lRM4JMghfcb5NGSYhIM2VPRA37YSCkVK_4,25437
42
50
  canns/analyzer/slow_points/fixed_points.py,sha256=Qp-iezwydWWUTchb2hGXJv0QKJqIm9gSG6hh0H9Eb6E,10099
43
51
  canns/analyzer/slow_points/visualization.py,sha256=sRmmxs900OSB680MTp0PNIGLpS5i5AmJ58ek20vmrSE,10610
44
- canns/analyzer/visualization/__init__.py,sha256=pNIokzS8y3ydzEMmVm1FNrOMRALDeuOHbcwZicPUm90,2131
52
+ canns/analyzer/visualization/__init__.py,sha256=_4a8mrVOr8TR63LZbXym-djYbW-6vxxI78dxiHpSsho,2211
45
53
  canns/analyzer/visualization/energy_plots.py,sha256=u0TOLzd7AWEfs-tRYZg1UBwsGYGPF_eWsMip1ZG9jPA,35671
46
54
  canns/analyzer/visualization/spatial_plots.py,sha256=30m02xhYkZfEETCtvBSwLix9SEOPcLZTg0AGGFvPc2w,34605
47
55
  canns/analyzer/visualization/spike_plots.py,sha256=wOm4gh_3obJy6gwo31maoaiZ7O8rsoYeFdhseoVmX78,12280
48
- canns/analyzer/visualization/theta_sweep_plots.py,sha256=2kiP7-IizqGm0q-ohQ4HhDZpm3sqs_lgn3GErHEZzbI,62262
56
+ canns/analyzer/visualization/theta_sweep_plots.py,sha256=BPW0VRR-rSJcJkMkY-Z1NpMS3iPIgLe3w0ZLBnHfeog,67723
49
57
  canns/analyzer/visualization/tuning_plots.py,sha256=9JOeC4dlulVzpHQWDVy3dlJnxcBZiOPeapPdVFR-7Zk,5178
50
58
  canns/analyzer/visualization/core/__init__.py,sha256=Vngm2A05cTu9ZVEYepTF7lVpuwQvMRjXs9XPLfZzedI,1928
51
59
  canns/analyzer/visualization/core/animation.py,sha256=qfBYMd81_GwWEw4MHOu3GrVXJtHS9W1xxtmOx-J5ZyM,7664
52
60
  canns/analyzer/visualization/core/backend.py,sha256=Nbk-ARL_xeWlb3nl5SUPrFQNns2wq5BeHU3Q_tAbd_c,9539
53
- canns/analyzer/visualization/core/config.py,sha256=PI4GnEwjwDhRpWPfe-bdYBLIO9ica5B3dYUC_VhpSek,25542
61
+ canns/analyzer/visualization/core/config.py,sha256=2-YIFa-eqtUrNPJERTpPO-PPX0PdOaAioi95VT9WUbQ,26268
54
62
  canns/analyzer/visualization/core/jupyter_utils.py,sha256=JD56VeeWb7w9t5DJ8TpgnxRWkUK46ArbbPSTlFdIM10,6034
55
63
  canns/analyzer/visualization/core/rendering.py,sha256=YCbiXu8MOAqE9FVb_id5JKr5g9O64sCh-dOs0EK4gnU,18291
56
64
  canns/analyzer/visualization/core/writers.py,sha256=HLsP953hgsv140ZX2XPzHfCUTqenjmjbLNrbknKam_s,15607
@@ -76,12 +84,12 @@ canns/pipeline/launcher.py,sha256=GASiWSfezljY56swjfLUR_QZCUU5Acm4v3mh9kNYayE,19
76
84
  canns/pipeline/asa/__init__.py,sha256=JR4T0onfmkKMOrUq-k0San1RTSb1om6cd27tWovBp0c,466
77
85
  canns/pipeline/asa/__main__.py,sha256=_KgAeuGQ2-SXmuZhvZCkRx9luFf7VgKUCuszNlUswyA,197
78
86
  canns/pipeline/asa/app.py,sha256=L5al6PrGoEzRNosZlHbn-VaTxXCoVyfKFn0f1e-0FUI,49906
79
- canns/pipeline/asa/runner.py,sha256=Bq1uKEEtn-qzOnftpmQ1YCbDr_ygYFj98C1H2Oylkfo,45246
87
+ canns/pipeline/asa/runner.py,sha256=FFz1Sfk5ysyHgoXAl-TK100nA27plLcO7Z7xUZ0COd4,45398
80
88
  canns/pipeline/asa/screens.py,sha256=DbqidxmoKe4KzSLuxuriVv1PIVFn5Z-PfScVfjrIiEA,5954
81
89
  canns/pipeline/asa/state.py,sha256=XukidfcFIOmm9ttT226FOTYR5hv2VAY8_DZt7V1Ml2g,6955
82
90
  canns/pipeline/asa/styles.tcss,sha256=eaXI3rQeWdBYmWdLJMMiSO6acHtreLRVKKoIHb2-dBk,3349
83
91
  canns/pipeline/asa/widgets.py,sha256=3vPGGQWP9V5FwuwqykCVp7dzAHdpcFkDqib0DtIw-lQ,8087
84
- canns/pipeline/asa_gui/__init__.py,sha256=38gJUuQGfZ5gTJOJfYx8gJuy_bF69Qdpi1HNEYDKaH8,2250
92
+ canns/pipeline/asa_gui/__init__.py,sha256=FthSerbWbpOjwNp9z4c20mu1fcIvRnBiYzl5ALVh_NE,2280
85
93
  canns/pipeline/asa_gui/__main__.py,sha256=2UOQtIE5oXkcq9HcuY13M3Jk6-uaDu8A0VJfvr203ck,134
86
94
  canns/pipeline/asa_gui/app.py,sha256=Wd-tVGNPE1mQ0S9bET-cyjfj5UWsTIFFHOQRu0lngBs,833
87
95
  canns/pipeline/asa_gui/main_window.py,sha256=kQp8DTmp7SuYVCglh5lVja7DyQ7hAOxPgCEUmjKHgbk,7019
@@ -94,14 +102,14 @@ canns/pipeline/asa_gui/analysis_modes/decode_mode.py,sha256=uEe3lfWAA0pqmCXzNpaA
94
102
  canns/pipeline/asa_gui/analysis_modes/fr_mode.py,sha256=xzx1RhGVDbx6huEtEHGfUqWgRN_C6Sf-Ycj9BzIgTRY,3961
95
103
  canns/pipeline/asa_gui/analysis_modes/frm_mode.py,sha256=8rgh_P7dxYJfx2TxrhD00Ja6tK0q6NboqwZ7n0Sw_2U,3992
96
104
  canns/pipeline/asa_gui/analysis_modes/gridscore_mode.py,sha256=XC-O2lMx3NPxUkSoZo_69g7B_yFAYUnKIPKLj9-gKM4,5712
97
- canns/pipeline/asa_gui/analysis_modes/pathcompare_mode.py,sha256=oRZPB8y7ORDFDPk99joRNQRj_e5qmR-GuJHrGnSynS4,10808
105
+ canns/pipeline/asa_gui/analysis_modes/pathcompare_mode.py,sha256=d3R19eHz44z2YP3UFUNcQFDJGg0qp3Giv_7uWGCMzAo,10838
98
106
  canns/pipeline/asa_gui/analysis_modes/tda_mode.py,sha256=xnsWv_zfstzYPf_nLbQkCNHxxhYRznz4m-73ClaBQKs,6094
99
107
  canns/pipeline/asa_gui/controllers/__init__.py,sha256=RuQz960T4kEuQsBI_cjS0cQgFyqAdblLXy_dDoLPbTE,198
100
108
  canns/pipeline/asa_gui/controllers/analysis_controller.py,sha256=8cKs-RYHh_NflP7xeS0u0_y9WsZ268H1Wyp-wHZC97I,1769
101
109
  canns/pipeline/asa_gui/controllers/preprocess_controller.py,sha256=uNZifNGadYPxAVyWnfonOs5pwCgxwB1nrBGqvv8Y3hU,2825
102
110
  canns/pipeline/asa_gui/core/__init__.py,sha256=vfJVs5T999vh04Fi98kRLjD8AkbqpIGxmRiUhaxCNYY,371
103
111
  canns/pipeline/asa_gui/core/cache.py,sha256=qAg9Su_T1xIR5j8DK9KzwSdCGs0lKtMaZKr0Lhcj0KU,327
104
- canns/pipeline/asa_gui/core/runner.py,sha256=6Gz9ptWhVrUfsxW0EkyrSjilEj5GjyajhJ08RU8wye8,74509
112
+ canns/pipeline/asa_gui/core/runner.py,sha256=PgD4WHxKDo9Nos-djo98DRcYKNB0sdgrc41WjtxG6TE,74693
105
113
  canns/pipeline/asa_gui/core/state.py,sha256=hjv8NrgROlACgjm5VZtQL58_podJFWS2sLHi5YiVLJY,10148
106
114
  canns/pipeline/asa_gui/core/worker.py,sha256=ig6fwcMLNR6N3oSX3LW-bJdXm3Hol29iAVX9pU6KWSc,7778
107
115
  canns/pipeline/asa_gui/models/__init__.py,sha256=Pr5wfeu_iA8bh2ob9tfWQcWmzWydYjMwups29R6c8-U,217
@@ -122,7 +130,7 @@ canns/pipeline/asa_gui/views/__init__.py,sha256=ThoLlMw7bKxA7lkv_AvIR1mbpaoM0vkI
122
130
  canns/pipeline/asa_gui/views/help_content.py,sha256=kL7MSwc9v3gHLz86Apiy64xbwymt9r7sPEjz5ka6EB0,8452
123
131
  canns/pipeline/asa_gui/views/pages/__init__.py,sha256=xB7VTY_hKfoCNMGeWZbV3gHG9ErrzmwqW30UlUkbqgE,161
124
132
  canns/pipeline/asa_gui/views/pages/analysis_page.py,sha256=X6PGW_cgvAiNFqUpsS2TuVWl258Q6Q90C9NEQT1TetQ,22807
125
- canns/pipeline/asa_gui/views/pages/preprocess_page.py,sha256=AHWidQqNKF0TBx8i2dDmPfxjT4Qy45_FjBYh-O1zB8E,31364
133
+ canns/pipeline/asa_gui/views/pages/preprocess_page.py,sha256=QNKLCL5y_nmmdYUh6GiDI12-sBXYU_z3OpU9ovZ-DXc,31303
126
134
  canns/pipeline/asa_gui/views/panels/__init__.py,sha256=Spqmc0Sjh38cgr42gszmiogZQFFOLN1yL7ekSpVJCrE,36
127
135
  canns/pipeline/asa_gui/views/widgets/__init__.py,sha256=xaTYXw99OL8ye1cpfoKgSwqC7c2B6lrLLsYHRB16m64,481
128
136
  canns/pipeline/asa_gui/views/widgets/artifacts_tab.py,sha256=U_fuOCfSmkDhx3G97aod-8UPSIFVz_MrsU4b_ik_5qE,1431
@@ -158,8 +166,8 @@ canns/trainer/utils.py,sha256=ZdoLiRqFLfKXsWi0KX3wGUp0OqFikwiou8dPf3xvFhE,2847
158
166
  canns/typing/__init__.py,sha256=mXySdfmD8fA56WqZTb1Nj-ZovcejwLzNjuk6PRfTwmA,156
159
167
  canns/utils/__init__.py,sha256=OMyZ5jqZAIUS2Jr0qcnvvrx6YM-BZ1EJy5uZYeA3HC0,366
160
168
  canns/utils/benchmark.py,sha256=oJ7nvbvnQMh4_MZh7z160NPLp-197X0rEnmnLHYlev4,1361
161
- canns-0.14.3.dist-info/METADATA,sha256=UMyUaYFYtHoS60udBftAohcR0mIxJygdyUXyVdxfK18,9799
162
- canns-0.14.3.dist-info/WHEEL,sha256=WLgqFyCfm_KASv4WHyYy0P3pM_m7J5L9k2skdKLirC8,87
163
- canns-0.14.3.dist-info/entry_points.txt,sha256=57YF2HZp_BG3GeGB8L0m3wR1sSfNyMXF1q4CKEjce6U,164
164
- canns-0.14.3.dist-info/licenses/LICENSE,sha256=u6NJ1N-QSnf5yTwSk5UvFAdU2yKD0jxG0Xa91n1cPO4,11306
165
- canns-0.14.3.dist-info/RECORD,,
169
+ canns-0.15.0.dist-info/METADATA,sha256=18mW4kldZzRDEw-pm3KnNp_mIQWjoGbj_sFw43GnaSE,9799
170
+ canns-0.15.0.dist-info/WHEEL,sha256=WLgqFyCfm_KASv4WHyYy0P3pM_m7J5L9k2skdKLirC8,87
171
+ canns-0.15.0.dist-info/entry_points.txt,sha256=57YF2HZp_BG3GeGB8L0m3wR1sSfNyMXF1q4CKEjce6U,164
172
+ canns-0.15.0.dist-info/licenses/LICENSE,sha256=u6NJ1N-QSnf5yTwSk5UvFAdU2yKD0jxG0Xa91n1cPO4,11306
173
+ canns-0.15.0.dist-info/RECORD,,
File without changes