Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

ENH: Add raincloud plot capabilities #118

Merged
merged 1 commit into from
Jul 2, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 6 additions & 1 deletion nireports/interfaces/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -24,11 +24,16 @@

from nireports.interfaces.fmri import FMRISummary
from nireports.interfaces.mosaic import PlotContours, PlotMosaic, PlotSpikes
from nireports.interfaces.nuisance import CompCorVariancePlot, ConfoundsCorrelationPlot
from nireports.interfaces.nuisance import (
CompCorVariancePlot,
ConfoundsCorrelationPlot,
RaincloudPlot,
)

__all__ = (
"CompCorVariancePlot",
"ConfoundsCorrelationPlot",
"RaincloudPlot",
"FMRISummary",
"PlotContours",
"PlotMosaic",
Expand Down
108 changes: 107 additions & 1 deletion nireports/interfaces/nuisance.py
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,7 @@
)
from nipype.utils.filemanip import fname_presuffix

from nireports.reportlets.nuisance import confounds_correlation_plot
from nireports.reportlets.nuisance import confounds_correlation_plot, plot_raincloud
from nireports.reportlets.xca import compcor_variance_plot


Expand Down Expand Up @@ -142,3 +142,109 @@
ignore_initial_volumes=self.inputs.ignore_initial_volumes,
)
return runtime


class _RaincloudPlotInputSpec(BaseInterfaceInputSpec):
data_file = File(exists=True, mandatory=True, desc="File containing the data")
out_file = traits.Either(None, File, value=None, usedefault=True, desc="Path to save plot")
group_name = traits.Str(
"group_name",
mandatory=True,
desc="Group name of interest",
)
feature = traits.Str(
"feature",
mandatory=True,
desc="Feature of interest",
)
palette = traits.Str(
"Set2",
usedefault=True,
desc="Color palette name",
)
orient = traits.Str(
"v",
usedefault=True,
desc="Orientation",
)
density = traits.Bool(
True,
usedefault=True,
desc="``True`` to plot the density",
)
upper_limit_value = traits.Float(
None,
usedefault=True,
desc="Upper limit value over which any value in the data will be styled "
"with a different style",
)
upper_limit_color = traits.Str(
"gray",
usedefault=True,
desc="Lower limit value under which any value in the data will be styled "
"with a different style",
)
lower_limit_value = traits.Float(
None,
usedefault=True,
desc="",
)
lower_limit_color = traits.Str(
"gray",
usedefault=True,
desc="Color name to represent values under ``lower_limit_value``",
)
limit_offset = traits.Float(
None,
usedefault=True,
desc="Offset to plot the values over/under the upper/lower limit values",
)
mark_nans = traits.Bool(
True,
usedefault=True,
desc="``True`` to plot NaNs as dots. ``nans_values`` must be provided if True",
)
nans_value = traits.Float(
None,
usedefault=True,
desc="Value to use for NaN values`",
)
nans_color = traits.Str(
"black",
usedefault=True,
desc="Color name to represent NaN values",
)


class _RaincloudPlotOutputSpec(TraitedSpec):
out_file = File(exists=True, desc="Path to saved plot")


class RaincloudPlot(SimpleInterface):
"""Plot a raincloud of values."""

input_spec = _RaincloudPlotInputSpec
output_spec = _RaincloudPlotOutputSpec

def _run_interface(self, runtime, **kwargs):
if self.inputs.out_file is None:
self._results["out_file"] = fname_presuffix(
self.inputs.data_file,
suffix="_raincloud.svg",
use_ext=False,
newpath=runtime.cwd,
)
else:
self._results["out_file"] = self.inputs.out_file

Check warning on line 238 in nireports/interfaces/nuisance.py

View check run for this annotation

Codecov / codecov/patch

nireports/interfaces/nuisance.py#L238

Added line #L238 was not covered by tests
plot_raincloud(
data_file=self.inputs.data_file,
group_name=self.inputs.group_name,
feature=self.inputs.feature,
palette=self.inputs.palette,
orient=self.inputs.orient,
density=self.inputs.density,
mark_nans=self.inputs.mark_nans,
output_file=self._results["out_file"],
**kwargs,
)
return runtime
28 changes: 28 additions & 0 deletions nireports/reportlets/modality/dwi.py
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,8 @@
from mpl_toolkits.mplot3d import art3d
from nilearn.plotting import plot_anat

from nireports.reportlets.nuisance import plot_raincloud


def plot_dwi(dataobj, affine, gradient=None, **kwargs):
"""
Expand Down Expand Up @@ -405,3 +407,29 @@ def plot_gradients(
plt.suptitle(title)

return ax


def plot_tissue_values(data_file, group_name, feature, **kwargs):
"""Generate a raincloud plot with the data points corresponding to the
``feature`` value contained in the data file.

Parameters
----------
data_file : :obj:`str`
File containing the data of interest.
group_name : :obj:`str`
The group name of interest to be plot.
feature : :obj:`str`
The feature of interest to be plot.
kwargs : :obj:`dict`
Extra args given to :func:~`nireports.reportlets.nuisance.plot_raincloud`.

Returns
-------
axes and gridspec
Plotting axes and gridspec. Returned only if ``output_file`` is ``None``.
output_file : :obj:`str`
The file where the figure is saved.
"""

return plot_raincloud(data_file, group_name, feature, **kwargs)
Loading
Loading