Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Refactor volume widget #43

Merged
merged 12 commits into from
Nov 14, 2018
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@ var/
*.egg-info/
.installed.cfg
*.egg
.pytest_cache

# PyInstaller
# Usually these files are written by a python script from a template
Expand Down
191 changes: 191 additions & 0 deletions demo_update.ipynb
Original file line number Diff line number Diff line change
@@ -0,0 +1,191 @@
{
"cells": [
{
"cell_type": "code",
"execution_count": 1,
"metadata": {
"scrolled": false
},
"outputs": [
{
"name": "stderr",
"output_type": "stream",
"text": [
"/Users/janfreyberg/anaconda3/envs/py36/lib/python3.6/site-packages/h5py/__init__.py:36: FutureWarning: Conversion of the second argument of issubdtype from `float` to `np.floating` is deprecated. In future, it will be treated as `np.float64 == np.dtype(float).type`.\n",
" from ._conv import register_converters as _register_converters\n"
]
}
],
"source": [
"from niwidgets.niwidget_volume import VolumeWidget, NiftiWidget\n",
"from niwidgets.exampledata import examplet1\n",
"from IPython import display\n"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"The new volume widget works slightly differently: It doesn't rely on `widgets.interact`, and therefore allows more control over the interactive elements, and what happens when they change. For example, we can make cool play buttons to move through the brain smoothly.\n",
"\n",
"You also don't need to call a plotter / rendering function anymore (although you can)."
]
},
{
"cell_type": "code",
"execution_count": 3,
"metadata": {
"scrolled": false
},
"outputs": [
{
"data": {
"application/vnd.jupyter.widget-view+json": {
"model_id": "7932ddd4bdcd4fd883497ad46026882a",
"version_major": 2,
"version_minor": 0
},
"text/plain": [
"VBox(children=(Box(children=(PlaySlider(children=(Label(value='X: '), Play(value=45, interval=300, max=90), In…"
]
},
"metadata": {},
"output_type": "display_data"
}
],
"source": [
"widget = VolumeWidget(examplet1, colormap='viridis')\n",
"\n",
"widget # equivalent to widget.render()"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"Amongst other things, you can now choose whether to follow radiological standards (left-right mirror images). Turned on by default, you can either untick the checkbox, or pass it as an argument to the widget:"
]
},
{
"cell_type": "code",
"execution_count": 4,
"metadata": {},
"outputs": [
{
"data": {
"application/vnd.jupyter.widget-view+json": {
"model_id": "b7df1220e0104e8f9bd32971155cfe17",
"version_major": 2,
"version_minor": 0
},
"text/plain": [
"VBox(children=(Box(children=(PlaySlider(children=(Label(value='X: '), Play(value=45, interval=300, max=90), In…"
]
},
"metadata": {},
"output_type": "display_data"
}
],
"source": [
"widget = VolumeWidget(examplet1, orient_radiology=False)\n",
"\n",
"widget"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"In addition, composing the widget from scratch means that the control elements and plots can re-flow if the page isn't large enough. Try shrinking your browser window, or adjusting the figure size:"
]
},
{
"cell_type": "code",
"execution_count": 5,
"metadata": {
"scrolled": false
},
"outputs": [
{
"data": {
"application/vnd.jupyter.widget-view+json": {
"model_id": "883c5edfafd747fcaa8427d5c0926ba0",
"version_major": 2,
"version_minor": 0
},
"text/plain": [
"VBox(children=(Box(children=(PlaySlider(children=(Label(value='X: '), Play(value=45, interval=300, max=90), In…"
]
},
"metadata": {},
"output_type": "display_data"
}
],
"source": [
"widget = VolumeWidget(examplet1, figsize=(6, 6))\n",
"\n",
"widget"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"Lastly, making the control elements part of the class means you can interact with it more like a normal python object, e.g. get and set the elements of the graph as python attributes:"
]
},
{
"cell_type": "code",
"execution_count": 6,
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"[45, 54, 45]\n",
"viridis\n",
"summer\n"
]
}
],
"source": [
"print(widget.indices)\n",
"print(widget.colormap)\n",
"widget.colormap = 'summer'\n",
"print(widget.colormap)"
]
}
],
"metadata": {
"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.3"
},
"toc": {
"nav_menu": {},
"number_sections": true,
"sideBar": true,
"skip_h1_title": false,
"toc_cell": false,
"toc_position": {},
"toc_section_display": "block",
"toc_window_display": false
}
},
"nbformat": 4,
"nbformat_minor": 2
}
130 changes: 0 additions & 130 deletions figure_handle_update_test.ipynb

This file was deleted.

10 changes: 7 additions & 3 deletions niwidgets/colormaps.py
Original file line number Diff line number Diff line change
@@ -1,13 +1,17 @@
import ipywidgets
from matplotlib import pyplot as plt

# from matplotlib import pyplot as plt


def get_cmap_dropdown(colormap):
# set default colormap options & add them to the kwargs
if colormap is None:
options = (sorted(m for m in plt.cm.datad if not m.endswith("_r")))
# options = (sorted(m for m in plt.cm.datad if not m.endswith("_r")))
options = ['viridis', 'summer', 'gray', 'Blues', 'Greens', 'Greys',
'Oranges', 'Purples', 'Reds', 'nipy_spectral']
return ipywidgets.Dropdown(
options=options, value='summer', description='Colormap:'
options=options, value='viridis', description='Colormap:',
indent=False
)
elif isinstance(colormap, (list, tuple)):
return ipywidgets.Dropdown(
Expand Down
35 changes: 35 additions & 0 deletions niwidgets/controls.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
import ipywidgets as widgets
import traitlets


class PlaySlider(widgets.HBox):
"""
A combined Play / IntSlider widget.
"""

max = traitlets.Integer(100)
min = traitlets.Integer(0)
value = traitlets.Integer(0)
step = traitlets.Integer(1)
interval = traitlets.Integer(500)

def __init__(self, *args, min=0, max=100, value=100, step=1, interval=500,
label='Value', continuous_update=True, **kwargs):

# initialise the hbox widget
super().__init__([
widgets.Label(label + ': '),
widgets.Play(min=min, max=max, value=value,
interval=interval),
widgets.IntSlider(
min=min, max=max, value=value,
step=step, continuous_update=continuous_update
)
])
for trait in ('min', 'max', 'value', 'step'):
# first the two control elements:
widgets.link((self.children[1], trait), (self.children[2], trait))
# then link the latter with self:
widgets.link((self.children[2], trait), (self, trait))

widgets.link((self.children[1], 'interval'), (self, 'interval'))
Loading