{ "cells": [ { "cell_type": "markdown", "id": "intro", "metadata": {}, "source": [ "# Connect and Show\n", "\n", "This notebook is the **hello world** for `mitk-workbench-remote`. You will learn how to:\n", "\n", "- Connect to a running MITK Workbench\n", "- Inspect the connection with `wb.ping()` and `wb.info`\n", "- Show a numpy array in the Workbench with `wb.show()`\n", "- Set visual properties (name, color, opacity)\n", "- Browse the DataStorage\n", "- Enable debug logging\n", "\n", "**Prerequisites:** A running MITK Workbench instance with the REST API enabled." ] }, { "cell_type": "markdown", "id": "sec-connect", "metadata": {}, "source": [ "## 1. Connect to a running Workbench\n", "\n", "`mw.connect()` creates a `Workbench` handle. No HTTP call is made until you use it —\n", "the connection is established lazily on first access.\n", "\n", "Use `wb.ping()` to verify reachability, and `wb.info` to inspect the server." ] }, { "cell_type": "code", "execution_count": 1, "id": "connect", "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "Reachable: True\n", "Server: MITK Workbench REST API\n", "MITK: 2025.12.99-1b4706d3\n", "API: v1\n" ] } ], "source": [ "import mitk_workbench_remote as mw\n", "\n", "wb = mw.connect(\"http://localhost:8080\")\n", "print(f\"Reachable: {wb.ping()}\")\n", "print(f\"Server: {wb.info.name}\")\n", "print(f\"MITK: {wb.info.mitk_version}\")\n", "print(f\"API: {wb.info.api_version}\")" ] }, { "cell_type": "markdown", "id": "52f8c306", "source": [ "### Authenticated connections\n", "\n", "If the Workbench requires authentication (REST API preferences with\n", "`requireAuth=true` and a configured `apiToken`), pass the token to `connect()`.\n", "It is sent as the `Authorization: Bearer ` header on every request:\n", "\n", "```python\n", "wb = mw.connect(\"http://localhost:8080\", token=\"your-api-token\")\n", "```\n", "\n", "`launch()` (covered in the Discovery and Launch notebook) generates and wires a\n", "token for you, so you only need this when connecting to an instance you secured\n", "yourself." ], "metadata": {} }, { "cell_type": "markdown", "id": "sec-show-array", "metadata": {}, "source": [ "## 2. Show a numpy array\n", "\n", "`wb.show()` is the primary one-liner for displaying data. It creates a node,\n", "uploads the data, sets display properties, and reinitialises the render views —\n", "all in a single call.\n", "\n", "The return value is the newly created `DataNode`." ] }, { "cell_type": "code", "execution_count": 2, "id": "show-array", "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "Created node: \n" ] } ], "source": [ "import numpy as np\n", "\n", "# Create a simple gradient volume\n", "size = 64\n", "arr = np.sum(np.indices((size, size, size), dtype=np.float32), axis=0)\n", "arr /= arr.max()\n", "\n", "node = wb.show(arr, name=\"Gradient\")\n", "print(f\"Created node: {node}\")" ] }, { "cell_type": "markdown", "id": "sec-visual-props", "metadata": {}, "source": [ "## 3. Visual properties\n", "\n", "`show()` accepts `color` (RGB tuple, 0.0-1.0) and `opacity` (0.0-1.0) as keyword\n", "arguments." ] }, { "cell_type": "code", "execution_count": 3, "id": "visual-props", "metadata": {}, "outputs": [], "source": [ "# Show a second volume with visual properties set at creation\n", "mask = (arr > 0.5).astype(np.uint8)\n", "mask_node = wb.show(mask, name=\"Threshold\", color=(1.0, 0.0, 0.0), opacity=0.5)" ] }, { "cell_type": "markdown", "id": "bd4d0113", "metadata": { "collapsed": false, "jupyter": { "outputs_hidden": false } }, "source": [ "You can also change them afterwards via the node's properties. The new property values will be directly transferred. In order to update the rendering, you have to call update on the workbench." ] }, { "cell_type": "code", "execution_count": 4, "id": "7ce7ca82", "metadata": { "collapsed": false, "jupyter": { "outputs_hidden": false } }, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "Color: (0.0, 1.0, 0.0)\n", "Opacity: 0.20000000298023224\n" ] } ], "source": [ "# Change properties after creation\n", "mask_node.color = (0.0, 1.0, 0.0)\n", "mask_node.opacity = 0.2\n", "wb.update()\n", "\n", "print(f\"Color: {mask_node.color}\")\n", "print(f\"Opacity: {mask_node.opacity}\")" ] }, { "cell_type": "markdown", "id": "sec-browse", "metadata": {}, "source": [ "## 4. Browse the DataStorage\n", "\n", "The `wb.storage` object provides iteration, `len()`, and `__getitem__` access\n", "over all nodes in the Workbench's DataStorage. In Jupyter, it renders as an\n", "HTML table." ] }, { "cell_type": "code", "execution_count": 5, "id": "browse", "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "Total nodes: 6\n", "\n", " node_3 stdmulti.widget0.plane type=PlaneGeometryData\n", " node_5 stdmulti.widget1.plane type=PlaneGeometryData\n", " node_6 stdmulti.widget2.plane type=PlaneGeometryData\n", " node_4 Widgets type=None\n", " node_2 Threshold type=Image\n", " node_1 Gradient type=Image\n" ] } ], "source": [ "print(f\"Total nodes: {len(wb.storage)}\\n\")\n", "\n", "for n in wb.storage:\n", " print(f\" {n.uid:10s} {n._name:20s} type={n.data_type}\")" ] }, { "cell_type": "code", "execution_count": 6, "id": "browse-rich", "metadata": {}, "outputs": [ { "data": { "text/plain": "DataStorage(url='http://localhost:8080')", "text/html": "
uidnametypepath
node_3stdmulti.widget0.planePlaneGeometryData/Widgets/stdmulti.widget0.plane
node_5stdmulti.widget1.planePlaneGeometryData/Widgets/stdmulti.widget1.plane
node_6stdmulti.widget2.planePlaneGeometryData/Widgets/stdmulti.widget2.plane
node_4Widgets/Widgets
node_2ThresholdImage/Threshold
node_1GradientImage/Gradient
" }, "execution_count": 6, "metadata": {}, "output_type": "execute_result" } ], "source": [ "# Rich display in Jupyter\n", "wb.storage" ] }, { "cell_type": "markdown", "id": "sec-logging", "metadata": {}, "source": [ "## 5. Enable debug logging\n", "\n", "`mitk-workbench-remote` uses Python's standard `logging` module. By default\n", "all output is suppressed (NullHandler). Enable it to see HTTP requests,\n", "transfer mode negotiation, and other internals.\n", "\n", "You can also filter to a specific sub-logger, e.g.\n", "`logging.getLogger(\"mitk_workbench_remote.transport\").setLevel(logging.DEBUG)`." ] }, { "cell_type": "code", "execution_count": 7, "id": "logging", "metadata": {}, "outputs": [ { "name": "stderr", "output_type": "stream", "text": [ "urllib3.connectionpool DEBUG http://localhost:8080 \"GET /api/v1/health HTTP/1.1\" 200 90\n", "mitk_workbench_remote.transport DEBUG [http://localhost:8080] GET /health -> 200 (0ms)\n", "mitk_workbench_remote.workbench DEBUG [http://localhost:8080] ping -> True\n" ] }, { "data": { "text/plain": "True" }, "execution_count": 7, "metadata": {}, "output_type": "execute_result" } ], "source": [ "import logging\n", "\n", "logging.basicConfig(level=logging.DEBUG, format=\"%(name)s %(levelname)s %(message)s\")\n", "\n", "# This call will now print DEBUG output showing the HTTP request\n", "wb.ping()" ] }, { "cell_type": "code", "execution_count": 8, "id": "logging-reset", "metadata": {}, "outputs": [], "source": [ "# Reset to suppress logging for the rest of the notebook\n", "logging.getLogger().setLevel(logging.WARNING)\n", "logging.getLogger(\"mitk_workbench_remote\").setLevel(logging.WARNING)" ] }, { "cell_type": "markdown", "id": "sec-cleanup", "metadata": {}, "source": [ "## 6. Clean up" ] }, { "cell_type": "code", "execution_count": 9, "id": "cleanup", "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "Done.\n" ] } ], "source": [ "node.remove()\n", "mask_node.remove()\n", "print(\"Done.\")" ] } ], "metadata": { "kernelspec": { "display_name": "Python 3 (ipykernel)", "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.12.1" } }, "nbformat": 4, "nbformat_minor": 5 }