From 5c13a2a9cc35c9d16b406d9c91132fbf1e0d7273 Mon Sep 17 00:00:00 2001 From: Chris Gorgolewski Date: Wed, 2 Aug 2017 17:58:04 -0700 Subject: [PATCH 1/6] support plotting good/bad components --- niworkflows/viz/utils.py | 36 ++++++++++++++++++++++++++++-------- 1 file changed, 28 insertions(+), 8 deletions(-) diff --git a/niworkflows/viz/utils.py b/niworkflows/viz/utils.py index e73bd8d095f..39bbea19b3d 100644 --- a/niworkflows/viz/utils.py +++ b/niworkflows/viz/utils.py @@ -488,7 +488,8 @@ def transform_to_2d(data, max_axis): def plot_melodic_components(melodic_dir, in_file, tr=None, out_file='melodic_reportlet.svg', - compress='auto', report_mask=None): + compress='auto', report_mask=None, + noise_components_file=None): from nilearn.plotting import plot_glass_brain from nilearn.image import index_img, iter_img import nibabel as nb @@ -497,6 +498,7 @@ def plot_melodic_components(melodic_dir, in_file, tr=None, import seaborn as sns from matplotlib.gridspec import GridSpec import os + import re from io import StringIO sns.set_style("white") current_palette = sns.color_palette() @@ -534,6 +536,10 @@ def plot_melodic_components(melodic_dir, in_file, tr=None, width_ratios=[1, 1, 1, 4, 0.001, 1, 1, 1, 4, ], height_ratios=[1.1, 1] * n_rows) + if noise_components_file: + with open(noise_components_file) as cf: + noise_components = [int(c) for c in cf.read().split(",")] + for i, img in enumerate( iter_img(os.path.join(melodic_dir, "melodic_IC.nii.gz"))): @@ -541,6 +547,16 @@ def plot_melodic_components(melodic_dir, in_file, tr=None, row = int(i / 2) l_row = row * 2 + if noise_components_file: + if (i + 1) in noise_components: + color_title = color_time = color_power = 'r' + else: + color_title = color_time = color_power = 'g' + else: + color_title = 'k' + color_time = current_palette[0] + color_power = current_palette[1] + data = img.get_data() for j in range(3): ax1 = fig.add_subplot(gs[l_row:l_row + 2, j + col * 5]) @@ -556,29 +572,33 @@ def plot_melodic_components(melodic_dir, in_file, tr=None, "C%d: Tot. var. expl. %.2g%%" % (i + 1, stats[i, 1]), x=0, y=1.18, fontsize=7, horizontalalignment='left', - verticalalignment='top') + verticalalignment='top', + color=color_title) ax2 = fig.add_subplot(gs[l_row, 3 + col * 5]) ax3 = fig.add_subplot(gs[l_row + 1, 3 + col * 5]) ax2.plot(np.arange(len(timeseries[:, i])) * tr, timeseries[:, i], - linewidth=min(200 / len(timeseries[:, i]), 1.0)) + linewidth=min(200 / len(timeseries[:, i]), 1.0), + color=color_time) ax2.set_xlim([0, len(timeseries[:, i]) * tr]) ax2.axes.get_yaxis().set_visible(False) ax2.autoscale_view('tight') ax2.tick_params(axis='both', which='major', pad=0) sns.despine(left=True, bottom=True) - zed = [tick.label.set_fontsize(6) for tick in - ax2.xaxis.get_major_ticks()] + for tick in ax2.xaxis.get_major_ticks(): + tick.label.set_fontsize(6) + tick.label.set_color(color_time) - ax3.plot(f[0:], power[0:, i], color=current_palette[1], + ax3.plot(f[0:], power[0:, i], color=color_power, linewidth=min(100 / len(power[0:, i]), 1.0)) ax3.set_xlim([f[0], f.max()]) ax3.axes.get_yaxis().set_visible(False) ax3.autoscale_view('tight') ax3.tick_params(axis='both', which='major', pad=0) - zed = [tick.label.set_fontsize(6) for tick in - ax3.xaxis.get_major_ticks()] + for tick in ax3.xaxis.get_major_ticks(): + tick.label.set_fontsize(6) + tick.label.set_color(color_power) sns.despine(left=True, bottom=True) plt.subplots_adjust(hspace=0.5) From cc5dfbb971405af81c5ca07afea7ab05a28baee6 Mon Sep 17 00:00:00 2001 From: Chris Gorgolewski Date: Wed, 2 Aug 2017 18:16:41 -0700 Subject: [PATCH 2/6] adding reportlet interface --- niworkflows/interfaces/segmentation.py | 36 ++++++++++++++++++++++++++ 1 file changed, 36 insertions(+) diff --git a/niworkflows/interfaces/segmentation.py b/niworkflows/interfaces/segmentation.py index 9e744cf657a..dc613a7153c 100644 --- a/niworkflows/interfaces/segmentation.py +++ b/niworkflows/interfaces/segmentation.py @@ -115,3 +115,39 @@ def _post_run_hook(self, runtime): self._melodic_dir = outputs.out_dir NIWORKFLOWS_LOG.info('Generating report for MELODIC') + + +class ICA_AROMAInputSpecRPT(nrc.ReportCapableInputSpec, + fsl.aroma.ICA_AROMAInputSpec): + out_report = File( + 'ica_aroma_reportlet.svg', usedefault=True, desc='Filename for the visual' + ' report generated ' + 'by Nipype.') + report_mask = File(desc='Mask used to draw the outline on the reportlet. ' + 'If not set the mask will be derived from the data.') + +class ICA_AROMAOutputSpecRPT(nrc.ReportCapableOutputSpec, + fsl.aroma.ICA_AROMAOutputSpec): + pass + + +class ICA_AROMARPT(nrc.ReportCapableInterface, fsl.ICA_AROMA): + input_spec = ICA_AROMAInputSpecRPT + output_spec = ICA_AROMAOutputSpecRPT + + def _generate_report(self): + from niworkflows.viz.utils import plot_melodic_components + plot_melodic_components(melodic_dir=self.inputs.melodic_dir, + in_file=self.inputs.in_file, + out_file=self.inputs.out_report, + compress=self.inputs.compress_report, + report_mask=self.inputs.report_mask, + noise_components_file=self._noise_components_file + ) + + def _post_run_hook(self, runtime): + outputs = self.aggregate_outputs(runtime=runtime) + self._noise_components_file = os.path.join(outputs.out_dir, + "classified_motion_ICs.txt") + + NIWORKFLOWS_LOG.info('Generating report for MELODIC') \ No newline at end of file From d54a90368116bc26bcbe8016bad84369531283f9 Mon Sep 17 00:00:00 2001 From: Chris Gorgolewski Date: Fri, 4 Aug 2017 10:58:41 -0700 Subject: [PATCH 3/6] better text --- nipype | 2 +- niworkflows/interfaces/segmentation.py | 2 +- niworkflows/nipype | 1 - 3 files changed, 2 insertions(+), 3 deletions(-) delete mode 120000 niworkflows/nipype diff --git a/nipype b/nipype index 86c41d3c545..9b0686d7ea8 160000 --- a/nipype +++ b/nipype @@ -1 +1 @@ -Subproject commit 86c41d3c545d14af75070e8f7ce20fc71ab31fdb +Subproject commit 9b0686d7ea8b5da7af87ef779062f96e3bb3bb47 diff --git a/niworkflows/interfaces/segmentation.py b/niworkflows/interfaces/segmentation.py index dc613a7153c..74ff5745d45 100644 --- a/niworkflows/interfaces/segmentation.py +++ b/niworkflows/interfaces/segmentation.py @@ -150,4 +150,4 @@ def _post_run_hook(self, runtime): self._noise_components_file = os.path.join(outputs.out_dir, "classified_motion_ICs.txt") - NIWORKFLOWS_LOG.info('Generating report for MELODIC') \ No newline at end of file + NIWORKFLOWS_LOG.info('Generating report for ICA AROMA') \ No newline at end of file diff --git a/niworkflows/nipype b/niworkflows/nipype deleted file mode 120000 index 1876990bd20..00000000000 --- a/niworkflows/nipype +++ /dev/null @@ -1 +0,0 @@ -../nipype/nipype \ No newline at end of file From 056d03b67c705b440ad42020de9e8fc35ad033e6 Mon Sep 17 00:00:00 2001 From: Chris Gorgolewski Date: Fri, 4 Aug 2017 15:41:40 -0700 Subject: [PATCH 4/6] Revert "better text" This reverts commit d54a90368116bc26bcbe8016bad84369531283f9. --- nipype | 2 +- niworkflows/interfaces/segmentation.py | 2 +- niworkflows/nipype | 1 + 3 files changed, 3 insertions(+), 2 deletions(-) create mode 120000 niworkflows/nipype diff --git a/nipype b/nipype index 9b0686d7ea8..86c41d3c545 160000 --- a/nipype +++ b/nipype @@ -1 +1 @@ -Subproject commit 9b0686d7ea8b5da7af87ef779062f96e3bb3bb47 +Subproject commit 86c41d3c545d14af75070e8f7ce20fc71ab31fdb diff --git a/niworkflows/interfaces/segmentation.py b/niworkflows/interfaces/segmentation.py index 74ff5745d45..dc613a7153c 100644 --- a/niworkflows/interfaces/segmentation.py +++ b/niworkflows/interfaces/segmentation.py @@ -150,4 +150,4 @@ def _post_run_hook(self, runtime): self._noise_components_file = os.path.join(outputs.out_dir, "classified_motion_ICs.txt") - NIWORKFLOWS_LOG.info('Generating report for ICA AROMA') \ No newline at end of file + NIWORKFLOWS_LOG.info('Generating report for MELODIC') \ No newline at end of file diff --git a/niworkflows/nipype b/niworkflows/nipype new file mode 120000 index 00000000000..1876990bd20 --- /dev/null +++ b/niworkflows/nipype @@ -0,0 +1 @@ +../nipype/nipype \ No newline at end of file From fa2956beadddffd68f0e8270155e15cd250e136c Mon Sep 17 00:00:00 2001 From: Chris Gorgolewski Date: Fri, 4 Aug 2017 15:43:31 -0700 Subject: [PATCH 5/6] fixes --- niworkflows/interfaces/segmentation.py | 2 +- niworkflows/viz/utils.py | 16 +++++++++++----- 2 files changed, 12 insertions(+), 6 deletions(-) diff --git a/niworkflows/interfaces/segmentation.py b/niworkflows/interfaces/segmentation.py index dc613a7153c..74ff5745d45 100644 --- a/niworkflows/interfaces/segmentation.py +++ b/niworkflows/interfaces/segmentation.py @@ -150,4 +150,4 @@ def _post_run_hook(self, runtime): self._noise_components_file = os.path.join(outputs.out_dir, "classified_motion_ICs.txt") - NIWORKFLOWS_LOG.info('Generating report for MELODIC') \ No newline at end of file + NIWORKFLOWS_LOG.info('Generating report for ICA AROMA') \ No newline at end of file diff --git a/niworkflows/viz/utils.py b/niworkflows/viz/utils.py index cceab04035e..39d94019354 100644 --- a/niworkflows/viz/utils.py +++ b/niworkflows/viz/utils.py @@ -448,18 +448,24 @@ def compose_view(bg_svgs, fg_svgs, ref=0, out_file='report.svg'): out_file = op.abspath(out_file) fig.save(out_file) + # Post processing + with open(out_file, 'r' if PY3 else 'rb') as f: + svg = f.read().split('\n') + + # Remove @keyframes flickerAnimation%s { 0%% {opacity: 1;} 100%% { opacity: 0; }} .foreground-svg { animation: 1s ease-in-out 0s alternate none infinite paused flickerAnimation%s;} .foreground-svg:hover { animation-play-state: running;} """ % tuple([uuid4()] * 2)) - with open(out_file, 'w' if PY3 else 'wb') as f: - f.write('\n'.join(svg)) + + with open(out_file, 'w' if PY3 else 'wb') as f: + f.write('\n'.join(svg)) return out_file From 3acfea6e73bb893ed84e1e7dad9346769a57227f Mon Sep 17 00:00:00 2001 From: Chris Gorgolewski Date: Fri, 4 Aug 2017 16:07:52 -0700 Subject: [PATCH 6/6] new line --- niworkflows/interfaces/segmentation.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/niworkflows/interfaces/segmentation.py b/niworkflows/interfaces/segmentation.py index 74ff5745d45..fd2522f52cb 100644 --- a/niworkflows/interfaces/segmentation.py +++ b/niworkflows/interfaces/segmentation.py @@ -150,4 +150,4 @@ def _post_run_hook(self, runtime): self._noise_components_file = os.path.join(outputs.out_dir, "classified_motion_ICs.txt") - NIWORKFLOWS_LOG.info('Generating report for ICA AROMA') \ No newline at end of file + NIWORKFLOWS_LOG.info('Generating report for ICA AROMA')