{ "cells": [ { "cell_type": "markdown", "metadata": { "tags": [] }, "source": [ "# Slicer Jupyter using docker\n", "\n", "This notebook is shows how views and full application window can be displayed and configured to be used in JupyterLab when Slicer runs in a **docker container** or on a **remote workstation**.\n", "\n", "It relies on a remote desktop connection and web proxy set up in the [slicer-notebook docker image](https://github.com/Slicer/SlicerDocker/tree/master/slicer-notebook).\n", "\n", "This notebook can be [run in the web browser via Binder](https://mybinder.org/v2/gh/slicer/SlicerNotebooks/master?filepath=05_SlicerDockerNotebook.ipynb) or locally using a Jupyter server started by this command:\n", "\n", " docker run -p 8888:8888 -p49053:49053 -v path/to/my/notebooks:/home/sliceruser/work --rm -ti lassoan/slicer-notebook:latest\n", " \n", "Notes:\n", "- Replace `path/to/my/notebooks` by the actual local path to your notebook folder.\n", "- After the container is started, open `https://127.0.0.1:8888` page in your web browser and copy-paste the token from the docker container's output." ] }, { "cell_type": "code", "execution_count": 1, "metadata": { "tags": [] }, "outputs": [], "source": [ "# Read an image using SimpleITK\n", "\n", "import JupyterNotebooksLib as slicernb\n", "import slicer\n", "import SimpleITK as sitk\n", "import sitkUtils as su\n", "\n", "# Load 3D image using SimpleITK\n", "reader = sitk.ImageFileReader()\n", "reader.SetFileName(\"data/MRBrainTumor1.nrrd\")\n", "image = reader.Execute()" ] }, { "cell_type": "code", "execution_count": 2, "metadata": { "tags": [] }, "outputs": [ { "data": { "application/vnd.jupyter.widget-view+json": { "model_id": "03771e9b05c448c7a9861e5243e6189b", "version_major": 2, "version_minor": 0 }, "text/plain": [ "VBox(children=(ViewSliceWidget(children=(FloatSlider(value=0.0, description='Offset', max=78.40000000000003, m…" ] }, "metadata": {}, "output_type": "display_data" } ], "source": [ "# Get the SimpleITK image into the Slicer scene\n", "slicer.mrmlScene.Clear(False) # clear any previously loaded data from the scene\n", "volumeNode = su.PushVolumeToSlicer(image)\n", "\n", "# Show volume in slice views\n", "slicernb.ViewDisplay(\"FourUp\") # choose a layout where 3 slice views are present\n", "slicer.util.setSliceViewerLayers(background=volumeNode, fit=True) # show this volume in slice viewers\n", "\n", "# Create slice view widgets in the notebook\n", "from ipywidgets import VBox\n", "viewWidgets = VBox([slicernb.ViewSliceWidget('Red'), slicernb.ViewSliceWidget('Yellow'), slicernb.ViewSliceWidget('Green')])\n", "viewWidgets.layout.max_width=\"400px\"\n", "display(viewWidgets)" ] }, { "cell_type": "code", "execution_count": 3, "metadata": {}, "outputs": [], "source": [ "# Apply some processing and view the udpated results\n", "\n", "# Process image\n", "blurFilter = sitk.SmoothingRecursiveGaussianImageFilter()\n", "blurFilter.SetSigma(1.0)\n", "blurredImage = blurFilter.Execute(image)\n", "\n", "# Update view widgets (without this, the user would need to move the sliders to get an updated image)\n", "su.PushVolumeToSlicer(blurredImage, targetNode=volumeNode)\n", "for viewWidget in viewWidgets.children:\n", " viewWidget.sliceView.updateImage()" ] }, { "cell_type": "code", "execution_count": 4, "metadata": { "tags": [] }, "outputs": [ { "data": { "text/html": [ "\n", " <iframe\n", " width=\"960\"\n", " height=\"768\"\n", " src=\"/desktop/\"\n", " frameborder=\"0\"\n", " allowfullscreen\n", " \n", " ></iframe>\n", " " ], "text/plain": [ "<JupyterNotebooksLib.widgets.AppWindow at 0x247fa76d9d0>" ] }, "metadata": {}, "output_type": "display_data" } ], "source": [ "# Set up application window\n", "app = slicernb.AppWindow()\n", "# Hide patient information from slice view\n", "slicernb.showSliceViewAnnotations(False)\n", "\n", "# Show markups toolbar\n", "slicer.modules.markups.toolBarVisible=True\n", "\n", "# Show volume in 3D view using volume rendering\n", "slicernb.showVolumeRendering(volumeNode, True)\n", "\n", "display(app)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## Add markups\n", "Before executing the next cell, add markups to the scene: click on the toolbar buttons to create markups, then click in the viewers to place them.\n", "\n", "If no markups are added then the output of the next cell will be empty." ] }, { "cell_type": "code", "execution_count": 7, "metadata": {}, "outputs": [ { "data": { "text/html": [ "<h3>Markup: OC</h3>" ], "text/plain": [ "<IPython.core.display.HTML object>" ] }, "metadata": {}, "output_type": "display_data" }, { "data": { "text/html": [ "<div>\n", "<style scoped>\n", " .dataframe tbody tr th:only-of-type {\n", " vertical-align: middle;\n", " }\n", "\n", " .dataframe tbody tr th {\n", " vertical-align: top;\n", " }\n", "\n", " .dataframe thead th {\n", " text-align: right;\n", " }\n", "</style>\n", "<table border=\"1\" class=\"dataframe\">\n", " <thead>\n", " <tr style=\"text-align: right;\">\n", " <th></th>\n", " <th>label</th>\n", " <th>position.R</th>\n", " <th>position.A</th>\n", " <th>position.S</th>\n", " <th>selected</th>\n", " <th>visible</th>\n", " <th>description</th>\n", " </tr>\n", " </thead>\n", " <tbody>\n", " <tr>\n", " <th>0</th>\n", " <td>OC-1</td>\n", " <td>56.622961</td>\n", " <td>-12.807881</td>\n", " <td>0.7</td>\n", " <td>True</td>\n", " <td>True</td>\n", " <td></td>\n", " </tr>\n", " <tr>\n", " <th>1</th>\n", " <td>OC-2</td>\n", " <td>-22.919169</td>\n", " <td>-16.178310</td>\n", " <td>0.7</td>\n", " <td>True</td>\n", " <td>True</td>\n", " <td></td>\n", " </tr>\n", " <tr>\n", " <th>2</th>\n", " <td>OC-3</td>\n", " <td>-22.919169</td>\n", " <td>-16.178310</td>\n", " <td>0.7</td>\n", " <td>True</td>\n", " <td>True</td>\n", " <td></td>\n", " </tr>\n", " <tr>\n", " <th>3</th>\n", " <td>OC-4</td>\n", " <td>-34.378628</td>\n", " <td>56.622961</td>\n", " <td>0.7</td>\n", " <td>True</td>\n", " <td>True</td>\n", " <td></td>\n", " </tr>\n", " </tbody>\n", "</table>\n", "</div>" ], "text/plain": [ " label position.R position.A position.S selected visible description\n", "0 OC-1 56.622961 -12.807881 0.7 True True \n", "1 OC-2 -22.919169 -16.178310 0.7 True True \n", "2 OC-3 -22.919169 -16.178310 0.7 True True \n", "3 OC-4 -34.378628 56.622961 0.7 True True " ] }, "metadata": {}, "output_type": "display_data" }, { "data": { "text/html": [ "<h3>Markup: A</h3>" ], "text/plain": [ "<IPython.core.display.HTML object>" ] }, "metadata": {}, "output_type": "display_data" }, { "data": { "text/html": [ "<div>\n", "<style scoped>\n", " .dataframe tbody tr th:only-of-type {\n", " vertical-align: middle;\n", " }\n", "\n", " .dataframe tbody tr th {\n", " vertical-align: top;\n", " }\n", "\n", " .dataframe thead th {\n", " text-align: right;\n", " }\n", "</style>\n", "<table border=\"1\" class=\"dataframe\">\n", " <thead>\n", " <tr style=\"text-align: right;\">\n", " <th></th>\n", " <th>label</th>\n", " <th>position.R</th>\n", " <th>position.A</th>\n", " <th>position.S</th>\n", " <th>selected</th>\n", " <th>visible</th>\n", " <th>description</th>\n", " </tr>\n", " </thead>\n", " <tbody>\n", " <tr>\n", " <th>0</th>\n", " <td>A-1</td>\n", " <td>30.814281</td>\n", " <td>0.4685</td>\n", " <td>40.719202</td>\n", " <td>True</td>\n", " <td>True</td>\n", " <td></td>\n", " </tr>\n", " <tr>\n", " <th>1</th>\n", " <td>A-2</td>\n", " <td>57.226737</td>\n", " <td>0.4685</td>\n", " <td>19.149030</td>\n", " <td>True</td>\n", " <td>True</td>\n", " <td></td>\n", " </tr>\n", " <tr>\n", " <th>2</th>\n", " <td>A-3</td>\n", " <td>44.020509</td>\n", " <td>0.4685</td>\n", " <td>11.225294</td>\n", " <td>True</td>\n", " <td>True</td>\n", " <td></td>\n", " </tr>\n", " </tbody>\n", "</table>\n", "</div>" ], "text/plain": [ " label position.R position.A position.S selected visible description\n", "0 A-1 30.814281 0.4685 40.719202 True True \n", "1 A-2 57.226737 0.4685 19.149030 True True \n", "2 A-3 44.020509 0.4685 11.225294 True True " ] }, "metadata": {}, "output_type": "display_data" }, { "data": { "text/html": [ "<h3>Markup: F</h3>" ], "text/plain": [ "<IPython.core.display.HTML object>" ] }, "metadata": {}, "output_type": "display_data" }, { "data": { "text/html": [ "<div>\n", "<style scoped>\n", " .dataframe tbody tr th:only-of-type {\n", " vertical-align: middle;\n", " }\n", "\n", " .dataframe tbody tr th {\n", " vertical-align: top;\n", " }\n", "\n", " .dataframe thead th {\n", " text-align: right;\n", " }\n", "</style>\n", "<table border=\"1\" class=\"dataframe\">\n", " <thead>\n", " <tr style=\"text-align: right;\">\n", " <th></th>\n", " <th>label</th>\n", " <th>position.R</th>\n", " <th>position.A</th>\n", " <th>position.S</th>\n", " <th>selected</th>\n", " <th>visible</th>\n", " <th>description</th>\n", " </tr>\n", " </thead>\n", " <tbody>\n", " <tr>\n", " <th>0</th>\n", " <td>F-1</td>\n", " <td>-0.469</td>\n", " <td>84.299504</td>\n", " <td>27.072767</td>\n", " <td>True</td>\n", " <td>True</td>\n", " <td></td>\n", " </tr>\n", " <tr>\n", " <th>1</th>\n", " <td>F-2</td>\n", " <td>-0.469</td>\n", " <td>-30.594678</td>\n", " <td>9.024256</td>\n", " <td>True</td>\n", " <td>True</td>\n", " <td></td>\n", " </tr>\n", " <tr>\n", " <th>2</th>\n", " <td>F-3</td>\n", " <td>-0.469</td>\n", " <td>36.757084</td>\n", " <td>-7.263425</td>\n", " <td>True</td>\n", " <td>True</td>\n", " <td></td>\n", " </tr>\n", " <tr>\n", " <th>3</th>\n", " <td>F-4</td>\n", " <td>-0.469</td>\n", " <td>27.072517</td>\n", " <td>30.594428</td>\n", " <td>True</td>\n", " <td>True</td>\n", " <td></td>\n", " </tr>\n", " <tr>\n", " <th>4</th>\n", " <td>F-5</td>\n", " <td>-0.469</td>\n", " <td>-14.747204</td>\n", " <td>-45.121278</td>\n", " <td>True</td>\n", " <td>True</td>\n", " <td></td>\n", " </tr>\n", " <tr>\n", " <th>5</th>\n", " <td>F-6</td>\n", " <td>-0.469</td>\n", " <td>-45.121528</td>\n", " <td>-48.642939</td>\n", " <td>True</td>\n", " <td>True</td>\n", " <td></td>\n", " </tr>\n", " <tr>\n", " <th>6</th>\n", " <td>F-7</td>\n", " <td>-0.469</td>\n", " <td>-64.050455</td>\n", " <td>-24.431521</td>\n", " <td>True</td>\n", " <td>True</td>\n", " <td></td>\n", " </tr>\n", " <tr>\n", " <th>7</th>\n", " <td>F-8</td>\n", " <td>-0.469</td>\n", " <td>1.540477</td>\n", " <td>52.164600</td>\n", " <td>True</td>\n", " <td>True</td>\n", " <td></td>\n", " </tr>\n", " <tr>\n", " <th>8</th>\n", " <td>F-9</td>\n", " <td>-0.469</td>\n", " <td>85.620127</td>\n", " <td>-36.757334</td>\n", " <td>True</td>\n", " <td>True</td>\n", " <td></td>\n", " </tr>\n", " <tr>\n", " <th>9</th>\n", " <td>F-10</td>\n", " <td>-0.469</td>\n", " <td>36.316876</td>\n", " <td>-40.278995</td>\n", " <td>True</td>\n", " <td>True</td>\n", " <td></td>\n", " </tr>\n", " </tbody>\n", "</table>\n", "</div>" ], "text/plain": [ " label position.R position.A position.S selected visible description\n", "0 F-1 -0.469 84.299504 27.072767 True True \n", "1 F-2 -0.469 -30.594678 9.024256 True True \n", "2 F-3 -0.469 36.757084 -7.263425 True True \n", "3 F-4 -0.469 27.072517 30.594428 True True \n", "4 F-5 -0.469 -14.747204 -45.121278 True True \n", "5 F-6 -0.469 -45.121528 -48.642939 True True \n", "6 F-7 -0.469 -64.050455 -24.431521 True True \n", "7 F-8 -0.469 1.540477 52.164600 True True \n", "8 F-9 -0.469 85.620127 -36.757334 True True \n", "9 F-10 -0.469 36.316876 -40.278995 True True " ] }, "metadata": {}, "output_type": "display_data" } ], "source": [ "# Display control point positions in each markup node.\n", "from IPython.display import HTML\n", "for markupsNode in slicer.util.getNodesByClass(\"vtkMRMLMarkupsNode\"):\n", " display(HTML(f\"<h3>Markup: {markupsNode.GetName()}</h3>\"))\n", " display(slicernb.displayable(markupsNode))" ] }, { "cell_type": "code", "execution_count": 8, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "'OC'" ] }, "execution_count": 8, "metadata": {}, "output_type": "execute_result" } ], "source": [ "markupsNode = slicer.util.getNodesByClass(\"vtkMRMLMarkupsNode\")[0]\n", "markupsNode.GetName()" ] }, { "cell_type": "code", "execution_count": 9, "metadata": {}, "outputs": [], "source": [ "# Show full markups module GUI\n", "app.setContents(\"viewers\")\n", "slicer.util.findChild(slicer.util.mainWindow(), \"PanelDockWidget\").show()\n", "slicer.modules.markups.toolBarVisible=True\n", "slicer.util.selectModule(\"Markups\")" ] }, { "cell_type": "code", "execution_count": 10, "metadata": {}, "outputs": [], "source": [ "# Show full application GUI\n", "app.setContents(\"full\")" ] }, { "cell_type": "code", "execution_count": 11, "metadata": {}, "outputs": [ { "data": { "application/vnd.jupyter.widget-view+json": { "model_id": "e506318ecb204be2a57cacab1234c877", "version_major": 2, "version_minor": 0 }, "text/plain": [ "HTML(value='<a href=\"/desktop/\" target=\"_blank\">\\n<b>Click here</b> to open application window in a new browse…" ] }, "metadata": {}, "output_type": "display_data" } ], "source": [ "# Create link that shows the application GUI in a new browser tab\n", "from ipywidgets import HTML\n", "HTML(f\"\"\"<a href=\"{slicernb.AppWindow.defaultDesktopUrl()}\" target=\"_blank\">\n", "<b>Click here</b> to open application window in a new browser tab.</a>\"\"\")" ] }, { "cell_type": "code", "execution_count": 12, "metadata": {}, "outputs": [], "source": [ "# Show only viewers\n", "app.setContents(\"viewers\")" ] }, { "cell_type": "code", "execution_count": 13, "metadata": { "tags": [] }, "outputs": [ { "data": { "application/vnd.jupyter.widget-view+json": { "model_id": "7a95bed771e74a8697dc5ee53155f9f6", "version_major": 2, "version_minor": 0 }, "text/plain": [ "HBox(children=(Button(description='Full', style=ButtonStyle()), Button(description='Viewers', style=ButtonStyl…" ] }, "metadata": {}, "output_type": "display_data" } ], "source": [ "from ipywidgets import Button, HBox\n", "import JupyterNotebooksLib as slicernb\n", "fullButton = Button(description='Full')\n", "fullButton.on_click(lambda b: slicernb.AppWindow().setContents(\"full\"))\n", "viewersButton = Button(description='Viewers')\n", "viewersButton.on_click(lambda b: slicernb.AppWindow().setContents(\"viewers\"))\n", "markupsToolbarToggleButton = Button(description='Markups toolbar')\n", "def toggleMarkupsToolBar(b):\n", " slicer.modules.markups.toolBarVisible = not slicer.modules.markups.toolBarVisible\n", "markupsToolbarToggleButton.on_click(toggleMarkupsToolBar)\n", "HBox([fullButton, viewersButton, markupsToolbarToggleButton]) " ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "#### Run this example in your browser using Binder: [](https://mybinder.org/v2/gh/slicer/SlicerNotebooks/master?filepath=05_SlicerDockerNotebook.ipynb)" ] } ], "metadata": { "kernelspec": { "display_name": "Slicer 4.13", "language": "python", "name": "slicer-4.13" }, "language_info": { "file_extension": ".py", "mimetype": "text/x-python", "name": "python", "version": "3.9.10" } }, "nbformat": 4, "nbformat_minor": 4 }