{ "cells": [ { "cell_type": "markdown", "metadata": { "deletable": true, "editable": true }, "source": [ "PyAnatomist tutorial\n", "====================\n", "\n", "Programming with Anatomist in Python language\n", "---------------------------------------------\n", "\n", "Anatomist is written in C++ language but has also a python API:\n", "**PyAnatomist**. This python API enables to drive Anatomist application\n", "through python scripts : using Anatomist, loading volumes, meshes,\n", "graphs, viewing them in windows, merging objects, changing color\n", "palettes, etc... It can be useful in order to automate a repetitive\n", "visualization task or to add features to Anatomist application by\n", "developping a python plugin, which is much more easier than developping\n", "directly in Anatomist C++ library. Actually, several features in\n", "Anatomist have been added via a python plugin like the gradient palette\n", "for example. The python API is also used by several viewers in\n", "BrainVISA.\n", "\n", "Description of the API\n", "----------------------\n", "\n", "The main entry point is the [Anatomist](pyanatomist_base.html#anatomist.base.Anatomist) class which must be instantiated\n", "before any operation can be performed. It represents Anatomist\n", "application. This class contains a number of nested classes:\n", "[AObject](pyanatomist_base.html#anatomist.base.Anatomist.AObject), [AWindow](pyanatomist_base.html#anatomist.base.Anatomist.AWindow)... that represent the elements\n", "of Anatomist application.\n", "\n", "This notebook is using Qt gui, so first of all let's do:" ] }, { "cell_type": "code", "execution_count": 1, "metadata": { "collapsed": true, "deletable": true, "editable": true }, "outputs": [], "source": [ "import os\n", "os.environ[\"QT_API\"] = \"pyqt5\"\n", "%gui qt" ] }, { "cell_type": "markdown", "metadata": { "deletable": true, "editable": true }, "source": [ "The entry point of this API is the module **anatomist.api**, you can\n", "import it as below:" ] }, { "cell_type": "code", "execution_count": 2, "metadata": { "collapsed": false, "deletable": true, "editable": true }, "outputs": [], "source": [ "import anatomist.api as anatomist" ] }, { "cell_type": "markdown", "metadata": { "deletable": true, "editable": true }, "source": [ "And then create an instance of Anatomist:" ] }, { "cell_type": "code", "execution_count": 3, "metadata": { "collapsed": false, "deletable": true, "editable": true }, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "global modules: /volatile/riviere/brainvisa/build-stable-qt5/share/anatomist-4.6/python_plugins\n", "home modules: /home/dr144257/.anatomist/python_plugins\n", "loading module palettecontrols\n", "loading module profilewindow\n", "loading module bundles_split_by_cortical_regions\n", "loading module foldsplit\n", "loading module volumepalettes\n", "loading module paletteViewer\n", "loading module bundles_small_brains\n", "loading module bsa_proba\n", "loading module meshsplit\n", "loading module selection\n", "loading module gradientpalette\n", "loading module anacontrolmenu\n", "loading module histogram\n", "loading module modelGraphs\n", "loading module synccameracontrol\n", "all python modules loaded\n", "Anatomist started.\n" ] } ], "source": [ "a = anatomist.Anatomist()" ] }, { "cell_type": "markdown", "metadata": { "deletable": true, "editable": true }, "source": [ "So you can send commands to Anatomist application, for example creating\n", "a window:" ] }, { "cell_type": "code", "execution_count": 4, "metadata": { "collapsed": true, "deletable": true, "editable": true }, "outputs": [], "source": [ "window = a.createWindow('3D')" ] }, { "cell_type": "markdown", "metadata": { "deletable": true, "editable": true }, "source": [ "Implementation\n", "--------------\n", "\n", "Several means of driving Anatomist in python scripts exist :\n", "\n", "- **Python bindings for the C++ library** (SIP bindings). In this\n", " mode, all bound features are available. You handle directly the\n", " Anatomist objects. But Anatomist is loaded directly in your python\n", " program, it is not an independent program in this mode. So the\n", " errors that occur in Anatomist are reported in the python script.\n", "- **Sending commands via a network socket**. Anatomist is run in\n", " server mode and listen for commands on the socket connection. In\n", " this mode, the available features are limited to what can be\n", " expressed with Anatomist commands system, so a limited set of\n", " features. A list of these commands can be found\n", " [here (main page in french, sorry)](../../anatomist/html/fr/programmation/commands.html).\n", " You cannot handle directly the Anatomist objects, they are\n", " represented by a key. But Anatomist application runs in a separate\n", " process so potential errors in Anatomist don't crash the application\n", " that uses the API.\n", "\n", "Behind a general interface, this api provides 2 implementations, one for\n", "each method of communication with Anatomist.\n", "\n", "The implementation that uses the python bindings is called *direct*\n", "implementation and is in the module\n", "[anatomist.direct.api](pyanatomist_direct.html). The implementation that\n", "uses socket communication is called *socket* implementation and is in\n", "the module anatomist.socket.api [anatomist.socket.api](pyanatomist_socket.html). By default, the\n", "implementation used when you import anatomist.api is the *direct*\n", "implementation.\n", "\n", "A third implementation is a thread-safe variant of the direct module:\n", "[anatomist.threaded.api](pyanatomist_threaded.html) module. It redirects\n", "every call to the API to be actually called from the main thread. It is\n", "obviously slower.\n", "\n", "Another specific implementation for Brainvisa also exists:\n", "*brainvisa.anatomist* module. It enables to use brainvisa database\n", "information on loaded objects to automatically load associated\n", "referentials and transformations. It uses the same api, so it is\n", "possible to switch from one implementation to the other.\n", "\n", "By default, the brainvisa module uses the threaded implementation. But\n", "it is possible to switch to the socket implementation in the\n", "configuration options.\n", "\n", "Using the API\n", "-------------\n", "\n", "In this part, we will use the same story as in the\n", "[anatomist tutorial](../../anatomist/user_doc/anatomist_tutorial.html) and see how to\n", "do the same with a python script. The data for the examples in this\n", "section are the same:\n", ".\n", "\n", "The following examples use the general API functions that are available\n", "in both direct and socket implementations. To run the following\n", "examples, we will use an interactive python shell\n", "[IPython](http://ipython.org). It is much more practical than the\n", "classic python shell because it offers useful features like automatic\n", "completion. This program is available in the BrainVISA package with all\n", "other executable programs in the *bin* directory of the BrainVISA\n", "package directory. *IPython* should be run with the option *--gui=qt*,\n", "which runs a Qt event loop, needed for the graphical interface." ] }, { "cell_type": "markdown", "metadata": { "attributes": { "classes": [ "sourceCode" ], "id": "" }, "deletable": true, "editable": true }, "source": [ "
\n",
    "<brainvisa_installation_directory>/bin/ipython --gui=qt
\n" ] }, { "cell_type": "markdown", "metadata": { "deletable": true, "editable": true }, "source": [ "The following code is to work in a temporary directory, download and uncompress the demo data." ] }, { "cell_type": "code", "execution_count": 4, "metadata": { "collapsed": false, "deletable": true, "editable": true }, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "we are working in: /tmp/pyanatomist_tutorial_E7iVO2\n" ] } ], "source": [ "from __future__ import print_function\n", "import urllib2\n", "import zipfile\n", "import os\n", "import os.path\n", "import tempfile\n", "# let's work in a temporary directory\n", "tuto_dir = tempfile.mkdtemp(prefix='pyanatomist_tutorial_')\n", "f = urllib2.urlopen('ftp://ftp.cea.fr/pub/dsv/anatomist/data/demo_data.zip')\n", "demo_data = os.path.join(tuto_dir, 'demo_data.zip')\n", "open(demo_data, 'w').write(f.read())\n", "f.close()\n", "older_cwd = os.getcwd()\n", "os.chdir(tuto_dir)\n", "f = zipfile.ZipFile(demo_data)\n", "f.extractall()\n", "del f\n", "print('we are working in:', tuto_dir)" ] }, { "cell_type": "markdown", "metadata": { "deletable": true, "editable": true }, "source": [ "### Run Anatomist\n", "\n", "First of all, we need to import anatomist API module. Here, in a Python\n", "shell, the default implementation is the direct one (Python bindings).\n", "\n", "Then we can create an instance of Anatomist class." ] }, { "cell_type": "code", "execution_count": 6, "metadata": { "collapsed": true, "deletable": true, "editable": true }, "outputs": [], "source": [ "import anatomist.api as ana\n", "\n", "a = ana.Anatomist()" ] }, { "cell_type": "markdown", "metadata": { "deletable": true, "editable": true }, "source": [ "### Load an object\n", "\n", "In this example, we will put the path to the *data\\_for\\_anatomist*\n", "directory in a variable named src. We will use this variable in all the\n", "next examples. We will also load a python module named *os* which has\n", "useful functions to handle files and paths." ] }, { "cell_type": "code", "execution_count": 7, "metadata": { "collapsed": true, "deletable": true, "editable": true }, "outputs": [], "source": [ "import os\n", "src = tuto_dir\n", "# Load an object\n", "t1mri = a.loadObject(os.path.join(src, \"data_for_anatomist\", \"subject01\", \"subject01.nii\"))" ] }, { "cell_type": "markdown", "metadata": { "deletable": true, "editable": true }, "source": [ "See\n", "[the corresponding actions in the graphical interface](../../anatomist/user_doc/anatomist_tutorial.html#load-an-object).\n", "\n", "### View an object\n", "\n", "We open an axial window and add the volume loaded in the previous\n", "example in this window." ] }, { "cell_type": "code", "execution_count": 8, "metadata": { "collapsed": true, "deletable": true, "editable": true }, "outputs": [], "source": [ "# view an object\n", "axial = a.createWindow(\"Axial\")\n", "axial.addObjects(t1mri)" ] }, { "cell_type": "markdown", "metadata": { "deletable": true, "editable": true }, "source": [ "See\n", "[the corresponding actions in the graphical interface](../../anatomist/user_doc/anatomist_tutorial.html#view-an-object).\n", "\n", "When opening a new window, it is possible to change its initial position\n", "and size with the *geometry* parameter. This parameter is a list of 4\n", "values (in pixels) : [x, y, width, height]." ] }, { "cell_type": "code", "execution_count": 9, "metadata": { "collapsed": true, "deletable": true, "editable": true }, "outputs": [], "source": [ "# customizing the position and size of a new window:\n", "# the windows will be displayed at position (100, 150)\n", "# with a size of (300, 300)\n", "w = a.createWindow(\"Axial\", geometry=[100, 150, 300, 300])" ] }, { "cell_type": "markdown", "metadata": { "deletable": true, "editable": true }, "source": [ "### Windows block\n", "\n", "We create 4 views in the same windows block and add the image in each\n", "views." ] }, { "cell_type": "code", "execution_count": 10, "metadata": { "collapsed": true, "deletable": true, "editable": true }, "outputs": [], "source": [ "# view an object in a 4 views block\n", "block = a.createWindowsBlock(2) # 2 columns\n", "w1 = a.createWindow(\"Axial\", block=block)\n", "w2 = a.createWindow(\"Sagittal\", block=block)\n", "w3 = a.createWindow(\"Coronal\", block=block)\n", "w4 = a.createWindow(\"3D\", block=block)\n", "t1mri.addInWindows([w1, w2, w3, w4])" ] }, { "cell_type": "markdown", "metadata": { "deletable": true, "editable": true }, "source": [ "### Move the cursor" ] }, { "cell_type": "code", "execution_count": 11, "metadata": { "collapsed": false, "deletable": true, "editable": true }, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "\n", "Cursor at : \n", "(161.24998474121094, 148.75975036621094, 77.3426513671875)\n", "\n", "Cursor at : \n", "(150.0, 100.0, 60.0)\n" ] } ], "source": [ "# show the cursor position\n", "print(\"\\nCursor at : \", a.linkCursorLastClickedPosition())\n", "# move the linked cursor \n", "w1.moveLinkedCursor([150, 100, 60])\n", "print(\"\\nCursor at : \", a.linkCursorLastClickedPosition())" ] }, { "cell_type": "markdown", "metadata": { "deletable": true, "editable": true }, "source": [ "### Camera\n", "\n", "This method enables to change the [camera](pyanatomist_base.html#anatomist.base.Anatomist.AWindow.camera) parameters\n", "of a window. In this example, we change the zoom." ] }, { "cell_type": "code", "execution_count": 12, "metadata": { "collapsed": true, "deletable": true, "editable": true }, "outputs": [], "source": [ "axial.camera(zoom=2)" ] }, { "cell_type": "markdown", "metadata": { "deletable": true, "editable": true }, "source": [ "You can also change the rotation of the view by changing the\n", "*view\\_quaternion* parameters. The rotation is represented by a\n", "quaternion which is a vector with 4 parameters.\n", "\n", "As the interpretation of quaternions is not easy at first time, it is\n", "useful to look at the current value of the parameter in a window with\n", "the method [getInfos](pyanatomist_base.html#anatomist.base.Anatomist.AItem.getInfos)." ] }, { "cell_type": "code", "execution_count": 13, "metadata": { "collapsed": true, "deletable": true, "editable": true }, "outputs": [], "source": [ "axial.getInfos()\n", "axial.camera(view_quaternion=[0.9, -0.2, -0.2, 0.3])" ] }, { "cell_type": "markdown", "metadata": { "deletable": true, "editable": true }, "source": [ "It is possible to change the orientation of the slice plane with the\n", "parameter *slice\\_quaternion*." ] }, { "cell_type": "code", "execution_count": 14, "metadata": { "collapsed": true, "deletable": true, "editable": true }, "outputs": [], "source": [ "axial.camera(slice_quaternion=[0.3, 0.3, 0, 0.9])" ] }, { "cell_type": "markdown", "metadata": { "deletable": true, "editable": true }, "source": [ "See [the corresponding actions in the graphical interface](../../anatomist/user_doc/anatomist_tutorial.html#zoom-translation-and-rotation-of-a-volume).\n", "\n", "### View header information" ] }, { "cell_type": "code", "execution_count": 15, "metadata": { "collapsed": true, "deletable": true, "editable": true }, "outputs": [], "source": [ "# view header\n", "browser = a.createWindow(\"Browser\")\n", "browser.addObjects(t1mri)" ] }, { "cell_type": "markdown", "metadata": { "deletable": true, "editable": true }, "source": [ "See [the corresponding actions in the graphical interface](../../anatomist/user_doc/anatomist_tutorial.html#read-header-information-voxel-size-dimension-image).\n", "\n", "### Change the color palette" ] }, { "cell_type": "code", "execution_count": 16, "metadata": { "collapsed": true, "deletable": true, "editable": true }, "outputs": [], "source": [ "# color palette\n", "palette = a.getPalette(\"Blue-Green-Red-Yellow\")\n", "t1mri.setPalette(palette)" ] }, { "cell_type": "markdown", "metadata": { "deletable": true, "editable": true }, "source": [ "See [the corresponding actions in the graphical interface](../../anatomist/user_doc/anatomist_tutorial.html#modification-of-color-palette).\n", "\n", "#### Custom palette\n", "\n", "You can create a new palette by giving the list of RGB parameters of the\n", "palette colors." ] }, { "cell_type": "code", "execution_count": 17, "metadata": { "collapsed": true, "deletable": true, "editable": true }, "outputs": [], "source": [ "# custom palette\n", "customPalette = a.createPalette(\"customPalette\")\n", "colors = []\n", "for x in xrange(255):\n", " colors.extend([0, 0, x])\n", "\n", "customPalette.setColors(colors=colors)\n", "t1mri.setPalette(customPalette)" ] }, { "cell_type": "markdown", "metadata": { "deletable": true, "editable": true }, "source": [ "### View meshes" ] }, { "cell_type": "code", "execution_count": 18, "metadata": { "collapsed": true, "deletable": true, "editable": true }, "outputs": [], "source": [ "# view meshes\n", "lwhite = a.loadObject(os.path.join(src, \"data_for_anatomist\", \"subject01\", \"subject01_Lwhite.mesh\"))\n", "rwhite = a.loadObject(os.path.join(src, \"data_for_anatomist\", \"subject01\", \"subject01_Rwhite.mesh\"))\n", "w3d = a.createWindow(\"3D\")\n", "w3d.addObjects([lwhite, rwhite])" ] }, { "cell_type": "markdown", "metadata": { "deletable": true, "editable": true }, "source": [ "See [the corresponding actions in the graphical interface](../../anatomist/user_doc/anatomist_tutorial.html#view-meshes).\n", "\n", "### Superimposing" ] }, { "cell_type": "code", "execution_count": 19, "metadata": { "collapsed": true, "deletable": true, "editable": true }, "outputs": [], "source": [ "# superimposing\n", "a.addObjects(t1mri, w3d)" ] }, { "cell_type": "markdown", "metadata": { "deletable": true, "editable": true }, "source": [ "See [the corresponding actions in the graphical interface](../../anatomist/user_doc/anatomist_tutorial.html#superimposing-objects).\n", "\n", "### Change mesh material" ] }, { "cell_type": "code", "execution_count": 20, "metadata": { "collapsed": true, "deletable": true, "editable": true }, "outputs": [], "source": [ "# mesh material\n", "head = a.loadObject(os.path.join(src, \"data_for_anatomist\", \"subject01\", \"subject01_head.mesh\"))\n", "head.addInWindows(w3d)\n", "material = a.Material(diffuse=[0.8, 0.6, 0.6, 0.5])\n", "head.setMaterial(material)" ] }, { "cell_type": "markdown", "metadata": { "deletable": true, "editable": true }, "source": [ "See [the corresponding actions in the graphical interface](../../anatomist/user_doc/anatomist_tutorial.html#change-the-mesh-material).\n", "\n", "### Fusion between two volumes" ] }, { "cell_type": "code", "execution_count": 21, "metadata": { "collapsed": false, "deletable": true, "editable": true }, "outputs": [ { "data": { "text/plain": [ "" ] }, "execution_count": 21, "metadata": {}, "output_type": "execute_result" } ], "source": [ "brain_mask = a.loadObject(os.path.join(src, \"data_for_anatomist\", \"subject01\", \"brain_subject01.nii\"))\n", "brain_mask.setPalette(\"GREEN-ufusion\")\n", "t1mri.setPalette(\"B-W LINEAR\")\n", "# fusion 2D\n", "fusion2d = a.fusionObjects([brain_mask, t1mri], \"Fusion2DMethod\")\n", "axial = a.createWindow(\"Axial\")\n", "axial.addObjects(fusion2d)\n", "# params of the fusion : linear on non null\n", "a.execute(\"Fusion2DParams\", object=fusion2d, mode=\"linear_on_defined\", rate=0.4)" ] }, { "cell_type": "markdown", "metadata": { "deletable": true, "editable": true }, "source": [ "It is possible to do different types of fusions using the same method\n", "[Anatomist.fusionObjects](pyanatomist_base.html#anatomist.base.Anatomist.fusionObjects) and changing the list of objects and the type of\n", "fusion.\n", "\n", "See [the corresponding actions in the graphical interface](../../anatomist/user_doc/anatomist_tutorial.html#fusion-between-2-volumes).\n", "\n", "### Load a transformation" ] }, { "cell_type": "code", "execution_count": 22, "metadata": { "collapsed": true, "deletable": true, "editable": true }, "outputs": [], "source": [ "t1mri_s2 = a.loadObject(os.path.join(src, \"data_for_anatomist\", \"subject02\", \"sujet02.ima\"))\n", "t1mri_s2.setPalette(\"Blue-White\")\n", "fusion2d = a.fusionObjects([t1mri, t1mri_s2], \"Fusion2DMethod\")\n", "r1 = a.createReferential()\n", "r2 = a.createReferential()\n", "cr = a.centralRef\n", "t1mri.assignReferential(r1)\n", "t1mri_s2.assignReferential(r2)\n", "# load a transformation\n", "a.loadTransformation(os.path.join(src, \"data_for_anatomist\", \"subject01\", \"RawT1-subject01_default_acquisition_TO_Talairach-ACPC.trm\"), r1, cr)\n", "a.loadTransformation(os.path.join(src, \"data_for_anatomist\", \"subject02\", \"RawT1-sujet02_200810_TO_Talairach-ACPC.trm\"), r2, cr)\n", "axial = a.createWindow(\"Axial\")\n", "axial.addObjects(fusion2d)" ] }, { "cell_type": "markdown", "metadata": { "deletable": true, "editable": true }, "source": [ "See [the corresponding actions in the graphical interface](../../anatomist/user_doc/anatomist_tutorial.html#load-a-transformation).\n", "\n", "### Load an existing referential" ] }, { "cell_type": "code", "execution_count": 23, "metadata": { "collapsed": true, "deletable": true, "editable": true }, "outputs": [], "source": [ "lwhite.assignReferential(r1)\n", "axial.addObjects(lwhite)" ] }, { "cell_type": "markdown", "metadata": { "deletable": true, "editable": true }, "source": [ "See [the corresponding actions in the graphical interface](../../anatomist/user_doc/anatomist_tutorial.html#load-an-existing-referential).\n", "\n", "### Load referential information from file header" ] }, { "cell_type": "code", "execution_count": 28, "metadata": { "collapsed": false, "deletable": true, "editable": true }, "outputs": [ { "data": { "text/plain": [ "" ] }, "execution_count": 28, "metadata": {}, "output_type": "execute_result" } ], "source": [ "map = a.loadObject(os.path.join(src, \"data_for_anatomist\", \"subject01\", \"Audio-Video_T_map.nii\"))\n", "map.setPalette(\"tvalues100-200-100\")\n", "t1mri.loadReferentialFromHeader()\n", "map.loadReferentialFromHeader()\n", "fusion_map = a.fusionObjects([map, t1mri], \"Fusion2DMethod\")\n", "axial = a.createWindow(\"Axial\")\n", "axial.addObjects(fusion_map)\n", "a.execute(\"Fusion2DParams\", object=fusion_map, mode=\"linear_on_defined\", rate=0.5)" ] }, { "cell_type": "markdown", "metadata": { "deletable": true, "editable": true }, "source": [ "See [the corresponding actions in the graphical interface](../../anatomist/user_doc/anatomist_tutorial.html#load-referential-information-from-file-header).\n", "\n", "### Display a ROI graph" ] }, { "cell_type": "code", "execution_count": 29, "metadata": { "collapsed": true, "deletable": true, "editable": true }, "outputs": [], "source": [ "graph = a.loadObject(os.path.join(src, \"data_for_anatomist\", \"roi\", \"basal_ganglia.arg\"))\n", "w = a.createWindow('3D')\n", "w.addObjects(graph, add_graph_nodes=True)" ] }, { "cell_type": "markdown", "metadata": { "deletable": true, "editable": true }, "source": [ "See [the corresponding actions in the graphical interface](../../anatomist/user_doc/anatomist_tutorial.html#display-a-graph-of-roi).\n", "\n", "### Sending a command to Anatomist\n", "\n", "A lot of commands that can be processed by Anatomist are encapsulted in\n", "Anatomist class methods. But some commands, less commonly used are not\n", "available through specific methods. Nevertheless, they can be called\n", "through a generic method [Anatomist.execute](pyanatomist_base.html#anatomist.base.Anatomist.execute).\n", "\n", "The list of available commands is listed in the following page:\n", "[anatomist commands](../../anatomist/dev_doc/commands.html).\n", "\n", "In the previous examples, we use this method to call the\n", "[Fusion2DParams command](../../anatomist/dev_doc/commands.html#fusion2dparams)\n", "which is not encapsulated in a specific method." ] }, { "cell_type": "code", "execution_count": 30, "metadata": { "collapsed": false, "deletable": true, "editable": true }, "outputs": [ { "data": { "text/plain": [ "" ] }, "execution_count": 30, "metadata": {}, "output_type": "execute_result" } ], "source": [ "a.execute(\"Fusion2DParams\", object=fusion_map, mode=\"linear_on_defined\", rate=0.5)" ] }, { "cell_type": "markdown", "metadata": { "deletable": true, "editable": true }, "source": [ "Using the direct implementation\n", "-------------------------------\n", "\n", "When you use the direct implementation of Anatomist Python API, more\n", "features are available. Indeed, each C++ class and function that are\n", "declared in the SIP bindings are available in Python. Moreover, the\n", "Python script and Anatomist objects share memory, so lower level\n", "manipulations are possible.\n", "\n", "See the [Anatomist doxygen documentation](../../anatomist/doxygen/index.html) about the\n", "C++ API to have more information about the classes and functions that\n", "may be available in Python (if the bindings are done).\n", "\n", "In this mode, it is also possible to interact on objects directly and\n", "interactively with Python Aims API. See more details about that in\n", "[PyAnatomist / PyAIMS tutorial: mixing Anatomist and AIMS in Python language.](pyanatomist_pyaims_tutorial.html).\n", "\n", "Amongst the noticeable benefits of the direct implementation is the\n", "possibility to use Anatomist views as Qt widgets to build custom\n", "interfaces. This is what has been used to program the\n", "[AnaSimpleViewer](../../anatomist/user_doc/anatomist_tutorial.html#anasimpleviewer) application. See the\n", "[Simple Viewer](pyanatomist_examples.html#simple-viewer) example." ] }, { "cell_type": "markdown", "metadata": { "deletable": true, "editable": true }, "source": [ "At the end, cleanup the temporary working directory\n", "---------------------------------------------------" ] }, { "cell_type": "code", "execution_count": 31, "metadata": { "collapsed": true, "deletable": true, "editable": true }, "outputs": [], "source": [ "# cleanup data\n", "import shutil\n", "os.chdir(older_cwd)\n", "shutil.rmtree(tuto_dir)" ] } ], "metadata": { "celltoolbar": "Edit Metadata", "kernelspec": { "display_name": "Python 2", "language": "python", "name": "python2" }, "language_info": { "codemirror_mode": { "name": "ipython", "version": 2 }, "file_extension": ".py", "mimetype": "text/x-python", "name": "python", "nbconvert_exporter": "python", "pygments_lexer": "ipython2", "version": "2.7.12" } }, "nbformat": 4, "nbformat_minor": 0 }