Show Sidebar Hide Sidebar

Visualizing MRI Volume Slices in Python

How to create an plotly animation with slider that cycles through MRI cross-sections of a human brain.

New to Plotly?¶

Plotly's Python library is free and open source! Get started by downloading the client and reading the primer.
You can set up Plotly to work in online or offline mode, or in jupyter notebooks.
We also have a quick-reference cheatsheet (new!) to help you get started!

Version Check¶

Note: Animations are available in version 1.12.10+ Run pip install plotly --upgrade to update your Plotly version.

In [1]:
import plotly
plotly.__version__
Out[1]:
'2.0.15'

Import Data¶

In [2]:
import plotly.plotly as py
from plotly.grid_objs import Grid, Column

import time
import numpy as np

from skimage import io

vol = io.imread("https://s3.amazonaws.com/assets.datacamp.com/blog_assets/attention-mri.tif")
volume = vol.T
r, c = volume[0].shape

Set the Color Scale¶

In [3]:
pl_bone = [
    [0.0, 'rgb(0, 0, 0)'],
    [0.05, 'rgb(10, 10, 14)'],
    [0.1, 'rgb(21, 21, 30)'],
    [0.15, 'rgb(33, 33, 46)'],
    [0.2, 'rgb(44, 44, 62)'],
    [0.25, 'rgb(56, 55, 77)'],
    [0.3, 'rgb(66, 66, 92)'],
    [0.35, 'rgb(77, 77, 108)'],
    [0.4, 'rgb(89, 92, 121)'],
    [0.45, 'rgb(100, 107, 132)'],
    [0.5, 'rgb(112, 123, 143)'],
    [0.55, 'rgb(122, 137, 154)'],
    [0.6, 'rgb(133, 153, 165)'],
    [0.65, 'rgb(145, 169, 177)'],
    [0.7, 'rgb(156, 184, 188)'],
    [0.75, 'rgb(168, 199, 199)'],
    [0.8, 'rgb(185, 210, 210)'],
    [0.85, 'rgb(203, 221, 221)'],
    [0.9, 'rgb(220, 233, 233)'],
    [0.95, 'rgb(238, 244, 244)'],
    [1.0, 'rgb(255, 255, 255)']
]

Upload the Grid¶

Note: Since you cannot upload a grid with a filename shared by another grid you own in your profile, str(time.time()) is appended to the filename to ensure a unique name is given to the grid.

Note: Due to the magnanimous size of data being uploaded, it will not work unless your daily data upload limit is high enough. Make sure your subscription is above the Free Community version. See the Pricing and Plans page for more information.

In [8]:
my_columns = []
nr_frames = 68
for k in range(nr_frames):
    my_columns.extend(
        [Column((6.7 - k * 0.1) * np.ones((r, c)), 'z{}'.format(k + 1)),
         Column(np.flipud(volume[67 - k]), 'surfc{}'.format(k + 1))]
    )
grid = Grid(my_columns)
py.grid_ops.upload(grid, 'anim_sliceshead'+str(time.time()), auto_open=False)
Out[8]:
u'https://plot.ly/~AdamKulidjian/3668/'

Create Data, Frames, Layout and Sliders¶

In [9]:
data=[
    dict(
        type='surface', 
        zsrc=grid.get_column_reference('z1'),
        surfacecolorsrc=grid.get_column_reference('surfc1'),
        colorscale=pl_bone,
        colorbar=dict(thickness=20, ticklen=4)
    )
]

frames=[]
for k in range(nr_frames):
    frames.append(
        dict(
            data=[dict(zsrc=grid.get_column_reference('z{}'.format(k + 1)),
                       surfacecolorsrc=grid.get_column_reference('surfc{}'.format(k + 1)))],
            name='frame{}'.format(k + 1)
        )
    )

sliders=[
    dict(
        steps=[dict(method='animate',
                    args= [['frame{}'.format(k + 1)],
                            dict(mode='immediate',
                                 frame= dict(duration=70, redraw= False),
                                 transition=dict(duration=0))],
                    label='{:d}'.format(k+1)) for k in range(68)], 
        transition= dict(duration=0),
        x=0,
        y=0, 
        currentvalue=dict(font=dict(size=12), 
                          prefix='slice: ', 
                          visible=True, 
                          xanchor='center'
                         ),  
        len=1.0
    )
]

axis3d = dict(
    showbackground=True, 
    backgroundcolor="rgb(230, 230,230)",
    gridcolor="rgb(255, 255, 255)",      
    zerolinecolor="rgb(255, 255, 255)",  
)

layout3d = dict(
         title='Slices in volumetric data', 
         font=dict(family='Balto'),
         width=600,
         height=600,
         scene=dict(xaxis=(axis3d),
                    yaxis=(axis3d), 
                    zaxis=dict(axis3d, **dict(range=[-0.1, 6.8], autorange=False)), 
                    aspectratio=dict(x=1, y=1, z=1),
                    ),
         updatemenus=[
             dict(type='buttons',
                  showactive=False,
                  y=1,
                  x=1.3,
                  xanchor='right',
                  yanchor='top',
                  pad=dict(t=0, r=10),
                  buttons=[dict(label='Play',
                                method='animate',
                                args=[
                                    None, 
                                    dict(frame=dict(duration=70, redraw=False),
                                         transition=dict(duration=0),
                                         fromcurrent=True,
                                         mode='immediate')
                                ])])
         ],
        sliders=sliders
)

Upload to Plotly¶

In [10]:
fig=dict(data=data, layout=layout3d, frames=frames)
py.icreate_animations(fig, filename='animslicesHead'+str(time.time()))
Out[10]:

Credit:¶

All credit goes to Emilia Petrisor for this excellent animation!

Here's where you can find her:

Reference¶

For additional information and help setting up a slider in an animation, see https://plot.ly/python/gapminder-example/. For more documentation on creating animations with Plotly, see https://plot.ly/python/#animations.

Still need help?
Contact Us

For guaranteed 24 hour response turnarounds, upgrade to a Developer Support Plan.