{
 "cells": [
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "\"\"\"\n",
    "Demonstrates a variety of uses for ROI. This class provides a user-adjustable\n",
    "region of interest marker. It is possible to customize the layout and \n",
    "function of the scale/rotate handles in very flexible ways. \n",
    "\"\"\"\n",
    "from pyqtgraph.jupyter import GraphicsLayoutWidget\n",
    "from IPython.display import display\n",
    "\n",
    "import pyqtgraph as pg\n",
    "import numpy as np\n",
    "\n",
    "pg.setConfigOptions(imageAxisOrder='row-major')\n",
    "\n",
    "## Create image to display\n",
    "arr = np.ones((100, 100), dtype=float)\n",
    "arr[45:55, 45:55] = 0\n",
    "arr[25, :] = 5\n",
    "arr[:, 25] = 5\n",
    "arr[75, :] = 5\n",
    "arr[:, 75] = 5\n",
    "arr[50, :] = 10\n",
    "arr[:, 50] = 10\n",
    "arr += np.sin(np.linspace(0, 20, 100)).reshape(1, 100)\n",
    "arr += np.random.normal(size=(100,100))\n",
    "\n",
    "# add an arrow for asymmetry\n",
    "arr[10, :50] = 10\n",
    "arr[9:12, 44:48] = 10\n",
    "arr[8:13, 44:46] = 10\n",
    "\n",
    "\n",
    "## create GUI\n",
    "app = pg.mkQApp()\n",
    "font = app.font()\n",
    "if font.pointSize() > 10:\n",
    "    font.setPointSize(10)\n",
    "    app.setFont(font)\n",
    "w = GraphicsLayoutWidget(css_width=\"1000px\", css_height=\"800px\")\n",
    "\n",
    "text = \"\"\"Data Selection From Image.<br>\\n\n",
    "Drag an ROI or its handles to update the selected image.<br>\n",
    "Hold CTRL while dragging to snap to pixel boundaries<br>\n",
    "and 15-degree rotation angles.\n",
    "\"\"\"\n",
    "w1 = w.addLayout(row=0, col=0)\n",
    "label1 = w1.addLabel(text, row=0, col=0)\n",
    "v1a = w1.addViewBox(row=1, col=0, lockAspect=True)\n",
    "v1b = w1.addViewBox(row=2, col=0, lockAspect=True)\n",
    "img1a = pg.ImageItem(arr)\n",
    "v1a.addItem(img1a)\n",
    "img1b = pg.ImageItem()\n",
    "v1b.addItem(img1b)\n",
    "v1a.disableAutoRange('xy')\n",
    "v1b.disableAutoRange('xy')\n",
    "v1a.autoRange()\n",
    "v1b.autoRange()\n",
    "\n",
    "rois = []\n",
    "rois.append(pg.RectROI([20, 20], [20, 20], pen=(0,9)))\n",
    "rois[-1].addRotateHandle([1,0], [0.5, 0.5])\n",
    "rois.append(pg.LineROI([0, 60], [20, 80], width=5, pen=(1,9)))\n",
    "rois.append(pg.TriangleROI([80, 75], 20, pen=(5, 9)))\n",
    "rois.append(pg.MultiRectROI([[20, 90], [50, 60], [60, 90]], width=5, pen=(2,9)))\n",
    "rois.append(pg.EllipseROI([60, 10], [30, 20], pen=(3,9)))\n",
    "rois.append(pg.CircleROI([80, 50], [20, 20], pen=(4,9)))\n",
    "#rois.append(pg.LineSegmentROI([[110, 50], [20, 20]], pen=(5,9)))\n",
    "rois.append(pg.PolyLineROI([[80, 60], [90, 30], [60, 40]], pen=(6,9), closed=True))\n",
    "\n",
    "def update(roi):\n",
    "    img1b.setImage(roi.getArrayRegion(arr, img1a), levels=(0, arr.max()))\n",
    "    v1b.autoRange()\n",
    "    \n",
    "for roi in rois:\n",
    "    roi.sigRegionChanged.connect(update)\n",
    "    v1a.addItem(roi)\n",
    "\n",
    "update(rois[-1])\n",
    "    \n",
    "\n",
    "\n",
    "text = \"\"\"User-Modifiable ROIs<br>\n",
    "Click on a line segment to add a new handle.\n",
    "Right click on a handle to remove.\n",
    "\"\"\"\n",
    "w2 = w.addLayout(row=0, col=1)\n",
    "label2 = w2.addLabel(text, row=0, col=0)\n",
    "v2a = w2.addViewBox(row=1, col=0, lockAspect=True)\n",
    "r2a = pg.PolyLineROI([[0,0], [10,10], [10,30], [30,10]], closed=True)\n",
    "v2a.addItem(r2a)\n",
    "r2b = pg.PolyLineROI([[0,-20], [10,-10], [10,-30]], closed=False)\n",
    "v2a.addItem(r2b)\n",
    "v2a.disableAutoRange('xy')\n",
    "#v2b.disableAutoRange('xy')\n",
    "v2a.autoRange()\n",
    "#v2b.autoRange()\n",
    "\n",
    "text = \"\"\"Building custom ROI types<Br>\n",
    "ROIs can be built with a variety of different handle types<br>\n",
    "that scale and rotate the roi around an arbitrary center location\n",
    "\"\"\"\n",
    "w3 = w.addLayout(row=1, col=0)\n",
    "label3 = w3.addLabel(text, row=0, col=0)\n",
    "v3 = w3.addViewBox(row=1, col=0, lockAspect=True)\n",
    "\n",
    "r3a = pg.ROI([0,0], [10,10])\n",
    "v3.addItem(r3a)\n",
    "## handles scaling horizontally around center\n",
    "r3a.addScaleHandle([1, 0.5], [0.5, 0.5])\n",
    "r3a.addScaleHandle([0, 0.5], [0.5, 0.5])\n",
    "\n",
    "## handles scaling vertically from opposite edge\n",
    "r3a.addScaleHandle([0.5, 0], [0.5, 1])\n",
    "r3a.addScaleHandle([0.5, 1], [0.5, 0])\n",
    "\n",
    "## handles scaling both vertically and horizontally\n",
    "r3a.addScaleHandle([1, 1], [0, 0])\n",
    "r3a.addScaleHandle([0, 0], [1, 1])\n",
    "\n",
    "r3b = pg.ROI([20,0], [10,10])\n",
    "v3.addItem(r3b)\n",
    "## handles rotating around center\n",
    "r3b.addRotateHandle([1, 1], [0.5, 0.5])\n",
    "r3b.addRotateHandle([0, 0], [0.5, 0.5])\n",
    "\n",
    "## handles rotating around opposite corner\n",
    "r3b.addRotateHandle([1, 0], [0, 1])\n",
    "r3b.addRotateHandle([0, 1], [1, 0])\n",
    "\n",
    "## handles rotating/scaling around center\n",
    "r3b.addScaleRotateHandle([0, 0.5], [0.5, 0.5])\n",
    "\n",
    "# handles rotating/scaling around arbitrary point\n",
    "r3b.addScaleRotateHandle([0.3, 0], [0.9, 0.7])\n",
    "\n",
    "v3.disableAutoRange('xy')\n",
    "v3.autoRange()\n",
    "\n",
    "\n",
    "text = \"\"\"Transforming objects with ROI\"\"\"\n",
    "w4 = w.addLayout(row=1, col=1)\n",
    "label4 = w4.addLabel(text, row=0, col=0)\n",
    "v4 = w4.addViewBox(row=1, col=0, lockAspect=True)\n",
    "g = pg.GridItem()\n",
    "v4.addItem(g)\n",
    "r4 = pg.ROI([0,0], [100,100], resizable=False, removable=True)\n",
    "r4.addRotateHandle([1,0], [0.5, 0.5])\n",
    "r4.addRotateHandle([0,1], [0.5, 0.5])\n",
    "img4 = pg.ImageItem(arr)\n",
    "v4.addItem(r4)\n",
    "img4.setParentItem(r4)\n",
    "\n",
    "v4.disableAutoRange('xy')\n",
    "v4.autoRange()\n",
    "\n",
    "# Provide a callback to remove the ROI (and its children) when\n",
    "# \"remove\" is selected from the context menu.\n",
    "def remove():\n",
    "    v4.removeItem(r4)\n",
    "r4.sigRemoveRequested.connect(remove)\n",
    "\n",
    "\n",
    "display(w)\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
}
