TreeLens is a lightweight local web tool for exploring C. elegans lineage-tree figures. It detects a top-to-bottom rectilinear tree, reconstructs its ordered binary topology, aligns that topology to a bundled canonical C. elegans lineage, and adds transparent hover targets over the original image.
The source image is never redrawn. Colors, labels, dots, line widths, legends, and annotations remain exactly as uploaded. TreeLens does not infer fate, expression, or any other biological meaning from color.
The browser interface has three parts:
- a file-picker/drag-and-drop upload and parser status area;
- the unchanged uploaded image with a coordinate-matched SVG interaction layer; and
- identity-correction, saved-result, alignment/root, and debug controls.
Each detected cell branch receives an invisible, approximately 14 CSS-pixel hover path. Hovering shows a high-confidence canonical cell name and a thin temporary cyan highlight. Clicking adds a small persistent label beside that branch; multiple labels remain until their individual × controls are used. Known cells can be supplied as anchors to constrain detected ancestors, revise related subtree assignments, and restart alignment inside an uncertain or disconnected subtree. If a thin branch was not detected at all, the user can draw its vertical extent and assign its canonical name; the line is injected into geometry reconstruction before re-alignment. Overlay Alignment is collapsed by default. Debug View keeps only the coordinate-matched overlay diagnostics; the separate detected-mask block has been removed.
Export result saves a fingerprinted .treelens.json file containing the complete recognized geometry/names, root, anchors, manually drawn branches, persistent labels, and overlay settings. Importing it with the exact original image restores the saved annotation directly without running detection again.
- macOS or Linux;
- Conda; and
- a modern browser.
Python packages are declared in both environment.yml and requirements.txt:
- Flask;
- NumPy;
- OpenCV (headless build); and
- pytest (development/test only).
No server database, user account, OCR engine, or machine-learning model is required.
From this directory:
conda env create --prefix ./.conda --file environment.ymlThe prefix form keeps the environment inside the TreeLens project. If dependencies change later, update it with:
conda env update --prefix ./.conda --file environment.yml --prune./run.shThen visit http://127.0.0.1:5000. The equivalent explicit command is:
conda run --no-capture-output --prefix ./.conda python -m treelens.appUploads are processed in memory and are not retained by the app.
Large images are automatically reduced to at most 24 megapixels for analysis. The browser still displays the untouched original upload, and all detected coordinates are mapped back to its original dimensions. The compressed-file upload limit is 64 MB and the decoded-dimension safety limit is 120 megapixels.
browser upload
-> Flask validation / original-byte data URL
-> automatic analysis-copy reduction when above 24 megapixels
-> background-distance foreground mask
-> strict + fine-scale horizontal/vertical morphology
-> main rectilinear component selection
-> line-segment extraction and conservative gap merge
-> explicit and implicit-root junction reconstruction
-> confidence-gated canonical ordered-tree alignment + anchors
-> JSON branch geometry + canonical names
-> original <img> + transparent SVG paths
-> optional fingerprinted result export/direct restore
treelens/
app.py Flask routes and validation
parser/
image_preprocess.py decoding and color-independent foreground mask
line_detection.py rectilinear morphology and segment extraction
tree_reconstruction.py junctions, relationships, root selection
lineage_alignment.py ordered detected-to-canonical mapping
pipeline.py reusable parser API and diagnostics
models.py geometry/tree data classes
lineage/
celegans_lineage.csv bundled 1,341-cell canonical reference
lineage.py validated, reusable canonical data adapter
templates/index.html web UI shell
static/app.js SVG interaction and correction controls
static/style.css interface styles
tests/ unit and synthetic parser/API tests
scripts/run_regression.py read-only image-directory regression runner
examples/README.md fixture policy and usage
USER_GUIDE.md end-user guide
DEVELOPMENT_NOTES.md v0.1 results and fragile areas
environment.yml reproducible Conda environment
requirements.txt pinned Python packages
run.sh one-command launcher
OpenCV decodes a separate in-memory copy for analysis. If it exceeds 24 megapixels, only that copy is reduced proportionally before masking. The API returns the original upload bytes as the browser <img> source, and parser coordinates are scaled back to the original dimensions, so the displayed figure is never recolored, rescaled, or replaced.
The parser estimates a light background from the image border and thresholds distance from that background across all color channels. This retains black, gray, red, green, blue, and yellow branches without assigning semantic meaning to any color.
Horizontal and vertical morphology runs at a strict scale plus a locally derived fine scale. The strict pass selects the dominant tree component; the fine pass recovers short late-stage connectors only near that structure. This reduces dependence on one global minimum line length while suppressing detached axes, titles, and legends.
Horizontal connectors are matched to one vertical parent ending at the connector and two vertical children beginning near its endpoints. Small anti-aliasing gaps are tolerated; large gaps are rejected. A top connector with two independent child trees can become an implicit P0 even when no parent stem is visible. Candidate roots are scored by reconstructed descendants, position, and root-scale span. A manual root click can override this choice.
The detected structure is treated as an ordered rooted binary tree. It is paired with explicit children in celegans_lineage.csv, sorted by canonical x-position/tree order. Strong canonical asymmetry is used only as a structural prior—vertical branch duration is not an identity feature. Early relationships such as P0 -> AB/P1, P1 -> EMS/P2, EMS -> MS/E, and P2 -> C/P3 come from the data table, not name suffixes. Low-confidence identities are withheld. A validated user anchor is exact; TreeLens propagates it toward the detected component root, revises the constrained ancestor path and sibling allocation, then maps descendants again. This also works inside a structural subtree disconnected by a missed connector.
The SVG viewBox exactly matches the original image coordinates. Every detected structural branch and its division connector get a transparent wide hit path, including unresolved branches that can be selected as anchors. A manually drawn vertical branch is added to the analysis mask and required structural segments, allowing nearby connectors and descendants to rejoin the tree when possible. Translation and center-based uniform scaling are applied only to the overlay group.
treelens/lineage/celegans_lineage.csv contains 1,341 unique cells with explicit parent references and canonical x/order information. The adapter is isolated from Flask and can be imported by a future CeXplore integration:
from treelens.lineage import load_default_lineage
lineage = load_default_lineage()
children = lineage.nodes["P1"].childrenRun the unit, synthetic multicolor, and API byte-preservation tests:
conda run --prefix ./.conda pytest -qRun the parser against a directory of real figures without modifying them:
conda run --prefix ./.conda python scripts/run_regression.py \
--input-dir /path/to/lineage-figuresThe table reports high-confidence identified branches, all structural candidates, root mode, horizontal/vertical candidates, and geometry confidence. A file fails if it cannot be parsed or identifies fewer than --minimum-identified branches (default: 3). The old --minimum-mapped option remains as an alias.
Place only redistributable images in examples/ and document source/license in examples/README.md. For private or unpublished figures, keep them outside the repository and pass their containing directory to scripts/run_regression.py. The script performs read-only analysis.
Suggested fixture categories are:
- dense full lineage with arbitrary colors and a legend;
- sparse early lineage with labels and terminal dots;
- dense reporter-expression lineage with selected colored paths; and
- a full, time-scaled lineage with irregular vertical branch lengths.
- v0.1 assumes a light background, top-to-bottom orientation, rectilinear binary divisions, and canonical left-to-right ordering.
- Raster resolution places a hard limit on separable terminal branches in very dense images.
- Automatic reduction can merge extremely fine lines in very large figures; the analysis size is shown in diagnostics.
- Overlapping text can create line candidates; structure/connectivity filtering removes many but not all.
- A missed connector can still reduce automatic coverage, but disconnected structural subtrees can be recovered with a named anchor.
- Manual branch drawing currently creates a vertical cell branch; it works best when the drag endpoints touch its parent and daughter connectors.
- Manual root selection aligns the selected branch to P0; use a named identity anchor for other subtrees.
- JPEG EXIF orientation, rotated trees, partial subtrees, non-binary divisions, and abnormal lineage topology are not handled reliably.
- Confidence is a simple geometry diagnostic, not a biological correctness estimate.
See USER_GUIDE.md for supported input and troubleshooting, OVERLAY_ALIGNMENT_中文说明.md for a Chinese explanation of every sidebar control and diagnostic, and DEVELOPMENT_NOTES.md for current regression observations.
- better automatic root and subtree recognition;
- search cell by name;
- correction history and sidecar migration tools;
- ancestor/descendant highlighting; and
- PDF/SVG support.
- partial subtree handling;
- abnormal-lineage mismatch detection;
- calibrated confidence estimates; and
- integration with CeXplore.