Skip to content

montage_visualizer

tit.tools.montage_visualizer

Render PNG visualizations of electrode montage placements.

Overlays coloured rings and arc connections on a template EEG cap image using ImageMagick convert. Called automatically by the simulation pipeline to document the active montage.

Public API

visualize_montage Render a PNG for a single montage or a combined multi-montage image.

See Also

tit.tools.map_electrodes : Map optimised positions to net labels. tit.sim : Simulation pipeline that invokes the visualiser.

get_expected_output_filename

get_expected_output_filename(montage_name: str, sim_mode: str = 'U') -> str

Return the expected montage visualization PNG filename.

Source code in tit/tools/montage_visualizer.py
def get_expected_output_filename(montage_name: str, sim_mode: str = "U") -> str:
    """Return the expected montage visualization PNG filename."""
    if sim_mode == "U":
        return f"{montage_name}_highlighted_visualization.png"
    return "combined_montage_visualization.png"

is_skipped_net

is_skipped_net(eeg_net: str) -> bool

Return True when montage visualization is intentionally skipped.

Source code in tit/tools/montage_visualizer.py
def is_skipped_net(eeg_net: str) -> bool:
    """Return True when montage visualization is intentionally skipped."""
    return eeg_net in _SKIP_NETS

is_supported_net

is_supported_net(eeg_net: str) -> bool

Return True when a coordinate map exists for eeg_net.

Source code in tit/tools/montage_visualizer.py
def is_supported_net(eeg_net: str) -> bool:
    """Return True when a coordinate map exists for *eeg_net*."""
    return eeg_net in _COORD_FILES

visualize_montage

visualize_montage(montage_name: str, electrode_pairs: list[list[str]], eeg_net: str, output_dir: str, sim_mode: str = 'U', logger=None) -> None

Render a PNG showing electrode positions and connection arcs.

Parameters

montage_name : str Used as the output filename base (unipolar) or "combined" (multipolar). electrode_pairs : list of list of str Electrode pairs, e.g. [["E030", "E020"], ["E095", "E070"]]. eeg_net : str EEG cap name, e.g. "GSN-HydroCel-185.csv". output_dir : str Directory to write the output PNG(s) into. sim_mode : str, optional "U" produces one image per montage; "M" produces a single combined image. Default "U".

Source code in tit/tools/montage_visualizer.py
def visualize_montage(
    montage_name: str,
    electrode_pairs: list[list[str]],
    eeg_net: str,
    output_dir: str,
    sim_mode: str = "U",
    logger=None,
) -> None:
    """Render a PNG showing electrode positions and connection arcs.

    Parameters
    ----------
    montage_name : str
        Used as the output filename base (unipolar) or ``"combined"``
        (multipolar).
    electrode_pairs : list of list of str
        Electrode pairs, e.g.
        ``[["E030", "E020"], ["E095", "E070"]]``.
    eeg_net : str
        EEG cap name, e.g. ``"GSN-HydroCel-185.csv"``.
    output_dir : str
        Directory to write the output PNG(s) into.
    sim_mode : str, optional
        ``"U"`` produces one image per montage; ``"M"`` produces a
        single combined image.  Default ``"U"``.
    """
    if is_skipped_net(eeg_net):
        expected = get_expected_output_filename(montage_name, sim_mode)
        if logger is not None:
            logger.warning(
                "Montage visualization unavailable for EEG net '%s'; "
                "skipping render. Expected output would be %s in %s.",
                eeg_net,
                expected,
                output_dir,
            )
        return

    coords = _load_coordinates(eeg_net)

    template = os.path.join(_RESOURCES_DIR, "GSN-256.png")
    os.makedirs(output_dir, exist_ok=True)

    if sim_mode == "U":
        out_image = os.path.join(
            output_dir, get_expected_output_filename(montage_name, sim_mode)
        )
        subprocess.run(["cp", template, out_image], check=True)
    else:
        out_image = os.path.join(
            output_dir, get_expected_output_filename(montage_name, sim_mode)
        )
        if not os.path.exists(out_image):
            subprocess.run(["cp", template, out_image], check=True)

    for i, pair in enumerate(electrode_pairs):
        e1, e2 = pair
        color = _COLORS[i % len(_COLORS)]
        ring = os.path.join(_RESOURCES_DIR, _RINGS[i % len(_RINGS)])
        if e1 in coords:
            _overlay_ring(out_image, *coords[e1], color, ring)
        if e2 in coords:
            _overlay_ring(out_image, *coords[e2], color, ring)
        if e1 in coords and e2 in coords:
            _draw_arc(out_image, *coords[e1], *coords[e2], color)