brkraw-viewer 0.2.7__tar.gz

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 (34) hide show
  1. brkraw_viewer-0.2.7/PKG-INFO +170 -0
  2. brkraw_viewer-0.2.7/README.md +151 -0
  3. brkraw_viewer-0.2.7/pyproject.toml +46 -0
  4. brkraw_viewer-0.2.7/setup.cfg +4 -0
  5. brkraw_viewer-0.2.7/src/brkraw_viewer/__init__.py +4 -0
  6. brkraw_viewer-0.2.7/src/brkraw_viewer/apps/__init__.py +0 -0
  7. brkraw_viewer-0.2.7/src/brkraw_viewer/apps/config.py +90 -0
  8. brkraw_viewer-0.2.7/src/brkraw_viewer/apps/convert.py +1754 -0
  9. brkraw_viewer-0.2.7/src/brkraw_viewer/apps/hooks.py +36 -0
  10. brkraw_viewer-0.2.7/src/brkraw_viewer/apps/viewer.py +5541 -0
  11. brkraw_viewer-0.2.7/src/brkraw_viewer/assets/icon.ico +0 -0
  12. brkraw_viewer-0.2.7/src/brkraw_viewer/assets/icon.png +0 -0
  13. brkraw_viewer-0.2.7/src/brkraw_viewer/frames/__init__.py +2 -0
  14. brkraw_viewer-0.2.7/src/brkraw_viewer/frames/params_panel.py +80 -0
  15. brkraw_viewer-0.2.7/src/brkraw_viewer/frames/viewer_canvas.py +546 -0
  16. brkraw_viewer-0.2.7/src/brkraw_viewer/frames/viewer_config.py +101 -0
  17. brkraw_viewer-0.2.7/src/brkraw_viewer/plugin.py +125 -0
  18. brkraw_viewer-0.2.7/src/brkraw_viewer/registry.py +258 -0
  19. brkraw_viewer-0.2.7/src/brkraw_viewer/snippets/context_map/basic.yaml +4 -0
  20. brkraw_viewer-0.2.7/src/brkraw_viewer/snippets/context_map/enum-map.yaml +5 -0
  21. brkraw_viewer-0.2.7/src/brkraw_viewer/snippets/rule/basic.yaml +10 -0
  22. brkraw_viewer-0.2.7/src/brkraw_viewer/snippets/rule/when-contains.yaml +10 -0
  23. brkraw_viewer-0.2.7/src/brkraw_viewer/snippets/spec/basic.yaml +5 -0
  24. brkraw_viewer-0.2.7/src/brkraw_viewer/snippets/spec/list-source.yaml +5 -0
  25. brkraw_viewer-0.2.7/src/brkraw_viewer/snippets/spec/with-default.yaml +5 -0
  26. brkraw_viewer-0.2.7/src/brkraw_viewer/utils/__init__.py +2 -0
  27. brkraw_viewer-0.2.7/src/brkraw_viewer/utils/orientation.py +17 -0
  28. brkraw_viewer-0.2.7/src/brkraw_viewer.egg-info/PKG-INFO +170 -0
  29. brkraw_viewer-0.2.7/src/brkraw_viewer.egg-info/SOURCES.txt +32 -0
  30. brkraw_viewer-0.2.7/src/brkraw_viewer.egg-info/dependency_links.txt +1 -0
  31. brkraw_viewer-0.2.7/src/brkraw_viewer.egg-info/entry_points.txt +2 -0
  32. brkraw_viewer-0.2.7/src/brkraw_viewer.egg-info/requires.txt +9 -0
  33. brkraw_viewer-0.2.7/src/brkraw_viewer.egg-info/top_level.txt +1 -0
  34. brkraw_viewer-0.2.7/tests/test_smoke_viewer.py +29 -0
@@ -0,0 +1,170 @@
1
+ Metadata-Version: 2.4
2
+ Name: brkraw-viewer
3
+ Version: 0.2.7
4
+ Summary: BrkRaw scan viewer plugin for brkraw CLI.
5
+ Author: BrkRaw
6
+ License: MIT
7
+ Classifier: Programming Language :: Python :: 3
8
+ Classifier: License :: OSI Approved :: MIT License
9
+ Classifier: Operating System :: OS Independent
10
+ Requires-Python: >=3.9
11
+ Description-Content-Type: text/markdown
12
+ Requires-Dist: brkraw>=0.5.0rc1
13
+ Requires-Dist: nibabel>=5.0
14
+ Requires-Dist: pillow>=10.0
15
+ Provides-Extra: docs
16
+ Requires-Dist: mkdocs-material>=9.5.0; extra == "docs"
17
+ Provides-Extra: test
18
+ Requires-Dist: pytest>=7.4; extra == "test"
19
+
20
+ <h1 align="left">
21
+ <picture>
22
+ <source media="(prefers-color-scheme: dark)" srcset="docs/assets/brkraw-viewer-logo-dark.svg">
23
+ <img alt="BrkRaw Viewer" src="docs/assets/brkraw-viewer-logo-light.svg" width="410">
24
+ </picture>
25
+ </h1>
26
+
27
+ BrkRaw Viewer is an interactive dataset viewer implemented as a
28
+ separate CLI plugin for the `brkraw` command.
29
+
30
+ The viewer is intentionally maintained outside the BrkRaw core to
31
+ enable independent development and community contributions around
32
+ user-facing interfaces.
33
+
34
+ ---
35
+
36
+ ## Scope and intent
37
+
38
+ BrkRaw Viewer is designed for **interactive inspection** of Bruker
39
+ Paravision datasets. It focuses on quick exploration and validation
40
+ rather than data conversion or analysis.
41
+
42
+ The goal is to provide practical, researcher-focused features that are
43
+ useful in everyday workflows, such as quick dataset triage, metadata
44
+ checks, and lightweight visual QC.
45
+
46
+ Typical use cases include:
47
+
48
+ - Browsing studies, scans, and reconstructions
49
+ - Verifying scan and reconstruction IDs
50
+ - Inspecting acquisition metadata before conversion
51
+ - Lightweight visual sanity checks
52
+
53
+ All data conversion and reproducible workflows are handled by the
54
+ BrkRaw CLI and Python API.
55
+
56
+ ---
57
+
58
+ ## Why these features exist
59
+
60
+ **Viewer**
61
+ The Viewer tab makes it easy to confirm the right scan and orientation before
62
+ running a larger workflow.
63
+
64
+ **Registry**
65
+ The Registry reduces repeated filesystem navigation and lets you re-open the
66
+ current session with a single menu action.
67
+
68
+ **Extensions/hooks**
69
+ Extensions allow modality-specific panels (MRS, BIDS, etc.) to live outside the
70
+ core viewer so the default install stays lightweight.
71
+
72
+ ---
73
+
74
+ ## Design goal: shared extensibility
75
+
76
+ brkraw-viewer keeps the BrkRaw design philosophy: extend the ecosystem
77
+ without changing core logic. The viewer uses the same rules/spec/layout
78
+ system as the CLI and Python API, and it exposes UI extensions via the
79
+ `brkraw.viewer.hook` entry point so new tabs can be added with standalone
80
+ packages. Viewer hooks can coexist with converter hooks and CLI hooks,
81
+ so modality-specific logic can flow from conversion into UI without
82
+ patching the viewer itself.
83
+
84
+ ---
85
+
86
+ ## UI direction
87
+
88
+ The default viewer targets a **tkinter-based** implementation.
89
+
90
+ This choice is intentional: we want a lightweight tool that can be
91
+ used directly on scanner consoles or constrained environments with
92
+ minimal dependencies.
93
+
94
+ More modern GUI frameworks are welcome, but should be developed as
95
+ separate CLI extensions to keep the default viewer small and easy to
96
+ install.
97
+
98
+ ---
99
+
100
+ ## Viewer hooks
101
+
102
+ Viewer extensions are implemented as hooks discovered through
103
+ `brkraw.viewer.hook`. Each hook can register a new tab and provide
104
+ dataset callbacks, enabling feature panels to live outside the core
105
+ viewer while staying compatible with BrkRaw rules, specs, and converter
106
+ hooks. See `docs/dev/hooks.md` for the hook interface and entry point
107
+ setup.
108
+
109
+ ---
110
+
111
+ ## Installation
112
+
113
+ For development and testing, install in editable mode:
114
+
115
+ pip install -e .
116
+
117
+ ---
118
+
119
+ ## Usage
120
+
121
+ Launch the viewer via the BrkRaw CLI:
122
+
123
+ brkraw viewer /path/to/bruker/study
124
+
125
+ Optional arguments allow opening a specific scan or slice:
126
+
127
+ brkraw viewer /path/to/bruker/study \
128
+ --scan 3 \
129
+ --reco 1
130
+
131
+ The viewer can also open `.zip` or Paravision-exported `.PvDatasets`
132
+ archives using `Load` (folder or archive file).
133
+
134
+ ---
135
+
136
+ ## Update
137
+
138
+ Recent updates:
139
+
140
+ - Open folders or archives (`.zip` / `.PvDatasets`)
141
+ - Viewer: `Space` (`raw/scanner/subject_ras`), nibabel RAS display, click-to-set `X/Y/Z`, optional crosshair + zoom,
142
+ slicepack/frame sliders only when needed
143
+ - Info: rule + spec selection (installed or file), parameter search, lazy Viewer refresh on tab focus
144
+ - Registry: add the current session from the `+` menu when a dataset is loaded
145
+ - Convert: BrkRaw layout engine, template + suffix defaults from `~/.brkraw/config.yaml`, keys browser (click to add),
146
+ optional config `layout_entries`
147
+ - Config: edit `~/.brkraw/config.yaml` in-app; basic focus/icon UX
148
+
149
+ This update keeps dependencies minimal and preserves compatibility with
150
+ the core BrkRaw rule/spec/hook system.
151
+
152
+ ---
153
+
154
+ ## Contributing
155
+
156
+ We welcome contributions related to:
157
+
158
+ - New viewer hooks that add modality-specific panels or workflows
159
+ - Alternative UI implementations delivered as separate CLI extensions
160
+ - fMRI/MRS/BIDS-focused visualization or QC helpers built on hooks
161
+ - Multi-dataset session management and registry enhancements
162
+ - Performance and memory improvements for large datasets
163
+
164
+ Contributions should prefer designs where new hooks extend the viewer
165
+ implicitly through shared BrkRaw abstractions, and where richer UIs are
166
+ provided as optional CLI extensions rather than increasing the default
167
+ dependency footprint.
168
+
169
+ If you are interested in contributing, please start a discussion or
170
+ open an issue describing your use case and goals.
@@ -0,0 +1,151 @@
1
+ <h1 align="left">
2
+ <picture>
3
+ <source media="(prefers-color-scheme: dark)" srcset="docs/assets/brkraw-viewer-logo-dark.svg">
4
+ <img alt="BrkRaw Viewer" src="docs/assets/brkraw-viewer-logo-light.svg" width="410">
5
+ </picture>
6
+ </h1>
7
+
8
+ BrkRaw Viewer is an interactive dataset viewer implemented as a
9
+ separate CLI plugin for the `brkraw` command.
10
+
11
+ The viewer is intentionally maintained outside the BrkRaw core to
12
+ enable independent development and community contributions around
13
+ user-facing interfaces.
14
+
15
+ ---
16
+
17
+ ## Scope and intent
18
+
19
+ BrkRaw Viewer is designed for **interactive inspection** of Bruker
20
+ Paravision datasets. It focuses on quick exploration and validation
21
+ rather than data conversion or analysis.
22
+
23
+ The goal is to provide practical, researcher-focused features that are
24
+ useful in everyday workflows, such as quick dataset triage, metadata
25
+ checks, and lightweight visual QC.
26
+
27
+ Typical use cases include:
28
+
29
+ - Browsing studies, scans, and reconstructions
30
+ - Verifying scan and reconstruction IDs
31
+ - Inspecting acquisition metadata before conversion
32
+ - Lightweight visual sanity checks
33
+
34
+ All data conversion and reproducible workflows are handled by the
35
+ BrkRaw CLI and Python API.
36
+
37
+ ---
38
+
39
+ ## Why these features exist
40
+
41
+ **Viewer**
42
+ The Viewer tab makes it easy to confirm the right scan and orientation before
43
+ running a larger workflow.
44
+
45
+ **Registry**
46
+ The Registry reduces repeated filesystem navigation and lets you re-open the
47
+ current session with a single menu action.
48
+
49
+ **Extensions/hooks**
50
+ Extensions allow modality-specific panels (MRS, BIDS, etc.) to live outside the
51
+ core viewer so the default install stays lightweight.
52
+
53
+ ---
54
+
55
+ ## Design goal: shared extensibility
56
+
57
+ brkraw-viewer keeps the BrkRaw design philosophy: extend the ecosystem
58
+ without changing core logic. The viewer uses the same rules/spec/layout
59
+ system as the CLI and Python API, and it exposes UI extensions via the
60
+ `brkraw.viewer.hook` entry point so new tabs can be added with standalone
61
+ packages. Viewer hooks can coexist with converter hooks and CLI hooks,
62
+ so modality-specific logic can flow from conversion into UI without
63
+ patching the viewer itself.
64
+
65
+ ---
66
+
67
+ ## UI direction
68
+
69
+ The default viewer targets a **tkinter-based** implementation.
70
+
71
+ This choice is intentional: we want a lightweight tool that can be
72
+ used directly on scanner consoles or constrained environments with
73
+ minimal dependencies.
74
+
75
+ More modern GUI frameworks are welcome, but should be developed as
76
+ separate CLI extensions to keep the default viewer small and easy to
77
+ install.
78
+
79
+ ---
80
+
81
+ ## Viewer hooks
82
+
83
+ Viewer extensions are implemented as hooks discovered through
84
+ `brkraw.viewer.hook`. Each hook can register a new tab and provide
85
+ dataset callbacks, enabling feature panels to live outside the core
86
+ viewer while staying compatible with BrkRaw rules, specs, and converter
87
+ hooks. See `docs/dev/hooks.md` for the hook interface and entry point
88
+ setup.
89
+
90
+ ---
91
+
92
+ ## Installation
93
+
94
+ For development and testing, install in editable mode:
95
+
96
+ pip install -e .
97
+
98
+ ---
99
+
100
+ ## Usage
101
+
102
+ Launch the viewer via the BrkRaw CLI:
103
+
104
+ brkraw viewer /path/to/bruker/study
105
+
106
+ Optional arguments allow opening a specific scan or slice:
107
+
108
+ brkraw viewer /path/to/bruker/study \
109
+ --scan 3 \
110
+ --reco 1
111
+
112
+ The viewer can also open `.zip` or Paravision-exported `.PvDatasets`
113
+ archives using `Load` (folder or archive file).
114
+
115
+ ---
116
+
117
+ ## Update
118
+
119
+ Recent updates:
120
+
121
+ - Open folders or archives (`.zip` / `.PvDatasets`)
122
+ - Viewer: `Space` (`raw/scanner/subject_ras`), nibabel RAS display, click-to-set `X/Y/Z`, optional crosshair + zoom,
123
+ slicepack/frame sliders only when needed
124
+ - Info: rule + spec selection (installed or file), parameter search, lazy Viewer refresh on tab focus
125
+ - Registry: add the current session from the `+` menu when a dataset is loaded
126
+ - Convert: BrkRaw layout engine, template + suffix defaults from `~/.brkraw/config.yaml`, keys browser (click to add),
127
+ optional config `layout_entries`
128
+ - Config: edit `~/.brkraw/config.yaml` in-app; basic focus/icon UX
129
+
130
+ This update keeps dependencies minimal and preserves compatibility with
131
+ the core BrkRaw rule/spec/hook system.
132
+
133
+ ---
134
+
135
+ ## Contributing
136
+
137
+ We welcome contributions related to:
138
+
139
+ - New viewer hooks that add modality-specific panels or workflows
140
+ - Alternative UI implementations delivered as separate CLI extensions
141
+ - fMRI/MRS/BIDS-focused visualization or QC helpers built on hooks
142
+ - Multi-dataset session management and registry enhancements
143
+ - Performance and memory improvements for large datasets
144
+
145
+ Contributions should prefer designs where new hooks extend the viewer
146
+ implicitly through shared BrkRaw abstractions, and where richer UIs are
147
+ provided as optional CLI extensions rather than increasing the default
148
+ dependency footprint.
149
+
150
+ If you are interested in contributing, please start a discussion or
151
+ open an issue describing your use case and goals.
@@ -0,0 +1,46 @@
1
+ [build-system]
2
+ requires = ["setuptools>=68", "wheel"]
3
+ build-backend = "setuptools.build_meta"
4
+
5
+ [project]
6
+ name = "brkraw-viewer"
7
+ version = "0.2.7"
8
+ description = "BrkRaw scan viewer plugin for brkraw CLI."
9
+ readme = "README.md"
10
+ requires-python = ">=3.9"
11
+ dependencies = [
12
+ "brkraw>=0.5.0rc1",
13
+ "nibabel>=5.0",
14
+ "pillow>=10.0",
15
+ ]
16
+ authors = [{name = "BrkRaw"}]
17
+ license = {text = "MIT"}
18
+ classifiers = [
19
+ "Programming Language :: Python :: 3",
20
+ "License :: OSI Approved :: MIT License",
21
+ "Operating System :: OS Independent",
22
+ ]
23
+
24
+ [project.entry-points."brkraw.cli"]
25
+ viewer = "brkraw_viewer.plugin:register"
26
+
27
+ [project.optional-dependencies]
28
+ docs = [
29
+ "mkdocs-material>=9.5.0",
30
+ ]
31
+ test = [
32
+ "pytest>=7.4",
33
+ ]
34
+
35
+ [tool.pytest.ini_options]
36
+ testpaths = ["tests"]
37
+ addopts = "-q"
38
+
39
+ [tool.setuptools]
40
+ package-dir = {"" = "src"}
41
+
42
+ [tool.setuptools.packages.find]
43
+ where = ["src"]
44
+
45
+ [tool.setuptools.package-data]
46
+ brkraw_viewer = ["assets/*.png", "assets/*.ico", "snippets/**/*.yaml"]
@@ -0,0 +1,4 @@
1
+ [egg_info]
2
+ tag_build =
3
+ tag_date = 0
4
+
@@ -0,0 +1,4 @@
1
+ """BrkRaw viewer plugin package."""
2
+
3
+ __all__ = ["__version__"]
4
+ __version__ = '0.2.7'
File without changes
@@ -0,0 +1,90 @@
1
+ from __future__ import annotations
2
+
3
+ import datetime as dt
4
+ import logging
5
+ import shutil
6
+ import tkinter as tk
7
+ from tkinter import messagebox, ttk
8
+ from pathlib import Path
9
+
10
+ from brkraw.core import config as config_core
11
+
12
+ logger = logging.getLogger("brkraw.viewer")
13
+
14
+
15
+ class ConfigTabMixin:
16
+ _config_text: tk.Text
17
+ _config_path_var: tk.StringVar
18
+
19
+ def _build_config_tab(self, config_tab: ttk.Frame) -> None:
20
+ config_tab.columnconfigure(0, weight=1)
21
+ config_tab.rowconfigure(1, weight=1)
22
+ config_bar = ttk.Frame(config_tab, padding=(6, 6))
23
+ config_bar.grid(row=0, column=0, sticky="ew")
24
+ ttk.Button(config_bar, text="Save", command=self._save_config_text).pack(side=tk.LEFT)
25
+ ttk.Button(config_bar, text="Backup", command=self._backup_config_text).pack(side=tk.LEFT, padx=(6, 0))
26
+ ttk.Button(config_bar, text="Reset", command=self._reset_config_text).pack(side=tk.LEFT, padx=(6, 0))
27
+ self._config_path_var = tk.StringVar(value="")
28
+ ttk.Label(config_bar, textvariable=self._config_path_var).pack(side=tk.LEFT, padx=(12, 0))
29
+
30
+ config_body = ttk.Frame(config_tab, padding=(6, 6))
31
+ config_body.grid(row=1, column=0, sticky="nsew")
32
+ config_body.columnconfigure(0, weight=1)
33
+ config_body.rowconfigure(0, weight=1)
34
+ self._config_text = tk.Text(config_body, wrap="none")
35
+ self._config_text.grid(row=0, column=0, sticky="nsew")
36
+ config_scroll = ttk.Scrollbar(config_body, orient="vertical", command=self._config_text.yview)
37
+ config_scroll.grid(row=0, column=1, sticky="ns")
38
+ self._config_text.configure(yscrollcommand=config_scroll.set)
39
+
40
+ def _load_config_text(self) -> None:
41
+ try:
42
+ paths = config_core.ensure_initialized(root=None, create_config=True, exist_ok=True)
43
+ self._config_path_var.set(str(paths.config_file))
44
+ content = paths.config_file.read_text(encoding="utf-8")
45
+ except Exception as exc:
46
+ logger.error("Failed to load config.yaml: %s", exc, exc_info=logger.isEnabledFor(logging.DEBUG))
47
+ self._config_path_var.set("")
48
+ self._config_text.delete("1.0", tk.END)
49
+ self._config_text.insert(tk.END, f"# Failed to load config.yaml: {exc}\n")
50
+ return
51
+ self._config_text.delete("1.0", tk.END)
52
+ self._config_text.insert(tk.END, content)
53
+
54
+ def _save_config_text(self) -> None:
55
+ try:
56
+ paths = config_core.ensure_initialized(root=None, create_config=True, exist_ok=True)
57
+ self._config_path_var.set(str(paths.config_file))
58
+ text = self._config_text.get("1.0", tk.END)
59
+ paths.config_file.write_text(text, encoding="utf-8")
60
+ logger.info("Saved config.yaml: %s", paths.config_file)
61
+ except Exception as exc:
62
+ logger.error("Failed to save config.yaml: %s", exc, exc_info=logger.isEnabledFor(logging.DEBUG))
63
+ messagebox.showerror("Save error", f"Failed to save config.yaml:\n{exc}")
64
+
65
+ def _backup_config_text(self) -> None:
66
+ try:
67
+ paths = config_core.ensure_initialized(root=None, create_config=True, exist_ok=True)
68
+ config_path = paths.config_file
69
+ self._config_path_var.set(str(config_path))
70
+ if not config_path.exists():
71
+ messagebox.showwarning("Backup", f"Config file not found:\n{config_path}")
72
+ return
73
+ ts = dt.datetime.now().strftime("%Y%m%d-%H%M%S")
74
+ backup_path = Path(f"{config_path}.bak-{ts}")
75
+ shutil.copy2(config_path, backup_path)
76
+ logger.info("Backed up config.yaml: %s", backup_path)
77
+ messagebox.showinfo("Backup", f"Created backup:\n{backup_path}")
78
+ except Exception as exc:
79
+ logger.error("Failed to back up config.yaml: %s", exc, exc_info=logger.isEnabledFor(logging.DEBUG))
80
+ messagebox.showerror("Backup error", f"Failed to back up config.yaml:\n{exc}")
81
+
82
+ def _reset_config_text(self) -> None:
83
+ try:
84
+ config_core.reset_config(root=None)
85
+ logger.info("Reset config.yaml to defaults.")
86
+ except Exception as exc:
87
+ logger.error("Failed to reset config.yaml: %s", exc, exc_info=logger.isEnabledFor(logging.DEBUG))
88
+ messagebox.showerror("Reset error", f"Failed to reset config.yaml:\n{exc}")
89
+ return
90
+ self._load_config_text()