Skip to content

visualizer

tit.plotting.nilearn.visualizer

TI-Toolbox Visualization Module Provides comprehensive visualization tools for electric field distributions from TES simulations.

Features: 1. Multiple surface views (lateral, medial, left/right hemispheres) saved as high-res PDF 2. Interactive 3D visualization saved as HTML using plotly 3. Atlas contour overlays for anatomical context 4. Support for both subject-specific and MNI space visualizations

Based on: https://nilearn.github.io/dev/auto_examples/01_plotting/plot_3d_map_to_surface_projection.html

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