{
  "nbformat_minor": 0, 
  "nbformat": 4, 
  "cells": [
    {
      "execution_count": null, 
      "cell_type": "code", 
      "source": [
        "%matplotlib inline"
      ], 
      "outputs": [], 
      "metadata": {
        "collapsed": false
      }
    }, 
    {
      "source": [
        "\nMeasurements on a volume\n------------------------\n\nComplete example with a specific graphical interface that embeds an Anatomist window and a matplotlib widget. Shows a 4D volume and a curve of the values in a selected voxel or the mean of values in a selected region.\n\n"
      ], 
      "cell_type": "markdown", 
      "metadata": {}
    }, 
    {
      "execution_count": null, 
      "cell_type": "code", 
      "source": [
        "from __future__ import absolute_import\nimport sys\nimport os\nimport weakref\nimport gc\nimport operator\nimport anatomist.direct.api as anatomist\nfrom soma.qt_gui.qt_backend.QtCore import Qt, QPoint\nfrom soma.qt_gui.qt_backend.QtGui import QSplitter, QListWidget, QTextEdit, \\\n    QApplication\nfrom soma import aims\n\nfrom soma.qt_gui import qt_backend\nimport six\nfrom six.moves import zip\nfrom functools import reduce\nqt_backend.init_matplotlib_backend()\nimport matplotlib\nimport numpy\nimport pylab\n\nFigureCanvas = qt_backend.FigureCanvas\nfrom matplotlib.figure import Figure\n\n\nclass MeasuresWindow(QSplitter):\n\n    def __init__(self, fileName, roiIterator=None, parent=None,\n                 anatomistInstance=None):\n        QSplitter.__init__(self, Qt.Horizontal, parent)\n        if anatomistInstance is None:\n            # initialize Anatomist\n            self.anatomist = anatomist.Anatomist()\n        else:\n            self.anatomist = anatomistInstance\n\n        # open an axial window\n        self.aWindow = self.anatomist.createWindow(\n            'Axial', no_decoration=True)\n        self.aWindow.setParent(self)\n\n        if roiIterator is not None:\n            self.roiList = QListWidget(self)\n            self.maskIterators = []\n            # Iterate on each region\n            while roiIterator.isValid():\n                self.roiList.addItem(roiIterator.regionName())\n                maskIterator = roiIterator.maskIterator().get()\n                maskIterator.bucket = None\n                self.maskIterators.append(maskIterator)\n                next(roiIterator)\n            self.selectedBucket = None\n            self.roiList.currentRowChanged.connect(self.regionSelected)\n        else:\n            self.roiList = None\n\n        self.infoSplitter = QSplitter(Qt.Vertical, self)\n        self.info = QTextEdit(self.infoSplitter)\n        self.info.setReadOnly(True)\n\n        self.matplotFigure = Figure()\n        self.matplotAxes = self.matplotFigure.add_subplot(111)\n        # We want the axes cleared every time plot() is called\n        self.matplotAxes.hold(False)\n\n        self.matplotCanvas = FigureCanvas(self.matplotFigure)\n        self.matplotCanvas.setParent(self.infoSplitter)\n        self.matplotCanvas.updateGeometry()\n\n        self.anatomist.onCursorNotifier.add(self.clicked2)\n\n        self.resize(800, 600)\n\n        # Read the image\n        dir, base = os.path.split(fileName)\n        if dir:\n            self.setWindowTitle(base + ' (' + dir + ')')\n        else:\n            self.setWindowTitle(base)\n        # load any volume as a aims.Volume_* object\n        r = aims.Reader({'Volume': 'AimsData'})\n        self.volume = r.read(fileName)\n        self.interpolator = aims.aims.getLinearInterpolator(self.volume).get()\n\n        # convert the AimsData volume to Anatomist API\n        avol = self.anatomist.toAObject(self.volume)\n        avol.releaseAppRef()\n        # put volume in window\n        self.aWindow.addObjects(avol)\n\n        self._ignoreClicked = False\n        voxelSize = self.volume.header()['voxel_size']\n        tmp = self.volume.header()['volume_dimension']\n        volumeSize = [int(i) for i in tmp]\n        volumeCenter = [v * s / 2 for v, s in zip(volumeSize, voxelSize)]\n        self.clicked(volumeCenter)\n\n        infoHeight = self.info.sizeHint().height()\n        self.infoSplitter.setSizes([infoHeight, self.height() - infoHeight])\n\n    def clicked2(self, eventName, eventParameters):\n        self.clicked(eventParameters['position'], eventParameters['window'])\n\n    def clicked(self, posMM, aWindow=None):\n        posMM = [float(i) for i in posMM]\n        if self._ignoreClicked:\n            return\n        text = '<html><body>\\n'\n        text += '<b>Coordinate millimeters:</b> %.2f, %.2f, %.2f, %.2f' % tuple(\n            posMM) + '<br/>\\n'\n        voxelSize = self.volume.header()['voxel_size']\n        posVoxel = [int(round(i / j)) for i, j in zip(posMM, voxelSize)]\n        text += '<b>Coordinate voxels:</b> %d, %d, %d, %d' % tuple(\n            posVoxel) + '<br/>\\n'\n        tmp = self.volume.header()['volume_dimension']\n        volumeSize = [int(i) for i in tmp]\n        if not [None for i in posVoxel if i < 0] and  \\\n           not [None for i, j in zip(posVoxel, volumeSize) if i >= j]:\n            text += '<b>Voxel value</b>: ' + \\\n                str(self.volume.value(*posVoxel)) + '<br/>\\n'\n            if volumeSize[3] > 1:\n                indices = numpy.arange(volumeSize[3])\n                # Extract values as numarray structure\n                values = self.interpolator.values(posVoxel[0] * voxelSize[0],\n                                                  posVoxel[1] * voxelSize[1],\n                                                  posVoxel[2] * voxelSize[2])\n                self.matplotAxes.plot(indices, numpy.array(values))\n                self.matplotCanvas.draw()\n        text += '</body></html>'\n        self.info.setText(text)\n\n    def regionSelected(self):\n        index = self.roiList.currentRow()\n        if index >= 0:\n            text = '<html><body>\\n'\n            text += '<h2>' + \\\n                six.text_type(self.roiList.item(index).text()) + '</h2>\\n'\n\n            maskIterator = self.maskIterators[index]\n            if maskIterator.bucket is None:\n                roiCenter = aims.Point3df(0, 0, 0)\n                bucket = aims.BucketMap_VOID()\n                bucket.setSizeXYZT(\n                    *list(maskIterator.voxelSize().items()) + (1,))\n                maskIterator.restart()\n                valid = 0\n                invalid = 0\n                sum = None\n                # Iterate on each point of a region\n                while maskIterator.isValid():\n                    bucket[0][maskIterator.value()] = 1\n                    p = maskIterator.valueMillimeters()\n                    roiCenter += p\n                    # Check if the point is in the image limit\n                    if self.interpolator.isValid(p):\n                        values = self.interpolator.values(p)\n                        if sum is None:\n                            sum = values\n                        else:\n                            sum = [s + v for s, v in zip(sum, values)]\n                        valid += 1\n                    else:\n                        invalid += 1\n                    next(maskIterator)\n                text += '<b>valid points:</b> ' + str(valid) + '<br/>\\n'\n                text += '<b>invalid points:</b> ' + str(invalid) + '<br/>\\n'\n                if valid:\n                    means = [s / float(valid) for s in sum]\n                    mean = reduce(operator.add, means) / len(means)\n                else:\n                    means = []\n                    mean = 'N/A'\n                text += '<b>mean:</b> ' + str(mean) + '<br/>\\n'\n                text += '</body></html>'\n                maskIterator.text = text\n                # convert the BucketMap to Anatomist API\n                maskIterator.bucket = self.anatomist.toAObject(bucket)\n                maskIterator.bucket.releaseAppRef()\n                maskIterator.bucket.setName(\n                    str(self.roiList.item(index).text()))\n                maskIterator.bucket.setChanged()\n                count = valid + invalid\n                if count:\n                    maskIterator.roiCenter = [\n                        c / count for c in roiCenter.items()]\n                else:\n                    maskIterator.roiCenter = None\n                maskIterator.means = means\n\n            # put bucket in window\n            self.info.setText(maskIterator.text)\n            self.aWindow.addObjects([maskIterator.bucket])\n            # Set selected color to bucket\n            maskIterator.bucket.setMaterial(self.anatomist.Material(\n                diffuse=[1, 0, 0, 0.5],\n                lighting=0,\n                face_culling=1,\n            ))\n            # Set unselected color to previously selected bucket\n            if self.selectedBucket is not None:\n                self.selectedBucket.setMaterial(\n                    self.anatomist.Material(diffuse=[0, 0.8, 0.8, 0.8]))\n            self.selectedBucket = maskIterator.bucket\n            if maskIterator.roiCenter is not None:\n                self._ignoreClicked = True\n                self.aWindow.moveLinkedCursor(maskIterator.roiCenter)\n                self._ignoreClicked = False\n            if len(maskIterator.means) > 1:\n                indices = numpy.arange(len(maskIterator.means))\n                self.matplotAxes.plot(\n                    indices, numpy.array(maskIterator.means))\n                self.matplotCanvas.draw()\n\n\nif __name__ == '__main__':\n    qApp = QApplication(sys.argv)\n\n    if len(sys.argv) == 3:\n        roiIterator = aims.aims.getRoiIterator(sys.argv[2]).get()\n        w = MeasuresWindow(sys.argv[1], roiIterator=roiIterator)\n    else:\n        w = MeasuresWindow(sys.argv[1])\n    w.show()\n\n    anatomist.Anatomist().getControlWindow().hide()\n    qApp.exec_()\n    del w"
      ], 
      "outputs": [], 
      "metadata": {
        "collapsed": false
      }
    }
  ], 
  "metadata": {
    "kernelspec": {
      "display_name": "Python 2", 
      "name": "python2", 
      "language": "python"
    }, 
    "language_info": {
      "mimetype": "text/x-python", 
      "nbconvert_exporter": "python", 
      "name": "python", 
      "file_extension": ".py", 
      "version": "2.7.17", 
      "pygments_lexer": "ipython2", 
      "codemirror_mode": {
        "version": 2, 
        "name": "ipython"
      }
    }
  }
}