canns 0.14.2__py3-none-any.whl → 0.14.3__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.
- canns/pipeline/asa_gui/analysis_modes/pathcompare_mode.py +29 -3
- canns/pipeline/asa_gui/views/pages/preprocess_page.py +251 -4
- {canns-0.14.2.dist-info → canns-0.14.3.dist-info}/METADATA +2 -1
- {canns-0.14.2.dist-info → canns-0.14.3.dist-info}/RECORD +7 -7
- {canns-0.14.2.dist-info → canns-0.14.3.dist-info}/WHEEL +0 -0
- {canns-0.14.2.dist-info → canns-0.14.3.dist-info}/entry_points.txt +0 -0
- {canns-0.14.2.dist-info → canns-0.14.3.dist-info}/licenses/LICENSE +0 -0
|
@@ -10,6 +10,7 @@ from PySide6.QtWidgets import (
|
|
|
10
10
|
QHBoxLayout,
|
|
11
11
|
QLabel,
|
|
12
12
|
QLineEdit,
|
|
13
|
+
QPushButton,
|
|
13
14
|
QSpinBox,
|
|
14
15
|
QWidget,
|
|
15
16
|
)
|
|
@@ -49,7 +50,7 @@ class PathCompareMode(AbstractAnalysisMode):
|
|
|
49
50
|
self.dim2.setValue(2)
|
|
50
51
|
|
|
51
52
|
self.use_box = QCheckBox("Use coordsbox / times_box")
|
|
52
|
-
self.use_box.setChecked(
|
|
53
|
+
self.use_box.setChecked(True)
|
|
53
54
|
|
|
54
55
|
self.interp_full = QCheckBox("Interpolate to full trajectory")
|
|
55
56
|
self.interp_full.setChecked(True)
|
|
@@ -57,8 +58,13 @@ class PathCompareMode(AbstractAnalysisMode):
|
|
|
57
58
|
|
|
58
59
|
self.coords_key = QLineEdit()
|
|
59
60
|
self.coords_key.setPlaceholderText("coords / coordsbox (optional)")
|
|
61
|
+
self.btn_coordsbox = QPushButton("coordsbox")
|
|
62
|
+
self.btn_coordsbox.clicked.connect(lambda: self.coords_key.setText("coordsbox"))
|
|
63
|
+
|
|
60
64
|
self.times_key = QLineEdit()
|
|
61
65
|
self.times_key.setPlaceholderText("times_box (optional)")
|
|
66
|
+
self.btn_times_box = QPushButton("times_box")
|
|
67
|
+
self.btn_times_box.clicked.connect(lambda: self.times_key.setText("times_box"))
|
|
62
68
|
|
|
63
69
|
self.slice_mode = PopupComboBox()
|
|
64
70
|
self.slice_mode.addItem("Time (tmin/tmax)", userData="time")
|
|
@@ -125,8 +131,20 @@ class PathCompareMode(AbstractAnalysisMode):
|
|
|
125
131
|
form.addRow(self._dims2d_label, dims_2d)
|
|
126
132
|
form.addRow(self.use_box)
|
|
127
133
|
form.addRow(self.interp_full)
|
|
128
|
-
|
|
129
|
-
|
|
134
|
+
coords_row = QWidget()
|
|
135
|
+
coords_layout = QHBoxLayout(coords_row)
|
|
136
|
+
coords_layout.setContentsMargins(0, 0, 0, 0)
|
|
137
|
+
coords_layout.addWidget(self.coords_key, 1)
|
|
138
|
+
coords_layout.addWidget(self.btn_coordsbox)
|
|
139
|
+
|
|
140
|
+
times_row = QWidget()
|
|
141
|
+
times_layout = QHBoxLayout(times_row)
|
|
142
|
+
times_layout.setContentsMargins(0, 0, 0, 0)
|
|
143
|
+
times_layout.addWidget(self.times_key, 1)
|
|
144
|
+
times_layout.addWidget(self.btn_times_box)
|
|
145
|
+
|
|
146
|
+
form.addRow("coords key", coords_row)
|
|
147
|
+
form.addRow("times key", times_row)
|
|
130
148
|
form.addRow("Slice mode", self.slice_mode)
|
|
131
149
|
form.addRow("tmin (sec, -1=auto)", self.tmin)
|
|
132
150
|
form.addRow("tmax (sec, -1=auto)", self.tmax)
|
|
@@ -150,6 +168,10 @@ class PathCompareMode(AbstractAnalysisMode):
|
|
|
150
168
|
def _refresh_enabled() -> None:
|
|
151
169
|
use_box = bool(self.use_box.isChecked())
|
|
152
170
|
self.interp_full.setEnabled(use_box)
|
|
171
|
+
self.coords_key.setEnabled(use_box)
|
|
172
|
+
self.times_key.setEnabled(use_box)
|
|
173
|
+
self.btn_coordsbox.setEnabled(use_box)
|
|
174
|
+
self.btn_times_box.setEnabled(use_box)
|
|
153
175
|
|
|
154
176
|
def _refresh_slice_mode() -> None:
|
|
155
177
|
is_time = self.slice_mode.currentData() == "time"
|
|
@@ -210,6 +232,8 @@ class PathCompareMode(AbstractAnalysisMode):
|
|
|
210
232
|
self.interp_full.setToolTip("插值回完整轨迹。")
|
|
211
233
|
self.coords_key.setToolTip("可选:解码坐标键(默认 coords/coordsbox)。")
|
|
212
234
|
self.times_key.setToolTip("可选:times_box 键名。")
|
|
235
|
+
self.btn_coordsbox.setToolTip("填入 coordsbox。")
|
|
236
|
+
self.btn_times_box.setToolTip("填入 times_box。")
|
|
213
237
|
self.slice_mode.setToolTip("按时间或索引裁剪。")
|
|
214
238
|
self.tmin.setToolTip("起始时间(秒),-1 自动。")
|
|
215
239
|
self.tmax.setToolTip("结束时间(秒),-1 自动。")
|
|
@@ -230,6 +254,8 @@ class PathCompareMode(AbstractAnalysisMode):
|
|
|
230
254
|
self.interp_full.setToolTip("Interpolate back to full trajectory.")
|
|
231
255
|
self.coords_key.setToolTip("Optional decode coords key (default coords/coordsbox).")
|
|
232
256
|
self.times_key.setToolTip("Optional times_box key.")
|
|
257
|
+
self.btn_coordsbox.setToolTip("Fill coordsbox.")
|
|
258
|
+
self.btn_times_box.setToolTip("Fill times_box.")
|
|
233
259
|
self.slice_mode.setToolTip("Slice by time or index.")
|
|
234
260
|
self.tmin.setToolTip("Start time (sec), -1 = auto.")
|
|
235
261
|
self.tmax.setToolTip("End time (sec), -1 = auto.")
|
|
@@ -4,6 +4,8 @@ from __future__ import annotations
|
|
|
4
4
|
|
|
5
5
|
from pathlib import Path
|
|
6
6
|
|
|
7
|
+
import numpy as np
|
|
8
|
+
|
|
7
9
|
from PySide6.QtCore import QSettings, Qt, Signal
|
|
8
10
|
from PySide6.QtGui import QColor
|
|
9
11
|
from PySide6.QtWidgets import (
|
|
@@ -15,6 +17,7 @@ from PySide6.QtWidgets import (
|
|
|
15
17
|
QGroupBox,
|
|
16
18
|
QHBoxLayout,
|
|
17
19
|
QLabel,
|
|
20
|
+
QLineEdit,
|
|
18
21
|
QProgressBar,
|
|
19
22
|
QPushButton,
|
|
20
23
|
QSpinBox,
|
|
@@ -86,6 +89,12 @@ class PreprocessPage(QWidget):
|
|
|
86
89
|
self.preset.addItems(["grid", "hd", "none"])
|
|
87
90
|
self.preset.setToolTip("Preset hints apply to analysis mode defaults.")
|
|
88
91
|
|
|
92
|
+
self.input_source = PopupComboBox()
|
|
93
|
+
self.input_source.addItem("Local file", userData="local")
|
|
94
|
+
self.input_source.addItem("CANNs dataset", userData="dataset")
|
|
95
|
+
self.input_source.addItem("URL", userData="url")
|
|
96
|
+
self.input_source.currentIndexChanged.connect(self._toggle_input_source)
|
|
97
|
+
|
|
89
98
|
self.label_mode = QLabel("Mode")
|
|
90
99
|
top_row.addWidget(self.label_mode)
|
|
91
100
|
top_row.addWidget(self.input_mode)
|
|
@@ -93,6 +102,10 @@ class PreprocessPage(QWidget):
|
|
|
93
102
|
self.label_preset = QLabel("Preset")
|
|
94
103
|
top_row.addWidget(self.label_preset)
|
|
95
104
|
top_row.addWidget(self.preset)
|
|
105
|
+
top_row.addSpacing(16)
|
|
106
|
+
self.label_source = QLabel("Source")
|
|
107
|
+
top_row.addWidget(self.label_source)
|
|
108
|
+
top_row.addWidget(self.input_source)
|
|
96
109
|
top_row.addStretch(1)
|
|
97
110
|
input_layout.addLayout(top_row)
|
|
98
111
|
|
|
@@ -126,6 +139,46 @@ class PreprocessPage(QWidget):
|
|
|
126
139
|
input_layout.addLayout(neuron_row)
|
|
127
140
|
input_layout.addLayout(traj_row)
|
|
128
141
|
|
|
142
|
+
self.dataset_group = QGroupBox("Dataset")
|
|
143
|
+
self.dataset_group.setObjectName("card")
|
|
144
|
+
dataset_form = QFormLayout(self.dataset_group)
|
|
145
|
+
|
|
146
|
+
self.dataset_key = PopupComboBox()
|
|
147
|
+
self.dataset_key.addItem("grid_1", userData="grid_1")
|
|
148
|
+
self.dataset_key.addItem("grid_2", userData="grid_2")
|
|
149
|
+
self.dataset_key.addItem("roi_data", userData="roi_data")
|
|
150
|
+
self.dataset_key.addItem("left_right_data_of", userData="left_right_data_of")
|
|
151
|
+
self.dataset_key.currentIndexChanged.connect(self._update_dataset_hint)
|
|
152
|
+
|
|
153
|
+
self.dataset_session = QLineEdit()
|
|
154
|
+
self.dataset_session.setPlaceholderText("e.g. 26034_3")
|
|
155
|
+
|
|
156
|
+
self.dataset_filename = QLineEdit()
|
|
157
|
+
self.dataset_filename.setPlaceholderText("e.g. 26034_3_ASA_full.npz")
|
|
158
|
+
|
|
159
|
+
self.dataset_url = QLineEdit()
|
|
160
|
+
self.dataset_url.setPlaceholderText("https://.../data.npz")
|
|
161
|
+
|
|
162
|
+
self.dataset_hint = QLabel("")
|
|
163
|
+
self.dataset_hint.setObjectName("muted")
|
|
164
|
+
self.dataset_hint.setWordWrap(True)
|
|
165
|
+
|
|
166
|
+
dataset_form.addRow("Dataset", self.dataset_key)
|
|
167
|
+
self.label_dataset = dataset_form.labelForField(self.dataset_key)
|
|
168
|
+
dataset_form.addRow("Session id", self.dataset_session)
|
|
169
|
+
self.label_session = dataset_form.labelForField(self.dataset_session)
|
|
170
|
+
dataset_form.addRow("Filename", self.dataset_filename)
|
|
171
|
+
self.label_filename = dataset_form.labelForField(self.dataset_filename)
|
|
172
|
+
url_row = QWidget()
|
|
173
|
+
url_layout = QHBoxLayout(url_row)
|
|
174
|
+
url_layout.setContentsMargins(0, 0, 0, 0)
|
|
175
|
+
url_layout.addWidget(self.dataset_url, 1)
|
|
176
|
+
dataset_form.addRow("URL", url_row)
|
|
177
|
+
self.label_url = dataset_form.labelForField(self.dataset_url)
|
|
178
|
+
dataset_form.addRow(self.dataset_hint)
|
|
179
|
+
|
|
180
|
+
input_layout.addWidget(self.dataset_group)
|
|
181
|
+
|
|
129
182
|
top_layout.addWidget(input_group)
|
|
130
183
|
|
|
131
184
|
# Preprocess group
|
|
@@ -244,6 +297,8 @@ class PreprocessPage(QWidget):
|
|
|
244
297
|
self.asa_browse.clicked.connect(self._update_run_enabled)
|
|
245
298
|
|
|
246
299
|
self._toggle_input_mode()
|
|
300
|
+
self._toggle_input_source()
|
|
301
|
+
self._update_dataset_hint()
|
|
247
302
|
self._toggle_embed_params()
|
|
248
303
|
self._update_run_enabled()
|
|
249
304
|
self._apply_card_effects([input_group, preprocess_group, preclass_group])
|
|
@@ -270,6 +325,7 @@ class PreprocessPage(QWidget):
|
|
|
270
325
|
|
|
271
326
|
self.label_mode.setText("模式" if is_zh else "Mode")
|
|
272
327
|
self.label_preset.setText("预设" if is_zh else "Preset")
|
|
328
|
+
self.label_source.setText("来源" if is_zh else "Source")
|
|
273
329
|
if self.label_method is not None:
|
|
274
330
|
self.label_method.setText("方法" if is_zh else "Method")
|
|
275
331
|
if self.label_preclass is not None:
|
|
@@ -317,6 +373,34 @@ class PreprocessPage(QWidget):
|
|
|
317
373
|
self.stop_btn.setText("停止" if is_zh else "Stop")
|
|
318
374
|
self.logs_label.setText("日志" if is_zh else "Logs")
|
|
319
375
|
|
|
376
|
+
self.dataset_group.setTitle("数据集" if is_zh else "Dataset")
|
|
377
|
+
if self.label_dataset is not None:
|
|
378
|
+
self.label_dataset.setText("数据集" if is_zh else "Dataset")
|
|
379
|
+
if self.label_session is not None:
|
|
380
|
+
self.label_session.setText("Session id" if not is_zh else "会话 id")
|
|
381
|
+
if self.label_filename is not None:
|
|
382
|
+
self.label_filename.setText("Filename" if not is_zh else "文件名")
|
|
383
|
+
if self.label_url is not None:
|
|
384
|
+
self.label_url.setText("URL")
|
|
385
|
+
|
|
386
|
+
self.input_source.setToolTip(
|
|
387
|
+
"选择本地文件、内置数据集或 URL"
|
|
388
|
+
if is_zh
|
|
389
|
+
else "Choose local file, built-in dataset, or URL."
|
|
390
|
+
)
|
|
391
|
+
self.dataset_key.setToolTip(
|
|
392
|
+
"选择内置数据集" if is_zh else "Select a built-in dataset."
|
|
393
|
+
)
|
|
394
|
+
self.dataset_session.setToolTip(
|
|
395
|
+
"Left-Right 数据集的会话 id。" if is_zh else "Session id for Left-Right dataset."
|
|
396
|
+
)
|
|
397
|
+
self.dataset_filename.setToolTip(
|
|
398
|
+
"Left-Right 数据集文件名。" if is_zh else "Filename within Left-Right dataset."
|
|
399
|
+
)
|
|
400
|
+
self.dataset_url.setToolTip(
|
|
401
|
+
"直接加载 .npz 链接。" if is_zh else "Load a .npz URL directly."
|
|
402
|
+
)
|
|
403
|
+
|
|
320
404
|
self.input_mode.setToolTip(
|
|
321
405
|
"仅支持 ASA .npz 输入" if is_zh else "Only ASA .npz input is supported in this GUI."
|
|
322
406
|
)
|
|
@@ -346,6 +430,15 @@ class PreprocessPage(QWidget):
|
|
|
346
430
|
else "Speed threshold (same unit as t/x/y)."
|
|
347
431
|
)
|
|
348
432
|
|
|
433
|
+
self.dataset_session.setPlaceholderText("例如 26034_3" if is_zh else "e.g. 26034_3")
|
|
434
|
+
self.dataset_filename.setPlaceholderText(
|
|
435
|
+
"例如 26034_3_ASA_full.npz" if is_zh else "e.g. 26034_3_ASA_full.npz"
|
|
436
|
+
)
|
|
437
|
+
self.dataset_url.setPlaceholderText(
|
|
438
|
+
"https://.../data.npz" if not is_zh else "https://.../data.npz"
|
|
439
|
+
)
|
|
440
|
+
self._update_dataset_hint()
|
|
441
|
+
|
|
349
442
|
def _show_help(self) -> None:
|
|
350
443
|
lang = str(QSettings("canns", "asa_gui").value("lang", "en"))
|
|
351
444
|
title = (
|
|
@@ -386,6 +479,63 @@ class PreprocessPage(QWidget):
|
|
|
386
479
|
self.traj_zone.setVisible(not use_asa)
|
|
387
480
|
self.traj_browse.setVisible(not use_asa)
|
|
388
481
|
|
|
482
|
+
def _toggle_input_source(self) -> None:
|
|
483
|
+
source = self.input_source.currentData() or "local"
|
|
484
|
+
use_local = source == "local"
|
|
485
|
+
self.asa_zone.setVisible(use_local)
|
|
486
|
+
self.asa_browse.setVisible(use_local)
|
|
487
|
+
self.asa_hint.setVisible(use_local)
|
|
488
|
+
self.dataset_group.setVisible(not use_local)
|
|
489
|
+
self._update_dataset_hint()
|
|
490
|
+
self._update_run_enabled()
|
|
491
|
+
|
|
492
|
+
def _update_dataset_hint(self) -> None:
|
|
493
|
+
source = self.input_source.currentData() or "local"
|
|
494
|
+
key = self.dataset_key.currentData() or self.dataset_key.currentText()
|
|
495
|
+
is_left_right = key == "left_right_data_of"
|
|
496
|
+
is_zh = str(self._lang).lower().startswith("zh")
|
|
497
|
+
show_dataset = source == "dataset"
|
|
498
|
+
if self.label_session is not None:
|
|
499
|
+
self.label_session.setVisible(is_left_right and show_dataset)
|
|
500
|
+
self.dataset_session.setVisible(is_left_right and show_dataset)
|
|
501
|
+
if self.label_filename is not None:
|
|
502
|
+
self.label_filename.setVisible(is_left_right and show_dataset)
|
|
503
|
+
self.dataset_filename.setVisible(is_left_right and show_dataset)
|
|
504
|
+
if self.label_dataset is not None:
|
|
505
|
+
self.label_dataset.setVisible(show_dataset)
|
|
506
|
+
self.dataset_key.setVisible(show_dataset)
|
|
507
|
+
if self.label_url is not None:
|
|
508
|
+
self.label_url.setVisible(source == "url")
|
|
509
|
+
self.dataset_url.setVisible(source == "url")
|
|
510
|
+
|
|
511
|
+
hint = ""
|
|
512
|
+
if source == "url":
|
|
513
|
+
hint = (
|
|
514
|
+
"加载包含 spike/x/y/t 的 .npz 链接。"
|
|
515
|
+
if is_zh
|
|
516
|
+
else "Load a .npz URL that contains spike/x/y/t."
|
|
517
|
+
)
|
|
518
|
+
elif source == "dataset":
|
|
519
|
+
try:
|
|
520
|
+
from canns.data import datasets as _datasets
|
|
521
|
+
|
|
522
|
+
info = _datasets.DATASETS.get(str(key))
|
|
523
|
+
if info:
|
|
524
|
+
size = info.get("size_mb", "?")
|
|
525
|
+
desc = info.get("description", "")
|
|
526
|
+
hint = f"{desc} (size ~{size} MB)" if not is_zh else f"{desc} (约 {size} MB)"
|
|
527
|
+
except Exception:
|
|
528
|
+
hint = ""
|
|
529
|
+
if is_left_right:
|
|
530
|
+
hint = (
|
|
531
|
+
(hint + "\n") if hint else ""
|
|
532
|
+
) + (
|
|
533
|
+
"左/右数据集需要 session id 和文件名。"
|
|
534
|
+
if is_zh
|
|
535
|
+
else "Left-right dataset requires session id + filename."
|
|
536
|
+
)
|
|
537
|
+
self.dataset_hint.setText(hint)
|
|
538
|
+
|
|
389
539
|
def _toggle_embed_params(self) -> None:
|
|
390
540
|
method = self.preprocess_method.currentData() or "none"
|
|
391
541
|
self.embed_params.setVisible(method == "embed_spike_trains")
|
|
@@ -420,6 +570,96 @@ class PreprocessPage(QWidget):
|
|
|
420
570
|
}
|
|
421
571
|
return params
|
|
422
572
|
|
|
573
|
+
def _slugify(self, text: str) -> str:
|
|
574
|
+
out = []
|
|
575
|
+
for ch in text:
|
|
576
|
+
if ch.isalnum() or ch in ("-", "_"):
|
|
577
|
+
out.append(ch)
|
|
578
|
+
else:
|
|
579
|
+
out.append("_")
|
|
580
|
+
return "".join(out).strip("_") or "dataset"
|
|
581
|
+
|
|
582
|
+
def _normalize_npz_payload(self, data: dict) -> dict:
|
|
583
|
+
payload: dict = {}
|
|
584
|
+
for key, value in data.items():
|
|
585
|
+
if isinstance(value, dict):
|
|
586
|
+
payload[key] = np.array(value, dtype=object)
|
|
587
|
+
else:
|
|
588
|
+
payload[key] = value
|
|
589
|
+
return payload
|
|
590
|
+
|
|
591
|
+
def _prepare_dataset_asa(self) -> str | None:
|
|
592
|
+
source = self.input_source.currentData() or "local"
|
|
593
|
+
if source == "local":
|
|
594
|
+
return self.asa_zone.path()
|
|
595
|
+
|
|
596
|
+
data = None
|
|
597
|
+
label = ""
|
|
598
|
+
if source == "url":
|
|
599
|
+
url = self.dataset_url.text().strip()
|
|
600
|
+
if not url:
|
|
601
|
+
self.log_box.log("Please provide a dataset URL.")
|
|
602
|
+
return None
|
|
603
|
+
label = self._slugify(Path(url).stem or "dataset_url")
|
|
604
|
+
try:
|
|
605
|
+
from canns.data import datasets as _datasets
|
|
606
|
+
|
|
607
|
+
data = _datasets.load(url, file_type="numpy")
|
|
608
|
+
except Exception as exc:
|
|
609
|
+
self.log_box.log(f"Failed to load URL dataset: {exc}")
|
|
610
|
+
return None
|
|
611
|
+
elif source == "dataset":
|
|
612
|
+
key = self.dataset_key.currentData() or self.dataset_key.currentText()
|
|
613
|
+
label = self._slugify(str(key))
|
|
614
|
+
try:
|
|
615
|
+
from canns.data import loaders as _loaders
|
|
616
|
+
from canns.data import datasets as _datasets
|
|
617
|
+
|
|
618
|
+
if key == "roi_data":
|
|
619
|
+
data = _loaders.load_roi_data()
|
|
620
|
+
elif key == "left_right_data_of":
|
|
621
|
+
session_id = self.dataset_session.text().strip()
|
|
622
|
+
filename = self.dataset_filename.text().strip()
|
|
623
|
+
if not session_id or not filename:
|
|
624
|
+
self.log_box.log("Left-Right dataset requires session id + filename.")
|
|
625
|
+
return None
|
|
626
|
+
data = _loaders.load_left_right_npz(session_id=session_id, filename=filename)
|
|
627
|
+
label = self._slugify(f"{session_id}_{filename}")
|
|
628
|
+
elif str(key).startswith("grid_"):
|
|
629
|
+
data = _loaders.load_grid_data(dataset_key=str(key))
|
|
630
|
+
else:
|
|
631
|
+
path = _datasets.download_dataset(str(key))
|
|
632
|
+
if path is not None and path.exists():
|
|
633
|
+
data = dict(np.load(path, allow_pickle=True))
|
|
634
|
+
except Exception as exc:
|
|
635
|
+
self.log_box.log(f"Failed to load dataset '{key}': {exc}")
|
|
636
|
+
return None
|
|
637
|
+
|
|
638
|
+
if data is None:
|
|
639
|
+
self.log_box.log("Dataset load failed or returned empty data.")
|
|
640
|
+
return None
|
|
641
|
+
|
|
642
|
+
if not isinstance(data, dict):
|
|
643
|
+
self.log_box.log("Dataset is not an ASA .npz dict (missing spike/x/y/t).")
|
|
644
|
+
return None
|
|
645
|
+
|
|
646
|
+
payload = self._normalize_npz_payload(data)
|
|
647
|
+
if "spike" not in payload or "t" not in payload:
|
|
648
|
+
self.log_box.log("Dataset does not contain required keys: spike, t.")
|
|
649
|
+
return None
|
|
650
|
+
|
|
651
|
+
out_dir = Path.cwd() / "Results" / "asa_gui_datasets"
|
|
652
|
+
out_dir.mkdir(parents=True, exist_ok=True)
|
|
653
|
+
out_path = out_dir / f"{label}.npz"
|
|
654
|
+
try:
|
|
655
|
+
np.savez_compressed(out_path, **payload)
|
|
656
|
+
except Exception as exc:
|
|
657
|
+
self.log_box.log(f"Failed to save dataset as npz: {exc}")
|
|
658
|
+
return None
|
|
659
|
+
|
|
660
|
+
self.asa_zone.set_path(str(out_path))
|
|
661
|
+
return str(out_path)
|
|
662
|
+
|
|
423
663
|
def _run_preprocess(self) -> None:
|
|
424
664
|
if self._workers.is_running():
|
|
425
665
|
self.log_box.log("A task is already running.")
|
|
@@ -433,6 +673,9 @@ class PreprocessPage(QWidget):
|
|
|
433
673
|
neuron_file = self.neuron_zone.path() if input_mode != "asa" else None
|
|
434
674
|
traj_file = self.traj_zone.path() if input_mode != "asa" else None
|
|
435
675
|
|
|
676
|
+
if input_mode == "asa":
|
|
677
|
+
asa_file = self._prepare_dataset_asa()
|
|
678
|
+
|
|
436
679
|
if not self._validate_inputs(asa_file):
|
|
437
680
|
return
|
|
438
681
|
|
|
@@ -509,13 +752,17 @@ class PreprocessPage(QWidget):
|
|
|
509
752
|
return True
|
|
510
753
|
|
|
511
754
|
def _update_run_enabled(self) -> None:
|
|
755
|
+
source = self.input_source.currentData() or "local"
|
|
512
756
|
asa_file = self.asa_zone.path()
|
|
513
757
|
valid = False
|
|
514
|
-
if asa_file:
|
|
758
|
+
if source == "local" and asa_file:
|
|
515
759
|
path = Path(asa_file)
|
|
516
760
|
valid = path.exists() and path.suffix.lower() == ".npz"
|
|
517
761
|
self.run_btn.setEnabled(True)
|
|
518
|
-
if
|
|
519
|
-
|
|
762
|
+
if source == "local":
|
|
763
|
+
if valid:
|
|
764
|
+
self.run_btn.setToolTip("")
|
|
765
|
+
else:
|
|
766
|
+
self.run_btn.setToolTip("Select a valid ASA .npz file to run preprocessing.")
|
|
520
767
|
else:
|
|
521
|
-
self.run_btn.setToolTip("
|
|
768
|
+
self.run_btn.setToolTip("Dataset/URL will be loaded on Run.")
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: canns
|
|
3
|
-
Version: 0.14.
|
|
3
|
+
Version: 0.14.3
|
|
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>
|
|
@@ -44,6 +44,7 @@ Requires-Dist: imageio; extra == 'gui'
|
|
|
44
44
|
Requires-Dist: pillow; extra == 'gui'
|
|
45
45
|
Requires-Dist: pyside6>=6.6.0; extra == 'gui'
|
|
46
46
|
Requires-Dist: qtawesome; extra == 'gui'
|
|
47
|
+
Requires-Dist: requests>=2.31.0; extra == 'gui'
|
|
47
48
|
Provides-Extra: tpu
|
|
48
49
|
Requires-Dist: brainpy[tpu]; (platform_system == 'Linux') and extra == 'tpu'
|
|
49
50
|
Description-Content-Type: text/markdown
|
|
@@ -94,7 +94,7 @@ canns/pipeline/asa_gui/analysis_modes/decode_mode.py,sha256=uEe3lfWAA0pqmCXzNpaA
|
|
|
94
94
|
canns/pipeline/asa_gui/analysis_modes/fr_mode.py,sha256=xzx1RhGVDbx6huEtEHGfUqWgRN_C6Sf-Ycj9BzIgTRY,3961
|
|
95
95
|
canns/pipeline/asa_gui/analysis_modes/frm_mode.py,sha256=8rgh_P7dxYJfx2TxrhD00Ja6tK0q6NboqwZ7n0Sw_2U,3992
|
|
96
96
|
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=
|
|
97
|
+
canns/pipeline/asa_gui/analysis_modes/pathcompare_mode.py,sha256=oRZPB8y7ORDFDPk99joRNQRj_e5qmR-GuJHrGnSynS4,10808
|
|
98
98
|
canns/pipeline/asa_gui/analysis_modes/tda_mode.py,sha256=xnsWv_zfstzYPf_nLbQkCNHxxhYRznz4m-73ClaBQKs,6094
|
|
99
99
|
canns/pipeline/asa_gui/controllers/__init__.py,sha256=RuQz960T4kEuQsBI_cjS0cQgFyqAdblLXy_dDoLPbTE,198
|
|
100
100
|
canns/pipeline/asa_gui/controllers/analysis_controller.py,sha256=8cKs-RYHh_NflP7xeS0u0_y9WsZ268H1Wyp-wHZC97I,1769
|
|
@@ -122,7 +122,7 @@ canns/pipeline/asa_gui/views/__init__.py,sha256=ThoLlMw7bKxA7lkv_AvIR1mbpaoM0vkI
|
|
|
122
122
|
canns/pipeline/asa_gui/views/help_content.py,sha256=kL7MSwc9v3gHLz86Apiy64xbwymt9r7sPEjz5ka6EB0,8452
|
|
123
123
|
canns/pipeline/asa_gui/views/pages/__init__.py,sha256=xB7VTY_hKfoCNMGeWZbV3gHG9ErrzmwqW30UlUkbqgE,161
|
|
124
124
|
canns/pipeline/asa_gui/views/pages/analysis_page.py,sha256=X6PGW_cgvAiNFqUpsS2TuVWl258Q6Q90C9NEQT1TetQ,22807
|
|
125
|
-
canns/pipeline/asa_gui/views/pages/preprocess_page.py,sha256=
|
|
125
|
+
canns/pipeline/asa_gui/views/pages/preprocess_page.py,sha256=AHWidQqNKF0TBx8i2dDmPfxjT4Qy45_FjBYh-O1zB8E,31364
|
|
126
126
|
canns/pipeline/asa_gui/views/panels/__init__.py,sha256=Spqmc0Sjh38cgr42gszmiogZQFFOLN1yL7ekSpVJCrE,36
|
|
127
127
|
canns/pipeline/asa_gui/views/widgets/__init__.py,sha256=xaTYXw99OL8ye1cpfoKgSwqC7c2B6lrLLsYHRB16m64,481
|
|
128
128
|
canns/pipeline/asa_gui/views/widgets/artifacts_tab.py,sha256=U_fuOCfSmkDhx3G97aod-8UPSIFVz_MrsU4b_ik_5qE,1431
|
|
@@ -158,8 +158,8 @@ canns/trainer/utils.py,sha256=ZdoLiRqFLfKXsWi0KX3wGUp0OqFikwiou8dPf3xvFhE,2847
|
|
|
158
158
|
canns/typing/__init__.py,sha256=mXySdfmD8fA56WqZTb1Nj-ZovcejwLzNjuk6PRfTwmA,156
|
|
159
159
|
canns/utils/__init__.py,sha256=OMyZ5jqZAIUS2Jr0qcnvvrx6YM-BZ1EJy5uZYeA3HC0,366
|
|
160
160
|
canns/utils/benchmark.py,sha256=oJ7nvbvnQMh4_MZh7z160NPLp-197X0rEnmnLHYlev4,1361
|
|
161
|
-
canns-0.14.
|
|
162
|
-
canns-0.14.
|
|
163
|
-
canns-0.14.
|
|
164
|
-
canns-0.14.
|
|
165
|
-
canns-0.14.
|
|
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,,
|
|
File without changes
|
|
File without changes
|
|
File without changes
|