{ "cells": [ { "cell_type": "markdown", "source": [ "# Imports and Setup\n", "\n", "First we will, pretty obviously, import that Jupyter functions from `nanslice`. We are also going to use `urllib` and `tarfile` to get some example data from https://peerj.com/articles/2632. The data is a group template T2-weighted image, the difference in group average quantitative T1, the p-value for a two group comparison between control and treated animals, and a brain mask.\n", "\n", "*Important* - The `%matplotlib widget` magic is required if you want to use the interactive three-plane viewer. If you are only making static plots you can use another backend." ], "metadata": {} }, { "cell_type": "code", "execution_count": null, "source": [ "%matplotlib widget\n", "!pip install nanslice\n", "import urllib.request\n", "import tarfile\n", "\n", "url = 'https://osf.io/hmtyr/download'\n", "urllib.request.urlretrieve(url, 'nanslice_example.tar.gz')\n", "tgz = tarfile.open('nanslice_example.tar.gz')\n", "tgz.extractall()\n", "tgz.close()\n", "data_dir = 'nanslice_example/'\n", "\n", "import nanslice.jupyter as ns" ], "outputs": [], "metadata": { "inputHidden": false, "outputHidden": false } }, { "cell_type": "markdown", "source": [ "# Basic Slicing\n", "\n", "The files are now contained in the `data_dir` directory. `nanslice` provides a simple `three_plane` function to give a quick view through an image, and an interactive `three_plane_viewer`. For convenience you can pass these functions a file name instead of loading the file first.\n", "\n", "*Note* If you \"Run All\" cells in this notebook, you will have to run the interactive viewer cell again to enable the sliders. This is because the interactive viewer requires a call to `matplotlib.pyplot.ion()`. The non-interactive plots require a call to `matplotlib.pyplot.ioff()`, otherwise extra white-space is shown. Calling this in later cells turns off the sliders." ], "metadata": {} }, { "cell_type": "code", "execution_count": null, "source": [ "ns.three_plane(data_dir + 'template_T2w.nii.gz', title='An Image')" ], "outputs": [], "metadata": { "inputHidden": false, "outputHidden": false } }, { "cell_type": "code", "execution_count": null, "source": [ "ns.three_plane(data_dir + 'template_T2w.nii.gz', interactive=True, title='Drag the Sliders')" ], "outputs": [], "metadata": { "inputHidden": false, "outputHidden": false } }, { "cell_type": "markdown", "source": [ "However, if you are going to use the same image multiple times, e.g. a structural template image, then it makes sense to load it first" ], "metadata": {} }, { "cell_type": "markdown", "source": [ "# Masking and Colormaps\n", "\n", "The above examples are the fatest way to display an image in `nanslice`. However, if we want to have a more advanced plot or use overlays, then we need to use a `Layer` object. Here, we add a mask to the base image. The bounding box of the slices will be automatically cropped to the mask, making better use of the space in the plot." ], "metadata": {} }, { "cell_type": "code", "execution_count": null, "source": [ "base = ns.Layer(data_dir + 'template_T2w.nii.gz', mask=data_dir + 'study_mask.nii.gz')\n", "ns.three_plane(base, title='Mask')" ], "outputs": [], "metadata": { "inputHidden": false, "outputHidden": false } }, { "cell_type": "markdown", "source": [ "Now that we have a `Layer` object, we can re-use it for future plots without having to reload the image from disk. For example, we can change the colormap (this can also be specified when creating the `Layer`). We can also add a colormap to the plot." ], "metadata": {} }, { "cell_type": "code", "execution_count": null, "source": [ "base.cmap = 'viridis'\n", "ns.three_plane(base, cbar=True, title='Colormap')" ], "outputs": [], "metadata": { "inputHidden": false, "outputHidden": false } }, { "cell_type": "markdown", "source": [ "# Overlays\n", "\n", "Now we are ready to start adding overlays to images. First we will add a standard single-coded statistical overlay, in this case a p-value thresholded at p < 0.05. Because this p-value was generated with FSL randomise, it is stored as 1-p so we threshold at (1 - p) > 0.95. We also add a colorbar, and specify that we want to take it from layer 1 (Python arrays count from 0, so this is the 1st overlay). Note that the colorbar has been automatically labelled using the `label` property of the `Layer`." ], "metadata": {} }, { "cell_type": "code", "execution_count": null, "source": [ "base.cmap = 'gist_gray'\n", "pval = ns.Layer(data_dir + 'T1_tfce_p_tstat1.nii.gz', cmap='Reds', clim=(0.95,1.0), label='1-p', mask_threshold=0.95)\n", "ns.three_plane([base, pval],cbar=1, title='P-Value Overlay')" ], "outputs": [], "metadata": { "scrolled": true } }, { "cell_type": "markdown", "source": [ "One of the key reasons `nanslice` was written was to demonstrate dual-coded overlays, where both color and transparency have meaning - see https://www.cell.com/neuron/fulltext/S0896-6273(12)00428-X. To create a dual-coded overlay we specify an 'alpha' or transparency image when creating the `Layer`. In this case we will encode the difference in group T1 (essentially effect-size) as color and the p-value (significance) as transparency. Areas of strong color are hence interesting regions, but we will also be able to see areas with a large effect but low significance which normally would be hidden with a simply thresholded single-coded statistical overlay. Note that now the colorbar has become an 'alphabar', with two meaningful axes. Traditional significance levels can be indicated with a contour. Using this method we see that there are there several areas of T1 change that appear anatomically plausible but do not meet the traditional level of significance after multiple comparisons correction." ], "metadata": {} }, { "cell_type": "code", "execution_count": null, "source": [ "dual = ns.Layer(data_dir + 'T1_difference.nii.gz',\n", " cmap='RdYlBu_r', clim=(-100, 100), scale=1000, label='T1 Difference (ms)',\n", " alpha=data_dir + 'T1_tfce_p_tstat1.nii.gz', alpha_lim=(0.5, 1.0), alpha_label='1-p')\n", "ns.three_plane([base, dual], cbar=1, contour=0.95, title='All the Bells & Whistles')" ], "outputs": [], "metadata": {} }, { "cell_type": "markdown", "source": [ "# Controlling Slices\n", "\n", "The above examples all use the `three_plane` function. We can get better control of which slices are shown using the `slice_axis` and `slices` function. `slice_axis` is a thin wrapper that specifies a set of slices along one axis, while `slices` allows full control over which slices are drawn." ], "metadata": {} }, { "cell_type": "code", "execution_count": null, "source": [ "ns.slice_axis([base, dual], nrows=2, ncols=5,\n", " slice_axis='z', slice_lims=(0.3, 0.75),\n", " cbar=1, contour=0.95, title='Two Rows')" ], "outputs": [], "metadata": {} }, { "cell_type": "code", "execution_count": null, "source": [ "slice_ax = ['x','y','z','x','y','z','x','y','z']\n", "slice_pos = [0.2, 0.2, 0.2, 0.3, 0.3, 0.3, 0.5, 0.5, 0.5]\n", "ns.slices([base, dual], nrows=3, ncols=3,\n", " slice_axes=slice_ax, slice_pos=slice_pos,\n", " cbar=1, contour=0.95, title='3x3 Grid')" ], "outputs": [], "metadata": {} }, { "cell_type": "code", "execution_count": null, "source": [], "outputs": [], "metadata": {} } ], "metadata": { "kernel_info": { "name": "python3" }, "kernelspec": { "display_name": "Python 3", "language": "python", "name": "python3" }, "language_info": { "codemirror_mode": { "name": "ipython", "version": 3 }, "file_extension": ".py", "mimetype": "text/x-python", "name": "python", "nbconvert_exporter": "python", "pygments_lexer": "ipython3", "version": "3.6.5" }, "nteract": { "version": "0.8.4" } }, "nbformat": 4, "nbformat_minor": 4 }