Skip to content

nilearn

tit.plotting.nilearn

Nilearn-based plotting helpers for TI-Toolbox.

This package provides neuroimaging visualization utilities built on nilearn <https://nilearn.github.io/>_, including multi-slice PDF exports, glass-brain PNG exports, and interactive HTML surface views.

Public API

NilearnVisualizer High-level class combining PDF, HTML, and glass-brain workflows. create_pdf_entry_point / create_pdf_entry_point_group CLI-oriented helpers for multi-slice PDF generation. create_glass_brain_entry_point / create_glass_brain_entry_point_group CLI-oriented helpers for glass-brain PNG generation. create_html_entry_point CLI-oriented helper for interactive HTML surface reports.

See Also

tit.plotting.ti_metrics : TI-specific metric plots (histograms, scatter). tit.blender : Blender-based 3-D visualizations.

NilearnVisualizer

NilearnVisualizer(subject_id: str | None = None)

Main visualization class for electric field distributions.

Provides methods for creating both static PDF visualizations and interactive HTML plots. Uses PathManager for consistent path handling and supports multiple atlas overlays.

Parameters

subject_id : str or None, optional Subject identifier. When None, PathManager auto-detection is used instead.

Attributes

pm : PathManager Resolved path-manager instance. subject_id : str or None Subject identifier passed at construction time. output_dir : str Directory where visualizations are saved.

See Also

tit.plotting.nilearn.img_slices : Convenience entry-points for PDF creation. tit.plotting.nilearn.img_glass : Convenience entry-points for glass-brain PNGs. tit.plotting.nilearn.html_report : Convenience entry-point for HTML reports.

Create a new visualizer instance.

Parameters

subject_id : str or None, optional Subject identifier. When None, PathManager auto-detection is used instead.

Source code in tit/plotting/nilearn/visualizer.py
def __init__(self, subject_id: str | None = None):
    """Create a new visualizer instance.

    Parameters
    ----------
    subject_id : str or None, optional
        Subject identifier.  When *None*, PathManager auto-detection
        is used instead.
    """
    self.pm = get_path_manager()
    self.subject_id = subject_id
    self.output_dir = None

    # Set up output directory
    self._setup_output_directory()

create_pdf_visualization

create_pdf_visualization(subject_id: str, simulation_name: str, min_cutoff: float = 0.3, max_cutoff: float = None, atlas_name: str = 'harvard_oxford_sub', selected_regions: list[int] | None = None) -> str | None

Create a multi-slice PDF with atlas contours for a single subject.

Generates sagittal, coronal, and axial slice rows with the electric field overlaid as a hot colormap and optional atlas contour lines.

Parameters

subject_id : str Subject identifier (e.g. '070'). simulation_name : str Name of the simulation folder. min_cutoff : float, optional Lower display threshold in V/m. Default is 0.3. max_cutoff : float or None, optional Upper display threshold in V/m. When None the 99.9th percentile of non-zero voxels is used. atlas_name : str, optional Nilearn atlas key. One of 'harvard_oxford', 'harvard_oxford_sub', 'aal', 'schaefer_2018'. selected_regions : list of int or None, optional 0-indexed region indices to include in the atlas overlay. When None, all regions are shown.

Returns

str or None Path to the saved PDF, or None on failure.

Source code in tit/plotting/nilearn/visualizer.py
def create_pdf_visualization(
    self,
    subject_id: str,
    simulation_name: str,
    min_cutoff: float = 0.3,
    max_cutoff: float = None,
    atlas_name: str = "harvard_oxford_sub",
    selected_regions: list[int] | None = None,
) -> str | None:
    """Create a multi-slice PDF with atlas contours for a single subject.

    Generates sagittal, coronal, and axial slice rows with the electric
    field overlaid as a hot colormap and optional atlas contour lines.

    Parameters
    ----------
    subject_id : str
        Subject identifier (e.g. ``'070'``).
    simulation_name : str
        Name of the simulation folder.
    min_cutoff : float, optional
        Lower display threshold in V/m.  Default is ``0.3``.
    max_cutoff : float or None, optional
        Upper display threshold in V/m.  When *None* the 99.9th
        percentile of non-zero voxels is used.
    atlas_name : str, optional
        Nilearn atlas key.  One of ``'harvard_oxford'``,
        ``'harvard_oxford_sub'``, ``'aal'``, ``'schaefer_2018'``.
    selected_regions : list of int or None, optional
        0-indexed region indices to include in the atlas overlay.
        When *None*, all regions are shown.

    Returns
    -------
    str or None
        Path to the saved PDF, or *None* on failure.
    """
    print(f"=== Creating PDF Visualization for {subject_id}/{simulation_name} ===")

    # Get simulation files
    sim_files = self._get_simulation_files(subject_id)
    if simulation_name not in sim_files:
        print(
            f"Error: Simulation '{simulation_name}' not found for subject {subject_id}"
        )
        return None

    ef_filepath = sim_files[simulation_name]
    ef_img = self._load_electric_field_data(ef_filepath)
    if ef_img is None:
        return None

    # Load and analyze data
    data = ef_img.get_fdata()
    data_nonzero = data[data > 0]
    if len(data_nonzero) == 0:
        print("Warning: No non-zero field values found")
        return None

    max_value = np.max(data)
    percentile_999 = np.percentile(data_nonzero, 99.9)
    min_value = np.min(data_nonzero)

    # Use provided max_cutoff or default to 99.9th percentile
    if max_cutoff is None:
        max_cutoff = percentile_999

    print(f"Electric field statistics:")
    print(f"  Absolute maximum: {max_value:.2f} V/m")
    print(f"  99.9th percentile: {percentile_999:.2f} V/m")
    print(f"  Minimum (non-zero): {min_value:.2f} V/m")
    print(f"  Visualization range: {min_cutoff:.2f} - {max_cutoff:.2f} V/m")

    # Create output filename
    pdf_filename = f"{subject_id}_{simulation_name}_multiple_views.pdf"
    pdf_filepath = os.path.join(self.output_dir, pdf_filename)

    # Load atlas for contours
    atlas_img, atlas_display_name = self._load_atlas(atlas_name, selected_regions)

    # Create multi-slice plot with atlas contours
    self._create_multi_slice_plot_with_atlas(
        ef_img, atlas_img, atlas_display_name, pdf_filepath, min_cutoff, max_cutoff
    )

    print(f"✓ Saved: {pdf_filepath}")
    print(f"  Colorbar range: {min_cutoff:.2f} - {max_cutoff:.2f} V/m")

    return pdf_filepath

create_html_visualization

create_html_visualization(subject_id: str, simulation_name: str, min_cutoff: float = 0.3) -> str | None

Create an interactive HTML surface visualization.

Uses nilearn.plotting.view_img_on_surf to project the electric-field map onto the cortical surface and saves the result as a self-contained HTML file.

Parameters

subject_id : str Subject identifier. simulation_name : str Name of the simulation folder. min_cutoff : float, optional Lower display threshold in V/m. Default is 0.3.

Returns

str or None Path to the saved HTML file, or None on failure.

Source code in tit/plotting/nilearn/visualizer.py
def create_html_visualization(
    self, subject_id: str, simulation_name: str, min_cutoff: float = 0.3
) -> str | None:
    """Create an interactive HTML surface visualization.

    Uses ``nilearn.plotting.view_img_on_surf`` to project the
    electric-field map onto the cortical surface and saves the result
    as a self-contained HTML file.

    Parameters
    ----------
    subject_id : str
        Subject identifier.
    simulation_name : str
        Name of the simulation folder.
    min_cutoff : float, optional
        Lower display threshold in V/m.  Default is ``0.3``.

    Returns
    -------
    str or None
        Path to the saved HTML file, or *None* on failure.
    """
    print(f"=== Creating HTML Visualization for {subject_id}/{simulation_name} ===")

    # Get simulation files
    sim_files = self._get_simulation_files(subject_id)
    if simulation_name not in sim_files:
        print(
            f"Error: Simulation '{simulation_name}' not found for subject {subject_id}"
        )
        return None

    ef_filepath = sim_files[simulation_name]
    ef_img = self._load_electric_field_data(ef_filepath)
    if ef_img is None:
        return None

    # Analyze data for thresholds
    data = ef_img.get_fdata()
    data_nonzero = data[data > 0]
    if len(data_nonzero) == 0:
        print("Warning: No non-zero field values found")
        return None

    percentile_999 = np.percentile(data_nonzero, 99.9)

    # Create output filename
    html_filename = f"{subject_id}_{simulation_name}_interactive.html"
    html_filepath = os.path.join(self.output_dir, html_filename)

    # Create interactive visualization
    view = view_img_on_surf(
        stat_map=ef_img,
        threshold=min_cutoff,
        vmax=percentile_999,
        cmap="hot",
        symmetric_cmap=False,
        bg_on_data=True,
        title=f"Electric Field - {subject_id}/{simulation_name}",
    )

    # Save as HTML
    view.save_as_html(html_filepath)
    print(f"✓ Saved interactive HTML: {html_filepath}")

    return html_filepath

create_pdf_visualization_group

create_pdf_visualization_group(averaged_img, base_filename: str, output_dir: str, min_cutoff: float = 0.3, max_cutoff: float = None, atlas_name: str = 'harvard_oxford_sub', selected_regions: list[int] | None = None) -> str | None

Create a multi-slice PDF from a pre-averaged group NIfTI image.

Identical layout to :meth:create_pdf_visualization but accepts an already-averaged nibabel.Nifti1Image instead of looking up a per-subject simulation file.

Parameters

averaged_img : nibabel.Nifti1Image Pre-averaged electric-field image. base_filename : str Base filename for output (without extension). output_dir : str Directory where the PDF will be saved. min_cutoff : float, optional Lower display threshold in V/m. Default is 0.3. max_cutoff : float or None, optional Upper display threshold in V/m. When None the 99.9th percentile of non-zero voxels is used. atlas_name : str, optional Nilearn atlas key. selected_regions : list of int or None, optional 0-indexed region indices for the atlas overlay.

Returns

str or None Path to the saved PDF, or None on failure.

Source code in tit/plotting/nilearn/visualizer.py
def create_pdf_visualization_group(
    self,
    averaged_img,
    base_filename: str,
    output_dir: str,
    min_cutoff: float = 0.3,
    max_cutoff: float = None,
    atlas_name: str = "harvard_oxford_sub",
    selected_regions: list[int] | None = None,
) -> str | None:
    """Create a multi-slice PDF from a pre-averaged group NIfTI image.

    Identical layout to :meth:`create_pdf_visualization` but accepts
    an already-averaged ``nibabel.Nifti1Image`` instead of looking up
    a per-subject simulation file.

    Parameters
    ----------
    averaged_img : nibabel.Nifti1Image
        Pre-averaged electric-field image.
    base_filename : str
        Base filename for output (without extension).
    output_dir : str
        Directory where the PDF will be saved.
    min_cutoff : float, optional
        Lower display threshold in V/m.  Default is ``0.3``.
    max_cutoff : float or None, optional
        Upper display threshold in V/m.  When *None* the 99.9th
        percentile of non-zero voxels is used.
    atlas_name : str, optional
        Nilearn atlas key.
    selected_regions : list of int or None, optional
        0-indexed region indices for the atlas overlay.

    Returns
    -------
    str or None
        Path to the saved PDF, or *None* on failure.
    """
    print(f"=== Creating PDF Visualization for Group Averaged Data ===")

    # Load and analyze data
    data = averaged_img.get_fdata()
    data_nonzero = data[data > 0]
    if len(data_nonzero) == 0:
        print("Warning: No non-zero field values found")
        return None

    max_value = np.max(data)
    percentile_999 = np.percentile(data_nonzero, 99.9)
    min_value = np.min(data_nonzero)

    # Use provided max_cutoff or default to 99.9th percentile
    if max_cutoff is None:
        max_cutoff = percentile_999

    print(f"Electric field statistics (averaged data):")
    print(f"  Absolute maximum: {max_value:.2f} V/m")
    print(f"  99.9th percentile: {percentile_999:.2f} V/m")
    print(f"  Minimum (non-zero): {min_value:.2f} V/m")
    print(f"  Visualization range: {min_cutoff:.2f} - {max_cutoff:.2f} V/m")

    # Create output filename
    pdf_filename = f"{base_filename}_multiple_views.pdf"
    pdf_filepath = os.path.join(output_dir, pdf_filename)

    # Load atlas for contours
    atlas_img, atlas_display_name = self._load_atlas(atlas_name, selected_regions)

    # Create multi-slice plot with atlas contours
    self._create_multi_slice_plot_with_atlas(
        averaged_img,
        atlas_img,
        atlas_display_name,
        pdf_filepath,
        min_cutoff,
        max_cutoff,
    )

    print(f"✓ Saved: {pdf_filepath}")
    print(f"  Colorbar range: {min_cutoff:.2f} - {max_cutoff:.2f} V/m")

    return pdf_filepath

create_glass_brain_visualization

create_glass_brain_visualization(subject_id: str, simulation_name: str, min_cutoff: float = 0.3, max_cutoff: float = None, cmap: str = 'hot') -> str | None

Create a glass-brain PNG for a single subject simulation.

Uses nilearn.plotting.plot_glass_brain to render a maximum-intensity projection of the electric-field map.

Parameters

subject_id : str Subject identifier. simulation_name : str Name of the simulation folder. min_cutoff : float, optional Lower display threshold in V/m. Default is 0.3. max_cutoff : float or None, optional Upper display threshold in V/m. When None the 99.9th percentile of non-zero voxels is used. cmap : str, optional Matplotlib colormap name. Default is 'hot'.

Returns

str or None Path to the saved PNG file, or None on failure.

Source code in tit/plotting/nilearn/visualizer.py
def create_glass_brain_visualization(
    self,
    subject_id: str,
    simulation_name: str,
    min_cutoff: float = 0.3,
    max_cutoff: float = None,
    cmap: str = "hot",
) -> str | None:
    """Create a glass-brain PNG for a single subject simulation.

    Uses ``nilearn.plotting.plot_glass_brain`` to render a
    maximum-intensity projection of the electric-field map.

    Parameters
    ----------
    subject_id : str
        Subject identifier.
    simulation_name : str
        Name of the simulation folder.
    min_cutoff : float, optional
        Lower display threshold in V/m.  Default is ``0.3``.
    max_cutoff : float or None, optional
        Upper display threshold in V/m.  When *None* the 99.9th
        percentile of non-zero voxels is used.
    cmap : str, optional
        Matplotlib colormap name.  Default is ``'hot'``.

    Returns
    -------
    str or None
        Path to the saved PNG file, or *None* on failure.
    """
    print(
        f"=== Creating Glass Brain Visualization for {subject_id}/{simulation_name} ==="
    )

    # Get simulation files
    sim_files = self._get_simulation_files(subject_id)
    if simulation_name not in sim_files:
        print(
            f"Error: Simulation '{simulation_name}' not found for subject {subject_id}"
        )
        return None

    ef_filepath = sim_files[simulation_name]
    ef_img = self._load_electric_field_data(ef_filepath)
    if ef_img is None:
        return None

    # Load and analyze data
    data = ef_img.get_fdata()
    data_nonzero = data[data > 0]
    if len(data_nonzero) == 0:
        print("Warning: No non-zero field values found")
        return None

    max_value = np.max(data)
    percentile_999 = np.percentile(data_nonzero, 99.9)
    min_value = np.min(data_nonzero)

    # Use provided max_cutoff or default to 99.9th percentile
    if max_cutoff is None:
        max_cutoff = percentile_999

    print(f"Electric field statistics:")
    print(f"  Absolute maximum: {max_value:.2f} V/m")
    print(f"  99.9th percentile: {percentile_999:.2f} V/m")
    print(f"  Minimum (non-zero): {min_value:.2f} V/m")
    print(f"  Visualization range: {min_cutoff:.2f} - {max_cutoff:.2f} V/m")

    # Create output filename
    png_filename = f"{subject_id}_{simulation_name}_glass_brain.png"
    png_filepath = os.path.join(self.output_dir, png_filename)

    # Create glass brain visualization
    plotting.plot_glass_brain(
        stat_map_img=ef_img,
        threshold=min_cutoff,
        vmax=max_cutoff,
        cmap=cmap,
        colorbar=True,
        plot_abs=False,
        symmetric_cbar=False,
        title=f"Electric Field - {subject_id}/{simulation_name}\n{min_cutoff:.2f}-{max_cutoff:.2f} V/m",
        output_file=png_filepath,
    )

    print(f"✓ Saved glass brain visualization: {png_filepath}")

    return png_filepath

glass_brain_to_base64 staticmethod

glass_brain_to_base64(nifti_path: str, title: str = 'Electric Field', min_cutoff: float = 0.1, max_cutoff: float | None = None, cmap: str = 'hot') -> str | None

Render a glass-brain PNG and return it as a base64 string.

Intended for embedding in HTML reports via ImageReportlet.set_base64_data().

Parameters

nifti_path : str Path to a NIfTI file (e.g. TI_max volume). title : str, optional Title text rendered on the figure. min_cutoff : float, optional Lower display threshold in V/m. max_cutoff : float or None, optional Upper display threshold. Defaults to the 99.9th percentile. cmap : str, optional Matplotlib colormap name.

Returns

str or None Base64-encoded PNG string, or None on failure.

Source code in tit/plotting/nilearn/visualizer.py
@staticmethod
def glass_brain_to_base64(
    nifti_path: str,
    title: str = "Electric Field",
    min_cutoff: float = 0.1,
    max_cutoff: float | None = None,
    cmap: str = "hot",
) -> str | None:
    """Render a glass-brain PNG and return it as a base64 string.

    Intended for embedding in HTML reports via
    ``ImageReportlet.set_base64_data()``.

    Parameters
    ----------
    nifti_path : str
        Path to a NIfTI file (e.g. TI_max volume).
    title : str, optional
        Title text rendered on the figure.
    min_cutoff : float, optional
        Lower display threshold in V/m.
    max_cutoff : float or None, optional
        Upper display threshold.  Defaults to the 99.9th percentile.
    cmap : str, optional
        Matplotlib colormap name.

    Returns
    -------
    str or None
        Base64-encoded PNG string, or *None* on failure.
    """
    if not os.path.exists(nifti_path):
        return None

    img = nib.load(nifti_path)
    data = img.get_fdata()
    data_nonzero = data[data > 0]
    if len(data_nonzero) == 0:
        return None

    if max_cutoff is None:
        max_cutoff = float(np.percentile(data_nonzero, 99.9))

    fig = plt.figure(figsize=(10, 4), facecolor="white")
    display = plotting.plot_glass_brain(
        stat_map_img=img,
        threshold=min_cutoff,
        vmax=max_cutoff,
        cmap=cmap,
        colorbar=True,
        plot_abs=False,
        symmetric_cbar=False,
        title=f"{title}\n{min_cutoff:.2f}\u2013{max_cutoff:.2f} V/m",
        figure=fig,
    )

    buf = io.BytesIO()
    fig.savefig(buf, format="png", dpi=150, bbox_inches="tight")
    plt.close(fig)
    buf.seek(0)
    return base64.b64encode(buf.read()).decode("ascii")

multi_slice_to_base64 staticmethod

multi_slice_to_base64(nifti_path: str, title: str = 'Electric Field', min_cutoff: float = 0.1, max_cutoff: float | None = None) -> str | None

Render a multi-slice overview and return it as a base64 string.

Creates a compact 3-row (sagittal / coronal / axial) x 5-column slice grid suitable for embedding in HTML reports.

Parameters

nifti_path : str Path to a NIfTI file. title : str, optional Title text rendered on the figure. min_cutoff : float, optional Lower display threshold in V/m. max_cutoff : float or None, optional Upper display threshold. Defaults to the 99.9th percentile.

Returns

str or None Base64-encoded PNG string, or None on failure.

Source code in tit/plotting/nilearn/visualizer.py
@staticmethod
def multi_slice_to_base64(
    nifti_path: str,
    title: str = "Electric Field",
    min_cutoff: float = 0.1,
    max_cutoff: float | None = None,
) -> str | None:
    """Render a multi-slice overview and return it as a base64 string.

    Creates a compact 3-row (sagittal / coronal / axial) x 5-column
    slice grid suitable for embedding in HTML reports.

    Parameters
    ----------
    nifti_path : str
        Path to a NIfTI file.
    title : str, optional
        Title text rendered on the figure.
    min_cutoff : float, optional
        Lower display threshold in V/m.
    max_cutoff : float or None, optional
        Upper display threshold.  Defaults to the 99.9th percentile.

    Returns
    -------
    str or None
        Base64-encoded PNG string, or *None* on failure.
    """
    if not os.path.exists(nifti_path):
        return None

    img = nib.load(nifti_path)
    data = img.get_fdata()
    data_nonzero = data[data > 0]
    if len(data_nonzero) == 0:
        return None

    if max_cutoff is None:
        max_cutoff = float(np.percentile(data_nonzero, 99.9))

    field_thresholded = threshold_img(img, threshold=min_cutoff)

    fig, axes = plt.subplots(3, 5, figsize=(20, 10), facecolor="white")
    fig.patch.set_facecolor("white")

    sagittal_coords = [-40, -20, 0, 20, 40]
    coronal_coords = [-55, -20, 5, 30, 55]
    axial_coords = [-10, 10, 30, 50, 70]

    all_coords = [sagittal_coords, coronal_coords, axial_coords]
    view_names = ["Sagittal", "Coronal", "Axial"]
    coord_labels = ["x", "y", "z"]

    for row, (coords, view_name, coord_label) in enumerate(
        zip(all_coords, view_names, coord_labels)
    ):
        for col, cut_coord in enumerate(coords):
            ax = axes[row, col]
            plotting.plot_stat_map(
                field_thresholded,
                cut_coords=[cut_coord],
                display_mode=coord_label.lower(),
                axes=ax,
                annotate=True,
                black_bg=False,
                cmap="hot",
                vmin=min_cutoff,
                vmax=max_cutoff,
                colorbar=False,
            )
            if col == 0:
                ax.set_ylabel(
                    view_name,
                    fontsize=9,
                    fontweight="bold",
                    rotation=90,
                    labelpad=8,
                )

    import matplotlib.cm as cm
    import matplotlib.colors as mcolors

    norm = mcolors.Normalize(vmin=min_cutoff, vmax=max_cutoff)
    sm = cm.ScalarMappable(cmap="hot", norm=norm)
    sm.set_array([])

    cbar_ax = fig.add_axes([0.15, 0.03, 0.7, 0.02])
    cbar = fig.colorbar(
        sm,
        cax=cbar_ax,
        orientation="horizontal",
        label="Electric Field (V/m)",
    )
    cbar.set_ticks([min_cutoff, max_cutoff])
    cbar.set_ticklabels([f"{min_cutoff:.2f}", f"{max_cutoff:.2f}"])

    fig.suptitle(
        f"{title}  ({min_cutoff:.2f}\u2013{max_cutoff:.2f} V/m)",
        fontsize=12,
        fontweight="bold",
    )
    plt.tight_layout(rect=[0, 0.08, 1, 0.93])

    buf = io.BytesIO()
    fig.savefig(buf, format="png", dpi=150, bbox_inches="tight")
    plt.close(fig)
    buf.seek(0)
    return base64.b64encode(buf.read()).decode("ascii")

interactive_volume_to_html staticmethod

interactive_volume_to_html(nifti_path: str, title: str = 'Electric Field', min_cutoff: float = 0.1, max_cutoff: float | None = None, cmap: str = 'hot') -> str | None

Render an interactive volumetric stat-map viewer as HTML.

Uses nilearn.plotting.view_img to create an interactive slice-based viewer suitable for embedding in HTML reports.

Parameters

nifti_path : str Path to a NIfTI file. title : str, optional Title text for the viewer. min_cutoff : float, optional Lower display threshold in V/m. max_cutoff : float or None, optional Upper display threshold. Defaults to the 99.9th percentile. cmap : str, optional Matplotlib colormap name.

Returns

str or None HTML string for embedding, or None on failure.

Source code in tit/plotting/nilearn/visualizer.py
@staticmethod
def interactive_volume_to_html(
    nifti_path: str,
    title: str = "Electric Field",
    min_cutoff: float = 0.1,
    max_cutoff: float | None = None,
    cmap: str = "hot",
) -> str | None:
    """Render an interactive volumetric stat-map viewer as HTML.

    Uses ``nilearn.plotting.view_img`` to create an interactive
    slice-based viewer suitable for embedding in HTML reports.

    Parameters
    ----------
    nifti_path : str
        Path to a NIfTI file.
    title : str, optional
        Title text for the viewer.
    min_cutoff : float, optional
        Lower display threshold in V/m.
    max_cutoff : float or None, optional
        Upper display threshold.  Defaults to the 99.9th percentile.
    cmap : str, optional
        Matplotlib colormap name.

    Returns
    -------
    str or None
        HTML string for embedding, or *None* on failure.
    """
    if not os.path.exists(nifti_path):
        return None

    try:
        img = nib.load(nifti_path)
        data = img.get_fdata()
        data_nonzero = data[data > 0]
        if len(data_nonzero) == 0:
            return None

        if max_cutoff is None:
            max_cutoff = float(np.percentile(data_nonzero, 99.9))

        v = view_img(
            stat_map_img=img,
            threshold=min_cutoff,
            vmax=max_cutoff,
            cmap=cmap,
            symmetric_cmap=False,
            title=title,
        )
        return v._repr_html_()
    except Exception:
        return None

interactive_surface_to_html staticmethod

interactive_surface_to_html(nifti_path: str, title: str = 'Electric Field', min_cutoff: float = 0.1, max_cutoff: float | None = None, cmap: str = 'hot') -> str | None

Render an interactive 3-D surface projection as HTML.

Uses nilearn.plotting.view_img_on_surf to project the stat-map onto a cortical surface mesh suitable for embedding in HTML reports.

Parameters

nifti_path : str Path to a NIfTI file. title : str, optional Title text for the viewer. min_cutoff : float, optional Lower display threshold in V/m. max_cutoff : float or None, optional Upper display threshold. Defaults to the 99.9th percentile. cmap : str, optional Matplotlib colormap name.

Returns

str or None HTML string for embedding, or None on failure.

Source code in tit/plotting/nilearn/visualizer.py
@staticmethod
def interactive_surface_to_html(
    nifti_path: str,
    title: str = "Electric Field",
    min_cutoff: float = 0.1,
    max_cutoff: float | None = None,
    cmap: str = "hot",
) -> str | None:
    """Render an interactive 3-D surface projection as HTML.

    Uses ``nilearn.plotting.view_img_on_surf`` to project the
    stat-map onto a cortical surface mesh suitable for embedding
    in HTML reports.

    Parameters
    ----------
    nifti_path : str
        Path to a NIfTI file.
    title : str, optional
        Title text for the viewer.
    min_cutoff : float, optional
        Lower display threshold in V/m.
    max_cutoff : float or None, optional
        Upper display threshold.  Defaults to the 99.9th percentile.
    cmap : str, optional
        Matplotlib colormap name.

    Returns
    -------
    str or None
        HTML string for embedding, or *None* on failure.
    """
    if not os.path.exists(nifti_path):
        return None

    try:
        img = nib.load(nifti_path)
        data = img.get_fdata()
        data_nonzero = data[data > 0]
        if len(data_nonzero) == 0:
            return None

        if max_cutoff is None:
            max_cutoff = float(np.percentile(data_nonzero, 99.9))

        v = view_img_on_surf(
            stat_map=img,
            threshold=min_cutoff,
            vmax=max_cutoff,
            cmap=cmap,
            symmetric_cmap=False,
            title=title,
        )
        return v._repr_html_()
    except Exception:
        return None

create_pdf_entry_point

create_pdf_entry_point(subject_id: str, simulation_name: str, min_cutoff: float = 0.3, max_cutoff: float = None, atlas_name: str = 'harvard_oxford_sub', selected_regions: list = None, output_callback=None)

Entry point for PDF visualization creation.

Parameters:

Name Type Description Default
subject_id str

Subject ID

required
simulation_name str

Simulation name

required
min_cutoff float

Minimum cutoff for visualization (V/m)

0.3
max_cutoff float

Maximum cutoff for visualization (V/m), if None uses 99.9th percentile

None
atlas_name str

Atlas name for contours

'harvard_oxford_sub'
selected_regions list

List of region indices to include (0-indexed), if None includes all

None
output_callback

Optional callback function for output (for GUI integration)

None
Source code in tit/plotting/nilearn/img_slices.py
def create_pdf_entry_point(
    subject_id: str,
    simulation_name: str,
    min_cutoff: float = 0.3,
    max_cutoff: float = None,
    atlas_name: str = "harvard_oxford_sub",
    selected_regions: list = None,
    output_callback=None,
):
    """
    Entry point for PDF visualization creation.

    Args:
        subject_id: Subject ID
        simulation_name: Simulation name
        min_cutoff: Minimum cutoff for visualization (V/m)
        max_cutoff: Maximum cutoff for visualization (V/m), if None uses 99.9th percentile
        atlas_name: Atlas name for contours
        selected_regions: List of region indices to include (0-indexed), if None includes all
        output_callback: Optional callback function for output (for GUI integration)
    """
    # Redirect stdout if callback provided (for GUI integration)
    import sys
    from contextlib import redirect_stdout
    import io

    if output_callback:
        # Capture stdout and send to callback
        captured_output = io.StringIO()
        with redirect_stdout(captured_output):
            visualizer = NilearnVisualizer()
            result = visualizer.create_pdf_visualization(
                subject_id,
                simulation_name,
                min_cutoff,
                max_cutoff,
                atlas_name,
                selected_regions,
            )

        # Send captured output to callback line by line
        output_text = captured_output.getvalue()
        for line in output_text.split("\n"):
            if line.strip():
                output_callback(line)

        if result:
            output_callback(f"✓ PDF visualization completed: {result}")
            return result
        else:
            output_callback("✗ PDF visualization failed")
            return None
    else:
        # Normal operation - print to stdout
        visualizer = NilearnVisualizer()
        result = visualizer.create_pdf_visualization(
            subject_id,
            simulation_name,
            min_cutoff,
            max_cutoff,
            atlas_name,
            selected_regions,
        )
        if result:
            print(f"\n✓ PDF visualization completed: {result}")
            return result
        else:
            print("\n✗ PDF visualization failed")
            return None

create_pdf_entry_point_group

create_pdf_entry_point_group(averaged_img, base_filename: str, output_dir: str, min_cutoff: float = 0.3, max_cutoff: float = None, atlas_name: str = 'harvard_oxford_sub', selected_regions: list = None, output_callback=None)

Entry point for PDF visualization creation with pre-averaged nifti data.

Parameters:

Name Type Description Default
averaged_img

Pre-averaged nibabel Nifti1Image

required
base_filename str

Base filename for output (without extension)

required
output_dir str

Output directory path

required
min_cutoff float

Minimum cutoff for visualization (V/m)

0.3
max_cutoff float

Maximum cutoff for visualization (V/m), if None uses 99.9th percentile

None
atlas_name str

Atlas name for contours

'harvard_oxford_sub'
selected_regions list

List of region indices to include (0-indexed), if None includes all

None
output_callback

Optional callback function for output (for GUI integration)

None
Source code in tit/plotting/nilearn/img_slices.py
def create_pdf_entry_point_group(
    averaged_img,
    base_filename: str,
    output_dir: str,
    min_cutoff: float = 0.3,
    max_cutoff: float = None,
    atlas_name: str = "harvard_oxford_sub",
    selected_regions: list = None,
    output_callback=None,
):
    """
    Entry point for PDF visualization creation with pre-averaged nifti data.

    Args:
        averaged_img: Pre-averaged nibabel Nifti1Image
        base_filename: Base filename for output (without extension)
        output_dir: Output directory path
        min_cutoff: Minimum cutoff for visualization (V/m)
        max_cutoff: Maximum cutoff for visualization (V/m), if None uses 99.9th percentile
        atlas_name: Atlas name for contours
        selected_regions: List of region indices to include (0-indexed), if None includes all
        output_callback: Optional callback function for output (for GUI integration)
    """
    # Redirect stdout if callback provided (for GUI integration)
    import sys
    from contextlib import redirect_stdout
    import io

    if output_callback:
        # Capture stdout and send to callback
        captured_output = io.StringIO()
        with redirect_stdout(captured_output):
            visualizer = NilearnVisualizer()
            result = visualizer.create_pdf_visualization_group(
                averaged_img,
                base_filename,
                output_dir,
                min_cutoff,
                max_cutoff,
                atlas_name,
                selected_regions,
            )

        # Send captured output to callback line by line
        output_text = captured_output.getvalue()
        for line in output_text.split("\n"):
            if line.strip():
                output_callback(line)

        if result:
            output_callback(f"✓ PDF visualization completed: {result}")
            return result
        else:
            output_callback("✗ PDF visualization failed")
            return None
    else:
        # Normal operation - print to stdout
        visualizer = NilearnVisualizer()
        result = visualizer.create_pdf_visualization_group(
            averaged_img,
            base_filename,
            output_dir,
            min_cutoff,
            max_cutoff,
            atlas_name,
            selected_regions,
        )
        if result:
            print(f"\n✓ PDF visualization completed: {result}")
            return result
        else:
            print("\n✗ PDF visualization failed")
            return None

create_glass_brain_entry_point

create_glass_brain_entry_point(subject_id: str, simulation_name: str, min_cutoff: float = 0.3, max_cutoff: float = None, cmap: str = 'hot', output_callback=None)

Entry point for glass brain visualization creation.

Parameters:

Name Type Description Default
subject_id str

Subject ID

required
simulation_name str

Simulation name

required
min_cutoff float

Minimum cutoff for visualization (V/m)

0.3
max_cutoff float

Maximum cutoff for visualization (V/m), if None uses 99.9th percentile

None
cmap str

Colormap name for visualization

'hot'
output_callback

Optional callback function for output (for GUI integration)

None
Source code in tit/plotting/nilearn/img_glass.py
def create_glass_brain_entry_point(
    subject_id: str,
    simulation_name: str,
    min_cutoff: float = 0.3,
    max_cutoff: float = None,
    cmap: str = "hot",
    output_callback=None,
):
    """
    Entry point for glass brain visualization creation.

    Args:
        subject_id: Subject ID
        simulation_name: Simulation name
        min_cutoff: Minimum cutoff for visualization (V/m)
        max_cutoff: Maximum cutoff for visualization (V/m), if None uses 99.9th percentile
        cmap: Colormap name for visualization
        output_callback: Optional callback function for output (for GUI integration)
    """
    # Redirect stdout if callback provided (for GUI integration)
    import sys
    from contextlib import redirect_stdout
    import io

    if output_callback:
        # Capture stdout and send to callback
        captured_output = io.StringIO()
        with redirect_stdout(captured_output):
            visualizer = NilearnVisualizer()
            result = visualizer.create_glass_brain_visualization(
                subject_id, simulation_name, min_cutoff, max_cutoff, cmap
            )

        # Send captured output to callback line by line
        output_text = captured_output.getvalue()
        for line in output_text.split("\n"):
            if line.strip():
                output_callback(line)

        if result:
            output_callback(f"✓ Glass brain visualization completed: {result}")
            return result
        else:
            output_callback("✗ Glass brain visualization failed")
            return None
    else:
        # Normal operation - print to stdout
        visualizer = NilearnVisualizer()
        result = visualizer.create_glass_brain_visualization(
            subject_id, simulation_name, min_cutoff, max_cutoff, cmap
        )
        if result:
            print(f"\n✓ Glass brain visualization completed: {result}")
            return result
        else:
            print("\n✗ Glass brain visualization failed")
            return None

create_glass_brain_entry_point_group

create_glass_brain_entry_point_group(averaged_img, base_filename: str, output_dir: str, min_cutoff: float = 0.3, max_cutoff: float = None, cmap: str = 'hot', output_callback=None)

Entry point for glass brain visualization creation with pre-averaged nifti data.

Parameters:

Name Type Description Default
averaged_img

Pre-averaged nibabel Nifti1Image

required
base_filename str

Base filename for output (without extension)

required
output_dir str

Output directory path

required
min_cutoff float

Minimum cutoff for visualization (V/m)

0.3
max_cutoff float

Maximum cutoff for visualization (V/m), if None uses 99.9th percentile

None
cmap str

Colormap name for visualization

'hot'
output_callback

Optional callback function for output (for GUI integration)

None
Source code in tit/plotting/nilearn/img_glass.py
def create_glass_brain_entry_point_group(
    averaged_img,
    base_filename: str,
    output_dir: str,
    min_cutoff: float = 0.3,
    max_cutoff: float = None,
    cmap: str = "hot",
    output_callback=None,
):
    """
    Entry point for glass brain visualization creation with pre-averaged nifti data.

    Args:
        averaged_img: Pre-averaged nibabel Nifti1Image
        base_filename: Base filename for output (without extension)
        output_dir: Output directory path
        min_cutoff: Minimum cutoff for visualization (V/m)
        max_cutoff: Maximum cutoff for visualization (V/m), if None uses 99.9th percentile
        cmap: Colormap name for visualization
        output_callback: Optional callback function for output (for GUI integration)
    """
    # Redirect stdout if callback provided (for GUI integration)
    import sys
    from contextlib import redirect_stdout
    import io
    import os
    import numpy as np
    import matplotlib.pyplot as plt
    from nilearn import plotting

    if output_callback:
        # Capture stdout and send to callback
        captured_output = io.StringIO()
        with redirect_stdout(captured_output):
            # Load and analyze data
            data = averaged_img.get_fdata()
            data_nonzero = data[data > 0]
            if len(data_nonzero) == 0:
                print("Warning: No non-zero field values found")
                return None

            max_value = np.max(data)
            percentile_999 = np.percentile(data_nonzero, 99.9)
            min_value = np.min(data_nonzero)

            # Use provided max_cutoff or default to 99.9th percentile
            if max_cutoff is None:
                max_cutoff = percentile_999

            print(f"Electric field statistics (averaged data):")
            print(f"  Absolute maximum: {max_value:.2f} V/m")
            print(f"  99.9th percentile: {percentile_999:.2f} V/m")
            print(f"  Minimum (non-zero): {min_value:.2f} V/m")
            print(f"  Visualization range: {min_cutoff:.2f} - {max_cutoff:.2f} V/m")

            # Create output filename
            pdf_filename = f"{base_filename}_glass_brain.pdf"
            pdf_filepath = os.path.join(output_dir, pdf_filename)

            # Create glass brain visualization
            plotting.plot_glass_brain(
                stat_map_img=averaged_img,
                threshold=min_cutoff,
                vmax=max_cutoff,
                cmap=cmap,
                colorbar=True,
                plot_abs=False,
                symmetric_cbar=False,
                display_mode="lyrz",
                title=f"Electric Field - Group Average\n{min_cutoff:.2f}-{max_cutoff:.2f} V/m",
                output_file=pdf_filepath,
            )

            print(f"✓ Saved glass brain visualization: {pdf_filepath}")
            result = pdf_filepath

        # Send captured output to callback line by line
        output_text = captured_output.getvalue()
        for line in output_text.split("\n"):
            if line.strip():
                output_callback(line)

        if result:
            output_callback(f"✓ Glass brain visualization completed: {result}")
            return result
        else:
            output_callback("✗ Glass brain visualization failed")
            return None
    else:
        # Normal operation - print to stdout
        # Load and analyze data
        data = averaged_img.get_fdata()
        data_nonzero = data[data > 0]
        if len(data_nonzero) == 0:
            print("Warning: No non-zero field values found")
            return None

        max_value = np.max(data)
        percentile_999 = np.percentile(data_nonzero, 99.9)
        min_value = np.min(data_nonzero)

        # Use provided max_cutoff or default to 99.9th percentile
        if max_cutoff is None:
            max_cutoff = percentile_999

        print(f"Electric field statistics (averaged data):")
        print(f"  Absolute maximum: {max_value:.2f} V/m")
        print(f"  99.9th percentile: {percentile_999:.2f} V/m")
        print(f"  Minimum (non-zero): {min_value:.2f} V/m")
        print(f"  Visualization range: {min_cutoff:.2f} - {max_cutoff:.2f} V/m")

        # Create output filename
        pdf_filename = f"{base_filename}_glass_brain.pdf"
        pdf_filepath = os.path.join(output_dir, pdf_filename)

        # Create glass brain visualization
        plotting.plot_glass_brain(
            stat_map_img=averaged_img,
            threshold=min_cutoff,
            vmax=max_cutoff,
            cmap=cmap,
            colorbar=True,
            plot_abs=False,
            symmetric_cbar=False,
            display_mode="lyrz",
            title=f"Electric Field - Group Average\n{min_cutoff:.2f}-{max_cutoff:.2f} V/m",
            output_file=pdf_filepath,
        )

        print(f"✓ Saved glass brain visualization: {pdf_filepath}")
        result = pdf_filepath

        if result:
            print(f"\n✓ Glass brain visualization completed: {result}")
            return result
        else:
            print("\n✗ Glass brain visualization failed")
            return None

create_html_entry_point

create_html_entry_point(subject_id: str, simulation_name: str, min_cutoff: float = 0.3)

Entry point for HTML visualization creation.

Parameters:

Name Type Description Default
subject_id str

Subject ID

required
simulation_name str

Simulation name

required
min_cutoff float

Minimum cutoff for visualization (V/m)

0.3
Source code in tit/plotting/nilearn/html_report.py
def create_html_entry_point(
    subject_id: str, simulation_name: str, min_cutoff: float = 0.3
):
    """
    Entry point for HTML visualization creation.

    Args:
        subject_id: Subject ID
        simulation_name: Simulation name
        min_cutoff: Minimum cutoff for visualization (V/m)
    """
    visualizer = NilearnVisualizer()
    result = visualizer.create_html_visualization(
        subject_id, simulation_name, min_cutoff
    )
    if result:
        print(f"\n✓ HTML visualization completed: {result}")
        return 0
    else:
        print("\n✗ HTML visualization failed")
        return 1