Skip to content

webknossos.skeleton.skeleton

Skeleton

Bases: Group

A hierarchical representation of skeleton annotations in WEBKNOSSOS.

The Skeleton class serves as the root container for all skeleton annotation data, organizing nodes and edges into a hierarchical structure of groups and trees. It contains dataset metadata and provides methods for loading, saving, and manipulating skeleton annotations.

Attributes:

  • voxel_size (Vector3) –

    3D tuple (x, y, z) specifying the size of voxels in nanometers.

  • dataset_name (str) –

    Name of the dataset this skeleton belongs to.

  • organization_id (Optional[str]) –

    Optional ID of the organization owning this skeleton.

  • description (Optional[str]) –

    Optional description of the skeleton annotation.

  • name (str) –

    Always set to "Root" as this is the root group of the hierarchy.

The skeleton structure follows a hierarchical organization
  • Skeleton (root)
    • Groups (optional organizational units)
      • Trees (collections of connected nodes)
        • Nodes (3D points with metadata)
        • Edges (connections between nodes)

Examples:

Create and populate a new skeleton:

# Create skeleton through an annotation
annotation = Annotation(
    name="dendrite_trace",
    dataset_name="cortex_sample",
    voxel_size=(11, 11, 24)
)
skeleton = annotation.skeleton

# Add hierarchical structure
dendrites = skeleton.add_group("dendrites")
basal = dendrites.add_group("basal")
tree = basal.add_tree("dendrite_1")

# Add and connect nodes
soma = tree.add_node(position=(100, 100, 100), comment="soma")
branch = tree.add_node(position=(200, 150, 100), radius=1.5)
tree.add_edge(soma, branch)

Load an existing skeleton:

# Load from NML file
skeleton = Skeleton.load("annotation.nml")

# Access existing structure
for group in skeleton.groups:
    for tree in group.trees:
        print(f"Tree {tree.name} has {len(tree.nodes)} nodes")
Notes
  • The Skeleton class inherits from Group, providing group and tree management methods.
  • To upload a skeleton to WEBKNOSSOS, create an Annotation with it.
  • For complex examples, see the skeleton synapse candidates example in the documentation.
See Also
  • Group: Base class providing group and tree management
  • Tree: Class representing connected node structures
  • Node: Class representing individual 3D points
  • Annotation: Container class for working with WEBKNOSSOS

children property

children: Iterator[GroupOrTree]

Returns an iterator over all immediate children (groups and trees).

This property provides access to both groups and trees that are direct children of this group, in no particular order. For nested access, use flattened_trees() or flattened_groups().

Returns:

  • Iterator[GroupOrTree]

    Iterator[GroupOrTree]: Iterator yielding all immediate child groups and trees.

Examples:

# Print all immediate children
for child in group.children:
    if isinstance(child, Tree):
        print(f"Tree: {child.name}")
    else:
        print(f"Group: {child.name}")

dataset_name instance-attribute

dataset_name: str

description class-attribute instance-attribute

description: Optional[str] = None

graphs property

graphs: Iterator[Tree]

Deprecated, please use trees.

groups property

groups: Iterator[Group]

Returns all (immediate) group children as an iterator. Use flattened_groups if you need also need groups within subgroups.

id property

id: int

Read-only property.

name class-attribute instance-attribute

name: str = field(default='Root', init=False, eq=False, repr=False)

Should not be used with Skeleton, this attribute is only useful for sub-groups. Set to Root.

organization_id class-attribute instance-attribute

organization_id: Optional[str] = None

scale property writable

scale: Tuple[float, float, float]

Deprecated, please use voxel_size.

trees property

trees: Iterator[Tree]

Returns all (immediate) tree children as an iterator. Use flattened_trees if you also need trees within subgroups.

voxel_size instance-attribute

voxel_size: Vector3

add_graph

add_graph(name: str, color: Optional[Union[Vector4, Vector3]] = None, _enforced_id: Optional[int] = None) -> Tree

Deprecated, please use add_tree.

add_group

add_group(name: str, _enforced_id: Optional[int] = None) -> Group

Creates and adds a new subgroup to this group.

Parameters:

  • name (str) –

    Name for the new group.

  • _enforced_id (Optional[int], default: None ) –

    Optional specific ID for the group (internal use).

Returns:

  • Group ( Group ) –

    The newly created group.

Examples:

# Create nested group hierarchy
dendrites = neuron.add_group("dendrites")
basal = dendrites.add_group("basal")
apical = dendrites.add_group("apical")

add_nx_graphs

add_nx_graphs(tree_dict: Union[List[Graph], Dict[str, List[Graph]]]) -> None

Import NetworkX graphs as skeleton trees.

Converts NetworkX Graph objects into skeleton trees, preserving node positions and edge connections. The graphs can be provided either as a list or as a dictionary mapping group names to lists of graphs.

Parameters:

  • tree_dict (Union[List[Graph], Dict[str, List[Graph]]]) –

    Either: - A list of NetworkX graphs to be added directly to the skeleton - A dictionary mapping group names to lists of graphs, which will create new groups with the specified names containing the graphs

Raises:

  • ValueError

    If any graph nodes lack required position attributes.

  • TypeError

    If tree_dict is neither a list nor a dictionary.

Examples:

Add graphs directly to skeleton:

import networkx as nx

# Create sample graphs
g1 = nx.Graph()
g1.add_node(1, position=(0, 0, 0))
g1.add_node(2, position=(100, 0, 0))
g1.add_edge(1, 2)

g2 = nx.Graph()
g2.add_node(1, position=(0, 100, 0))
g2.add_node(2, position=(100, 100, 0))
g2.add_edge(1, 2)

# Add graphs directly
skeleton.add_nx_graphs([g1, g2])

# Or organize graphs into groups
graphs_by_group = {
    "dendrites": [g1],
    "axons": [g2]
}
skeleton.add_nx_graphs(graphs_by_group)
Note
  • Each node in the input graphs must have a 'position' attribute containing (x, y, z) coordinates
  • Other node attributes (e.g., radius, rotation) will be preserved
  • Edge attributes are currently not preserved in the conversion

add_tree

add_tree(name_or_tree: Union[str, Tree], color: Optional[Union[Vector4, Vector3]] = None, _enforced_id: Optional[int] = None) -> Tree

Adds a new tree or copies an existing tree to this group.

This method supports two ways of adding trees: 1. Creating a new tree by providing a name 2. Copying an existing tree from another location

Parameters:

  • name_or_tree (Union[str, Tree]) –

    Either a string name for a new tree or an existing Tree instance to copy.

  • color (Optional[Union[Vector4, Vector3]], default: None ) –

    Optional RGBA color tuple (r, g, b, a) or RGB tuple (r, g, b). If an RGB tuple is provided, alpha will be set to 1.0.

  • _enforced_id (Optional[int], default: None ) –

    Optional specific ID for the tree (internal use).

Returns:

  • Tree ( Tree ) –

    The newly created or copied tree.

Examples:

# Create new tree
tree = group.add_tree("dendrite_1", color=(1, 0, 0, 1))

# Copy existing tree
copy = group.add_tree(existing_tree)
Notes

When copying a tree, a new ID will be generated if the original ID already exists in this group.

as_nml_group

as_nml_group() -> Group

Converts this group to its NML representation.

This method creates a lightweight representation of the group suitable for serialization in the NML format.

Returns:

  • Group

    wknml.Group: NML representation of this group.

Notes

This is primarily used internally for file I/O operations.

flattened_graphs

flattened_graphs() -> Iterator[Tree]

Deprecated, please use flattened_trees.

flattened_groups

flattened_groups() -> Iterator[Group]

Returns an iterator of all groups within this group (and its subgroups).

flattened_trees

flattened_trees() -> Iterator[Tree]

Returns an iterator of all trees in this group and its subgroups.

This method performs a recursive traversal of the group hierarchy, yielding all trees regardless of their nesting level.

Returns:

  • Iterator[Tree]

    Iterator[Tree]: Iterator yielding all contained trees.

Examples:

# Process all trees regardless of grouping
for tree in group.flattened_trees():
    print(f"Tree {tree.name} has {len(tree.nodes)} nodes")

from_path staticmethod

from_path(file_path: Union[PathLike, str]) -> Skeleton

Deprecated. Use Skeleton.load instead.

get_graph_by_id

get_graph_by_id(graph_id: int) -> Tree

Deprecated, please use get_tree_by_id.

get_group_by_id

get_group_by_id(group_id: int) -> Group

Returns the group which has the specified group id.

get_max_graph_id

get_max_graph_id() -> int

Deprecated, please use get_max_tree_id.

get_max_node_id

get_max_node_id() -> int

Returns the highest node id of all nodes of all trees within this group (and its subgroups).

get_max_tree_id

get_max_tree_id() -> int

Returns the highest tree id of all trees within this group (and its subgroups).

get_node_by_id

get_node_by_id(node_id: int) -> Node

Retrieves a node by its ID from any tree in this group or its subgroups.

Parameters:

  • node_id (int) –

    The ID of the node to find.

Returns:

  • Node ( Node ) –

    The node with the specified ID.

Raises:

  • ValueError

    If no node with the given ID exists in any tree.

Examples:

try:
    node = group.get_node_by_id(42)
    print(f"Found node at position {node.position}")
except ValueError:
    print("Node not found")

get_total_node_count

get_total_node_count() -> int

Counts all nodes in all trees within this group and its subgroups.

Returns:

  • int ( int ) –

    Total number of nodes across all contained trees.

Examples:

# Check total annotation points
count = group.get_total_node_count()
print(f"Total annotation points: {count}")

get_tree_by_id

get_tree_by_id(tree_id: int) -> Tree

Retrieves a tree by its ID from this group or its subgroups.

Parameters:

  • tree_id (int) –

    The ID of the tree to find.

Returns:

  • Tree ( Tree ) –

    The tree with the specified ID.

Raises:

  • ValueError

    If no tree with the given ID exists.

Examples:

try:
    tree = group.get_tree_by_id(42)
    print(f"Found tree '{tree.name}'")
except ValueError:
    print("Tree not found")

has_tree_id

has_tree_id(tree_id: int) -> bool

Checks if a tree with the given ID exists in this group or its subgroups.

Parameters:

  • tree_id (int) –

    The ID to check for.

Returns:

  • bool ( bool ) –

    True if a tree with the ID exists, False otherwise.

Examples:

if group.has_tree_id(42):
    tree = group.get_tree_by_id(42)
    print(f"Tree exists: {tree.name}")

load staticmethod

load(file_path: Union[PathLike, str]) -> Skeleton

Load a skeleton annotation from a file.

This method can load skeleton annotations from either a .nml file or a .zip file that contains an NML file. The .zip file may also contain volume layers.

Parameters:

  • file_path (Union[PathLike, str]) –

    Path to the .nml or .zip file containing the skeleton annotation.

Returns:

  • Skeleton ( Skeleton ) –

    A new Skeleton instance containing the loaded annotation data.

Raises:

  • FileNotFoundError

    If the specified file does not exist.

  • ValueError

    If the file format is not supported or the file is corrupted.

Examples:

Load from an NML file:

# Load a simple NML file
skeleton = Skeleton.load("dendrite_trace.nml")

# Load from a ZIP archive containing NML and volume data
skeleton = Skeleton.load("full_annotation.zip")
Note

If you need access to volume layers or other annotation data, use Annotation.load() instead, which returns an Annotation object containing both the skeleton and any additional data.

remove_tree_by_id

remove_tree_by_id(tree_id: int) -> None

save

save(out_path: Union[str, PathLike]) -> None

Save the skeleton annotation to a file.

Saves the skeleton data to either a .nml file or a .zip archive. The .zip format is recommended when the annotation includes volume layers or when you want to compress the data.

Parameters:

  • out_path (Union[str, PathLike]) –

    Destination path for the saved file. Must end with either .nml or .zip extension.

Raises:

  • AssertionError

    If the file extension is not .nml or .zip.

  • OSError

    If there are permission issues or insufficient disk space.

Examples:

# Save as NML file
skeleton.save("dendrite_annotation.nml")

# Save as ZIP archive (recommended for complex annotations)
skeleton.save("full_annotation.zip")
Note
  • The name of the annotation will be derived from the filename stem
  • When saving as .zip, any associated volume layers will be included
  • The .nml format is human-readable XML but may be larger in size
  • The .zip format provides compression and can store additional data

write

write(out_path: PathLike) -> None

Deprecated. Use Skeleton.save instead.