Module Reference#

This section covers backend modules by subsystem for developers.

Core Modules#

Feature config JSON helpers.

Each feature keeps a JSON file under:

swcstudio/tools/<tool>/configs/<feature>.json

swcstudio.core.config.merge_config(base, overrides)[source]#

Recursively merge config dictionaries without mutating inputs.

Parameters:
  • base (dict[str, Any])

  • overrides (dict[str, Any] | None)

Return type:

dict[str, Any]

Shared text report builders and file writers.

All interfaces (CLI + GUI) should use these helpers so generated log text stays consistent regardless of entry point.

Shared validation engine.

swcstudio.core.validation_engine.consolidate_complex_somas_array(arr)[source]#

Collapse connected soma groups without renumbering surviving node IDs.

Each connected type-1 soma component is reduced to one anchor soma node with updated centroid/radius. Non-anchor soma nodes are removed, and any child that pointed to a removed soma node is rewired to the surviving anchor ID. Surviving node IDs are preserved; no global reindexing is performed here.

Parameters:

arr (ndarray)

Return type:

dict[str, Any]

Structured validation result models.

class swcstudio.core.validation_results.PreCheckItem(key: 'str', label: 'str', source: 'str', severity: 'Severity', params: 'dict[str, Any]' = <factory>, enabled: 'bool' = True)[source]#

Bases: object

Parameters:
  • key (str)

  • label (str)

  • source (str)

  • severity (str)

  • params (dict[str, Any])

  • enabled (bool)

class swcstudio.core.validation_results.CheckResult(key: 'str', label: 'str', passed: 'bool', severity: 'Severity', message: 'str', failing_node_ids: 'list[int]' = <factory>, failing_section_ids: 'list[int]' = <factory>, metrics: 'dict[str, Any]' = <factory>, source: 'str' = 'native', params_used: 'dict[str, Any]' = <factory>, thresholds_used: 'dict[str, Any]' = <factory>, status: 'Status' = 'pass')[source]#

Bases: object

Parameters:
  • key (str)

  • label (str)

  • passed (bool)

  • severity (str)

  • message (str)

  • failing_node_ids (list[int])

  • failing_section_ids (list[int])

  • metrics (dict[str, Any])

  • source (str)

  • params_used (dict[str, Any])

  • thresholds_used (dict[str, Any])

  • status (str)

class swcstudio.core.validation_results.ValidationReport(profile: 'str', precheck: 'list[PreCheckItem]' = <factory>, results: 'list[CheckResult]' = <factory>)[source]#

Bases: object

Parameters:

Validation check registry.

class swcstudio.core.validation_registry.CheckDefinition(key: 'str', label: 'str', source: 'str', runner: 'ValidationCheckCallable')[source]#

Bases: object

Parameters:
  • key (str)

  • label (str)

  • source (str)

  • runner (Callable[[Any, dict[str, Any]], Any])

swcstudio.core.validation_registry.register_plugin_check(*, key, label, runner)[source]#

Register custom user-defined checks in the shared validation registry.

Parameters:
  • key (str)

  • label (str)

  • runner (Callable[[Any, dict[str, Any]], Any])

Return type:

None

Shared validation label/category catalog used by GUI and CLI.

Auto-typing engine for swcstudio (v12 QC-label-flag pipeline).

This package is the single auto-labeling backend used everywhere in swcstudio. It runs a four-stage pipeline that classifies every node in an SWC into soma / axon / basal dendrite / apical dendrite:

  • Stage 1: cell-type detector (sklearn ensemble, 49 whole-cell features) decides pyramidal vs interneuron.

  • Stage 2: per-subtree axon/basal/apical classifier (sklearn ensemble), propagated to all branches in the same primary subtree.

  • Stage 2b: GraphSAGE GNN over the branch graph re-decides apical-vs-basal for pyramidal dendrite branches.

  • Stage 3: topology refinement plus conservative Branch3 rescue.

  • QC/flag: runtime QC metadata and learned per-cell bad-label flag.

The core stages are required. The package’s required dependencies include sklearn, XGBoost, torch, and torch_geometric. Published wheels and source installs ship the trained model files for the pipeline and flag scorer.

End users typically reach this code through the CLI (swcstudio validation auto-label, swcstudio batch auto-typing) or through the GUI’s Validation / Batch panels. They rarely import these modules directly.

The model files are resolved via swcstudio.core.model_paths — override location with --model-dir, SWCSTUDIO_MODEL_DIR, or the GUI selector.

class swcstudio.core.auto_typing.BatchOptions(soma: 'bool' = True, axon: 'bool' = True, apic: 'bool' = True, basal: 'bool' = True, rad: 'bool' = False, zip_output: 'bool' = False, cell_type: 'str | None' = None, flag_enabled: 'bool' = True, flag_strictness: 'float' = 0.5, flag_feature_mode: 'str' = 'compact')[source]#

Bases: object

Parameters:
  • soma (bool)

  • axon (bool)

  • apic (bool)

  • basal (bool)

  • rad (bool)

  • zip_output (bool)

  • cell_type (str | None)

  • flag_enabled (bool)

  • flag_strictness (float)

  • flag_feature_mode (str)

class swcstudio.core.auto_typing.BatchResult(folder: 'str', out_dir: 'str | None', zip_path: 'str | None', files_total: 'int', files_processed: 'int', files_failed: 'int', total_nodes: 'int', total_type_changes: 'int', total_radius_changes: 'int', failures: 'list[str]', per_file: 'list[str]', log_path: 'str | None', files_flagged: 'int' = 0, files_qc_failed: 'int' = 0, commits: 'list[dict[str, Any]] | None' = None)[source]#

Bases: object

Parameters:
  • folder (str)

  • out_dir (str | None)

  • zip_path (str | None)

  • files_total (int)

  • files_processed (int)

  • files_failed (int)

  • total_nodes (int)

  • total_type_changes (int)

  • total_radius_changes (int)

  • failures (list[str])

  • per_file (list[str])

  • log_path (str | None)

  • files_flagged (int)

  • files_qc_failed (int)

  • commits (list[dict[str, Any]] | None)

class swcstudio.core.auto_typing.FileResult(input_file: 'str', output_file: 'str | None', nodes_total: 'int', type_changes: 'int', radius_changes: 'int', out_type_counts: 'dict[int, int]', cell_type: 'str | None', cell_type_source: 'str', stage1_confidence: 'float | None', qc_result: 'dict[str, Any] | None', flag_result: 'dict[str, Any] | None', failures: 'list[str]', change_details: 'list[str]', log_path: 'str | None', headers: 'list[str]', rows: 'list[dict[str, Any]]', types: 'list[int]', radii: 'list[float]')[source]#

Bases: object

Parameters:
  • input_file (str)

  • output_file (str | None)

  • nodes_total (int)

  • type_changes (int)

  • radius_changes (int)

  • out_type_counts (dict[int, int])

  • cell_type (str | None)

  • cell_type_source (str)

  • stage1_confidence (float | None)

  • qc_result (dict[str, Any] | None)

  • flag_result (dict[str, Any] | None)

  • failures (list[str])

  • change_details (list[str])

  • log_path (str | None)

  • headers (list[str])

  • rows (list[dict[str, Any]])

  • types (list[int])

  • radii (list[float])

swcstudio.core.auto_typing.get_config()[source]#

Return the merged auto-typing config (defaults + persisted user overrides). Cached for fast repeat access in batch mode.

Return type:

dict[str, Any]

swcstudio.core.auto_typing.save_config(cfg)[source]#

Save user-edited auto-typing config to disk.

Parameters:

cfg (dict[str, Any])

Return type:

None

swcstudio.core.auto_typing.is_available(*, model_dir=None)[source]#

Return (ok, reason) describing whether the auto-typing engine can run right now.

The engine requires the v12 model files (Stage 1 sklearn pickle, Stage 2 sklearn pickle, Stage 2b GNN checkpoint, Branch3 rescue checkpoint, and QC gate) plus torch and torch_geometric — they are required dependencies of the package, so a normal install satisfies them. When something is missing this returns (False, reason) with a search-path diagnostic so the GUI / CLI can fail fast with a clear message.

Parameters:

model_dir (str | None)

Return type:

tuple[bool, str]

swcstudio.core.auto_typing.backend_status(*, model_dir=None)[source]#

Structured status report. Used by the CLI models status command and the GUI to surface the resolved model paths and torch availability.

Parameters:

model_dir (str | None)

Return type:

dict[str, Any]

swcstudio.core.auto_typing.run_file(file_path, opts, *, output_path=None, write_output=True, write_log=True, model_dir=None, use_subtree_stage2=True)[source]#

Run the auto-typing engine on one SWC file.

Parameters:
  • file_path (str)

  • opts (BatchOptions)

  • output_path (str | None)

  • write_output (bool)

  • write_log (bool)

  • model_dir (str | None)

  • use_subtree_stage2 (bool)

Return type:

FileResult

swcstudio.core.auto_typing.run_batch(folder, opts, *, model_dir=None, use_subtree_stage2=True, progress_callback=None)[source]#

Run the auto-typing engine on every .swc file in folder.

progress_callback is invoked once per file before processing that file: progress_callback(index, total, current_filename). Use it to drive a GUI progress bar without blocking the engine. Exceptions raised inside the callback are propagated to the caller.

Parameters:
  • folder (str)

  • opts (BatchOptions)

  • model_dir (str | None)

  • use_subtree_stage2 (bool)

  • progress_callback (Callable[[int, int, str], None] | None)

Return type:

BatchResult

swcstudio.core.auto_typing.run_folder(folder, opts=None)[source]#

Convenience: run the engine on a folder with default options.

Parameters:
Return type:

BatchResult

class swcstudio.core.auto_typing.SWCNode(id: 'int', type: 'int', x: 'float', y: 'float', z: 'float', radius: 'float', parent: 'int')[source]#

Bases: object

Parameters:
  • id (int)

  • type (int)

  • x (float)

  • y (float)

  • z (float)

  • radius (float)

  • parent (int)

swcstudio.core.auto_typing.parse_swc(path, *, normalize_types=True)[source]#

Parse an SWC file into a list of SWCNode.

If normalize_types is True (the default), nodes carrying a positive custom SWC type value (anything above 4) are rewritten to the dominant standard type of the branch they belong to. Type 0 is preserved as the standard “unlabeled” sentinel. This absorbs custom sub-cellular annotations (axon hillock, spines, boutons, etc.) into their host neurite so downstream training and evaluation see only the four canonical neurite classes. Topology is never altered.

Pass normalize_types=False if you need the raw on-disk types.

Parameters:
  • path (str | Path)

  • normalize_types (bool)

Return type:

list[SWCNode]

class swcstudio.core.auto_typing.PipelineResult(stage1, stage3, node_labels, node_confidences)[source]#

Bases: object

Full pipeline output.

Parameters:
  • stage1 (CellTypeResult)

  • stage3 (RefinementResult)

  • node_labels (list[int])

  • node_confidences (list[float])

swcstudio.core.auto_typing.run_pipeline(swc_path, stage1_model=None, stage2_model=None, gnn_state=None, branch3_state=None)[source]#

Run the full 3-stage hybrid pipeline on an SWC file.

Parameters:
  • swc_path (str | Path) – path to SWC file

  • stage1_model (str | Path | None) – path to Stage 1 model (optional, uses default)

  • stage2_model (str | Path | None) – path to Stage 2 model (optional, uses default)

  • gnn_state (object | None) – optional pre-loaded GNN state (from paper.gnn_inference.load_gnn). When provided AND the cell is pyramidal, the GNN re-decides apical vs basal for every branch Stage 2 classified as a dendrite, before Stage 3 refinement runs.

  • branch3_state (object | None)

Returns:

PipelineResult with per-node labels and metadata.

Return type:

PipelineResult

swcstudio.core.auto_typing.run_pipeline_on_nodes(nodes, file_path='', stage1_model=None, stage2_model=None, soft_handoff_threshold=0.65, gnn_state=None, branch3_state=None, gnn_after_stage3=False, use_subtree_stage2=False, override_cell_type=None)[source]#

Run the full pipeline on pre-parsed nodes.

When Stage 1’s predicted-class probability falls below soft_handoff_threshold and the Stage 2 bundle has models for multiple cell types, the pipeline runs Stage 2+3 for both cell types and picks whichever produces higher mean per-node confidence. This recovers borderline files (e.g. slice-flat pyramidals or tall interneurons) that would otherwise be locked into the wrong Stage 2 branch by a hard Stage-1 label.

Pass soft_handoff_threshold=0.0 to disable the soft handoff and use the original hard-cascade behaviour.

Pass override_cell_type="pyramidal" (or “interneuron”) to BYPASS Stage 1 entirely and dispatch Stage 2 with the given cell type. Used for “Stage 2/3-only” evaluations where we want to measure the downstream model’s quality independent of Stage 1 errors. Disables soft handoff (no need; cell type is asserted).

Parameters:
  • nodes (list[SWCNode])

  • file_path (str)

  • stage1_model (str | Path | None)

  • stage2_model (str | Path | None)

  • soft_handoff_threshold (float)

  • gnn_state (object | None)

  • branch3_state (object | None)

  • gnn_after_stage3 (bool)

  • use_subtree_stage2 (bool)

  • override_cell_type (str | None)

Return type:

PipelineResult

Public entry points for the auto-typing engine.

The v12 QC-label-flag path drives every prediction:

  • Stage 1: cell-type detector (sklearn ensemble, 49 whole-cell features) decides pyramidal vs interneuron with a soft handoff.

  • Stage 2: per-subtree axon/basal/apical classifier (sklearn ensemble), propagated to all branches in the same primary subtree.

  • Stage 2b: GraphSAGE GNN over the branch graph re-decides apical-vs-basal for pyramidal dendrite branches.

  • Stage 3: topology refinement plus conservative Branch3 rescue.

  • QC/flag: runtime QC metadata and learned per-cell bad-label flag.

The core model files are required. is_available returns False if any of the Stage 1, Stage 2, GNN, Branch3, or QC-gate files are missing.

Public surface:

  • run_file(path, opts, ...) returns FileResult

  • run_batch(folder, opts, ...) returns BatchResult

  • is_available() returns (bool, reason)

  • backend_status() returns a diagnostic dict

swcstudio.core.auto_typing.runner.is_available(*, model_dir=None)[source]#

Return (ok, reason) describing whether the auto-typing engine can run right now.

The engine requires the v12 model files (Stage 1 sklearn pickle, Stage 2 sklearn pickle, Stage 2b GNN checkpoint, Branch3 rescue checkpoint, and QC gate) plus torch and torch_geometric — they are required dependencies of the package, so a normal install satisfies them. When something is missing this returns (False, reason) with a search-path diagnostic so the GUI / CLI can fail fast with a clear message.

Parameters:

model_dir (str | None)

Return type:

tuple[bool, str]

swcstudio.core.auto_typing.runner.backend_status(*, model_dir=None)[source]#

Structured status report. Used by the CLI models status command and the GUI to surface the resolved model paths and torch availability.

Parameters:

model_dir (str | None)

Return type:

dict[str, Any]

swcstudio.core.auto_typing.runner.run_file(file_path, opts, *, output_path=None, write_output=True, write_log=True, model_dir=None, use_subtree_stage2=True)[source]#

Run the auto-typing engine on one SWC file.

Parameters:
  • file_path (str)

  • opts (BatchOptions)

  • output_path (str | None)

  • write_output (bool)

  • write_log (bool)

  • model_dir (str | None)

  • use_subtree_stage2 (bool)

Return type:

FileResult

swcstudio.core.auto_typing.runner.run_batch(folder, opts, *, model_dir=None, use_subtree_stage2=True, progress_callback=None)[source]#

Run the auto-typing engine on every .swc file in folder.

progress_callback is invoked once per file before processing that file: progress_callback(index, total, current_filename). Use it to drive a GUI progress bar without blocking the engine. Exceptions raised inside the callback are propagated to the caller.

Parameters:
  • folder (str)

  • opts (BatchOptions)

  • model_dir (str | None)

  • use_subtree_stage2 (bool)

  • progress_callback (Callable[[int, int, str], None] | None)

Return type:

BatchResult

Public dataclasses for the auto-typing engine.

These describe the user-facing options (which neurite types to assign, whether to clean radii, whether to zip the batch output) and the result shapes returned by run_file() / run_batch().

class swcstudio.core.auto_typing.types.BatchOptions(soma: 'bool' = True, axon: 'bool' = True, apic: 'bool' = True, basal: 'bool' = True, rad: 'bool' = False, zip_output: 'bool' = False, cell_type: 'str | None' = None, flag_enabled: 'bool' = True, flag_strictness: 'float' = 0.5, flag_feature_mode: 'str' = 'compact')[source]#

Bases: object

Parameters:
  • soma (bool)

  • axon (bool)

  • apic (bool)

  • basal (bool)

  • rad (bool)

  • zip_output (bool)

  • cell_type (str | None)

  • flag_enabled (bool)

  • flag_strictness (float)

  • flag_feature_mode (str)

class swcstudio.core.auto_typing.types.BatchResult(folder: 'str', out_dir: 'str | None', zip_path: 'str | None', files_total: 'int', files_processed: 'int', files_failed: 'int', total_nodes: 'int', total_type_changes: 'int', total_radius_changes: 'int', failures: 'list[str]', per_file: 'list[str]', log_path: 'str | None', files_flagged: 'int' = 0, files_qc_failed: 'int' = 0, commits: 'list[dict[str, Any]] | None' = None)[source]#

Bases: object

Parameters:
  • folder (str)

  • out_dir (str | None)

  • zip_path (str | None)

  • files_total (int)

  • files_processed (int)

  • files_failed (int)

  • total_nodes (int)

  • total_type_changes (int)

  • total_radius_changes (int)

  • failures (list[str])

  • per_file (list[str])

  • log_path (str | None)

  • files_flagged (int)

  • files_qc_failed (int)

  • commits (list[dict[str, Any]] | None)

class swcstudio.core.auto_typing.types.FileResult(input_file: 'str', output_file: 'str | None', nodes_total: 'int', type_changes: 'int', radius_changes: 'int', out_type_counts: 'dict[int, int]', cell_type: 'str | None', cell_type_source: 'str', stage1_confidence: 'float | None', qc_result: 'dict[str, Any] | None', flag_result: 'dict[str, Any] | None', failures: 'list[str]', change_details: 'list[str]', log_path: 'str | None', headers: 'list[str]', rows: 'list[dict[str, Any]]', types: 'list[int]', radii: 'list[float]')[source]#

Bases: object

Parameters:
  • input_file (str)

  • output_file (str | None)

  • nodes_total (int)

  • type_changes (int)

  • radius_changes (int)

  • out_type_counts (dict[int, int])

  • cell_type (str | None)

  • cell_type_source (str)

  • stage1_confidence (float | None)

  • qc_result (dict[str, Any] | None)

  • flag_result (dict[str, Any] | None)

  • failures (list[str])

  • change_details (list[str])

  • log_path (str | None)

  • headers (list[str])

  • rows (list[dict[str, Any]])

  • types (list[int])

  • radii (list[float])

Persisted user-facing configuration for the auto-typing feature.

The auto-typing engine itself is the v12 QC-label-flag pipeline. The runtime knobs end users edit are model directory overrides, optional cell-type override, and compact flag scoring strictness. They live in the same JSON config the Batch Processing tool already persists, so the GUI / CLI continue to read and write a single file.

swcstudio.core.auto_typing.config.get_config()[source]#

Return the merged auto-typing config (defaults + persisted user overrides). Cached for fast repeat access in batch mode.

Return type:

dict[str, Any]

swcstudio.core.auto_typing.config.save_config(cfg)[source]#

Save user-edited auto-typing config to disk.

Parameters:

cfg (dict[str, Any])

Return type:

None

swcstudio.core.auto_typing.config.reset_cache()[source]#

Drop the in-memory config cache so the next get_config call reloads from disk. Used by tests.

Return type:

None

End-to-end hybrid auto-labeling pipeline.

Chains Stage 1 (cell-type detection) → Stage 2 (branch classification) → Stage 3 (topology refinement) into a single function call.

class swcstudio.core.auto_typing.pipeline.PipelineResult(stage1, stage3, node_labels, node_confidences)[source]#

Bases: object

Full pipeline output.

Parameters:
  • stage1 (CellTypeResult)

  • stage3 (RefinementResult)

  • node_labels (list[int])

  • node_confidences (list[float])

swcstudio.core.auto_typing.pipeline.run_pipeline(swc_path, stage1_model=None, stage2_model=None, gnn_state=None, branch3_state=None)[source]#

Run the full 3-stage hybrid pipeline on an SWC file.

Parameters:
  • swc_path (str | Path) – path to SWC file

  • stage1_model (str | Path | None) – path to Stage 1 model (optional, uses default)

  • stage2_model (str | Path | None) – path to Stage 2 model (optional, uses default)

  • gnn_state (object | None) – optional pre-loaded GNN state (from paper.gnn_inference.load_gnn). When provided AND the cell is pyramidal, the GNN re-decides apical vs basal for every branch Stage 2 classified as a dendrite, before Stage 3 refinement runs.

  • branch3_state (object | None)

Returns:

PipelineResult with per-node labels and metadata.

Return type:

PipelineResult

swcstudio.core.auto_typing.pipeline.run_pipeline_on_nodes(nodes, file_path='', stage1_model=None, stage2_model=None, soft_handoff_threshold=0.65, gnn_state=None, branch3_state=None, gnn_after_stage3=False, use_subtree_stage2=False, override_cell_type=None)[source]#

Run the full pipeline on pre-parsed nodes.

When Stage 1’s predicted-class probability falls below soft_handoff_threshold and the Stage 2 bundle has models for multiple cell types, the pipeline runs Stage 2+3 for both cell types and picks whichever produces higher mean per-node confidence. This recovers borderline files (e.g. slice-flat pyramidals or tall interneurons) that would otherwise be locked into the wrong Stage 2 branch by a hard Stage-1 label.

Pass soft_handoff_threshold=0.0 to disable the soft handoff and use the original hard-cascade behaviour.

Pass override_cell_type="pyramidal" (or “interneuron”) to BYPASS Stage 1 entirely and dispatch Stage 2 with the given cell type. Used for “Stage 2/3-only” evaluations where we want to measure the downstream model’s quality independent of Stage 1 errors. Disables soft handoff (no need; cell type is asserted).

Parameters:
  • nodes (list[SWCNode])

  • file_path (str)

  • stage1_model (str | Path | None)

  • stage2_model (str | Path | None)

  • soft_handoff_threshold (float)

  • gnn_state (object | None)

  • branch3_state (object | None)

  • gnn_after_stage3 (bool)

  • use_subtree_stage2 (bool)

  • override_cell_type (str | None)

Return type:

PipelineResult

Train custom hybrid auto-typing models on a user dataset.

End users who want a custom Stage 1 + Stage 2 + Stage 2b model tuned to their own SWC corpus can run this once and point the auto-typing backend at the resulting model directory.

The bundled production engine is the v12 QC-label-flag pipeline. In addition to the three custom-training artifacts below, full v12 deployment also uses a Branch3 rescue checkpoint, QC gate, and optional learned flag models. This helper currently trains the core Stage 1 + Stage 2 + Stage 2b stack only.

Expected input dataset layout:

<data-dir>/
    pyramidal/
        <files>.swc
    interneuron/
        <files>.swc

Subfolder names are the cell-type labels; filenames don’t matter. Each SWC’s type column (soma=1, axon=2, basal=3, apical=4) is the per-node ground truth.

Training stages (run in this order):

  1. Stage 1 cell-type classifier (sklearn ensemble, fast).

  2. Stage 2 per-branch / per-subtree classifier (sklearn ensemble, slow — minutes per 1000 cells).

  3. Stage 2b GraphSAGE GNN apical-vs-basal head on the pyramidal train split. Always trained as part of the pipeline (torch + torch_geometric are required dependencies of the package). Pass --no-gnn if you only want to retrain Stages 1+2 against an existing GNN checkpoint.

Output is a directory containing the three core model files (cell_type_classifier.pkl, branch_classifier.pkl, gnn_apical_basal.pt). Point swcstudio at this directory by setting the SWCSTUDIO_MODEL_DIR environment variable, by passing --model-dir to the CLI, or by selecting it in the GUI.

Usage from Python:

from swcstudio.core.auto_typing_train import train_user_models
train_user_models(
    data_dir="path/to/labeled/dataset",
    output_dir="path/to/save/models",
    train_gnn=True,
)

Usage from the CLI:

swcstudio train auto-typing --data-dir path/to/dataset \
                            --output-dir path/to/save/models
swcstudio.core.auto_typing_train.train_user_models(data_dir, output_dir, *, train_gnn=True, seed=42, gnn_hidden=128, gnn_layers=3, gnn_dropout=0.0, gnn_epochs=200, gnn_patience=25)[source]#

Train Stage 1 + Stage 2 (+ optional GNN) on data_dir and save the resulting model files to output_dir.

Parameters:
  • data_dir (str | Path) – Folder with pyramidal/ and interneuron/ subdirectories containing labeled SWCs.

  • output_dir (str | Path) – Where to write the trained model files. Created if missing.

  • train_gnn (bool) – Whether to retrain the GraphSAGE apical-vs-basal head. Default True. Set to False when you only want to refresh Stages 1+2 and re-use the existing bundled GNN checkpoint.

  • seed (int) – Hyperparameters. Defaults match the custom-training release configuration.

  • gnn_hidden (int) – Hyperparameters. Defaults match the custom-training release configuration.

  • gnn_layers (int) – Hyperparameters. Defaults match the custom-training release configuration.

  • gnn_dropout (float) – Hyperparameters. Defaults match the custom-training release configuration.

  • gnn_epochs (int) – Hyperparameters. Defaults match the custom-training release configuration.

  • gnn_patience (int) – Hyperparameters. Defaults match the custom-training release configuration.

Returns:

Paths and per-stage metrics. The dict-style metrics are the same the underlying training scripts produce so callers can log/persist them.

Return type:

TrainingResult

class swcstudio.core.auto_typing_train.TrainingResult(output_dir: 'str', stage1_path: 'str', stage2_path: 'str', gnn_path: 'str | None', stage1_metrics: 'dict[str, Any]', stage2_metrics: 'dict[str, Any]', gnn_metrics: 'dict[str, Any] | None')[source]#

Bases: object

Parameters:
  • output_dir (str)

  • stage1_path (str)

  • stage2_path (str)

  • gnn_path (str | None)

  • stage1_metrics (dict[str, Any])

  • stage2_metrics (dict[str, Any])

  • gnn_metrics (dict[str, Any] | None)

Resolve where the auto-typing models live on disk.

The auto-typing engine (swcstudio.core.auto_typing) is the v12 QC-label-flag path. Its required core model files are:

  • cell_type_classifier.pkl — Stage 1 (whole-cell pyramidal vs interneuron)

  • branch_classifier.pkl — Stage 2 (per-branch / per-subtree multiclass)

  • gnn_apical_basal.pt — Stage 2b GraphSAGE GNN

  • gnn_branch3_rescue.pt — conservative Branch3 rescue head

  • qc_gate.pkl — runtime QC gate

Optional learned flag models add per-cell bad-label flag scoring:

  • flag_model_pyramidal.joblib

  • flag_model_interneuron.joblib

  • flag_model_all.joblib

Search order (first existing wins):

  1. The directory passed in via the function argument or via the SWCSTUDIO_MODEL_DIR environment variable (highest precedence, used for “I trained my own models” workflows).

  2. The user data directory:

    • Windows: %APPDATA%\swcstudio\models

    • macOS: ~/Library/Application Support/swcstudio/models

    • Linux: ~/.local/share/swcstudio/models

  3. The modular desktop runtime model directory supplied by the bootstrap.

  4. The bundled directory inside the installed package (swcstudio/data/models). Source installs keep the current model files here; published wheels include the same production models.

Public API:

  • user_model_dir() — user data dir (creates if missing)

  • bundled_model_dir() — dir inside the installed package

  • resolve_model_path(name, override=None) — full path or None

  • available_models(override=None)dict[name -> Path | None]

Calling code never hard-codes paths. It calls resolve_model_path("gnn_apical_basal.pt") and gets either a real path or None.

swcstudio.core.model_paths.user_model_dir()[source]#

User data directory for swcstudio models. Created on first use.

Return type:

Path

swcstudio.core.model_paths.bundled_model_dir()[source]#

Directory shipped inside the installed swcstudio package.

Return type:

Path

swcstudio.core.model_paths.search_dirs(override=None)[source]#

Ordered list of directories that may hold model files.

Parameters:

override (str | PathLike | None)

Return type:

list[Path]

swcstudio.core.model_paths.resolve_model_path(name_or_filename, *, override=None, auto_download=True)[source]#

Locate one model file by short name or by literal filename.

name_or_filename accepts both "stage1" and "cell_type_classifier.pkl". Returns the first existing path found in search_dirs(), or None.

If no local copy is found and auto_download=True (default), falls back to fetching the models package from GitHub Releases via swcstudio.core.updater. Published wheels bundle the production models, so this network path is a repair/update fallback rather than a normal first-run requirement.

Set auto_download=False to skip the network fallback (used by diagnostic / testing paths that want to know “is the model physically here right now”).

Parameters:
  • name_or_filename (str)

  • override (str | PathLike | None)

  • auto_download (bool)

Return type:

Path | None

swcstudio.core.model_paths.available_models(override=None)[source]#

Return {short_name: Path | None} for every standard model.

Parameters:

override (str | PathLike | None)

Return type:

dict[str, Path | None]

swcstudio.core.model_paths.diagnostic_search_report(override=None)[source]#

Human-readable description of where the resolver looked. Useful in error messages when a model cannot be found.

Parameters:

override (str | PathLike | None)

Return type:

str

Tool Feature Modules#

Batch Processing#

Batch validation feature for Batch Processing.

SWC splitter feature for Batch Processing.

Auto-typing feature for the Batch Processing tool.

Thin wrapper around swcstudio.core.auto_typing. The engine itself is the v12 QC-label-flag pipeline and has no alternative backends; this module exists to register the feature with the plugin system and to expose the model directory, cell-type override, and flag strictness plumbing the GUI / CLI need.

class swcstudio.tools.batch_processing.features.auto_typing.BatchOptions(soma: 'bool' = True, axon: 'bool' = True, apic: 'bool' = True, basal: 'bool' = True, rad: 'bool' = False, zip_output: 'bool' = False, cell_type: 'str | None' = None, flag_enabled: 'bool' = True, flag_strictness: 'float' = 0.5, flag_feature_mode: 'str' = 'compact')[source]#

Bases: object

Parameters:
  • soma (bool)

  • axon (bool)

  • apic (bool)

  • basal (bool)

  • rad (bool)

  • zip_output (bool)

  • cell_type (str | None)

  • flag_enabled (bool)

  • flag_strictness (float)

  • flag_feature_mode (str)

Radii cleaning feature for Batch Processing.

This module is the shared backend used by: - Batch GUI radii cleaning tab - Validation GUI radii cleaning tab - CLI batch/validation radii-clean commands

Validation#

Structured validation runner feature.

Auto-fix validation feature.

This feature runs the shared validation backend and returns the sanitized SWC content that can be written back to disk.

Single-file auto-typing for the Validation tool.

Thin wrapper around swcstudio.core.auto_typing. The engine itself is the v12 QC-label-flag pipeline; there is no backend selection. The runtime knobs are the user model directory override, optional cell-type override, flag scoring strictness, and whether to use the subtree Stage 2 head.

class swcstudio.tools.validation.features.auto_typing.BatchOptions(soma: 'bool' = True, axon: 'bool' = True, apic: 'bool' = True, basal: 'bool' = True, rad: 'bool' = False, zip_output: 'bool' = False, cell_type: 'str | None' = None, flag_enabled: 'bool' = True, flag_strictness: 'float' = 0.5, flag_feature_mode: 'str' = 'compact')[source]#

Bases: object

Parameters:
  • soma (bool)

  • axon (bool)

  • apic (bool)

  • basal (bool)

  • rad (bool)

  • zip_output (bool)

  • cell_type (str | None)

  • flag_enabled (bool)

  • flag_strictness (float)

  • flag_feature_mode (str)

swcstudio.tools.validation.features.auto_typing.run_file(file_path, *, options=None, config_overrides=None, output_path=None, write_output=True, write_log=True)[source]#

Run auto-typing on a single file using the configured engine.

Parameters:
  • file_path (str)

  • options (BatchOptions | None)

  • config_overrides (dict | None)

  • output_path (str | None)

  • write_output (bool)

  • write_log (bool)

Validation radii-cleaning feature.

This is a thin wrapper over the shared Batch Processing radii-clean backend so GUI/CLI/Validation all use exactly the same cleaning implementation.

Visualization#

Mesh editing feature backend.

This module provides a reusable backend payload that both GUI and CLI can use for mesh-related operations without duplicating parsing logic.

Morphology Editing#

Dendrogram editing backend utilities.

Provides data-level operations used by interactive dendrogram editors.

Smart decimation wrapper for morphology editing.

Plugin System Internals#

Plugin contract models for swcstudio.

This module defines a minimal, versioned contract for external plugins.

Provenance requirement (PROVENANCE_SPEC.md M13)#

Any plugin that mutates SWC bytes MUST do so inside a swcstudio.core.provenance.tracked_op() context (or tracked_session() for multi-op interactive flows). Direct file writes bypass the provenance chain and are unsupported.

The canonical pattern:

from swcstudio.core.provenance import tracked_op

def my_plugin_op(swc_path, *, my_param):
    with tracked_op(swc_path, kind="plugin_op",
                    params={"plugin": "my-plugin", "my_param": my_param},
                    message="my plugin description") as op:
        new_bytes = mutate(op.input_bytes, my_param)
        op.set_output(new_bytes)
    return op.result

The plugin_op op kind is reserved for this purpose and accepts arbitrary params. Plugins that need a richer typed op kind should request an addition to OpKind in a future v1.x bump (additive only per spec §17).

class swcstudio.plugins.contracts.PluginManifest(plugin_id, name, version, api_version='1', description='', author='', capabilities=(), entrypoint='')[source]#

Bases: object

Structured plugin metadata required by the swcstudio plugin loader.

Parameters:
  • plugin_id (str)

  • name (str)

  • version (str)

  • api_version (str)

  • description (str)

  • author (str)

  • capabilities (tuple[str, ...])

  • entrypoint (str)

swcstudio.plugins.contracts.parse_plugin_manifest(raw)[source]#

Validate and normalize a plugin manifest dictionary.

Parameters:

raw (dict[str, Any])

Return type:

PluginManifest

swcstudio.plugins.contracts.plugin_manifest_to_dict(manifest)[source]#

Serialize a PluginManifest into JSON-friendly dictionary.

Parameters:

manifest (PluginManifest)

Return type:

dict[str, Any]

Dynamic plugin loader for swcstudio.

class swcstudio.plugins.loader.PluginRegistrar(plugin_id)[source]#

Bases: object

Registrar object passed to external plugins during registration.

Parameters:

plugin_id (str)

swcstudio.plugins.loader.load_plugin_module(module_name, *, force_reload=False)[source]#

Load one plugin module and register its methods.

Expected plugin contract: 1) PLUGIN_MANIFEST dict (or get_plugin_manifest()) 2) register_plugin(registrar) function OR PLUGIN_METHODS attribute

Parameters:
  • module_name (str)

  • force_reload (bool)

Return type:

dict[str, Any]

swcstudio.plugins.loader.load_plugins(modules)[source]#

Load multiple plugin modules and return per-module results.

Parameters:

modules (Iterable[str])

Return type:

list[dict[str, Any]]

swcstudio.plugins.loader.autoload_plugins_from_environment(env_var='SWCSTUDIO_PLUGINS')[source]#

Autoload plugin modules from comma-separated environment variable.

Parameters:

env_var (str)

Return type:

list[dict[str, Any]]

Plugin registry for swcstudio.

Supports: 1) Legacy flat keys (register(“name”, func) / get(“name”)) 2) Feature method keys (register_method(“tool.feature”, “method_name”, func)) 3) Plugin-aware registration with versioned manifest metadata

The feature-based API is preferred for modular override of algorithms used by CLI and GUI layers.

swcstudio.plugins.registry.register(name, func)[source]#

Register a callable under a flat legacy key.

Parameters:
  • name (str)

  • func (Callable)

Return type:

None

swcstudio.plugins.registry.get(name)[source]#

Retrieve a flat legacy callable or None.

Parameters:

name (str)

Return type:

Callable | None

swcstudio.plugins.registry.clear()[source]#

Clear all registry content (legacy + feature methods).

Return type:

None

swcstudio.plugins.registry.register_builtin_method(feature_key, method_name, func)[source]#

Register an internal builtin method for a feature.

Parameters:
  • feature_key (str)

  • method_name (str)

  • func (Callable)

Return type:

None

swcstudio.plugins.registry.register_plugin_manifest(manifest)[source]#

Register and validate a plugin manifest.

Parameters:

manifest (PluginManifest | dict[str, Any])

Return type:

PluginManifest

swcstudio.plugins.registry.unregister_plugin(plugin_id)[source]#

Remove plugin manifest and all methods owned by this plugin.

Parameters:

plugin_id (str)

Return type:

None

swcstudio.plugins.registry.register_plugin_method(plugin_id, feature_key, method_name, func)[source]#

Register a feature method owned by a named plugin.

Parameters:
  • plugin_id (str)

  • feature_key (str)

  • method_name (str)

  • func (Callable)

Return type:

None

swcstudio.plugins.registry.register_method(feature_key, method_name, func, *, plugin_id=None)[source]#

Register a user/plugin method that overrides builtins with same name.

Parameters:
  • feature_key (str)

  • method_name (str)

  • func (Callable)

  • plugin_id (str | None)

Return type:

None

swcstudio.plugins.registry.resolve_method(feature_key, method_name, fallback=None)[source]#

Resolve method by priority: plugin override -> builtin -> fallback.

Parameters:
  • feature_key (str)

  • method_name (str)

  • fallback (Callable | None)

Return type:

Callable

swcstudio.plugins.registry.list_feature_methods(feature_key)[source]#

Return plugin + builtin method names for a feature.

Parameters:

feature_key (str)

Return type:

dict

swcstudio.plugins.registry.list_all_feature_methods()[source]#

Return all feature method registrations.

Return type:

dict

swcstudio.plugins.registry.list_plugins()[source]#

Return registered plugin manifests.

Return type:

list[dict[str, Any]]

swcstudio.plugins.registry.get_plugin(plugin_id)[source]#

Return one plugin manifest as dictionary.

Parameters:

plugin_id (str)

Return type:

dict[str, Any] | None