Source code for nireports.interfaces.mosaic

# emacs: -*- mode: python; py-indent-offset: 4; indent-tabs-mode: nil -*-
# vi: set ft=python sts=4 ts=4 sw=4 et:
#
# Copyright 2023 The NiPreps Developers <nipreps@gmail.com>
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
#     http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
#
# We support and encourage derived works from this project, please read
# about our expectations at
#
#     https://www.nipreps.org/community/licensing/
#
# STATEMENT OF CHANGES: This file was ported carrying over full git history from MRIQC,
# another NiPreps project licensed under the Apache-2.0 terms, and has been changed since.
# The original file this work derives from is found at:
# https://github.com/nipreps/mriqc/blob/1ffd4c8d1a20b44ebfea648a7b12bb32a425d4ec/
# mriqc/interfaces/viz.py
"""Visualization of n-D images with mosaics cutting through planes."""

from pathlib import Path

import numpy as np
from nipype.interfaces.base import (
    BaseInterfaceInputSpec,
    File,
    SimpleInterface,
    TraitedSpec,
    isdefined,
    traits,
)

from nireports.interfaces.base import _PlotBaseInputSpec
from nireports.reportlets.mosaic import plot_mosaic, plot_segmentation, plot_spikes


class _PlotContoursInputSpec(BaseInterfaceInputSpec):
    in_file = File(exists=True, mandatory=True, desc="File to be plotted")
    in_contours = File(exists=True, mandatory=True, desc="file to pick the contours from")
    cut_coords = traits.Int(8, usedefault=True, desc="number of slices")
    levels = traits.List([0.5], traits.Float, usedefault=True, desc="add a contour per level")
    colors = traits.List(
        ["r"],
        traits.Str,
        usedefault=True,
        desc="colors to be used for contours",
    )
    display_mode = traits.Enum(
        "ortho",
        "x",
        "y",
        "z",
        "yx",
        "xz",
        "yz",
        usedefault=True,
        desc="visualization mode",
    )
    saturate = traits.Bool(False, usedefault=True, desc="saturate background")
    out_file = traits.File(exists=False, desc="output file name")
    vmin = traits.Float(desc="minimum intensity")
    vmax = traits.Float(desc="maximum intensity")


class _PlotContoursOutputSpec(TraitedSpec):
    out_file = File(exists=True, desc="output svg file")


[docs] class PlotContours(SimpleInterface): """Plot contours""" input_spec = _PlotContoursInputSpec output_spec = _PlotContoursOutputSpec def _run_interface(self, runtime): in_file_ref = Path(self.inputs.in_file) if isdefined(self.inputs.out_file): in_file_ref = Path(self.inputs.out_file) fname = in_file_ref.name.rstrip("".join(in_file_ref.suffixes)) out_file = (Path(runtime.cwd) / (f"plot_{fname}_contours.svg")).resolve() self._results["out_file"] = str(out_file) vmax = None if not isdefined(self.inputs.vmax) else self.inputs.vmax vmin = None if not isdefined(self.inputs.vmin) else self.inputs.vmin plot_segmentation( self.inputs.in_file, self.inputs.in_contours, out_file=str(out_file), cut_coords=self.inputs.cut_coords, display_mode=self.inputs.display_mode, levels=self.inputs.levels, colors=self.inputs.colors, saturate=self.inputs.saturate, vmin=vmin, vmax=vmax, ) return runtime
class _PlotMosaicInputSpec(_PlotBaseInputSpec): bbox_mask_file = File(exists=True, desc="brain mask") only_noise = traits.Bool(False, usedefault=True, desc="plot only noise") view = traits.List( traits.Enum("axial", "sagittal", "coronal"), value=["axial", "sagittal"], minlen=1, maxlen=3, help="Sequence of views to plot (up to three)", usedefault=True, ) class _PlotMosaicOutputSpec(TraitedSpec): out_file = File(exists=True, desc="output pdf file")
[docs] class PlotMosaic(SimpleInterface): """ Plots slices of a 3D volume into a pdf file """ input_spec = _PlotMosaicInputSpec output_spec = _PlotMosaicOutputSpec def _run_interface(self, runtime): mask = self.inputs.bbox_mask_file if isdefined(self.inputs.bbox_mask_file) else None title = self.inputs.title if isdefined(self.inputs.title) else None plot_mosaic( self.inputs.in_file, out_file=self.inputs.out_file, title=title, only_plot_noise=self.inputs.only_noise, bbox_mask_file=mask, cmap=self.inputs.cmap, annotate=self.inputs.annotate, views=self.inputs.view, ) self._results["out_file"] = str((Path(runtime.cwd) / self.inputs.out_file).resolve()) return runtime
class _PlotSpikesInputSpec(_PlotBaseInputSpec): in_spikes = File(exists=True, mandatory=True, desc="tsv file of spikes") in_fft = File(exists=True, mandatory=True, desc="nifti file with the 4D FFT") class _PlotSpikesOutputSpec(TraitedSpec): out_file = File(exists=True, desc="output svg file")
[docs] class PlotSpikes(SimpleInterface): """Plot slices of a dataset with spikes.""" input_spec = _PlotSpikesInputSpec output_spec = _PlotSpikesOutputSpec def _run_interface(self, runtime): out_file = str((Path(runtime.cwd) / self.inputs.out_file).resolve()) self._results["out_file"] = out_file spikes_list = np.loadtxt(self.inputs.in_spikes, dtype=int).tolist() # No spikes if not spikes_list: Path(out_file).write_text("<p>No high-frequency spikes were found in this dataset</p>") return runtime spikes_list = [tuple(i) for i in np.atleast_2d(spikes_list).tolist()] plot_spikes( self.inputs.in_file, self.inputs.in_fft, spikes_list, out_file=out_file, ) return runtime