slotsgeltool 1.0.0__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.
- slotsgeltool-1.0.0/CHANGELOG.md +50 -0
- slotsgeltool-1.0.0/Install_Windows.bat +56 -0
- slotsgeltool-1.0.0/Install_macOS.command +56 -0
- slotsgeltool-1.0.0/LICENSE +21 -0
- slotsgeltool-1.0.0/MANIFEST.in +16 -0
- slotsgeltool-1.0.0/PKG-INFO +285 -0
- slotsgeltool-1.0.0/README.md +251 -0
- slotsgeltool-1.0.0/gel_annotator/__init__.py +28 -0
- slotsgeltool-1.0.0/gel_annotator/__main__.py +19 -0
- slotsgeltool-1.0.0/gel_annotator/assets/README.md +33 -0
- slotsgeltool-1.0.0/gel_annotator/assets/android-chrome-192x192.png +0 -0
- slotsgeltool-1.0.0/gel_annotator/assets/android-chrome-512x512.png +0 -0
- slotsgeltool-1.0.0/gel_annotator/assets/apple-touch-icon.png +0 -0
- slotsgeltool-1.0.0/gel_annotator/assets/favicon-16x16.png +0 -0
- slotsgeltool-1.0.0/gel_annotator/assets/favicon-32x32.png +0 -0
- slotsgeltool-1.0.0/gel_annotator/assets/favicon.ico +0 -0
- slotsgeltool-1.0.0/gel_annotator/assets/icon-192.png +0 -0
- slotsgeltool-1.0.0/gel_annotator/assets/icon-512.png +0 -0
- slotsgeltool-1.0.0/gel_annotator/assets/icon.ico +0 -0
- slotsgeltool-1.0.0/gel_annotator/assets/site.webmanifest +1 -0
- slotsgeltool-1.0.0/gel_annotator/cli.py +625 -0
- slotsgeltool-1.0.0/gel_annotator/frontend/app.js +5063 -0
- slotsgeltool-1.0.0/gel_annotator/frontend/index.html +328 -0
- slotsgeltool-1.0.0/gel_annotator/frontend/style.css +598 -0
- slotsgeltool-1.0.0/gel_annotator/icon.py +90 -0
- slotsgeltool-1.0.0/gel_annotator/install_shortcut.py +254 -0
- slotsgeltool-1.0.0/gel_annotator/server/__init__.py +0 -0
- slotsgeltool-1.0.0/gel_annotator/server/main.py +590 -0
- slotsgeltool-1.0.0/pyproject.toml +87 -0
- slotsgeltool-1.0.0/setup.cfg +4 -0
- slotsgeltool-1.0.0/slotsgeltool.egg-info/PKG-INFO +285 -0
- slotsgeltool-1.0.0/slotsgeltool.egg-info/SOURCES.txt +34 -0
- slotsgeltool-1.0.0/slotsgeltool.egg-info/dependency_links.txt +1 -0
- slotsgeltool-1.0.0/slotsgeltool.egg-info/entry_points.txt +3 -0
- slotsgeltool-1.0.0/slotsgeltool.egg-info/requires.txt +7 -0
- slotsgeltool-1.0.0/slotsgeltool.egg-info/top_level.txt +1 -0
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
# Changelog
|
|
2
|
+
|
|
3
|
+
All notable changes to Slots Gel Annotator are recorded here.
|
|
4
|
+
The format follows [Keep a Changelog](https://keepachangelog.com/en/1.1.0/),
|
|
5
|
+
and this project adheres to [Semantic Versioning](https://semver.org/).
|
|
6
|
+
|
|
7
|
+
## [1.0.0] — 2026-05-10
|
|
8
|
+
|
|
9
|
+
Initial public release as **Slots Gel Annotator** on PyPI as
|
|
10
|
+
`slotsgeltool`, with the `slots` console-script entry point.
|
|
11
|
+
|
|
12
|
+
### Highlights
|
|
13
|
+
|
|
14
|
+
* Vector-native rendering — the on-screen SVG IS the export.
|
|
15
|
+
* Multi-format input (PNG / JPEG / TIFF / 16-bit raw / 16-bit TIFF), with
|
|
16
|
+
channel-max RGB→grayscale conversion that preserves imager-baked red
|
|
17
|
+
saturation contours from Bio-Rad / GelDoc / ChemiDoc TIFs.
|
|
18
|
+
* Auto-stretched LUT (p1 .. p99.5) so dark gels are visible on first
|
|
19
|
+
load.
|
|
20
|
+
* Saturation overlay tracks the source dynamic range (not the
|
|
21
|
+
auto-stretched preview), so flagged pixels are the imager's intent.
|
|
22
|
+
* Smart bracket rotation — minimum number of labels rotated to 90°
|
|
23
|
+
when overlap would otherwise occur.
|
|
24
|
+
* Multi-ladder support: any combination of left-flank, right-flank, or
|
|
25
|
+
internal ladders. Hide-Ladders collapses flanks only.
|
|
26
|
+
* Spreadsheet-style metadata table: drag-select cell ranges,
|
|
27
|
+
type-to-fill, click-out clears, Tab navigation respects ranges.
|
|
28
|
+
* Drag-to-reorder columns; per-column / per-lane visibility toggles.
|
|
29
|
+
* Undo / Redo for every state-changing action.
|
|
30
|
+
* Smooth (delta-proportional) wheel zoom + right-click drag pan.
|
|
31
|
+
* Single-instance launcher: re-running `slots` reuses the existing
|
|
32
|
+
window.
|
|
33
|
+
* Self-contained sessions: image embedded in the saved JSON.
|
|
34
|
+
|
|
35
|
+
### Bundled
|
|
36
|
+
|
|
37
|
+
* `slots` CLI with `--port`, `--host`, `--no-browser`, `--install`,
|
|
38
|
+
`--update`, `--no-update`, `--version`.
|
|
39
|
+
* Desktop-shortcut installer for Windows / macOS / Linux.
|
|
40
|
+
* `Install_Windows.bat` and `Install_macOS.command` wrappers around
|
|
41
|
+
`pip install -e .`.
|
|
42
|
+
|
|
43
|
+
### Known limitations
|
|
44
|
+
|
|
45
|
+
* The shortcut installer requires `tkinter`. Most Python distributions
|
|
46
|
+
include it; on minimal Linux installs run
|
|
47
|
+
`apt install python3-tk` (or your distro's equivalent) first.
|
|
48
|
+
* macOS `.app` icons require the system `sips` tool (always present on
|
|
49
|
+
macOS) for PNG → ICNS conversion. Failure is non-fatal — the
|
|
50
|
+
bundle works without an icon.
|
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
@echo off
|
|
2
|
+
REM ===============================================================
|
|
3
|
+
REM Slots Gel Annotator — Windows installer
|
|
4
|
+
REM Installs the package from this source tree (editable mode)
|
|
5
|
+
REM and launches the annotator. Re-run any time to update.
|
|
6
|
+
REM ===============================================================
|
|
7
|
+
SETLOCAL ENABLEDELAYEDEXPANSION
|
|
8
|
+
|
|
9
|
+
echo.
|
|
10
|
+
echo ==============================================
|
|
11
|
+
echo Slots Gel Annotator -- installing
|
|
12
|
+
echo ==============================================
|
|
13
|
+
echo.
|
|
14
|
+
|
|
15
|
+
REM Resolve a Python interpreter. py.exe is preferred on Windows;
|
|
16
|
+
REM fall back to "python" on PATH if absent.
|
|
17
|
+
set "PY="
|
|
18
|
+
where py >NUL 2>&1
|
|
19
|
+
if %ERRORLEVEL% EQU 0 (
|
|
20
|
+
set "PY=py -3"
|
|
21
|
+
) else (
|
|
22
|
+
where python >NUL 2>&1
|
|
23
|
+
if %ERRORLEVEL% EQU 0 (
|
|
24
|
+
set "PY=python"
|
|
25
|
+
) else (
|
|
26
|
+
echo ERROR: Python 3.10+ not found on PATH.
|
|
27
|
+
echo Install Python from https://www.python.org/downloads/ then re-run this installer.
|
|
28
|
+
pause
|
|
29
|
+
exit /b 1
|
|
30
|
+
)
|
|
31
|
+
)
|
|
32
|
+
|
|
33
|
+
REM Install / upgrade the package from this directory in editable mode
|
|
34
|
+
REM so that pulling new commits (`git pull`) reflects immediately.
|
|
35
|
+
echo Running: %PY% -m pip install -U pip
|
|
36
|
+
%PY% -m pip install -U pip
|
|
37
|
+
if %ERRORLEVEL% NEQ 0 (
|
|
38
|
+
echo Pip self-upgrade failed. Continuing anyway.
|
|
39
|
+
)
|
|
40
|
+
|
|
41
|
+
echo.
|
|
42
|
+
echo Running: %PY% -m pip install -e "%~dp0"
|
|
43
|
+
%PY% -m pip install -e "%~dp0"
|
|
44
|
+
if %ERRORLEVEL% NEQ 0 (
|
|
45
|
+
echo.
|
|
46
|
+
echo Install failed. Try:
|
|
47
|
+
echo %PY% -m pip install -e "%~dp0" --user
|
|
48
|
+
pause
|
|
49
|
+
exit /b 1
|
|
50
|
+
)
|
|
51
|
+
|
|
52
|
+
echo.
|
|
53
|
+
echo Install OK. Launching Slots Gel Annotator...
|
|
54
|
+
echo.
|
|
55
|
+
%PY% -m gel_annotator
|
|
56
|
+
ENDLOCAL
|
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
#!/usr/bin/env bash
|
|
2
|
+
# ===============================================================
|
|
3
|
+
# Slots Gel Annotator — macOS / Linux installer
|
|
4
|
+
# Installs the package from this source tree (editable mode)
|
|
5
|
+
# and launches the annotator. Re-run any time to update.
|
|
6
|
+
# ===============================================================
|
|
7
|
+
set -e
|
|
8
|
+
|
|
9
|
+
# Move into this script's directory so `pip install -e .` resolves
|
|
10
|
+
# correctly regardless of where the user double-clicked from.
|
|
11
|
+
cd "$(dirname "$0")"
|
|
12
|
+
|
|
13
|
+
echo
|
|
14
|
+
echo " =============================================="
|
|
15
|
+
echo " Slots Gel Annotator -- installing"
|
|
16
|
+
echo " =============================================="
|
|
17
|
+
echo
|
|
18
|
+
|
|
19
|
+
# Resolve a Python interpreter. macOS ships /usr/bin/python3 (Catalina+);
|
|
20
|
+
# Linux distros use python3 by convention. Refuse to use Python 2.
|
|
21
|
+
PY=""
|
|
22
|
+
for candidate in python3 python3.13 python3.12 python3.11 python3.10 python; do
|
|
23
|
+
if command -v "$candidate" >/dev/null 2>&1; then
|
|
24
|
+
ver="$("$candidate" -c 'import sys; print(sys.version_info.major)' 2>/dev/null || echo 0)"
|
|
25
|
+
if [ "$ver" = "3" ]; then
|
|
26
|
+
PY="$candidate"
|
|
27
|
+
break
|
|
28
|
+
fi
|
|
29
|
+
fi
|
|
30
|
+
done
|
|
31
|
+
|
|
32
|
+
if [ -z "$PY" ]; then
|
|
33
|
+
echo " ERROR: Python 3.10+ not found."
|
|
34
|
+
echo " macOS: brew install python (or download from https://www.python.org)"
|
|
35
|
+
echo " Linux: sudo apt install python3 python3-pip python3-tk"
|
|
36
|
+
exit 1
|
|
37
|
+
fi
|
|
38
|
+
|
|
39
|
+
echo " Using $PY ($("$PY" --version 2>&1))"
|
|
40
|
+
echo
|
|
41
|
+
|
|
42
|
+
echo " Running: $PY -m pip install -U pip"
|
|
43
|
+
"$PY" -m pip install -U pip || echo " Pip self-upgrade failed. Continuing anyway."
|
|
44
|
+
|
|
45
|
+
echo
|
|
46
|
+
echo " Running: $PY -m pip install -e ."
|
|
47
|
+
if ! "$PY" -m pip install -e . ; then
|
|
48
|
+
echo
|
|
49
|
+
echo " System-wide install failed. Retrying with --user ..."
|
|
50
|
+
"$PY" -m pip install -e . --user
|
|
51
|
+
fi
|
|
52
|
+
|
|
53
|
+
echo
|
|
54
|
+
echo " Install OK. Launching Slots Gel Annotator..."
|
|
55
|
+
echo
|
|
56
|
+
exec "$PY" -m gel_annotator
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 billy-ngo
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
include README.md
|
|
2
|
+
include CHANGELOG.md
|
|
3
|
+
include LICENSE
|
|
4
|
+
include MANIFEST.in
|
|
5
|
+
include Install_Windows.bat
|
|
6
|
+
include Install_macOS.command
|
|
7
|
+
|
|
8
|
+
# Frontend assets — required at runtime by the FastAPI server.
|
|
9
|
+
recursive-include gel_annotator/frontend *.html *.js *.css *.png *.svg *.ico
|
|
10
|
+
|
|
11
|
+
# Branding assets — optional but useful when present (loaded by
|
|
12
|
+
# gel_annotator.icon and the desktop-shortcut installer).
|
|
13
|
+
recursive-include gel_annotator/assets *.png *.ico *.icns *.svg README.md
|
|
14
|
+
|
|
15
|
+
# Source-tree extras the developer might want to ship.
|
|
16
|
+
include pyproject.toml
|
|
@@ -0,0 +1,285 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: slotsgeltool
|
|
3
|
+
Version: 1.0.0
|
|
4
|
+
Summary: Slots Gel Annotator — vector-native gel annotation tool with publication-ready SVG / PNG export.
|
|
5
|
+
Author-email: Billy Ngo <billy.ngo0108@gmail.com>
|
|
6
|
+
License-Expression: MIT
|
|
7
|
+
Project-URL: Homepage, https://github.com/billy-ngo/slots-gel-annotator
|
|
8
|
+
Project-URL: Repository, https://github.com/billy-ngo/slots-gel-annotator
|
|
9
|
+
Project-URL: Issues, https://github.com/billy-ngo/slots-gel-annotator/issues
|
|
10
|
+
Project-URL: Changelog, https://github.com/billy-ngo/slots-gel-annotator/blob/main/CHANGELOG.md
|
|
11
|
+
Keywords: gel,electrophoresis,annotation,biology,bioinformatics,molecular-biology,ladder,SVG,publication,slots
|
|
12
|
+
Classifier: Development Status :: 4 - Beta
|
|
13
|
+
Classifier: Intended Audience :: Science/Research
|
|
14
|
+
Classifier: Topic :: Scientific/Engineering :: Bio-Informatics
|
|
15
|
+
Classifier: Topic :: Scientific/Engineering :: Image Processing
|
|
16
|
+
Classifier: Topic :: Scientific/Engineering :: Visualization
|
|
17
|
+
Classifier: Programming Language :: Python :: 3
|
|
18
|
+
Classifier: Programming Language :: Python :: 3.10
|
|
19
|
+
Classifier: Programming Language :: Python :: 3.11
|
|
20
|
+
Classifier: Programming Language :: Python :: 3.12
|
|
21
|
+
Classifier: Programming Language :: Python :: 3.13
|
|
22
|
+
Classifier: Operating System :: OS Independent
|
|
23
|
+
Requires-Python: >=3.10
|
|
24
|
+
Description-Content-Type: text/markdown
|
|
25
|
+
License-File: LICENSE
|
|
26
|
+
Requires-Dist: numpy>=1.24
|
|
27
|
+
Requires-Dist: Pillow>=10.0
|
|
28
|
+
Requires-Dist: tifffile>=2023.1.0
|
|
29
|
+
Requires-Dist: scipy>=1.10
|
|
30
|
+
Requires-Dist: fastapi>=0.111
|
|
31
|
+
Requires-Dist: uvicorn[standard]>=0.29
|
|
32
|
+
Requires-Dist: python-multipart>=0.0.9
|
|
33
|
+
Dynamic: license-file
|
|
34
|
+
|
|
35
|
+
# Slots Gel Annotator
|
|
36
|
+
|
|
37
|
+
A vector-native, browser-based tool for annotating gel-electrophoresis images and exporting publication-ready figures. Designed for working biologists: drag-and-drop a gel image, draw an analysis region, label your lanes with brackets and ladder bands, and export the result as an SVG (vector — editable in Illustrator, Inkscape, or Figma) or a PNG (raster).
|
|
38
|
+
|
|
39
|
+
---
|
|
40
|
+
|
|
41
|
+
## Installation
|
|
42
|
+
|
|
43
|
+
### Recommended (PyPI)
|
|
44
|
+
|
|
45
|
+
```bash
|
|
46
|
+
pip install slotsgeltool
|
|
47
|
+
```
|
|
48
|
+
|
|
49
|
+
Requires Python 3.10 or newer and a modern browser (Chrome, Firefox, Safari, or Edge).
|
|
50
|
+
|
|
51
|
+
### Bundled installers (from the source distribution)
|
|
52
|
+
|
|
53
|
+
If you cloned the repository or downloaded a release archive:
|
|
54
|
+
|
|
55
|
+
* **Windows** — Double-click `Install_Windows.bat`
|
|
56
|
+
* **macOS** — Double-click `Install_macOS.command` (or run `bash Install_macOS.command`)
|
|
57
|
+
|
|
58
|
+
Both scripts call `pip install -e .` against the bundled source and then launch the annotator.
|
|
59
|
+
|
|
60
|
+
### From source
|
|
61
|
+
|
|
62
|
+
```bash
|
|
63
|
+
git clone https://github.com/billy-ngo/slots-gel-annotator
|
|
64
|
+
cd slots-gel-annotator
|
|
65
|
+
pip install -e .
|
|
66
|
+
```
|
|
67
|
+
|
|
68
|
+
---
|
|
69
|
+
|
|
70
|
+
## Quick start
|
|
71
|
+
|
|
72
|
+
```bash
|
|
73
|
+
slots # launch the annotator on port 8062; opens your browser
|
|
74
|
+
slots image.tif # launch and auto-load a gel image
|
|
75
|
+
slots --port 9000 # use a custom port
|
|
76
|
+
slots --no-browser # don't open the browser (useful on a headless host)
|
|
77
|
+
slots --install # create a desktop shortcut
|
|
78
|
+
slots --update # check PyPI for an update and install if available
|
|
79
|
+
slots --version # print version and exit
|
|
80
|
+
```
|
|
81
|
+
|
|
82
|
+
The annotator single-instances itself: re-running `slots` while it is already running brings the existing tab to the front instead of starting a duplicate server.
|
|
83
|
+
|
|
84
|
+
---
|
|
85
|
+
|
|
86
|
+
## Workflow
|
|
87
|
+
|
|
88
|
+
1. **Open** — Drag a gel image onto the canvas, or click *Open* to browse. PNG, JPEG, TIFF, and 16-bit raw / TIFF are supported. Bio-Rad / GelDoc / ChemiDoc TIFs (which often embed a red saturation contour) are auto-decoded with channel-max conversion so the imager's clipped-pixel marks survive.
|
|
89
|
+
2. **Draw region** — Click *Draw Region* (or press **D**) and trace the analysis area. Lane positions are auto-distributed across the region's width; you can adjust the per-lane separators by dragging.
|
|
90
|
+
3. **Label lanes** — Mark ladder lanes with the Ladder checkbox in the metadata table; click the lane on the gel to drop ladder-size bands. Type values in the metadata cells; consecutive cells with the same value automatically merge into a bracket above the gel.
|
|
91
|
+
4. **Add free-form annotation** — `+Text (T)` for text labels, `+Line (L)` for arrows or underlines, `Rotate (R)` to spin the image or a selected element Illustrator-style.
|
|
92
|
+
5. **Tune the LUT** — Click *LUT* to drag the histogram handles; saturated pixels are auto-flagged in red. The original pixel data is preserved on the server so re-tuning is non-destructive.
|
|
93
|
+
6. **Export** — Save as **SVG** (vector, editable, every text element preserved as text) or **PNG** (raster, 2× scale by default). Or save the whole project as a JSON file (image embedded) and reload it later from the same point.
|
|
94
|
+
|
|
95
|
+
A status bar at the bottom of the window narrates the last action and surfaces errors. All buttons have keyboard shortcuts (shown in their titles).
|
|
96
|
+
|
|
97
|
+
---
|
|
98
|
+
|
|
99
|
+
## Features
|
|
100
|
+
|
|
101
|
+
| Feature | Notes |
|
|
102
|
+
|---|---|
|
|
103
|
+
| **Vector-native rendering** | The on-screen SVG IS the export. No drift between preview and final figure. |
|
|
104
|
+
| **Multi-format input** | PNG / JPEG / TIFF (8-bit) / 16-bit raw / 16-bit TIFF. RGB → grayscale via channel-max so imager-baked red highlights survive. |
|
|
105
|
+
| **Auto-stretched LUT** | Default LUT clips at the central 98 % of the histogram (p1 .. p99.5) so dark gels become visible without manual tweaking. |
|
|
106
|
+
| **Saturation overlay** | Truly clipped pixels show in red. Threshold is relative to the source dynamic range so it tracks the imager's intent (not the auto-stretched preview). |
|
|
107
|
+
| **Multiple ladders** | Mark any number of lanes as ladders — left flank, right flank, internal. Hide-Ladders collapses flank ladders only; internal ladders stay visible with their labels routed to the left. |
|
|
108
|
+
| **Smart bracket rotation** | When metadata column labels would otherwise overlap, only the offending labels rotate to 90° — the minimum needed for legibility. |
|
|
109
|
+
| **Cell editing** | Spreadsheet-style multi-cell drag-fill, Tab navigation, Esc to cancel, Delete to clear. Click outside the range and the selection clears so the next keystroke can't accidentally overwrite cells you weren't pointing at. |
|
|
110
|
+
| **Column reorder** | Drag column headers to reorder; the brackets on the gel follow. |
|
|
111
|
+
| **Per-column / per-lane visibility** | A "Show" row lets you toggle lane numbers or any metadata column off without losing its data. |
|
|
112
|
+
| **Undo / Redo** | Every state-changing action is undoable (Ctrl+Z / Ctrl+Y). |
|
|
113
|
+
| **Smooth zoom + pan** | Mouse wheel zooms (proportional to delta — trackpad-friendly); right-click drag pans. |
|
|
114
|
+
| **Dark mode (Invert)** | One-click colour inversion of the gel image and ink colours, for posters with dark backgrounds. |
|
|
115
|
+
| **Single-instance** | Re-running `slots` reuses the existing window instead of starting a duplicate server. |
|
|
116
|
+
| **Self-contained sessions** | Save → JSON file with the image embedded. Reload anywhere, anytime, no original file needed. |
|
|
117
|
+
|
|
118
|
+
---
|
|
119
|
+
|
|
120
|
+
## File-format support
|
|
121
|
+
|
|
122
|
+
Slots Gel Annotator targets 16-bit raw images from gel-imaging systems (Bio-Rad, Azure, GE, etc.) but tolerates many real-world variations:
|
|
123
|
+
|
|
124
|
+
| Format | Notes |
|
|
125
|
+
|---|---|
|
|
126
|
+
| **PNG** | 8-bit and 16-bit grayscale or RGB. RGB is collapsed to grayscale via channel-max (preserves imager-baked red highlights). |
|
|
127
|
+
| **JPEG** | 8-bit RGB. Some features (LUT editing, saturation toggle) are disabled — JPEG can't reach the dynamic range needed for them — and an alert explains so on upload. |
|
|
128
|
+
| **TIFF** | 8-bit and 16-bit grayscale or RGB. Read via `tifffile` first, with PIL as a fallback for unusual TIFF flavours. |
|
|
129
|
+
| **`.raw16`** | 16-bit raw passed through `tifffile`. The format most modern imaging platforms produce. |
|
|
130
|
+
| **`.bmp`** | 8-bit. Same caveats as JPEG. |
|
|
131
|
+
|
|
132
|
+
8-bit uploads automatically enable the saturation overlay so clipped pixels are visible without further configuration. 16-bit uploads keep the LUT controls and saturation toggle enabled for fine-tuning.
|
|
133
|
+
|
|
134
|
+
---
|
|
135
|
+
|
|
136
|
+
## Branding & icons
|
|
137
|
+
|
|
138
|
+
The desktop shortcut (Windows `.lnk`, macOS `.app`, Linux `.desktop`) and the in-app favicon load their icons from `gel_annotator/assets/`. To customize:
|
|
139
|
+
|
|
140
|
+
| File | Purpose | Recommended size |
|
|
141
|
+
|----------------|--------------------------------------------------|------------------|
|
|
142
|
+
| `icon.ico` | Windows shortcut + window icon | multi-resolution `.ico` containing 16 / 32 / 48 / 64 / 128 / 256 |
|
|
143
|
+
| `icon.icns` | macOS `.app` bundle icon (skip if absent — macOS converts `icon-512.png` via `sips`) | 1024×1024 |
|
|
144
|
+
| `icon-512.png` | High-resolution PNG used for Linux `.desktop`, web favicon, and macOS fallback | 512×512 |
|
|
145
|
+
| `icon-192.png` | Smaller PNG (web manifest, web favicon) | 192×192 |
|
|
146
|
+
| `logo-wide.png`| Banner for the README header (optional, in-app header) | 1200×200 |
|
|
147
|
+
|
|
148
|
+
PNGs MUST be transparent-background. ICOs/ICNS should bundle multiple resolutions. If a file is missing the loader silently substitutes a 1×1 transparent PNG and the OS falls back to its default app icon.
|
|
149
|
+
|
|
150
|
+
See [`gel_annotator/assets/README.md`](gel_annotator/assets/README.md) for the `iconutil` / `sips` recipe to generate `.icns` from a single 1024×1024 source.
|
|
151
|
+
|
|
152
|
+
---
|
|
153
|
+
|
|
154
|
+
## Sessions
|
|
155
|
+
|
|
156
|
+
Use the **Save** button to download a JSON file containing the full project state: the image (base64-embedded), the region, lane separators, ladder lanes / bands, metadata column data, every annotation (text, line, custom rotation, custom dx/dy), per-column visibility, the LUT settings, the bit-depth-derived feature gates, and any per-lane ladder shifts.
|
|
157
|
+
|
|
158
|
+
Saved sessions are **fully self-contained** — the image is embedded as a `data:` URL so the file reloads on a different machine without needing the original raw image.
|
|
159
|
+
|
|
160
|
+
---
|
|
161
|
+
|
|
162
|
+
## Robustness
|
|
163
|
+
|
|
164
|
+
A few things designed to keep you out of trouble:
|
|
165
|
+
|
|
166
|
+
* **Drag-cancel invariants.** Every in-flight drag (region-draw, region-resize, line-draw, annotation-move, label-move, tick-move, rotation, marquee, multi-move) cleans up through a single `cancelDrag()` path on Esc, blur, pointer-cancel, or any state mutation that would invalidate the drag's coordinates. There is no second mode for the user to be stuck in.
|
|
167
|
+
* **Per-feature isolation.** A bug in (say) bracket rotation can't break ladder-band rendering; each rendering pass is isolated. The whole canvas never goes blank because of one bad annotation.
|
|
168
|
+
* **Saturation auto-on.** Every new image starts with the saturation overlay enabled so clipped pixels are visible from the moment the image is loaded.
|
|
169
|
+
* **Cell range memory.** Drag-select a range, click a cell INSIDE the range to type-fill all of them — Excel-style. Click OUTSIDE the range and the selection clears so the next keystroke can't accidentally overwrite cells you weren't pointing at.
|
|
170
|
+
* **Undo across structural changes.** Per-render selection state (`_cellRange`, `_regionSelected`, `_selectedTick`) is never persisted in undo snapshots, so an undo can never restore a "ghost" selection that no longer matches the rendered DOM.
|
|
171
|
+
|
|
172
|
+
---
|
|
173
|
+
|
|
174
|
+
## Architecture
|
|
175
|
+
|
|
176
|
+
```
|
|
177
|
+
┌─────────────────┐ ┌──────────────────┐
|
|
178
|
+
│ FastAPI server │ HTTP │ Browser (SVG) │
|
|
179
|
+
│ │ ──────> │ │
|
|
180
|
+
│ - upload │ │ - draw region │
|
|
181
|
+
│ - LUT preview │ │ - lanes/bands │
|
|
182
|
+
│ - rotate │ │ - brackets │
|
|
183
|
+
│ - saturation │ │ - export │
|
|
184
|
+
│ │ │ │
|
|
185
|
+
│ NO renderer │ │ the renderer │
|
|
186
|
+
└─────────────────┘ └──────────────────┘
|
|
187
|
+
```
|
|
188
|
+
|
|
189
|
+
* **Backend** (`gel_annotator/server/main.py`): handles image upload, RGB→grayscale collapse, LUT-stretched preview generation, saturation-overlay generation, destructive image rotation. Does not generate exports.
|
|
190
|
+
* **Frontend** (`gel_annotator/frontend/`): a single `<svg>` element, built and re-rendered from a state object. All annotations are real SVG primitives (`<rect>`, `<line>`, `<text>`, `<image>`, `<foreignObject>` for inline edit). PNG/SVG export operate on the same DOM nodes the user sees.
|
|
191
|
+
|
|
192
|
+
Why this design: an earlier iteration kept the on-screen renderer (canvas-based JavaScript) and the export renderer (Pillow + svgwrite, in Python) separate. Every UI tweak had to be ported twice, and the two paths drifted on every release. This rebuild has one renderer. Export is:
|
|
193
|
+
|
|
194
|
+
```javascript
|
|
195
|
+
// SVG: 2 lines
|
|
196
|
+
const xml = new XMLSerializer().serializeToString(svgEl);
|
|
197
|
+
download(xml, 'figure.svg', 'image/svg+xml');
|
|
198
|
+
|
|
199
|
+
// PNG: ~12 lines (rasterize the same SVG via a temporary canvas)
|
|
200
|
+
```
|
|
201
|
+
|
|
202
|
+
That's the entire export module.
|
|
203
|
+
|
|
204
|
+
---
|
|
205
|
+
|
|
206
|
+
## Troubleshooting
|
|
207
|
+
|
|
208
|
+
**The browser doesn't open** — Slots polls `/healthz` for up to 10 s before opening. If the browser still doesn't open, navigate to `http://localhost:8062` (or your `--port`) manually.
|
|
209
|
+
|
|
210
|
+
**"Address already in use"** — Slots single-instances itself, but if it crashed leaving a stale lock file, delete `~/.slots-gel-annotator/server.lock` and try again. Or just use a different `--port`.
|
|
211
|
+
|
|
212
|
+
**LUT and Saturation buttons are grayed out** — You uploaded an 8-bit image (PNG / JPEG / 8-bit TIFF). Those features need the wider dynamic range of a 16-bit raw to be useful. The hover tooltip says so. Upload a `.raw16` / 16-bit TIFF to unlock them.
|
|
213
|
+
|
|
214
|
+
**A figure exported as PNG looks pixelated** — PNG export defaults to 2× scale. Re-export as SVG and rasterize it at higher resolution in Inkscape / Illustrator if needed.
|
|
215
|
+
|
|
216
|
+
**A bracket label rotates 90° unexpectedly** — Smart-rotation kicks in when a label is wider than its bracket. To prevent it, shorten the label or widen the lane.
|
|
217
|
+
|
|
218
|
+
---
|
|
219
|
+
|
|
220
|
+
## Project file format (v2)
|
|
221
|
+
|
|
222
|
+
```json
|
|
223
|
+
{
|
|
224
|
+
"version": 2,
|
|
225
|
+
"image_filename": "western_blot_2026-05.tif",
|
|
226
|
+
"image_data_url": "data:image/png;base64,iVBORw0...",
|
|
227
|
+
"image_width": 2480,
|
|
228
|
+
"image_height": 1653,
|
|
229
|
+
"raw_min": 0.0, "raw_max": 255.0,
|
|
230
|
+
"bit_depth": 8,
|
|
231
|
+
"lut": { "min": 0.0, "max": 165.0, "gamma": 1.0 },
|
|
232
|
+
"invert_image": false,
|
|
233
|
+
"region": { "x": 200, "y": 100, "w": 2050, "h": 1400 },
|
|
234
|
+
"region_outline": true,
|
|
235
|
+
"cropped_to_region": false,
|
|
236
|
+
"region_border_width": 2,
|
|
237
|
+
"tick_width": 2,
|
|
238
|
+
"lane_count": 8,
|
|
239
|
+
"ladder": [true, false, false, false, false, false, false, true],
|
|
240
|
+
"lane_separators": null,
|
|
241
|
+
"tick_height": 10,
|
|
242
|
+
"ladder_label_dx": {},
|
|
243
|
+
"columns": [{"id": "col_xyz", "name": "Treatment"}, ...],
|
|
244
|
+
"cells": {"col_xyz": ["Ctrl", "Ctrl", "T1", "T1", "T2", "T2"]},
|
|
245
|
+
"column_visible": {"col_xyz": true},
|
|
246
|
+
"show_lane_numbers": true,
|
|
247
|
+
"bands": {"0": [{"id": "b0a", "y_center": 400, "label": "50"}]},
|
|
248
|
+
"annotations": [],
|
|
249
|
+
"label_overrides": {},
|
|
250
|
+
"hide_ladders": false,
|
|
251
|
+
"bracket_line_style": "solid",
|
|
252
|
+
"line_cap": "butt"
|
|
253
|
+
}
|
|
254
|
+
```
|
|
255
|
+
|
|
256
|
+
Sessions saved in v1 are silently upgraded on load.
|
|
257
|
+
|
|
258
|
+
---
|
|
259
|
+
|
|
260
|
+
## Citation
|
|
261
|
+
|
|
262
|
+
If Slots Gel Annotator contributes to a publication, please cite it as:
|
|
263
|
+
|
|
264
|
+
```
|
|
265
|
+
Ngo, B.M. (2026). Slots Gel Annotator [Software].
|
|
266
|
+
Available at https://github.com/billy-ngo/slots-gel-annotator
|
|
267
|
+
```
|
|
268
|
+
|
|
269
|
+
---
|
|
270
|
+
|
|
271
|
+
## Version history
|
|
272
|
+
|
|
273
|
+
See [CHANGELOG.md](CHANGELOG.md) for the full per-version history. Current release is shown via `slots --version`.
|
|
274
|
+
|
|
275
|
+
---
|
|
276
|
+
|
|
277
|
+
## License
|
|
278
|
+
|
|
279
|
+
MIT. See [LICENSE](LICENSE).
|
|
280
|
+
|
|
281
|
+
---
|
|
282
|
+
|
|
283
|
+
## Author
|
|
284
|
+
|
|
285
|
+
Billy M Ngo · billy.ngo0108@gmail.com · [github.com/billy-ngo](https://github.com/billy-ngo)
|