{
 "cells": [
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "\"\"\"\n",
    "Demonstrates common image analysis tools.\n",
    "\n",
    "Many of the features demonstrated here are already provided by the ImageView\n",
    "widget, but here we present a lower-level approach that provides finer control\n",
    "over the user interface.\n",
    "\"\"\"\n",
    "from pyqtgraph.jupyter import GraphicsLayoutWidget\n",
    "import ipywidgets\n",
    "from IPython.display import display\n",
    "\n",
    "import pyqtgraph as pg\n",
    "from pyqtgraph.Qt import QtCore, QtGui\n",
    "import numpy as np\n",
    "\n",
    "\n",
    "# Interpret image data as row-major instead of col-major\n",
    "pg.setConfigOptions(imageAxisOrder='row-major')\n",
    "\n",
    "pg.mkQApp()\n",
    "win = GraphicsLayoutWidget(css_width=\"800px\", css_height=\"480px\")\n",
    "\n",
    "# A plot area (ViewBox + axes) for displaying the image\n",
    "p1 = win.addPlot(title=\"\")\n",
    "\n",
    "# Item for displaying image data\n",
    "img = pg.ImageItem()\n",
    "p1.addItem(img)\n",
    "\n",
    "# Custom ROI for selecting an image region\n",
    "roi = pg.ROI([-8, 14], [6, 5])\n",
    "roi.addScaleHandle([0.5, 1], [0.5, 0.5])\n",
    "roi.addScaleHandle([0, 0.5], [0.5, 0.5])\n",
    "p1.addItem(roi)\n",
    "roi.setZValue(10)  # make sure ROI is drawn above image\n",
    "\n",
    "# Isocurve drawing\n",
    "iso = pg.IsocurveItem(level=0.8, pen='g')\n",
    "iso.setParentItem(img)\n",
    "iso.setZValue(5)\n",
    "\n",
    "# Contrast/color control\n",
    "hist = pg.HistogramLUTItem()\n",
    "hist.setImageItem(img)\n",
    "win.addItem(hist)\n",
    "\n",
    "# Draggable line for setting isocurve level\n",
    "isoLine = pg.InfiniteLine(angle=0, movable=True, pen='g')\n",
    "hist.vb.addItem(isoLine)\n",
    "hist.vb.setMouseEnabled(y=False) # makes user interaction a little easier\n",
    "isoLine.setValue(0.8)\n",
    "isoLine.setZValue(1000) # bring iso line above contrast controls\n",
    "\n",
    "# Another plot area for displaying ROI data\n",
    "win.nextRow()\n",
    "p2 = win.addPlot(colspan=2)\n",
    "p2.setMaximumHeight(250)\n",
    "\n",
    "\n",
    "# Generate image data\n",
    "data = np.random.normal(size=(200, 100))\n",
    "data[20:80, 20:80] += 2.\n",
    "data = pg.gaussianFilter(data, (3, 3))\n",
    "data += np.random.normal(size=(200, 100)) * 0.1\n",
    "img.setImage(data)\n",
    "hist.setLevels(data.min(), data.max())\n",
    "\n",
    "# build isocurves from smoothed data\n",
    "iso.setData(pg.gaussianFilter(data, (2, 2)))\n",
    "\n",
    "# set position and scale of image\n",
    "tr = QtGui.QTransform()\n",
    "img.setTransform(tr.scale(0.2, 0.2).translate(-50, 0))\n",
    "\n",
    "# zoom to fit imageo\n",
    "p1.autoRange()  \n",
    "\n",
    "\n",
    "# Callbacks for handling user interaction\n",
    "def updatePlot():\n",
    "    global img, roi, data, p2\n",
    "    selected = roi.getArrayRegion(data, img)\n",
    "    p2.plot(selected.mean(axis=0), clear=True)\n",
    "\n",
    "roi.sigRegionChanged.connect(updatePlot)\n",
    "updatePlot()\n",
    "\n",
    "def updateIsocurve():\n",
    "    global isoLine, iso\n",
    "    iso.setLevel(isoLine.value())\n",
    "\n",
    "isoLine.sigDragged.connect(updateIsocurve)\n",
    "\n",
    "def imageHoverEvent(event):\n",
    "    \"\"\"Show the position, pixel, and value under the mouse cursor.\n",
    "    \"\"\"\n",
    "    if event.isExit():\n",
    "        p1.setTitle(\"\")\n",
    "        return\n",
    "    pos = event.pos()\n",
    "    i, j = pos.y(), pos.x()\n",
    "    i = int(np.clip(i, 0, data.shape[0] - 1))\n",
    "    j = int(np.clip(j, 0, data.shape[1] - 1))\n",
    "    val = data[i, j]\n",
    "    ppos = img.mapToParent(pos)\n",
    "    x, y = ppos.x(), ppos.y()\n",
    "    p1.setTitle(\"pos: (%0.1f, %0.1f)  pixel: (%d, %d)  value: %.3g\" % (x, y, i, j, val))\n",
    "\n",
    "# Monkey-patch the image to use our custom hover function. \n",
    "# This is generally discouraged (you should subclass ImageItem instead),\n",
    "# but it works for a very simple use like this. \n",
    "img.hoverEvent = imageHoverEvent\n",
    "\n",
    "\n",
    "# disable HistogramLUTItem right-click context menus to prevent crashes\n",
    "hist.vb.setMenuEnabled(False)\n",
    "hist.gradient.showMenu = lambda ev : None\n",
    "display(win)\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": []
  }
 ],
 "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.8.10"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 2
}
