From 0c2653c772f60ad7c9b51410f86854675ab04e85 Mon Sep 17 00:00:00 2001 From: miykael Date: Tue, 1 May 2018 09:15:05 +0200 Subject: [PATCH 1/7] ENH: correctly handle notebook crashes --- notebooks/advanced_create_interfaces.ipynb | 56 +++++++++++++++++++--- test_notebooks.py | 2 +- 2 files changed, 50 insertions(+), 8 deletions(-) diff --git a/notebooks/advanced_create_interfaces.ipynb b/notebooks/advanced_create_interfaces.ipynb index b5fede0..a56bbad 100644 --- a/notebooks/advanced_create_interfaces.ipynb +++ b/notebooks/advanced_create_interfaces.ipynb @@ -45,7 +45,7 @@ " Do not have inputs/outputs, but expose them from the interfaces wrapped inside\n", " \n", " \n", - " Do not cache results (unless you use [interface caching](http://nipype.readthedocs.io/en/latest/users/caching_tutorial.html))\n", + " Do not cache results (unless you use [interface caching](advanced_interfaces_caching.ipynb))\n", " Cache results\n", " \n", " \n", @@ -383,7 +383,14 @@ "metadata": {}, "outputs": [], "source": [ - "TransformInfo().cmdline # This will CRASH" + "try:\n", + " TransformInfo().cmdline\n", + "\n", + "except(ValueError) as err:\n", + " print('It crashed with...')\n", + " print(\"ValueError:\", err)\n", + "else:\n", + " raise" ] }, { @@ -399,7 +406,14 @@ "metadata": {}, "outputs": [], "source": [ - "my_info_interface.inputs.in_file = 'idontexist.tfm' # This will CRASH, too" + "try:\n", + " my_info_interface.inputs.in_file = 'idontexist.tfm'\n", + "\n", + "except(Exception) as err:\n", + " print('It crashed with...')\n", + " print(\"TraitError:\", err)\n", + "else:\n", + " raise" ] }, { @@ -928,9 +942,23 @@ "source": [ "will_fail_at_run = TranslateImage(\n", " in_file='/data/ds000114/sub-01/ses-test/anat/sub-01_ses-test_T1w.nii.gz',\n", - " out_file='translated.nii.gz')\n", + " out_file='translated.nii.gz')" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "try:\n", + " result = will_fail_at_run.run()\n", "\n", - "result = will_fail_at_run.run() # This will CRASH" + "except(NotImplementedError) as err:\n", + " print('It crashed with...')\n", + " print(\"NotImplementedError:\", err)\n", + "else:\n", + " raise" ] }, { @@ -978,9 +1006,23 @@ "source": [ "half_works = TranslateImage(\n", " in_file='/data/ds000114/sub-01/ses-test/anat/sub-01_ses-test_T1w.nii.gz',\n", - " out_file='translated_nipype.nii.gz')\n", + " out_file='translated_nipype.nii.gz')" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "try:\n", + " result = half_works.run()\n", "\n", - "result = half_works.run() # This will CRASH, too" + "except(NotImplementedError) as err:\n", + " print('It crashed with...')\n", + " print(\"NotImplementedError:\", err)\n", + "else:\n", + " raise" ] }, { diff --git a/test_notebooks.py b/test_notebooks.py index acbb1d8..2a459d5 100644 --- a/test_notebooks.py +++ b/test_notebooks.py @@ -30,7 +30,7 @@ def _notebook_run(path): ep.preprocess(nb, {'metadata': {'path': this_file_directory}}) except CellExecutionError as e: - if "TAB" in e.traceback or "CRASH" in e.traceback: + if "TAB" in e.traceback: print(str(e.traceback).split("\n")[-2]) else: raise e From 7fea9a9f9e4901be7ac511c444818011ad0e3bf1 Mon Sep 17 00:00:00 2001 From: miykael Date: Tue, 1 May 2018 09:31:23 +0200 Subject: [PATCH 2/7] STY: run tests in sorted order --- test_notebooks.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/test_notebooks.py b/test_notebooks.py index 2a459d5..7301996 100644 --- a/test_notebooks.py +++ b/test_notebooks.py @@ -85,9 +85,9 @@ def reduce_notebook_load(path): Dir_path = os.path.join(os.path.dirname(os.path.realpath(__file__)), "notebooks") @pytest.mark.parametrize("notebook", - glob(os.path.join(Dir_path, "introduction_*.ipynb")) + - glob(os.path.join(Dir_path, "basic*.ipynb")) + - glob(os.path.join(Dir_path, "advanced*.ipynb")) + + sorted(glob(os.path.join(Dir_path, "introduction_*.ipynb"))) + + sorted(glob(os.path.join(Dir_path, "basic*.ipynb"))) + + sorted(glob(os.path.join(Dir_path, "advanced*.ipynb"))) + [os.path.join(Dir_path, "example_preprocessing.ipynb"), os.path.join(Dir_path, "example_1stlevel.ipynb"), os.path.join(Dir_path, "example_normalize.ipynb"), From 436d563a62b6cb26d11b694ac1b66508f344d33d Mon Sep 17 00:00:00 2001 From: miykael Date: Tue, 1 May 2018 14:08:42 +0200 Subject: [PATCH 3/7] ENH: adds fmriprep, mriqc, mindboggle and porcupine link --- index.ipynb | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/index.ipynb b/index.ipynb index 59eacb9..341d8fa 100644 --- a/index.ipynb +++ b/index.ipynb @@ -124,6 +124,10 @@ " NiBabel\n", " Nilearn\n", " BIDS Apps\n", + " fmriprep\n", + " MRIQC\n", + " Mindboggle\n", + " PORcupine\n", " \n", "

This section will give you helpful links and resources, so that you always know where to go to learn more.

\n", "\n", @@ -278,6 +282,10 @@ " NiBabel\n", " Nilearn\n", " BIDS Apps\n", + " fmriprep\n", + " MRIQC\n", + " Mindboggle\n", + " PORcupine\n", " \n", "

This section will give you helpful links and resources, so that you always know where to go to learn more.

\n", "\n", From 4902c99e82af82a7ab9101958bffb4e8aaae8dab Mon Sep 17 00:00:00 2001 From: miykael Date: Tue, 1 May 2018 14:11:00 +0200 Subject: [PATCH 4/7] ENH: adds OpenNeuro link to references [skip ci] --- index.ipynb | 2 ++ 1 file changed, 2 insertions(+) diff --git a/index.ipynb b/index.ipynb index 341d8fa..d2c6197 100644 --- a/index.ipynb +++ b/index.ipynb @@ -123,6 +123,7 @@ " Neurodocker\n", " NiBabel\n", " Nilearn\n", + " OpenNeuro\n", " BIDS Apps\n", " fmriprep\n", " MRIQC\n", @@ -281,6 +282,7 @@ " Neurodocker\n", " NiBabel\n", " Nilearn\n", + " OpenNeuro\n", " BIDS Apps\n", " fmriprep\n", " MRIQC\n", From cd7917146aabba43476fe5b5128d0f05d80e0c4e Mon Sep 17 00:00:00 2001 From: miykael Date: Sun, 6 May 2018 20:33:39 +0200 Subject: [PATCH 5/7] FIX: updates git-annex branches --- Dockerfile | 12 ++++++------ create_dockerfile.sh | 6 +++--- 2 files changed, 9 insertions(+), 9 deletions(-) diff --git a/Dockerfile b/Dockerfile index abb515f..2b2e313 100644 --- a/Dockerfile +++ b/Dockerfile @@ -5,7 +5,7 @@ # pull request on our GitHub repository: # https://github.com/kaczmarj/neurodocker # -# Timestamp: 2018-04-23 18:54:53 +# Timestamp: 2018-05-06 18:33:27 FROM neurodebian:stretch-non-free @@ -120,7 +120,7 @@ RUN conda create -y -q --name neuro python=3.6 \ && pip install -q --no-cache-dir https://github.com/nipy/nipype/tarball/master \ https://github.com/INCF/pybids/tarball/master \ nilearn \ - datalad[full] \ + datalad_neuroimaging \ nipy \ duecredit" \ && sync \ @@ -143,7 +143,7 @@ RUN mkdir /output && chmod 777 /output && chmod a+s /output USER neuro # User-defined BASH instruction -RUN bash -c "source activate neuro && cd /data && datalad install -r ///workshops/nih-2017/ds000114 && cd ds000114 && datalad get -r sub-01/ses-test/anat sub-01/ses-test/func/*fingerfootlips*" +RUN bash -c "source activate neuro && cd /data && datalad install -r ///workshops/nih-2017/ds000114 && cd ds000114 && datalad update -r && datalad get -r sub-01/ses-test/anat sub-01/ses-test/func/*fingerfootlips*" # User-defined BASH instruction RUN bash -c "curl -L https://files.osf.io/v1/resources/fvuh8/providers/osfstorage/580705089ad5a101f17944a9 -o /data/ds000114/derivatives/fmriprep/mni_icbm152_nlin_asym_09c.tar.gz && tar xf /data/ds000114/derivatives/fmriprep/mni_icbm152_nlin_asym_09c.tar.gz -C /data/ds000114/derivatives/fmriprep/. && rm /data/ds000114/derivatives/fmriprep/mni_icbm152_nlin_asym_09c.tar.gz && find /data/ds000114/derivatives/fmriprep/mni_icbm152_nlin_asym_09c -type f -not -name ?mm_T1.nii.gz -not -name ?mm_brainmask.nii.gz -not -name ?mm_tpm*.nii.gz -delete" @@ -218,7 +218,7 @@ RUN echo '{ \ \n { \ \n "miniconda_version": "4.3.31", \ \n "conda_install": "python=3.6 pytest jupyter jupyterlab jupyter_contrib_nbextensions traits pandas matplotlib scikit-learn scikit-image seaborn nbformat nb_conda", \ - \n "pip_install": "https://github.com/nipy/nipype/tarball/master https://github.com/INCF/pybids/tarball/master nilearn datalad[full] nipy duecredit", \ + \n "pip_install": "https://github.com/nipy/nipype/tarball/master https://github.com/INCF/pybids/tarball/master nilearn datalad_neuroimaging nipy duecredit", \ \n "env_name": "neuro", \ \n "activate": true \ \n } \ @@ -249,7 +249,7 @@ RUN echo '{ \ \n ], \ \n [ \ \n "run_bash", \ - \n "source activate neuro && cd /data && datalad install -r ///workshops/nih-2017/ds000114 && cd ds000114 && datalad get -r sub-01/ses-test/anat sub-01/ses-test/func/*fingerfootlips*" \ + \n "source activate neuro && cd /data && datalad install -r ///workshops/nih-2017/ds000114 && cd ds000114 && datalad update -r && datalad get -r sub-01/ses-test/anat sub-01/ses-test/func/*fingerfootlips*" \ \n ], \ \n [ \ \n "run_bash", \ @@ -289,6 +289,6 @@ RUN echo '{ \ \n ] \ \n ] \ \n ], \ - \n "generation_timestamp": "2018-04-23 18:54:53", \ + \n "generation_timestamp": "2018-05-06 18:33:27", \ \n "neurodocker_version": "0.3.2" \ \n}' > /neurodocker/neurodocker_specs.json diff --git a/create_dockerfile.sh b/create_dockerfile.sh index e5d8bc9..e87f970 100755 --- a/create_dockerfile.sh +++ b/create_dockerfile.sh @@ -1,6 +1,6 @@ #!/bin/bash -docker run --rm kaczmarj/neurodocker:master generate -b neurodebian:stretch-non-free -p apt \ +docker run --rm kaczmarj/neurodocker:v0.3.2 generate -b neurodebian:stretch-non-free -p apt \ --install convert3d ants fsl gcc g++ graphviz tree \ git-annex-standalone vim emacs-nox nano less ncdu \ tig git-annex-remote-rclone octave \ @@ -12,7 +12,7 @@ docker run --rm kaczmarj/neurodocker:master generate -b neurodebian:stretch-non- traits pandas matplotlib scikit-learn scikit-image seaborn nbformat nb_conda" \ pip_install="https://github.com/nipy/nipype/tarball/master https://github.com/INCF/pybids/tarball/master - nilearn datalad[full] nipy duecredit" \ + nilearn datalad_neuroimaging nipy duecredit" \ env_name="neuro" \ activate=True \ --run-bash "source activate neuro && jupyter nbextension enable exercise2/main && jupyter nbextension enable spellchecker/main" \ @@ -21,7 +21,7 @@ docker run --rm kaczmarj/neurodocker:master generate -b neurodebian:stretch-non- --run 'mkdir /data && chmod 777 /data && chmod a+s /data' \ --run 'mkdir /output && chmod 777 /output && chmod a+s /output' \ --user=neuro \ ---run-bash 'source activate neuro && cd /data && datalad install -r ///workshops/nih-2017/ds000114 && cd ds000114 && datalad get -r sub-01/ses-test/anat sub-01/ses-test/func/*fingerfootlips*' \ +--run-bash 'source activate neuro && cd /data && datalad install -r ///workshops/nih-2017/ds000114 && cd ds000114 && datalad update -r && datalad get -r sub-01/ses-test/anat sub-01/ses-test/func/*fingerfootlips*' \ --run-bash 'curl -L https://files.osf.io/v1/resources/fvuh8/providers/osfstorage/580705089ad5a101f17944a9 -o /data/ds000114/derivatives/fmriprep/mni_icbm152_nlin_asym_09c.tar.gz && tar xf /data/ds000114/derivatives/fmriprep/mni_icbm152_nlin_asym_09c.tar.gz -C /data/ds000114/derivatives/fmriprep/. && rm /data/ds000114/derivatives/fmriprep/mni_icbm152_nlin_asym_09c.tar.gz && find /data/ds000114/derivatives/fmriprep/mni_icbm152_nlin_asym_09c -type f -not -name ?mm_T1.nii.gz -not -name ?mm_brainmask.nii.gz -not -name ?mm_tpm*.nii.gz -delete' \ --copy . "/home/neuro/nipype_tutorial" \ --user=root \ From 7674c5b24131b89036321413e7ebfee3a3961a50 Mon Sep 17 00:00:00 2001 From: miykael Date: Mon, 7 May 2018 13:55:47 +0200 Subject: [PATCH 6/7] ENH: add datalad's cast to the nipype tutorial --- casts/cast_ipython.rc | 16 +++++ casts/cast_live_python | 112 ++++++++++++++++++++++++++++++ casts/nipype_tutorial_showcase.sh | 100 ++++++++++++++++++++++++++ 3 files changed, 228 insertions(+) create mode 100644 casts/cast_ipython.rc create mode 100755 casts/cast_live_python create mode 100644 casts/nipype_tutorial_showcase.sh diff --git a/casts/cast_ipython.rc b/casts/cast_ipython.rc new file mode 100644 index 0000000..7a68fee --- /dev/null +++ b/casts/cast_ipython.rc @@ -0,0 +1,16 @@ +# This file contains ipython configuration variables to be used for generating +# asciinema demos to guarantee consistent appearance. + +# make a fake temporary home dir and go into it +SCREENCAST_HOME=~/demo +if [ ! -e "$SCREENCAST_HOME" ]; then + mkdir -p ${SCREENCAST_HOME} || { + echo "FAILED to create $SCREENCAST_HOME" >&2 + exit 1; # we need demo directory! + } +fi +cd $SCREENCAST_HOME +ipython + +# cleanup at the end +trap "cd ; rm -rf ~/demo > /dev/null 2>&1" EXIT diff --git a/casts/cast_live_python b/casts/cast_live_python new file mode 100755 index 0000000..b7afb8f --- /dev/null +++ b/casts/cast_live_python @@ -0,0 +1,112 @@ +#!/bin/bash +# +set -u -e + +test ! -e $1 && echo "input file does not exist" && exit 1 +title="$(echo $(basename $1) | sed -e 's/.sh$//')" +bashrc_file="$(dirname $0)/cast_ipython.rc" + +# shortcut for making xdotool use the right window +function xdt() { + winid=$1 + shift + xdotool windowactivate --sync $winid + if [ "$#" -gt 0 ]; then + xdotool "$@" + fi +} + +# make sure the target xterm is up and running +width=106 +height=29 +fs=15 +text_width=$(($width - 8)) + +geometry=${width}x${height} +this_window=$(xdotool getwindowfocus) + +# For consistent appearance +xterm +sb -fa Hermit -fs $fs -bg black -fg white -geometry $geometry -title Screencast-xterm -e "bash --rcfile cast_ipython.rc" & +xterm_pid=$! +sleep 2 + +xterm_window=$(xdotool search --pid $xterm_pid) + +# By default should stay in the xterm window, so when we need to deal with +# current one (waiting etc), then switch +function wait () { + xdt $this_window + read -p "$@" in + echo "$in" + xdt $xterm_window +} +function instruct () { + xdt $this_window + wait "$@" +} +function type () { + xdt $xterm_window type --clearmodifiers --delay 40 "$1" +} +function key () { + xdt $xterm_window key --clearmodifiers $* +} +function sleep () { + xdotool sleep $1 +} +function execute () { + xdt $xterm_window sleep 0.5 key Return + sleep 0.2 +} +function say() +{ + ac=$(instruct "SAY: $1") + if [ "$ac" != "s" ] ; then + echo "skipping" + return + fi + type "$(printf "#\n# $1" | fmt -w ${text_width} --prefix '# ')" + key Return +} +function show () { + xdt $xterm_window type --clearmodifiers --delay 10 "$(printf "\n$1" | sed -e 's/^/# /g')" + sleep 0.1 + key Return +} +function run () { + help="Press Enter to type, s to skip this action" + ac=$(instruct "EXEC: $1. $help") + if [ "$ac" = "s" ]; then + echo "skipping" + return + fi + type "$1" + ac=$(instruct "EXEC: $1. $help") + if [ "$ac" = "s" ]; then + echo "skipping" + return + fi + execute +} +function run_expfail () { + # TODO we could announce or visualize the expected failure + run "$1" +} + +xdt $xterm_window sleep 0.1 + +echo "xterm PID $xterm_pid (window $xterm_window) this window $this_window" + +# now get the process tree attached to the terminal so we can +# figure out when it is idle, and when it is not +# XXX must happen after asciinema is running +xterm_pstree="$(pstree -p -A $xterm_pid)" + +. $1 + +sleep 1 + +show "$(cowsay "Demo was using $(datalad --version 2>&1 | head -n1). Discover more at http://datalad.org")" + +# key Control_L+d + +echo "INSTRUCTION: Press Ctrl-D or run exit to close the terminal" diff --git a/casts/nipype_tutorial_showcase.sh b/casts/nipype_tutorial_showcase.sh new file mode 100644 index 0000000..be2eb34 --- /dev/null +++ b/casts/nipype_tutorial_showcase.sh @@ -0,0 +1,100 @@ +say "Import nipype building blocks" +show "Import nipype building blocks" +run "from nipype import Node, Workflow" + +say "Import relevant interfaces" +show "Import relevant interfaces" +run "from nipype.interfaces.fsl import SliceTimer, MCFLIRT, Smooth" + +say "Create SliceTime correction node" +show "Create SliceTime correction node" +run "slicetimer = Node(SliceTimer(index_dir=False, + interleaved=True, + time_repetition=2.5), + name='slicetimer') +" + +say "Create Motion correction node" +show "Create Motion correction node" +run "mcflirt = Node(MCFLIRT(mean_vol=True, + save_plots=True), + name='mcflirt') +" + +say "Create Smoothing node" +show "Create Smoothing node" +run "smooth = Node(Smooth(fwhm=4), name='smooth')" + +say "Create Workflow" +show "Create Workflow" +run "preproc01 = Workflow(name='preproc01', base_dir='.')" + +say "Connect nodes within the workflow" +show "Connect nodes within the workflow" +run "preproc01.connect([(slicetimer, mcflirt, [('slice_time_corrected_file', 'in_file')]), + (mcflirt, smooth, [('out_file', 'in_file')])]) +" + +say "Create a visualization of the workflow" +show "Create a visualization of the workflow" +run "preproc01.write_graph(graph2use='orig')" + +say "Visualize the figure" +show "Visualize the figure" +run "!eog preproc01/graph_detailed.png +" + +say "Feed some input to the workflow" +show "Feed some input to the workflow" +run "slicetimer.inputs.in_file = 'path/to/your/func.nii.gz'" + +say "Run the Workflow and stop the time" +show "Run the Workflow and stop the time" +run "%time preproc01.run('MultiProc', plugin_args={'n_procs': 5})" + +say "Investigate the output" +show "Investigate the output" +run "!tree preproc01 -I '*js|*json|*pklz|_report|*.dot|*html'" + +say "Change the size of the smoothing kernel" +show "Change the size of the smoothing kernel" +run "smooth.inputs.fwhm = 2" + +say "Rerun the workflow" +show "Rerun the workflow" +run "%time preproc01.run('MultiProc', plugin_args={'n_procs': 5})" + +say "Create 4 additional copies of the workflow" +show "Create 4 additional copies of the workflow" +run "preproc02 = preproc01.clone('preproc02') +preproc03 = preproc01.clone('preproc03') +preproc04 = preproc01.clone('preproc04') +preproc05 = preproc01.clone('preproc05') +" + +say "Create a new workflow - metaflow" +show "Create a new workflow - metaflow" +run "metaflow = Workflow(name='metaflow', base_dir='.')" + +say "Add the 5 workflows to this metaflow" +show "Add the 5 workflows to this metaflow" +run "metaflow.add_nodes([preproc01, preproc02, preproc03, + preproc04, preproc05]) +" + +say "Visualize the workflow" +show "Visualize the workflow" +run "metaflow.write_graph(graph2use='flat') +!eog metaflow/graph_detailed.png +" + +say "Run this metaflow in parallel" +show "Run this metaflow in parallel" +run "%time metaflow.run('MultiProc', plugin_args={'n_procs': 5})" + +say "Investigate the output" +show "Investigate the output" +run "!tree metaflow -I '*js|*json|*pklz|_report|*.dot|*html'" + +say "The End." +show "The End." From efd7b84523df5b2741956917786694517c1b6122 Mon Sep 17 00:00:00 2001 From: miykael Date: Mon, 7 May 2018 22:44:11 +0200 Subject: [PATCH 7/7] FIX: install datalad via full, as neuroimaging crashes --- Dockerfile | 8 ++++---- create_dockerfile.sh | 2 +- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/Dockerfile b/Dockerfile index 2b2e313..6e30ccc 100644 --- a/Dockerfile +++ b/Dockerfile @@ -5,7 +5,7 @@ # pull request on our GitHub repository: # https://github.com/kaczmarj/neurodocker # -# Timestamp: 2018-05-06 18:33:27 +# Timestamp: 2018-05-07 20:43:57 FROM neurodebian:stretch-non-free @@ -120,7 +120,7 @@ RUN conda create -y -q --name neuro python=3.6 \ && pip install -q --no-cache-dir https://github.com/nipy/nipype/tarball/master \ https://github.com/INCF/pybids/tarball/master \ nilearn \ - datalad_neuroimaging \ + datalad[full] \ nipy \ duecredit" \ && sync \ @@ -218,7 +218,7 @@ RUN echo '{ \ \n { \ \n "miniconda_version": "4.3.31", \ \n "conda_install": "python=3.6 pytest jupyter jupyterlab jupyter_contrib_nbextensions traits pandas matplotlib scikit-learn scikit-image seaborn nbformat nb_conda", \ - \n "pip_install": "https://github.com/nipy/nipype/tarball/master https://github.com/INCF/pybids/tarball/master nilearn datalad_neuroimaging nipy duecredit", \ + \n "pip_install": "https://github.com/nipy/nipype/tarball/master https://github.com/INCF/pybids/tarball/master nilearn datalad[full] nipy duecredit", \ \n "env_name": "neuro", \ \n "activate": true \ \n } \ @@ -289,6 +289,6 @@ RUN echo '{ \ \n ] \ \n ] \ \n ], \ - \n "generation_timestamp": "2018-05-06 18:33:27", \ + \n "generation_timestamp": "2018-05-07 20:43:57", \ \n "neurodocker_version": "0.3.2" \ \n}' > /neurodocker/neurodocker_specs.json diff --git a/create_dockerfile.sh b/create_dockerfile.sh index e87f970..79ed49b 100755 --- a/create_dockerfile.sh +++ b/create_dockerfile.sh @@ -12,7 +12,7 @@ docker run --rm kaczmarj/neurodocker:v0.3.2 generate -b neurodebian:stretch-non- traits pandas matplotlib scikit-learn scikit-image seaborn nbformat nb_conda" \ pip_install="https://github.com/nipy/nipype/tarball/master https://github.com/INCF/pybids/tarball/master - nilearn datalad_neuroimaging nipy duecredit" \ + nilearn datalad[full] nipy duecredit" \ env_name="neuro" \ activate=True \ --run-bash "source activate neuro && jupyter nbextension enable exercise2/main && jupyter nbextension enable spellchecker/main" \