canns 0.12.7__py3-none-any.whl → 0.13.1__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 (36) hide show
  1. canns/analyzer/data/__init__.py +3 -11
  2. canns/analyzer/data/asa/__init__.py +84 -0
  3. canns/analyzer/data/asa/cohospace.py +905 -0
  4. canns/analyzer/data/asa/config.py +246 -0
  5. canns/analyzer/data/asa/decode.py +445 -0
  6. canns/analyzer/data/asa/embedding.py +269 -0
  7. canns/analyzer/data/asa/filters.py +208 -0
  8. canns/analyzer/data/{cann1d.py → asa/fly_roi.py} +98 -45
  9. canns/analyzer/data/asa/fr.py +431 -0
  10. canns/analyzer/data/asa/path.py +389 -0
  11. canns/analyzer/data/asa/plotting.py +1287 -0
  12. canns/analyzer/data/asa/tda.py +901 -0
  13. canns/analyzer/visualization/core/backend.py +1 -1
  14. canns/analyzer/visualization/core/config.py +77 -0
  15. canns/analyzer/visualization/core/rendering.py +10 -6
  16. canns/analyzer/visualization/energy_plots.py +22 -8
  17. canns/analyzer/visualization/spatial_plots.py +31 -11
  18. canns/analyzer/visualization/theta_sweep_plots.py +15 -6
  19. canns/pipeline/__init__.py +4 -8
  20. canns/pipeline/asa/__init__.py +21 -0
  21. canns/pipeline/asa/__main__.py +11 -0
  22. canns/pipeline/asa/app.py +1000 -0
  23. canns/pipeline/asa/runner.py +1095 -0
  24. canns/pipeline/asa/screens.py +215 -0
  25. canns/pipeline/asa/state.py +248 -0
  26. canns/pipeline/asa/styles.tcss +221 -0
  27. canns/pipeline/asa/widgets.py +233 -0
  28. canns/pipeline/gallery/__init__.py +7 -0
  29. canns/task/open_loop_navigation.py +3 -1
  30. {canns-0.12.7.dist-info → canns-0.13.1.dist-info}/METADATA +6 -3
  31. {canns-0.12.7.dist-info → canns-0.13.1.dist-info}/RECORD +34 -17
  32. {canns-0.12.7.dist-info → canns-0.13.1.dist-info}/entry_points.txt +1 -0
  33. canns/analyzer/data/cann2d.py +0 -2565
  34. canns/pipeline/theta_sweep.py +0 -573
  35. {canns-0.12.7.dist-info → canns-0.13.1.dist-info}/WHEEL +0 -0
  36. {canns-0.12.7.dist-info → canns-0.13.1.dist-info}/licenses/LICENSE +0 -0
@@ -0,0 +1,233 @@
1
+ """Custom Textual widgets for ASA TUI.
2
+
3
+ This module provides reusable UI components for the ASA analysis interface.
4
+ """
5
+
6
+ import os
7
+ import subprocess
8
+ import sys
9
+ from pathlib import Path
10
+
11
+ from rich.ansi import AnsiDecoder
12
+ from rich.text import Text
13
+ from textual.app import ComposeResult
14
+ from textual.containers import Horizontal, ScrollableContainer, Vertical
15
+ from textual.widgets import Button, Input, Label, Static
16
+
17
+
18
+ class ImagePreview(Vertical):
19
+ """Widget for previewing images in the terminal using climage."""
20
+
21
+ DEFAULT_CSS = """
22
+ ImagePreview {
23
+ height: auto;
24
+ min-height: 20;
25
+ border: solid $accent;
26
+ padding: 1;
27
+ }
28
+ #preview-content {
29
+ width: 100%;
30
+ height: auto;
31
+ }
32
+ #preview-scroll {
33
+ height: 1fr;
34
+ }
35
+ #preview-controls Button {
36
+ margin: 0 1 0 0;
37
+ }
38
+ #preview-arrows Button {
39
+ margin: 0 1 0 0;
40
+ }
41
+ #preview-controls, #preview-arrows {
42
+ height: auto;
43
+ }
44
+ """
45
+
46
+ def __init__(self, image_path: Path | None = None, **kwargs):
47
+ super().__init__(**kwargs)
48
+ self.image_path = image_path
49
+ self._zoom_step = 0
50
+
51
+ def compose(self) -> ComposeResult:
52
+ yield Label("Image Preview", id="preview-label")
53
+ yield Static("Path: (none)", id="preview-path")
54
+ yield Input(value="", id="preview-path-input")
55
+ with Horizontal(id="preview-controls"):
56
+ yield Button("Load", id="preview-load-btn")
57
+ yield Button("Open", id="preview-open-btn")
58
+ yield Button("Zoom +", id="preview-zoom-in-btn")
59
+ yield Button("Zoom -", id="preview-zoom-out-btn")
60
+ yield Button("Fit", id="preview-zoom-fit-btn")
61
+ with Horizontal(id="preview-arrows"):
62
+ yield Button("←", id="preview-pan-left-btn")
63
+ yield Button("→", id="preview-pan-right-btn")
64
+ yield Button("↑", id="preview-pan-up-btn")
65
+ yield Button("↓", id="preview-pan-down-btn")
66
+ with ScrollableContainer(id="preview-scroll"):
67
+ yield Static("No image loaded", id="preview-content")
68
+
69
+ def on_button_pressed(self, event: Button.Pressed) -> None:
70
+ if event.button.id == "preview-load-btn":
71
+ raw = self.query_one("#preview-path-input", Input).value.strip()
72
+ if not raw:
73
+ self.update_image(None)
74
+ return
75
+ path = self._resolve_path(raw)
76
+ self.update_image(path)
77
+ elif event.button.id == "preview-open-btn":
78
+ path = self.image_path
79
+ raw = self.query_one("#preview-path-input", Input).value.strip()
80
+ if raw:
81
+ path = self._resolve_path(raw)
82
+ if path is None or not path.exists():
83
+ content = self.query_one("#preview-content", Static)
84
+ content.update("No image to open")
85
+ return
86
+ try:
87
+ if sys.platform == "darwin":
88
+ subprocess.Popen(["open", str(path)])
89
+ elif sys.platform.startswith("win"):
90
+ os.startfile(str(path))
91
+ else:
92
+ subprocess.Popen(["xdg-open", str(path)])
93
+ except Exception as e:
94
+ content = self.query_one("#preview-content", Static)
95
+ content.update(f"Open failed: {e}")
96
+ elif event.button.id == "preview-zoom-in-btn":
97
+ self._zoom_step += 1
98
+ self.update_image(self.image_path)
99
+ elif event.button.id == "preview-zoom-out-btn":
100
+ self._zoom_step -= 1
101
+ self.update_image(self.image_path)
102
+ elif event.button.id == "preview-zoom-fit-btn":
103
+ self._zoom_step = 0
104
+ self.update_image(self.image_path)
105
+ elif event.button.id in {
106
+ "preview-pan-left-btn",
107
+ "preview-pan-right-btn",
108
+ "preview-pan-up-btn",
109
+ "preview-pan-down-btn",
110
+ }:
111
+ scroll = self.query_one("#preview-scroll", ScrollableContainer)
112
+ dx = 0
113
+ dy = 0
114
+ step = 5
115
+ if event.button.id == "preview-pan-left-btn":
116
+ dx = -step
117
+ elif event.button.id == "preview-pan-right-btn":
118
+ dx = step
119
+ elif event.button.id == "preview-pan-up-btn":
120
+ dy = -step
121
+ elif event.button.id == "preview-pan-down-btn":
122
+ dy = step
123
+ scroll.scroll_relative(x=dx, y=dy, animate=False)
124
+
125
+ def on_resize(self, event) -> None:
126
+ if self.image_path and self.image_path.exists():
127
+ self.update_image(self.image_path)
128
+
129
+ def update_image(self, path: Path | None):
130
+ """Update the previewed image."""
131
+ self.image_path = path
132
+ content = self.query_one("#preview-content", Static)
133
+ path_label = self.query_one("#preview-path", Static)
134
+ path_input = self.query_one("#preview-path-input", Input)
135
+
136
+ if path is None or not path.exists():
137
+ content.update("No image loaded")
138
+ path_label.update("Path: (none)")
139
+ path_input.value = ""
140
+ return
141
+ path_label.update(f"Path: {path}")
142
+ path_input.value = str(path)
143
+
144
+ # Try to use climage for terminal preview
145
+ try:
146
+ import climage
147
+
148
+ scroll = self.query_one("#preview-scroll", ScrollableContainer)
149
+ base_width = max(20, scroll.size.width - 4)
150
+ base_height = max(8, scroll.size.height - 2)
151
+ scale = max(0.4, 1 + (self._zoom_step * 0.1))
152
+ width = max(20, int(base_width * scale))
153
+ height = max(8, int(base_height * scale))
154
+ try:
155
+ img_output = climage.convert(str(path), width=width, height=height, is_unicode=True)
156
+ except TypeError:
157
+ img_output = climage.convert(str(path), width=width, is_unicode=True)
158
+ decoder = AnsiDecoder()
159
+ chunks = list(decoder.decode(img_output))
160
+ content.update(Text("\n").join(chunks) if chunks else "")
161
+ except ImportError:
162
+ content.update(f"Image: {path.name}\n(Install climage for preview)")
163
+ except Exception as e:
164
+ content.update(f"Error loading image: {e}")
165
+
166
+ def _resolve_path(self, raw: str) -> Path:
167
+ path = Path(raw).expanduser()
168
+ if path.is_absolute():
169
+ return path
170
+ app = getattr(self, "app", None)
171
+ if app is not None:
172
+ state = getattr(app, "state", None)
173
+ if state is not None and hasattr(state, "workdir"):
174
+ return Path(state.workdir) / path
175
+ return Path.cwd() / path
176
+
177
+
178
+ class ParamGroup(Vertical):
179
+ """Widget for grouping related parameters."""
180
+
181
+ DEFAULT_CSS = """
182
+ ParamGroup {
183
+ border: round $secondary;
184
+ padding: 1;
185
+ margin: 1 0;
186
+ height: auto;
187
+ width: 100%;
188
+ }
189
+ """
190
+
191
+ def __init__(self, title: str, **kwargs):
192
+ super().__init__(**kwargs)
193
+ self.title = title
194
+
195
+ def compose(self) -> ComposeResult:
196
+ yield Label(self.title, classes="param-group-title")
197
+
198
+
199
+ class LogViewer(Vertical):
200
+ """Widget for displaying log messages."""
201
+
202
+ DEFAULT_CSS = """
203
+ LogViewer {
204
+ height: 10;
205
+ border: solid $primary;
206
+ padding: 1;
207
+ overflow-y: scroll;
208
+ }
209
+ """
210
+
211
+ def __init__(self, **kwargs):
212
+ super().__init__(**kwargs)
213
+ self.log_lines = []
214
+
215
+ def compose(self) -> ComposeResult:
216
+ yield Static("", id="log-content")
217
+
218
+ def add_log(self, message: str):
219
+ """Add a log message."""
220
+ self.log_lines.append(message)
221
+ if len(self.log_lines) > 100:
222
+ self.log_lines = self.log_lines[-100:]
223
+
224
+ content = self.query_one("#log-content", Static)
225
+ content.update("\n".join(self.log_lines))
226
+ # Auto-scroll to latest entry
227
+ self.scroll_end(animate=False, immediate=True)
228
+
229
+ def clear(self):
230
+ """Clear all log messages."""
231
+ self.log_lines = []
232
+ content = self.query_one("#log-content", Static)
233
+ content.update("")
@@ -0,0 +1,7 @@
1
+ """Gallery module for model demonstrations and examples.
2
+
3
+ This module will contain interactive TUI demos for CANN models and other
4
+ visualization examples in the future.
5
+ """
6
+
7
+ __all__ = []
@@ -692,7 +692,9 @@ class OpenLoopNavigationTask(BaseNavigationTask):
692
692
 
693
693
  if not hasattr(self, "agent") or self.agent is None:
694
694
  self.agent = Agent(
695
- environment=self.env, params=copy.deepcopy(self.agent_params), rng_seed=self.rng_seed
695
+ environment=self.env,
696
+ params=copy.deepcopy(self.agent_params),
697
+ rng_seed=self.rng_seed,
696
698
  )
697
699
 
698
700
  # Set initial position
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: canns
3
- Version: 0.12.7
3
+ Version: 0.13.1
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>
@@ -18,6 +18,7 @@ Classifier: Typing :: Typed
18
18
  Requires-Python: <4.0,>=3.11
19
19
  Requires-Dist: brainpy[cpu]
20
20
  Requires-Dist: canns-lib>=0.6.2
21
+ Requires-Dist: climage>=0.2.2
21
22
  Requires-Dist: furo>=2025.7.19
22
23
  Requires-Dist: imageio[ffmpeg]>=2.37.0
23
24
  Requires-Dist: notebook>=7.4.4
@@ -25,6 +26,7 @@ Requires-Dist: numba>=0.56.0
25
26
  Requires-Dist: numpy<2.3,>=1.24
26
27
  Requires-Dist: scipy>=1.9.0
27
28
  Requires-Dist: seaborn>=0.13.2
29
+ Requires-Dist: textual>=7.3.0
28
30
  Requires-Dist: tqdm
29
31
  Provides-Extra: cpu
30
32
  Requires-Dist: brainpy[cpu]; extra == 'cpu'
@@ -65,7 +67,7 @@ CANNs is a Python library built on top of brainpy with performance‑critical mo
65
67
  - **Task-first API** – `canns.task.tracking` and `canns.task.open_loop_navigation` generate smooth tracking inputs, population coding stimuli, or import experimental trajectories.
66
68
  - **Rich analysis suite** – `canns.analyzer` covers energy landscapes, tuning curves, spike embeddings, UMAP/TDA helpers, and theta-sweep animations.
67
69
  - **Unified training** – `canns.trainer.HebbianTrainer` implements generic Hebbian learning and prediction, layered on the abstract `Trainer` base.
68
- - **Pipelines out of the box** `canns.pipeline.ThetaSweepPipeline` orchestrates navigation tasks, direction/grid-cell networks, and visualisation in a single call.
70
+ - **Pipeline workspace** the ASA TUI (Attractor Structure Analyzer) provides an end-to-end analysis workflow (TDA decode CohoMap/CohoSpace/FR/FRM) for interactive runs.
69
71
  - **Extensible foundations** – base classes (`BasicModel`, `Task`, `Trainer`, `Pipeline`) keep custom components consistent with the built-in ecosystem.
70
72
 
71
73
  ## Visual Gallery
@@ -115,6 +117,7 @@ pip install canns
115
117
  # Optional accelerators (Linux only)
116
118
  pip install canns[cuda12]
117
119
  pip install canns[tpu]
120
+
118
121
  ```
119
122
 
120
123
  ## Quick Start
@@ -150,7 +153,7 @@ us, inputs = bm.for_loop(
150
153
  )
151
154
  ```
152
155
 
153
- For an end-to-end theta sweep workflow, see `examples/pipeline/theta_sweep_from_external_data.py` or the `ThetaSweepPipeline` notebook in the docs.
156
+ For the ASA pipeline, run the TUI via `python -m canns.pipeline.asa` (or the `canns-tui` entrypoint) and point it at your ASA `.npz` inputs.
154
157
 
155
158
  ## Documentation & Notebooks
156
159
 
@@ -2,9 +2,18 @@ canns/__init__.py,sha256=ZK4buN-csoLKXaKtoDrOoZbNGCoLCNuF2XS96X8LbH8,1523
2
2
  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
- canns/analyzer/data/__init__.py,sha256=cnO-fwVAbieBnhBJqLLkMgx5B9NhF51XWUa8gvBp6A0,331
6
- canns/analyzer/data/cann1d.py,sha256=B96SBRAJk3sKJQ3Zg1A_CvhzNWDOSQnLA0-2miMn4qQ,35791
7
- canns/analyzer/data/cann2d.py,sha256=szs8bIl6671BFeIUfMbz5ZsCtUov6FzyqSjRM3_qrLs,86656
5
+ canns/analyzer/data/__init__.py,sha256=5LJ8Q4SyDpi6CAzyW3lSpra3I0BgG20kmQMceONw7A4,158
6
+ canns/analyzer/data/asa/__init__.py,sha256=vfZCggZ_FvXwlYXLKErc_eltN6nOQiHWIivGYqpt8NM,1885
7
+ canns/analyzer/data/asa/cohospace.py,sha256=n6DfPWUH_k67KrPbNMt1EUdxMuRFFmXCaqh4gcuXngM,27847
8
+ canns/analyzer/data/asa/config.py,sha256=zVs-snLkD93hGc97GEX9CkcjTtUqORvMCs3khHhqd64,6288
9
+ canns/analyzer/data/asa/decode.py,sha256=NG8vVx2cPG7uSJDovnC2vzk0dsqU8oR4jaNPxxrvCc0,16501
10
+ canns/analyzer/data/asa/embedding.py,sha256=rT3hOHk6BzHF1X5YznIFxE_dDveklbT0fx9GtA2w3z0,9550
11
+ canns/analyzer/data/asa/filters.py,sha256=D-1mDVn4hBEAphKUgx1gQEUfgbghKcNQhZmr4xEExQA,7146
12
+ canns/analyzer/data/asa/fly_roi.py,sha256=_scBOd-4t9yv_1tHk7wbXJwPieU-L-QtFJY6fhHpxDI,38031
13
+ canns/analyzer/data/asa/fr.py,sha256=jt99H50e1RRAQgMIdkfK0rBbembZJEr9SMrxK-ZI_LA,13449
14
+ canns/analyzer/data/asa/path.py,sha256=p3r8EGcJi8NewNFutr3kdO-ekdU_5Icpy6nAoELzSq4,12233
15
+ canns/analyzer/data/asa/plotting.py,sha256=xuKRuq12pITK0BOC4Bj3ZfJs-07DA2OUHCpJmtJLOnw,40852
16
+ canns/analyzer/data/asa/tda.py,sha256=Hn110SBN4wKgHmcwPRkxHdbQ5DFW2xLdSv26J37_Zxc,30342
8
17
  canns/analyzer/metrics/__init__.py,sha256=WaTCJE2WhqPtZXYTtMilF_f0LZUfz2h9a25HzwmCwP8,132
9
18
  canns/analyzer/metrics/spatial_metrics.py,sha256=ZdS7tGH3lMgNlSYoHlH8IPsCw4XL0KtEnGALg_WHRX8,8965
10
19
  canns/analyzer/metrics/systematic_ratemap.py,sha256=MzXfa6_fGgrxD5xEd4hfrZR_fyUmhXQCxnPE3hUonE8,14004
@@ -17,17 +26,17 @@ canns/analyzer/slow_points/finder.py,sha256=y-YKg-LI7lRM4JMghfcb5NGSYhIM2VPRA37Y
17
26
  canns/analyzer/slow_points/fixed_points.py,sha256=Qp-iezwydWWUTchb2hGXJv0QKJqIm9gSG6hh0H9Eb6E,10099
18
27
  canns/analyzer/slow_points/visualization.py,sha256=sRmmxs900OSB680MTp0PNIGLpS5i5AmJ58ek20vmrSE,10610
19
28
  canns/analyzer/visualization/__init__.py,sha256=pNIokzS8y3ydzEMmVm1FNrOMRALDeuOHbcwZicPUm90,2131
20
- canns/analyzer/visualization/energy_plots.py,sha256=Ql-_qGRGf0njqVy82rEjAY-dgOm2Ww6NlBwGzu67BfY,35509
21
- canns/analyzer/visualization/spatial_plots.py,sha256=6X_k17EuS7-KjbGtPVDB-jvV5j6MResux485snsEaQM,34352
29
+ canns/analyzer/visualization/energy_plots.py,sha256=u0TOLzd7AWEfs-tRYZg1UBwsGYGPF_eWsMip1ZG9jPA,35671
30
+ canns/analyzer/visualization/spatial_plots.py,sha256=30m02xhYkZfEETCtvBSwLix9SEOPcLZTg0AGGFvPc2w,34605
22
31
  canns/analyzer/visualization/spike_plots.py,sha256=wOm4gh_3obJy6gwo31maoaiZ7O8rsoYeFdhseoVmX78,12280
23
- canns/analyzer/visualization/theta_sweep_plots.py,sha256=BA9LMuHoEBzXle47IQvBqPJSaIb_Z3RUO4WuVJZ6SZ8,62159
32
+ canns/analyzer/visualization/theta_sweep_plots.py,sha256=2kiP7-IizqGm0q-ohQ4HhDZpm3sqs_lgn3GErHEZzbI,62262
24
33
  canns/analyzer/visualization/tuning_plots.py,sha256=9JOeC4dlulVzpHQWDVy3dlJnxcBZiOPeapPdVFR-7Zk,5178
25
34
  canns/analyzer/visualization/core/__init__.py,sha256=Vngm2A05cTu9ZVEYepTF7lVpuwQvMRjXs9XPLfZzedI,1928
26
35
  canns/analyzer/visualization/core/animation.py,sha256=qfBYMd81_GwWEw4MHOu3GrVXJtHS9W1xxtmOx-J5ZyM,7664
27
- canns/analyzer/visualization/core/backend.py,sha256=hS8o8TqffGw4fa74NLwzT128a4THA3UkvTNVHFbEj5A,9540
28
- canns/analyzer/visualization/core/config.py,sha256=KuZNzUsevXQbg_qHwGTVR2SwkFH7EAZoLciQFU4klco,21707
36
+ canns/analyzer/visualization/core/backend.py,sha256=Nbk-ARL_xeWlb3nl5SUPrFQNns2wq5BeHU3Q_tAbd_c,9539
37
+ canns/analyzer/visualization/core/config.py,sha256=9_n5hrvJXZgv32OlE_PuNh4JaPgw3dRAp_8LRzYnt_w,24131
29
38
  canns/analyzer/visualization/core/jupyter_utils.py,sha256=JD56VeeWb7w9t5DJ8TpgnxRWkUK46ArbbPSTlFdIM10,6034
30
- canns/analyzer/visualization/core/rendering.py,sha256=Cr44VqvsbhUr8JtcId28jKeO8U3xm4WQ25I_647-jeQ,18286
39
+ canns/analyzer/visualization/core/rendering.py,sha256=YCbiXu8MOAqE9FVb_id5JKr5g9O64sCh-dOs0EK4gnU,18291
31
40
  canns/analyzer/visualization/core/writers.py,sha256=HLsP953hgsv140ZX2XPzHfCUTqenjmjbLNrbknKam_s,15607
32
41
  canns/data/__init__.py,sha256=BjQWgDYxh4jqtcKzcEZbdTech92AUzt_1KsDU1S88kM,864
33
42
  canns/data/datasets.py,sha256=TRHxQGlMPoboiTPKhjTv1AMGbMnIt9T472Juyz4PYS0,13480
@@ -45,14 +54,22 @@ canns/models/brain_inspired/hopfield.py,sha256=KQmXWBvUTdQ17t9VG-8Sy_uJznEt4eunO
45
54
  canns/models/brain_inspired/linear.py,sha256=oRjJnTqrheAADA5unYBu83RSm4UoUH-BK2Mt_liwDtw,6141
46
55
  canns/models/brain_inspired/spiking.py,sha256=hr2w7c6Eobxwp2z6vkV9Yivpv1964-cno-XOfMSh3RU,5557
47
56
  canns/models/hybrid/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
48
- canns/pipeline/__init__.py,sha256=zxRUKIL7V60FSoRjfvxN3qj-gaGvmt-HqZuEXN4WK3s,490
57
+ canns/pipeline/__init__.py,sha256=OgFh5UXId99j_W4MkcpTaYD9qpQVXt-v9xN8cCY8sSc,371
49
58
  canns/pipeline/_base.py,sha256=bYCmvXQ_0vGF-MEVpi0sUljrqmW6Ax8csQ5fcnX7nAE,1869
50
- canns/pipeline/theta_sweep.py,sha256=tGC0N83n5H2NY_dejAoxz1wzziL_XTvesMRrU7BMd3g,20145
59
+ canns/pipeline/asa/__init__.py,sha256=JR4T0onfmkKMOrUq-k0San1RTSb1om6cd27tWovBp0c,466
60
+ canns/pipeline/asa/__main__.py,sha256=_KgAeuGQ2-SXmuZhvZCkRx9luFf7VgKUCuszNlUswyA,197
61
+ canns/pipeline/asa/app.py,sha256=L5al6PrGoEzRNosZlHbn-VaTxXCoVyfKFn0f1e-0FUI,49906
62
+ canns/pipeline/asa/runner.py,sha256=PfHXlI-m3m-IYVFcFRhSODfPoRlCrloDOqEftvAfasg,42723
63
+ canns/pipeline/asa/screens.py,sha256=DbqidxmoKe4KzSLuxuriVv1PIVFn5Z-PfScVfjrIiEA,5954
64
+ canns/pipeline/asa/state.py,sha256=XukidfcFIOmm9ttT226FOTYR5hv2VAY8_DZt7V1Ml2g,6955
65
+ canns/pipeline/asa/styles.tcss,sha256=eaXI3rQeWdBYmWdLJMMiSO6acHtreLRVKKoIHb2-dBk,3349
66
+ canns/pipeline/asa/widgets.py,sha256=3vPGGQWP9V5FwuwqykCVp7dzAHdpcFkDqib0DtIw-lQ,8087
67
+ canns/pipeline/gallery/__init__.py,sha256=PPOvxmTRzEnj33jHlsFlaWuEfhrcNe39pMPQkTisjlo,187
51
68
  canns/task/__init__.py,sha256=sfo8TBBVAqkx73Nu5lVv77UCwZjKqjt042ezW4Wv2Ec,350
52
69
  canns/task/_base.py,sha256=rdRy4mr6x53z4aJv04UJcpqCyv78AxB1k1DhxnriLpg,4401
53
70
  canns/task/closed_loop_navigation.py,sha256=QxxLdAg4Zd8763bS001jFqfts3A6_r6hpTTfrh1LdW8,10204
54
71
  canns/task/navigation_base.py,sha256=s7mgXKhJyxIEUnSY8zXL3k9kH26MMQDv2xptzObu7Fc,40692
55
- canns/task/open_loop_navigation.py,sha256=iJI_D4cH0R4ryaPdBDIWRFTr96hYzGEkXwse2ZUtpgo,45369
72
+ canns/task/open_loop_navigation.py,sha256=jD77GVIGLaBVm0zKmOfghKk_Vj_9pjkjK8_a40907bU,45402
56
73
  canns/task/tracking.py,sha256=KNJ7QkecRimxDa4lLC9JnzTvQGB-c0_lvU-InlmcLOY,31866
57
74
  canns/trainer/__init__.py,sha256=ouHRuCuLuwFyrsOWbaotGxHIs5BdiYBtMhqE2k7HcKI,660
58
75
  canns/trainer/_base.py,sha256=EQIXnvRvhCo0veTItGQumNeGuerHzsqipxyGZGIt2QI,1536
@@ -65,8 +82,8 @@ canns/trainer/utils.py,sha256=ZdoLiRqFLfKXsWi0KX3wGUp0OqFikwiou8dPf3xvFhE,2847
65
82
  canns/typing/__init__.py,sha256=mXySdfmD8fA56WqZTb1Nj-ZovcejwLzNjuk6PRfTwmA,156
66
83
  canns/utils/__init__.py,sha256=OMyZ5jqZAIUS2Jr0qcnvvrx6YM-BZ1EJy5uZYeA3HC0,366
67
84
  canns/utils/benchmark.py,sha256=oJ7nvbvnQMh4_MZh7z160NPLp-197X0rEnmnLHYlev4,1361
68
- canns-0.12.7.dist-info/METADATA,sha256=wTKP7fgj_PSiwyztni85Y4Xteq2PdiaPNMy4Wiboq5Q,8760
69
- canns-0.12.7.dist-info/WHEEL,sha256=WLgqFyCfm_KASv4WHyYy0P3pM_m7J5L9k2skdKLirC8,87
70
- canns-0.12.7.dist-info/entry_points.txt,sha256=u3PlKH_khJgJWk7xf1NH2cDCeFGXW-6HsuQjLQhZJNk,39
71
- canns-0.12.7.dist-info/licenses/LICENSE,sha256=u6NJ1N-QSnf5yTwSk5UvFAdU2yKD0jxG0Xa91n1cPO4,11306
72
- canns-0.12.7.dist-info/RECORD,,
85
+ canns-0.13.1.dist-info/METADATA,sha256=4HIOm94szk2GaS6A9Kbp9nZHXfoqVvNj_rOBdrExZWE,8827
86
+ canns-0.13.1.dist-info/WHEEL,sha256=WLgqFyCfm_KASv4WHyYy0P3pM_m7J5L9k2skdKLirC8,87
87
+ canns-0.13.1.dist-info/entry_points.txt,sha256=HDzYp0e9E1wfKYRkYtnUgVKK_u33_7eIn9exgm7t-wg,75
88
+ canns-0.13.1.dist-info/licenses/LICENSE,sha256=u6NJ1N-QSnf5yTwSk5UvFAdU2yKD0jxG0Xa91n1cPO4,11306
89
+ canns-0.13.1.dist-info/RECORD,,
@@ -1,2 +1,3 @@
1
1
  [console_scripts]
2
2
  canns = canns:master
3
+ canns-tui = canns.pipeline.asa:main