From 1e125219e4a5ca7e7d1cc2be95a79ed1a634abef Mon Sep 17 00:00:00 2001 From: Oscar Esteban Date: Sun, 25 Aug 2024 17:21:26 +0200 Subject: [PATCH 1/3] fix: remove all axes before fMRIPlot --- nireports/reportlets/modality/func.py | 15 ++++++++++++++- 1 file changed, 14 insertions(+), 1 deletion(-) diff --git a/nireports/reportlets/modality/func.py b/nireports/reportlets/modality/func.py index c7fad66..350769c 100644 --- a/nireports/reportlets/modality/func.py +++ b/nireports/reportlets/modality/func.py @@ -92,7 +92,7 @@ def __init__( def plot(self, figure=None, out_file=None, fontsize=24): """Main plotter""" - plt.rcParams.update({"font.size": 22}) + plt.rcParams.update({"font.size": fontsize}) nconfounds = len(self.confounds) nspikes = len(self.spikes) @@ -114,6 +114,19 @@ def plot(self, figure=None, out_file=None, fontsize=24): height_ratios=height_ratios, ) + # Remove axes visualization for the whole grid + for ax in grid.subplots(): + ax.spines[:].set_visible(False) + ax.spines[:].set_color("none") + ax.get_xaxis().set_visible(False) + ax.get_yaxis().set_visible(False) + + for ax in figure.axes: + ax.spines[:].set_visible(False) + ax.spines[:].set_color("none") + ax.get_xaxis().set_visible(False) + ax.get_yaxis().set_visible(False) + grid_id = 0 for tsz, name, iszs in self.spikes: spikesplot(tsz, title=name, outer_gs=grid[grid_id], tr=self.tr, zscored=iszs) From 64b9dcb9760df30bfe46ab5c9fee22087d9d54c9 Mon Sep 17 00:00:00 2001 From: Oscar Esteban Date: Mon, 26 Aug 2024 00:08:00 +0200 Subject: [PATCH 2/3] enh: move axis cleaning to ``plot_carpet()`` --- nireports/reportlets/modality/func.py | 13 -------- nireports/reportlets/nuisance.py | 17 +++++++---- nireports/tests/test_interfaces.py | 43 +++++++++++++++++++++++++++ 3 files changed, 54 insertions(+), 19 deletions(-) diff --git a/nireports/reportlets/modality/func.py b/nireports/reportlets/modality/func.py index 350769c..385d903 100644 --- a/nireports/reportlets/modality/func.py +++ b/nireports/reportlets/modality/func.py @@ -114,19 +114,6 @@ def plot(self, figure=None, out_file=None, fontsize=24): height_ratios=height_ratios, ) - # Remove axes visualization for the whole grid - for ax in grid.subplots(): - ax.spines[:].set_visible(False) - ax.spines[:].set_color("none") - ax.get_xaxis().set_visible(False) - ax.get_yaxis().set_visible(False) - - for ax in figure.axes: - ax.spines[:].set_visible(False) - ax.spines[:].set_color("none") - ax.get_xaxis().set_visible(False) - ax.get_yaxis().set_visible(False) - grid_id = 0 for tsz, name, iszs in self.spikes: spikesplot(tsz, title=name, outer_gs=grid[grid_id], tr=self.tr, zscored=iszs) diff --git a/nireports/reportlets/nuisance.py b/nireports/reportlets/nuisance.py index fc76d09..b74b421 100644 --- a/nireports/reportlets/nuisance.py +++ b/nireports/reportlets/nuisance.py @@ -325,14 +325,19 @@ def plot_carpet( # If subplot is not defined if subplot is None: figure, allaxes = plt.subplots(figsize=(19.2, 10)) - allaxes.spines[:].set_visible(False) - allaxes.spines[:].set_color("none") - allaxes.get_xaxis().set_visible(False) - allaxes.get_yaxis().set_visible(False) subplot = allaxes.get_subplotspec() - fontsize = fontsize or 24 else: - figure = plt.gcf() + subplotax = plt.subplot(subplot) + figure = subplotax.get_figure() + + # Remove spines and ticks in all figure's axes + for ax in figure.axes: + ax.spines[:].set_visible(False) + ax.spines[:].set_color("none") + ax.get_xaxis().set_visible(False) + ax.get_yaxis().set_visible(False) + + fontsize = fontsize or 24 # Length before decimation n_trs = data.shape[-1] - drop_trs diff --git a/nireports/tests/test_interfaces.py b/nireports/tests/test_interfaces.py index d027c0e..a31fc8a 100644 --- a/nireports/tests/test_interfaces.py +++ b/nireports/tests/test_interfaces.py @@ -25,8 +25,11 @@ import os from shutil import copy +import nibabel as nb +import numpy as np import pytest +from nireports.interfaces.fmri import FMRISummary from nireports.interfaces.nuisance import ( CompCorVariancePlot, ConfoundsCorrelationPlot, @@ -96,3 +99,43 @@ def test_RaincloudPlot(orient, density, tmp_path): mark_nans=mark_nans, ) _smoke_test_report(rc_rpt, f"raincloud_orient-{orient}_density-{density}.svg") + + +def test_FMRISummary(testdata_path, tmp_path, outdir): + """Exercise the FMRISummary interface.""" + rng = np.random.default_rng(2010) + + in_func = testdata_path / "sub-ds205s03_task-functionallocalizer_run-01_bold_volreg.nii.gz" + ntimepoints = nb.load(in_func).shape[-1] + + np.savetxt( + tmp_path / "fd.txt", + rng.normal(0.2, 0.2, ntimepoints - 1).T, + ) + + np.savetxt( + tmp_path / "outliers.txt", + rng.normal(0.2, 0.2, ntimepoints - 1).T, + ) + + np.savetxt( + tmp_path / "dvars.txt", + rng.normal(0.2, 0.2, (ntimepoints - 1, 2)), + ) + + interface = FMRISummary( + in_func=str(in_func), + in_segm=str( + testdata_path / "sub-ds205s03_task-functionallocalizer_run-01_bold_parc.nii.gz" + ), + fd=str(tmp_path / "fd.txt"), + outliers=str(tmp_path / "outliers.txt"), + dvars=str(tmp_path / "dvars.txt"), + ) + + result = interface.run() + + if outdir is not None: + from shutil import copy + + copy(result.outputs.out_file, outdir / "fmriplot_nipype.svg") From 716ddbf6c113340531ed5df4db1229983e464348 Mon Sep 17 00:00:00 2001 From: Oscar Esteban Date: Mon, 26 Aug 2024 01:13:46 +0200 Subject: [PATCH 3/3] fix: remove calls to ``plt.gcf()`` as they are problematic with memory --- nireports/reportlets/nuisance.py | 30 ++---------------------------- nireports/reportlets/xca.py | 3 +-- 2 files changed, 3 insertions(+), 30 deletions(-) diff --git a/nireports/reportlets/nuisance.py b/nireports/reportlets/nuisance.py index b74b421..4bc3f5e 100644 --- a/nireports/reportlets/nuisance.py +++ b/nireports/reportlets/nuisance.py @@ -34,7 +34,6 @@ import pandas as pd import seaborn as sns from matplotlib.backends.backend_pdf import FigureCanvasPdf as FigureCanvas -from matplotlib.colorbar import ColorbarBase from matplotlib.colors import Normalize from matplotlib.gridspec import GridSpec, GridSpecFromSubplotSpec @@ -614,26 +613,6 @@ def spikesplot( return ax -def spikesplot_cb(position, cmap="viridis", fig=None): - # Add colorbar - if fig is None: - fig = plt.gcf() - - cax = fig.add_axes(position) - cb = ColorbarBase( - cax, - cmap=mpl.colormaps[cmap], - spacing="proportional", - orientation="horizontal", - drawedges=False, - ) - cb.set_ticks([0, 0.5, 1.0]) - cb.set_ticklabels(["Inferior", "(axial slice)", "Superior"]) - cb.outline.set_linewidth(0) - cb.ax.xaxis.set_tick_params(width=0) - return cax - - def confoundplot( tseries, gs_ts, @@ -902,8 +881,7 @@ def confounds_correlation_plot( corr = corr.loc[features, features] np.fill_diagonal(corr.values, 0) - if figure is None: - plt.figure(figsize=(15, 5)) + figure = figure if figure is not None else plt.figure(figsize=(15, 5)) gs = GridSpec(1, 21) ax0 = plt.subplot(gs[0, :10]) ax1 = plt.subplot(gs[0, 11:]) @@ -944,7 +922,6 @@ def confounds_correlation_plot( ax1.spines[side].set_visible(False) if output_file is not None: - figure = plt.gcf() figure.savefig(output_file, bbox_inches="tight") plt.close(figure) figure = None @@ -1120,9 +1097,7 @@ def plot_raincloud( df_clip = df.copy(deep=True) df_clip[feature] = df[feature].clip(lower=lower_limit_value, upper=upper_limit_value) - if figure is None: - plt.figure(figsize=(7, 5)) - + figure = figure if figure is not None else plt.figure(figsize=(7, 5)) gs = GridSpec(1, 1) ax = plt.subplot(gs[0, 0]) @@ -1216,7 +1191,6 @@ def plot_raincloud( ) if output_file is not None: - figure = plt.gcf() plt.tight_layout() figure.savefig(output_file, bbox_inches="tight") plt.close(figure) diff --git a/nireports/reportlets/xca.py b/nireports/reportlets/xca.py index 97575fd..6826f0c 100644 --- a/nireports/reportlets/xca.py +++ b/nireports/reportlets/xca.py @@ -310,6 +310,7 @@ def compcor_variance_plot( elif len(decompositions) > 1: fig, ax = plt.subplots(1, len(decompositions), figsize=(5 * len(decompositions), 5)) else: + fig = plt.gcf() ax = [plt.axes()] for m, (source, mask) in enumerate(decompositions): @@ -367,8 +368,6 @@ def compcor_variance_plot( ax[m].spines[side].set_visible(False) if output_file is not None: - if fig is None: - fig = plt.gcf() fig.savefig(output_file, bbox_inches="tight") fig.clf() fig = None