Skip to content

reportlets

tit.reporting.reportlets

Specialized reportlets for TI-Toolbox reports.

This module provides domain-specific reportlets for brain imaging, simulation parameters, and analysis results.

SliceSeriesReportlet

SliceSeriesReportlet(title: str | None = None, slices: list[dict[str, Any]] | None = None, orientation: str = 'axial', caption: str | None = None)

Bases: BaseReportlet

Reportlet for displaying a series of brain slices.

Displays multiple slices (typically 7) across axial, sagittal, or coronal views, commonly used for QC visualizations.

Initialize the slice series reportlet.

Parameters:

Name Type Description Default
title str | None

Title for the slice series

None
slices list[dict[str, Any]] | None

List of slice data dicts with 'base64' and optional 'label'

None
orientation str

View orientation (axial, sagittal, coronal)

'axial'
caption str | None

Optional caption text

None
Source code in tit/reporting/reportlets/images.py
def __init__(
    self,
    title: str | None = None,
    slices: list[dict[str, Any]] | None = None,
    orientation: str = "axial",
    caption: str | None = None,
):
    """
    Initialize the slice series reportlet.

    Args:
        title: Title for the slice series
        slices: List of slice data dicts with 'base64' and optional 'label'
        orientation: View orientation (axial, sagittal, coronal)
        caption: Optional caption text
    """
    super().__init__(title)
    self.slices: list[dict[str, Any]] = slices or []
    self.orientation = orientation
    self.caption = caption

add_slice

add_slice(image_data: str | bytes | Path | Any, label: str | None = None, mime_type: str = 'image/png') -> None

Add a slice to the series.

Parameters:

Name Type Description Default
image_data str | bytes | Path | Any

Base64 string, bytes, path, or PIL Image

required
label str | None

Optional label for this slice

None
mime_type str

MIME type of the image

'image/png'
Source code in tit/reporting/reportlets/images.py
def add_slice(
    self,
    image_data: str | bytes | Path | Any,
    label: str | None = None,
    mime_type: str = "image/png",
) -> None:
    """
    Add a slice to the series.

    Args:
        image_data: Base64 string, bytes, path, or PIL Image
        label: Optional label for this slice
        mime_type: MIME type of the image
    """
    base64_data = self._process_image(image_data)
    self.slices.append(
        {
            "base64": base64_data,
            "label": label,
            "mime_type": mime_type,
        }
    )

load_from_files

load_from_files(file_paths: list[str | Path]) -> None

Load slices from a list of image files.

Parameters:

Name Type Description Default
file_paths list[str | Path]

List of paths to slice images

required
Source code in tit/reporting/reportlets/images.py
def load_from_files(self, file_paths: list[str | Path]) -> None:
    """
    Load slices from a list of image files.

    Args:
        file_paths: List of paths to slice images
    """
    for i, path in enumerate(file_paths):
        path = Path(path)
        if path.exists():
            self.add_slice(path, label=f"Slice {i + 1}")

render_html

render_html() -> str

Render the slice series as HTML.

Source code in tit/reporting/reportlets/images.py
def render_html(self) -> str:
    """Render the slice series as HTML."""
    if not self.slices:
        return f"""
        <div class="reportlet slice-series-reportlet" id="{self.reportlet_id}">
            <div class="image-placeholder">
                <em>No slices available</em>
            </div>
        </div>
        """

    slice_images = []
    for slice_data in self.slices:
        mime_type = slice_data.get("mime_type", "image/png")
        label = slice_data.get("label", "")
        label_html = f'<span class="slice-label">{label}</span>' if label else ""

        slice_images.append(f"""
            <div class="slice-image">
                <img src="data:{mime_type};base64,{slice_data["base64"]}"
                     alt="{label or 'Brain slice'}" />
                {label_html}
            </div>
            """)

    title_html = f"<h3>{self._title}</h3>" if self._title else ""
    caption_html = (
        f'<p class="series-caption">{self.caption}</p>' if self.caption else ""
    )

    return f"""
    <div class="reportlet slice-series-reportlet {self.orientation}" id="{self.reportlet_id}">
        {title_html}
        <div class="slice-series">
            {"".join(slice_images)}
        </div>
        {caption_html}
    </div>
    """

MontageImageReportlet

MontageImageReportlet(title: str | None = None, image_source: str | Path | bytes | Any | None = None, electrode_pairs: list[dict[str, Any]] | None = None, montage_name: str | None = None)

Bases: BaseReportlet

Reportlet for displaying electrode montage visualizations.

Shows electrode placement with labeled pairs and optional intensity annotations.

Initialize the montage image reportlet.

Parameters:

Name Type Description Default
title str | None

Title for the montage

None
image_source str | Path | bytes | Any | None

Montage image (path, bytes, or PIL Image)

None
electrode_pairs list[dict[str, Any]] | None

List of electrode pair configurations

None
montage_name str | None

Name of the montage

None
Source code in tit/reporting/reportlets/images.py
def __init__(
    self,
    title: str | None = None,
    image_source: str | Path | bytes | Any | None = None,
    electrode_pairs: list[dict[str, Any]] | None = None,
    montage_name: str | None = None,
):
    """
    Initialize the montage image reportlet.

    Args:
        title: Title for the montage
        image_source: Montage image (path, bytes, or PIL Image)
        electrode_pairs: List of electrode pair configurations
        montage_name: Name of the montage
    """
    super().__init__(title)
    self._base64_data: str | None = None
    self._mime_type: str = "image/png"
    self.electrode_pairs = electrode_pairs or []
    self.montage_name = montage_name

    if image_source is not None:
        self._load_image(image_source)

set_base64_data

set_base64_data(data: str, mime_type: str = 'image/png') -> None

Directly set base64 encoded image data.

Source code in tit/reporting/reportlets/images.py
def set_base64_data(self, data: str, mime_type: str = "image/png") -> None:
    """Directly set base64 encoded image data."""
    self._base64_data = data
    self._mime_type = mime_type

add_electrode_pair

add_electrode_pair(name: str, electrode1: str, electrode2: str, intensity: float | None = None) -> None

Add an electrode pair to the montage info.

Parameters:

Name Type Description Default
name str

Name of the pair (e.g., "Pair 1")

required
electrode1 str

First electrode position

required
electrode2 str

Second electrode position

required
intensity float | None

Optional current intensity

None
Source code in tit/reporting/reportlets/images.py
def add_electrode_pair(
    self,
    name: str,
    electrode1: str,
    electrode2: str,
    intensity: float | None = None,
) -> None:
    """
    Add an electrode pair to the montage info.

    Args:
        name: Name of the pair (e.g., "Pair 1")
        electrode1: First electrode position
        electrode2: Second electrode position
        intensity: Optional current intensity
    """
    self.electrode_pairs.append(
        {
            "name": name,
            "electrode1": electrode1,
            "electrode2": electrode2,
            "intensity": intensity,
        }
    )

render_html

render_html() -> str

Render the montage image as HTML.

Source code in tit/reporting/reportlets/images.py
def render_html(self) -> str:
    """Render the montage image as HTML."""
    title_html = (
        f"<h3>{self._title or self.montage_name or 'Electrode Montage'}</h3>"
    )

    # Electrode pairs table
    pairs_html = ""
    if self.electrode_pairs:
        rows = []
        for pair in self.electrode_pairs:
            intensity_value = pair.get("intensity")
            if intensity_value is None or intensity_value == "":
                intensity_str = "—"
            else:
                try:
                    intensity_str = f"{float(intensity_value):.2f} mA"
                except (TypeError, ValueError):
                    intensity_str = str(intensity_value)
            rows.append(f"""
                <tr>
                    <td>{pair.get("name", "")}</td>
                    <td>{pair.get("electrode1", "")}</td>
                    <td>{pair.get("electrode2", "")}</td>
                    <td>{intensity_str}</td>
                </tr>
                """)

        pairs_html = f"""
        <div class="electrode-pairs">
            <table class="data-table compact">
                <thead>
                    <tr>
                        <th>Pair</th>
                        <th>Electrode 1</th>
                        <th>Electrode 2</th>
                        <th>Intensity</th>
                    </tr>
                </thead>
                <tbody>
                    {"".join(rows)}
                </tbody>
            </table>
        </div>
        """

    # Image display
    image_html = ""
    if self._base64_data:
        image_html = f"""
        <figure class="montage-figure">
            <img src="data:{self._mime_type};base64,{self._base64_data}"
                 alt="{self.montage_name or 'Electrode montage'}"
                 class="report-image montage-image" />
        </figure>
        """
    else:
        image_html = """
        <div class="image-placeholder">
            <em>No montage image available</em>
        </div>
        """

    return f"""
    <div class="reportlet montage-reportlet" id="{self.reportlet_id}">
        {title_html}
        <div class="montage-content">
            {image_html}
            {pairs_html}
        </div>
    </div>
    """

MultiViewBrainReportlet

MultiViewBrainReportlet(title: str | None = None, axial_image: str | Path | bytes | None = None, sagittal_image: str | Path | bytes | None = None, coronal_image: str | Path | bytes | None = None, caption: str | None = None)

Bases: BaseReportlet

Reportlet for displaying brain images in multiple views.

Shows the same brain data in axial, sagittal, and coronal orientations side by side.

Initialize the multi-view brain reportlet.

Parameters:

Name Type Description Default
title str | None

Title for the visualization

None
axial_image str | Path | bytes | None

Axial view image

None
sagittal_image str | Path | bytes | None

Sagittal view image

None
coronal_image str | Path | bytes | None

Coronal view image

None
caption str | None

Optional caption

None
Source code in tit/reporting/reportlets/images.py
def __init__(
    self,
    title: str | None = None,
    axial_image: str | Path | bytes | None = None,
    sagittal_image: str | Path | bytes | None = None,
    coronal_image: str | Path | bytes | None = None,
    caption: str | None = None,
):
    """
    Initialize the multi-view brain reportlet.

    Args:
        title: Title for the visualization
        axial_image: Axial view image
        sagittal_image: Sagittal view image
        coronal_image: Coronal view image
        caption: Optional caption
    """
    super().__init__(title)
    self.views: dict[str, str | None] = {
        "axial": None,
        "sagittal": None,
        "coronal": None,
    }
    self.caption = caption

    if axial_image:
        self.set_view("axial", axial_image)
    if sagittal_image:
        self.set_view("sagittal", sagittal_image)
    if coronal_image:
        self.set_view("coronal", coronal_image)

set_view

set_view(view_name: str, image_data: str | Path | bytes | Any) -> None

Set an image for a specific view.

Parameters:

Name Type Description Default
view_name str

One of 'axial', 'sagittal', 'coronal'

required
image_data str | Path | bytes | Any

Image data (path, bytes, base64, or PIL Image)

required
Source code in tit/reporting/reportlets/images.py
def set_view(self, view_name: str, image_data: str | Path | bytes | Any) -> None:
    """
    Set an image for a specific view.

    Args:
        view_name: One of 'axial', 'sagittal', 'coronal'
        image_data: Image data (path, bytes, base64, or PIL Image)
    """
    if view_name not in self.views:
        raise ValueError(f"Invalid view name: {view_name}")

    if isinstance(image_data, (str, Path)):
        path = Path(image_data)
        if path.exists():
            with open(path, "rb") as f:
                self.views[view_name] = base64.b64encode(f.read()).decode("utf-8")
        else:
            # Assume already base64
            self.views[view_name] = str(image_data)
    elif isinstance(image_data, bytes):
        self.views[view_name] = base64.b64encode(image_data).decode("utf-8")
    else:
        # Assume PIL Image
        try:
            buffer = io.BytesIO()
            image_data.save(buffer, format="PNG")
            self.views[view_name] = base64.b64encode(buffer.getvalue()).decode(
                "utf-8"
            )
        except (AttributeError, ValueError):
            pass

render_html

render_html() -> str

Render the multi-view visualization as HTML.

Source code in tit/reporting/reportlets/images.py
def render_html(self) -> str:
    """Render the multi-view visualization as HTML."""
    title_html = f"<h3>{self._title}</h3>" if self._title else ""

    view_panels = []
    for view_name, base64_data in self.views.items():
        if base64_data:
            view_panels.append(f"""
                <div class="view-panel {view_name}">
                    <div class="view-label">{view_name.capitalize()}</div>
                    <img src="data:image/png;base64,{base64_data}"
                         alt="{view_name} view"
                         class="view-image" />
                </div>
                """)
        else:
            view_panels.append(f"""
                <div class="view-panel {view_name}">
                    <div class="view-label">{view_name.capitalize()}</div>
                    <div class="view-placeholder">Not available</div>
                </div>
                """)

    caption_html = (
        f'<p class="multiview-caption">{self.caption}</p>' if self.caption else ""
    )

    return f"""
    <div class="reportlet multiview-reportlet" id="{self.reportlet_id}">
        {title_html}
        <div class="multiview-grid">
            {"".join(view_panels)}
        </div>
        {caption_html}
    </div>
    """

ConductivityTableReportlet

ConductivityTableReportlet(conductivities: dict[str, dict[str, Any]] | None = None, title: str | None = None, show_sources: bool = True, conductivity_type: str = 'scalar')

Bases: BaseReportlet

Reportlet for displaying tissue conductivity values.

Shows conductivity values for different tissue types with their sources/references.

Initialize the conductivity table reportlet.

Parameters:

Name Type Description Default
conductivities dict[str, dict[str, Any]] | None

Dict mapping tissue names to conductivity info

None
title str | None

Title for the table

None
show_sources bool

Whether to show source references

True
conductivity_type str

Type of conductivity (scalar, anisotropic, etc.)

'scalar'
Source code in tit/reporting/reportlets/metadata.py
def __init__(
    self,
    conductivities: dict[str, dict[str, Any]] | None = None,
    title: str | None = None,
    show_sources: bool = True,
    conductivity_type: str = "scalar",
):
    """
    Initialize the conductivity table reportlet.

    Args:
        conductivities: Dict mapping tissue names to conductivity info
        title: Title for the table
        show_sources: Whether to show source references
        conductivity_type: Type of conductivity (scalar, anisotropic, etc.)
    """
    super().__init__(title or "Tissue Conductivities")
    self.conductivities = conductivities or DEFAULT_CONDUCTIVITIES.copy()
    self.show_sources = show_sources
    self.conductivity_type = conductivity_type

set_conductivity

set_conductivity(tissue: str, value: float, unit: str = 'S/m', source: str | None = None) -> None

Set conductivity for a tissue type.

Parameters:

Name Type Description Default
tissue str

Tissue name

required
value float

Conductivity value

required
unit str

Unit of measurement

'S/m'
source str | None

Source reference

None
Source code in tit/reporting/reportlets/metadata.py
def set_conductivity(
    self,
    tissue: str,
    value: float,
    unit: str = "S/m",
    source: str | None = None,
) -> None:
    """
    Set conductivity for a tissue type.

    Args:
        tissue: Tissue name
        value: Conductivity value
        unit: Unit of measurement
        source: Source reference
    """
    self.conductivities[tissue] = {
        "value": value,
        "unit": unit,
        "source": source or "User-defined",
    }

render_html

render_html() -> str

Render the conductivity table as HTML.

Source code in tit/reporting/reportlets/metadata.py
def render_html(self) -> str:
    """Render the conductivity table as HTML."""
    # Build table headers
    headers = ["Tissue", "Conductivity"]
    if self.show_sources:
        headers.append("Source")

    header_cells = "".join(f"<th>{h}</th>" for h in headers)

    # Build table rows
    rows = []
    for tissue, data in self.conductivities.items():
        # Handle both string keys ("white_matter") and integer keys (1)
        if isinstance(tissue, int):
            # Integer key - use the 'name' field from data if available
            tissue_name = data.get("name", f"Tissue {tissue}")
        else:
            tissue_name = str(tissue).replace("_", " ").title()
        # Handle both 'value' and 'conductivity' field names
        value = data.get("value", data.get("conductivity", 0))
        unit = data.get("unit", "S/m")

        cells = [
            f"<td>{tissue_name}</td>",
            f"<td>{value:.4f} {unit}</td>",
        ]

        if self.show_sources:
            # Handle both 'source' and 'reference' field names
            source = data.get("source", data.get("reference", "—"))
            cells.append(f"<td class='source-cell'>{source}</td>")

        rows.append(f"<tr>{''.join(cells)}</tr>")

    title_html = f"<h3>{self._title}</h3>" if self._title else ""
    type_badge = (
        f'<span class="conductivity-type-badge">{self.conductivity_type}</span>'
    )

    return f"""
    <div class="reportlet conductivity-reportlet" id="{self.reportlet_id}">
        {title_html}
        {type_badge}
        <div class="table-wrapper">
            <table class="data-table conductivity-table striped">
                <thead>
                    <tr>{header_cells}</tr>
                </thead>
                <tbody>
                    {"".join(rows)}
                </tbody>
            </table>
        </div>
    </div>
    """

ProcessingStepReportlet

ProcessingStepReportlet(title: str | None = None, steps: list[dict[str, Any]] | None = None)

Bases: BaseReportlet

Reportlet for displaying processing pipeline steps.

Shows collapsible processing steps with status, duration, and optional details.

Initialize the processing step reportlet.

Parameters:

Name Type Description Default
title str | None

Title for the processing steps section

None
steps list[dict[str, Any]] | None

List of step dictionaries

None
Source code in tit/reporting/reportlets/metadata.py
def __init__(
    self,
    title: str | None = None,
    steps: list[dict[str, Any]] | None = None,
):
    """
    Initialize the processing step reportlet.

    Args:
        title: Title for the processing steps section
        steps: List of step dictionaries
    """
    super().__init__(title or "Processing Steps")
    self.steps: list[dict[str, Any]] = steps or []

add_step

add_step(name: str, description: str | None = None, status: StatusType | str = PENDING, duration: float | None = None, parameters: dict[str, Any] | None = None, output_files: list[str] | None = None, error_message: str | None = None) -> None

Add a processing step.

Parameters:

Name Type Description Default
name str

Step name

required
description str | None

Step description

None
status StatusType | str

Step status (pending, running, completed, failed, skipped)

PENDING
duration float | None

Duration in seconds

None
parameters dict[str, Any] | None

Step parameters

None
output_files list[str] | None

List of output file paths

None
error_message str | None

Error message if failed

None
Source code in tit/reporting/reportlets/metadata.py
def add_step(
    self,
    name: str,
    description: str | None = None,
    status: StatusType | str = StatusType.PENDING,
    duration: float | None = None,
    parameters: dict[str, Any] | None = None,
    output_files: list[str] | None = None,
    error_message: str | None = None,
) -> None:
    """
    Add a processing step.

    Args:
        name: Step name
        description: Step description
        status: Step status (pending, running, completed, failed, skipped)
        duration: Duration in seconds
        parameters: Step parameters
        output_files: List of output file paths
        error_message: Error message if failed
    """
    if isinstance(status, StatusType):
        status = status.value

    self.steps.append(
        {
            "name": name,
            "description": description,
            "status": status,
            "duration": duration,
            "parameters": parameters or {},
            "output_files": output_files or [],
            "error_message": error_message,
        }
    )

render_html

render_html() -> str

Render the processing steps as HTML.

Source code in tit/reporting/reportlets/metadata.py
def render_html(self) -> str:
    """Render the processing steps as HTML."""
    if not self.steps:
        return f"""
        <div class="reportlet processing-steps-reportlet" id="{self.reportlet_id}">
            <em>No processing steps recorded</em>
        </div>
        """

    step_items = []
    for i, step in enumerate(self.steps):
        step_id = f"{self.reportlet_id}-step-{i}"
        status = step.get("status", "pending")
        icon = self._get_status_icon(status)
        s = step.get("duration")
        if s is None:
            duration = "—"
        elif s < 60:
            duration = f"{s:.1f}s"
        elif s < 3600:
            duration = f"{s / 60:.1f}m"
        else:
            duration = f"{s / 3600:.1f}h"

        # Build parameters section
        params_html = ""
        if step.get("parameters"):
            param_rows = "".join(
                f"<tr><td>{k}</td><td>{v}</td></tr>"
                for k, v in step["parameters"].items()
            )
            params_html = f"""
            <div class="step-parameters">
                <strong>Parameters:</strong>
                <table class="data-table compact">
                    <tbody>{param_rows}</tbody>
                </table>
            </div>
            """

        # Build output files section
        outputs_html = ""
        if step.get("output_files"):
            file_list = "".join(f"<li>{f}</li>" for f in step["output_files"])
            outputs_html = f"""
            <div class="step-outputs">
                <strong>Output Files:</strong>
                <ul>{file_list}</ul>
            </div>
            """

        # Build error section
        error_html = ""
        if step.get("error_message"):
            error_html = f"""
            <div class="step-error">
                <strong>Error:</strong>
                <span class="error-text">{step["error_message"]}</span>
            </div>
            """

        description_html = ""
        if step.get("description"):
            description_html = (
                f'<p class="step-description">{step["description"]}</p>'
            )

        step_items.append(f"""
            <div class="processing-step" id="{step_id}">
                <div class="step-header" onclick="toggleStep('{step_id}')">
                    <span class="step-status {status}">{icon}</span>
                    <span class="step-name">{step["name"]}</span>
                    <span class="step-duration">{duration}</span>
                </div>
                <div class="step-content" id="{step_id}-content">
                    {description_html}
                    {params_html}
                    {outputs_html}
                    {error_html}
                </div>
            </div>
            """)

    title_html = f"<h3>{self._title}</h3>" if self._title else ""

    # Summary counts
    completed = sum(1 for s in self.steps if s.get("status") == "completed")
    failed = sum(1 for s in self.steps if s.get("status") == "failed")
    total = len(self.steps)

    summary_html = f"""
    <div class="steps-summary">
        <span class="summary-item completed">{completed}/{total} completed</span>
        {f'<span class="summary-item failed">{failed} failed</span>' if failed > 0 else ''}
    </div>
    """

    return f"""
    <div class="reportlet processing-steps-reportlet" id="{self.reportlet_id}">
        {title_html}
        {summary_html}
        <div class="steps-list">
            {"".join(step_items)}
        </div>
    </div>
    """

SummaryCardsReportlet

SummaryCardsReportlet(title: str | None = None, cards: list[dict[str, Any]] | None = None, columns: int = 4)

Bases: BaseReportlet

Reportlet for displaying key summary metrics as cards.

Shows important values in a prominent card grid layout.

Initialize the summary cards reportlet.

Parameters:

Name Type Description Default
title str | None

Title for the summary section

None
cards list[dict[str, Any]] | None

List of card data dicts

None
columns int

Number of columns in grid

4
Source code in tit/reporting/reportlets/metadata.py
def __init__(
    self,
    title: str | None = None,
    cards: list[dict[str, Any]] | None = None,
    columns: int = 4,
):
    """
    Initialize the summary cards reportlet.

    Args:
        title: Title for the summary section
        cards: List of card data dicts
        columns: Number of columns in grid
    """
    super().__init__(title)
    self.cards: list[dict[str, Any]] = cards or []
    self.columns = columns

add_card

add_card(label: str, value: Any, icon: str | None = None, color: str | None = None, subtitle: str | None = None) -> None

Add a summary card.

Parameters:

Name Type Description Default
label str

Card label

required
value Any

Card value

required
icon str | None

Optional icon character

None
color str | None

Optional accent color

None
subtitle str | None

Optional subtitle text

None
Source code in tit/reporting/reportlets/metadata.py
def add_card(
    self,
    label: str,
    value: Any,
    icon: str | None = None,
    color: str | None = None,
    subtitle: str | None = None,
) -> None:
    """
    Add a summary card.

    Args:
        label: Card label
        value: Card value
        icon: Optional icon character
        color: Optional accent color
        subtitle: Optional subtitle text
    """
    self.cards.append(
        {
            "label": label,
            "value": value,
            "icon": icon,
            "color": color,
            "subtitle": subtitle,
        }
    )

render_html

render_html() -> str

Render the summary cards as HTML.

Source code in tit/reporting/reportlets/metadata.py
def render_html(self) -> str:
    """Render the summary cards as HTML."""
    if not self.cards:
        return ""

    card_items = []
    for card in self.cards:
        icon_html = (
            f'<span class="card-icon">{card["icon"]}</span>'
            if card.get("icon")
            else ""
        )
        subtitle_html = (
            f'<div class="card-subtitle">{card["subtitle"]}</div>'
            if card.get("subtitle")
            else ""
        )
        style = f'border-top-color: {card["color"]};' if card.get("color") else ""

        card_items.append(f"""
            <div class="summary-card" style="{style}">
                {icon_html}
                <div class="card-label">{card["label"]}</div>
                <div class="card-value">{card["value"]}</div>
                {subtitle_html}
            </div>
            """)

    title_html = f"<h3>{self._title}</h3>" if self._title else ""

    return f"""
    <div class="reportlet summary-cards-reportlet" id="{self.reportlet_id}">
        {title_html}
        <div class="card-grid columns-{self.columns}">
            {"".join(card_items)}
        </div>
    </div>
    """

ParameterListReportlet

ParameterListReportlet(title: str | None = None, parameters: dict[str, dict[str, Any]] | None = None)

Bases: BaseReportlet

Reportlet for displaying a categorized list of parameters.

Organizes parameters into groups with clear visual hierarchy.

Initialize the parameter list reportlet.

Parameters:

Name Type Description Default
title str | None

Title for the parameters section

None
parameters dict[str, dict[str, Any]] | None

Dict of category -> {param_name: param_value}

None
Source code in tit/reporting/reportlets/metadata.py
def __init__(
    self,
    title: str | None = None,
    parameters: dict[str, dict[str, Any]] | None = None,
):
    """
    Initialize the parameter list reportlet.

    Args:
        title: Title for the parameters section
        parameters: Dict of category -> {param_name: param_value}
    """
    super().__init__(title or "Parameters")
    self.parameters: dict[str, dict[str, Any]] = parameters or {}

add_category

add_category(category: str, params: dict[str, Any]) -> None

Add a parameter category.

Parameters:

Name Type Description Default
category str

Category name

required
params dict[str, Any]

Dict of parameter name to value

required
Source code in tit/reporting/reportlets/metadata.py
def add_category(self, category: str, params: dict[str, Any]) -> None:
    """
    Add a parameter category.

    Args:
        category: Category name
        params: Dict of parameter name to value
    """
    self.parameters[category] = params

add_parameter

add_parameter(category: str, name: str, value: Any) -> None

Add a single parameter to a category.

Parameters:

Name Type Description Default
category str

Category name

required
name str

Parameter name

required
value Any

Parameter value

required
Source code in tit/reporting/reportlets/metadata.py
def add_parameter(self, category: str, name: str, value: Any) -> None:
    """
    Add a single parameter to a category.

    Args:
        category: Category name
        name: Parameter name
        value: Parameter value
    """
    if category not in self.parameters:
        self.parameters[category] = {}
    self.parameters[category][name] = value

render_html

render_html() -> str

Render the parameter list as HTML.

Source code in tit/reporting/reportlets/metadata.py
def render_html(self) -> str:
    """Render the parameter list as HTML."""
    if not self.parameters:
        return ""

    category_sections = []
    for category, params in self.parameters.items():
        rows = []
        for name, value in params.items():
            formatted_name = name.replace("_", " ").title()
            formatted_value = self._format_value(value)
            rows.append(f"""<tr>
                    <td class="param-name">{formatted_name}</td>
                    <td class="param-value">{formatted_value}</td>
                </tr>""")

        category_sections.append(f"""
            <div class="parameter-category">
                <h4>{category}</h4>
                <table class="data-table compact">
                    <tbody>{"".join(rows)}</tbody>
                </table>
            </div>
            """)

    title_html = f"<h3>{self._title}</h3>" if self._title else ""

    return f"""
    <div class="reportlet parameter-list-reportlet" id="{self.reportlet_id}">
        {title_html}
        {"".join(category_sections)}
    </div>
    """

MethodsBoilerplateReportlet

MethodsBoilerplateReportlet(title: str | None = None, boilerplate_text: str | None = None, pipeline_type: str = 'simulation', parameters: dict[str, Any] | None = None)

Bases: BaseReportlet

Reportlet for displaying methods section boilerplate text.

Generates publication-ready text describing the methods used in the analysis, with a copy-to-clipboard button.

Initialize the methods boilerplate reportlet.

Parameters:

Name Type Description Default
title str | None

Title for the section

None
boilerplate_text str | None

Pre-written boilerplate text

None
pipeline_type str

Type of pipeline (simulation, preprocessing, optimization)

'simulation'
parameters dict[str, Any] | None

Parameters to include in generated text

None
Source code in tit/reporting/reportlets/text.py
def __init__(
    self,
    title: str | None = None,
    boilerplate_text: str | None = None,
    pipeline_type: str = "simulation",
    parameters: dict[str, Any] | None = None,
):
    """
    Initialize the methods boilerplate reportlet.

    Args:
        title: Title for the section
        boilerplate_text: Pre-written boilerplate text
        pipeline_type: Type of pipeline (simulation, preprocessing, optimization)
        parameters: Parameters to include in generated text
    """
    super().__init__(title or "Methods Boilerplate")
    self._boilerplate_text = boilerplate_text
    self.pipeline_type = pipeline_type
    self.parameters = parameters or {}

set_boilerplate

set_boilerplate(text: str) -> None

Set the boilerplate text directly.

Source code in tit/reporting/reportlets/text.py
def set_boilerplate(self, text: str) -> None:
    """Set the boilerplate text directly."""
    self._boilerplate_text = text

generate_boilerplate

generate_boilerplate() -> str

Generate boilerplate text based on pipeline type and parameters.

Returns:

Type Description
str

Generated boilerplate text

Source code in tit/reporting/reportlets/text.py
def generate_boilerplate(self) -> str:
    """
    Generate boilerplate text based on pipeline type and parameters.

    Returns:
        Generated boilerplate text
    """
    if self._boilerplate_text:
        return self._boilerplate_text

    match self.pipeline_type:
        case "simulation":
            return self._generate_simulation_boilerplate()
        case "preprocessing":
            return self._generate_preprocessing_boilerplate()
        case "optimization":
            return self._generate_optimization_boilerplate()
        case _:
            return self._generate_generic_boilerplate()

render_html

render_html() -> str

Render the boilerplate text as HTML.

Source code in tit/reporting/reportlets/text.py
def render_html(self) -> str:
    """Render the boilerplate text as HTML."""
    boilerplate = self.generate_boilerplate()

    title_html = f"<h3>{self._title}</h3>" if self._title else ""

    return f"""
    <div class="reportlet methods-boilerplate-reportlet" id="{self.reportlet_id}">
        {title_html}
        <p class="boilerplate-intro">
            The following text can be used as a starting point for the methods
            section of a publication. Please verify and adapt as needed.
        </p>
        <button class="copy-btn" onclick="copyToClipboard('{self.reportlet_id}-content')">
            Copy to Clipboard
        </button>
        <div class="text-content monospace copyable" id="{self.reportlet_id}-content">
            {boilerplate}
        </div>
    </div>
    """

DescriptionReportlet

DescriptionReportlet(content: str, title: str | None = None, format_type: str = 'paragraphs')

Bases: BaseReportlet

Reportlet for displaying descriptive text content.

Renders paragraphs of text with optional formatting.

Initialize the description reportlet.

Parameters:

Name Type Description Default
content str

Text content to display

required
title str | None

Optional section title

None
format_type str

How to format content (paragraphs, html, preformatted)

'paragraphs'
Source code in tit/reporting/reportlets/text.py
def __init__(
    self,
    content: str,
    title: str | None = None,
    format_type: str = "paragraphs",
):
    """
    Initialize the description reportlet.

    Args:
        content: Text content to display
        title: Optional section title
        format_type: How to format content (paragraphs, html, preformatted)
    """
    super().__init__(title)
    self.content = content
    self.format_type = format_type

render_html

render_html() -> str

Render the description text as HTML.

Source code in tit/reporting/reportlets/text.py
def render_html(self) -> str:
    """Render the description text as HTML."""
    title_html = f"<h3>{self._title}</h3>" if self._title else ""

    if self.format_type == "html":
        formatted_content = self.content
    elif self.format_type == "preformatted":
        formatted_content = f"<pre>{self._escape_html(self.content)}</pre>"
    else:
        # Split into paragraphs
        paragraphs = self.content.split("\n\n")
        formatted_content = "".join(
            f"<p>{p.strip()}</p>" for p in paragraphs if p.strip()
        )

    return f"""
    <div class="reportlet description-reportlet" id="{self.reportlet_id}">
        {title_html}
        <div class="text-content">
            {formatted_content}
        </div>
    </div>
    """

CommandLogReportlet

CommandLogReportlet(title: str | None = None, commands: list[dict[str, str]] | None = None)

Bases: BaseReportlet

Reportlet for displaying command execution logs.

Shows commands that were run with their outputs in a terminal-like display.

Initialize the command log reportlet.

Parameters:

Name Type Description Default
title str | None

Optional section title

None
commands list[dict[str, str]] | None

List of command dicts with 'command' and optional 'output'

None
Source code in tit/reporting/reportlets/text.py
def __init__(
    self,
    title: str | None = None,
    commands: list[dict[str, str]] | None = None,
):
    """
    Initialize the command log reportlet.

    Args:
        title: Optional section title
        commands: List of command dicts with 'command' and optional 'output'
    """
    super().__init__(title or "Command Log")
    self.commands: list[dict[str, str]] = commands or []

add_command

add_command(command: str, output: str | None = None, status: str = 'success') -> None

Add a command to the log.

Parameters:

Name Type Description Default
command str

The command that was executed

required
output str | None

Command output (if any)

None
status str

Execution status (success, error)

'success'
Source code in tit/reporting/reportlets/text.py
def add_command(
    self,
    command: str,
    output: str | None = None,
    status: str = "success",
) -> None:
    """
    Add a command to the log.

    Args:
        command: The command that was executed
        output: Command output (if any)
        status: Execution status (success, error)
    """
    self.commands.append(
        {
            "command": command,
            "output": output or "",
            "status": status,
        }
    )

render_html

render_html() -> str

Render the command log as HTML.

Source code in tit/reporting/reportlets/text.py
def render_html(self) -> str:
    """Render the command log as HTML."""
    if not self.commands:
        return ""

    command_items = []
    for cmd in self.commands:
        status_class = "success" if cmd.get("status") == "success" else "error"
        output_html = ""
        if cmd.get("output"):
            output_html = f'<div class="command-output">{self._escape_html(cmd["output"])}</div>'

        command_items.append(f"""
            <div class="command-item {status_class}">
                <div class="command-prompt">$ {self._escape_html(cmd["command"])}</div>
                {output_html}
            </div>
            """)

    title_html = f"<h3>{self._title}</h3>" if self._title else ""

    return f"""
    <div class="reportlet command-log-reportlet" id="{self.reportlet_id}">
        {title_html}
        <div class="command-log">
            {"".join(command_items)}
        </div>
    </div>
    """

TIToolboxReferencesReportlet

TIToolboxReferencesReportlet(title: str | None = None, include_defaults: bool = True, pipeline_components: list[str] | None = None)

Bases: ReferencesReportlet

Specialized references reportlet with TI-Toolbox default citations.

Automatically includes relevant citations based on the pipeline components used.

Initialize the TI-Toolbox references reportlet.

Parameters:

Name Type Description Default
title str | None

Section title

None
include_defaults bool

Whether to include default TI-Toolbox refs

True
pipeline_components list[str] | None

List of components used (to filter refs)

None
Source code in tit/reporting/reportlets/references.py
def __init__(
    self,
    title: str | None = None,
    include_defaults: bool = True,
    pipeline_components: list[str] | None = None,
):
    """
    Initialize the TI-Toolbox references reportlet.

    Args:
        title: Section title
        include_defaults: Whether to include default TI-Toolbox refs
        pipeline_components: List of components used (to filter refs)
    """
    super().__init__(title=title or "References")

    self.pipeline_components = pipeline_components or []

    if include_defaults:
        self._add_default_references()

add_default_reference

add_default_reference(key: str) -> bool

Add a default reference by key.

Parameters:

Name Type Description Default
key str

The reference key (e.g., 'freesurfer', 'qsiprep')

required

Returns:

Type Description
bool

True if reference was found and added, False otherwise

Source code in tit/reporting/reportlets/references.py
def add_default_reference(self, key: str) -> bool:
    """
    Add a default reference by key.

    Args:
        key: The reference key (e.g., 'freesurfer', 'qsiprep')

    Returns:
        True if reference was found and added, False otherwise
    """
    for ref_data in DEFAULT_REFERENCES:
        if ref_data["key"] == key:
            # Check if already added
            if not any(r["key"] == key for r in self.references):
                self.add_reference(
                    key=ref_data["key"],
                    citation=ref_data["citation"],
                    doi=ref_data.get("doi"),
                    url=ref_data.get("url"),
                )
            return True
    return False

get_default_references

get_default_references() -> list[dict[str, str]]

Get the list of default TI-Toolbox references.

Returns:

Type Description
list[dict[str, str]]

List of reference dictionaries

Source code in tit/reporting/reportlets/references.py
def get_default_references() -> list[dict[str, str]]:
    """
    Get the list of default TI-Toolbox references.

    Returns:
        List of reference dictionaries
    """
    return DEFAULT_REFERENCES.copy()

get_reference_by_key

get_reference_by_key(key: str) -> dict[str, str] | None

Get a specific reference by its key.

Parameters:

Name Type Description Default
key str

The reference key

required

Returns:

Type Description
dict[str, str] | None

Reference dictionary or None if not found

Source code in tit/reporting/reportlets/references.py
def get_reference_by_key(key: str) -> dict[str, str] | None:
    """
    Get a specific reference by its key.

    Args:
        key: The reference key

    Returns:
        Reference dictionary or None if not found
    """
    for ref in DEFAULT_REFERENCES:
        if ref["key"] == key:
            return ref.copy()
    return None