Skip to main content
Tissue grouping is Ganimede’s system for organizing cells into hierarchical structures. By using markdown cells with headings, you create “tissues” that group related cells together, forming a tree structure that mirrors your notebook’s logical organization.

What is a tissue?

A tissue is a markdown cell with a heading (lines starting with #). Any cells positioned after a heading cell become its children until the next heading of equal or higher level appears. Think of tissues like sections in a document:
  • # creates a top-level section
  • ## creates a subsection
  • ### creates a sub-subsection
  • And so on, up to 6 levels (######)

Parent-child relationships

Ganimede automatically builds a parent-children graph (pc_graph) that tracks which cells belong to each tissue:
def _connect_cells(self):
    """
    Forms the graph of cells:
    - next-prev (np_graph)
    - parent-children (pc_graph)
    """
    hlevel_map = {1: [], 2: [], 3: [], 4: [], 5: [], 6: []}
    
    for i, cell_id in enumerate(self.ycells):
        cell = self.ydoc.get_map(cell_id)
        source = cell.get("source").__str__()
        
        if source.startswith("#") and cell.get("type") == "markdown":
            level = source.split("/n")[0].count("#")
            hlevel_map[level].append(i)
            self.pc_graph[id] = []
The algorithm works from the deepest level up, assigning children to each heading cell.

How grouping works

When you create a notebook structure like this:
# Data Loading
Load and prepare the dataset

## Import Libraries
import pandas as pd
import numpy as np

## Read Data
df = pd.read_csv('data.csv')

# Analysis
Analyze the loaded data

## Summary Statistics
df.describe()
Ganimede builds this hierarchy:
  • Data Loading (level 1)
    • Import Libraries (level 2)
      • Code cell with imports
    • Read Data (level 2)
      • Code cell reading CSV
  • Analysis (level 1)
    • Summary Statistics (level 2)
      • Code cell with describe()

Graph structures

Ganimede maintains two graphs:

Parent-children graph (pc_graph)

Maps each heading cell to its direct children:
self.pc_graph = {
    "heading-cell-id-1": ["child-1", "child-2", "child-3"],
    "heading-cell-id-2": ["child-4", "child-5"]
}

Next-previous graph (np_graph)

Links top-level cells in sequence:
self.np_graph = {
    "cell-1": ["cell-2"],
    "cell-2": ["cell-3"]
}
Top-level cells are:
  • Level 1 headings (#)
  • Cells with no parent in pc_graph

Nested hierarchies

The algorithm handles deeply nested structures by recursively finding the last child:
# While last_child is a heading and has children,
# follow the chain to find the true last descendant
while (
    cells[last_child_idx]["is_heading"]
    and len(self.pc_graph[cells[last_child_idx]["id"]]) > 0
):
    last_child_id = self.pc_graph[cells[last_child_idx]["id"]][-1]
    last_child_idx = [
        i for i, cell in enumerate(cells)
        if cell["id"] == last_child_id
    ][0]
This ensures that cells after a nested hierarchy are correctly assigned to the next appropriate parent.

Heading detection

A cell is detected as a heading if:
  1. It’s a markdown cell
  2. Its source starts with # characters
@property
def is_heading(self):
    if self.type == "markdown":
        if any(line.lstrip().startswith("#") for line in self.source):
            return True
    return False

@property
def heading_level(self):
    if self.is_heading:
        for line in self.source:
            if line.lstrip().startswith("#"):
                return line.count("#")
    return None

Benefits of tissue grouping

Logical organization

Group related cells into coherent sections

Collapsible sections

Hide or show entire groups of cells at once

Navigation

Jump between major sections quickly

Execution order

Understand dependencies between cell groups

Persisting the structure

The graph structures are saved to your notebook file’s metadata:
{
  "metadata": {
    "gm": {
      "np_graph": {
        "cell-id-1": ["cell-id-2"]
      },
      "pc_graph": {
        "heading-id-1": ["child-1", "child-2"],
        "heading-id-2": ["child-3"]
      }
    }
  }
}
This ensures your organizational structure persists between sessions.
Use tissue grouping to create a table of contents structure for your notebook. Top-level headings become your main sections, and nested headings create subsections.

Working with tissues

Creating a tissue

  1. Add a markdown cell to your canvas
  2. Start the cell content with # for the heading level you want
  3. Position related cells after the heading cell

Modifying the hierarchy

Changing heading levels automatically updates the graph structure. When you:
  • Change ## to # → Cell becomes a top-level section
  • Change # to ### → Cell becomes a subsection
  • Remove # → Cell is no longer a heading
The next time you save or checkpoint, the graphs rebuild to reflect your changes.

Next steps

Cell management

Learn about cell types and properties

Version control

Understand how structure is saved

Build docs developers (and LLMs) love