{
 "cells": [
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# `dual_canvas` Python quick reference.\n",
    "\n",
    "This document is part of the \n",
    "<a href=\"https://github.com/AaronWatters/jp_doodle\">`jp_doodle` (https://github.com/AaronWatters/jp_doodle)</a>\n",
    "package.\n",
    "It provides a quick reference\n",
    "to using the `dual_canvas` object API in Python to build visualizations in\n",
    "interactive Jupyter widgets.\n",
    "\n",
    "The `dual_canvas` mechanism is designed to make it easy to develop special\n",
    "purpose interactive scientific visualizations in Jupyter and other web contexts.\n",
    "A `dual_canvas` widget built using the Python interface\n",
    "can be used to build interactive and animated visualizations that live inside\n",
    "a Jupyter IPython notebook document.  Discussions below illustrate how to create a canvas widget, draw things on the\n",
    "canvas, modify and animate elements of a canvas, and associate mouse event actions to elements of a\n",
    "canvas, among other topics.  \n",
    "\n",
    "**About this document:** This document is an executable Jupyter notebook, or another document format\n",
    "derived from the notebook.  The next \"code cell\" imports external functionality used in the notebook.\n",
    "In the following discussion\n",
    "we use the `eg.show(demo)` helper to optionally embed an image into\n",
    "this notebook in order to facilitate file format conversion.  Please replace\n",
    "this helper with `display(demo)` when you emulate these code fragments.\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 1,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/html": [
       "<style>.container { width:100% !important; }</style>"
      ],
      "text/plain": [
       "<IPython.core.display.HTML object>"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    }
   ],
   "source": [
    "from jp_doodle import dual_canvas\n",
    "from IPython.display import display\n",
    "\n",
    "import qr_helper as eg    # some helpers and tricks for embedding images\n",
    "eg.DO_EMBEDDINGS = False  # flag indicates whether to embed images in the notebook or not (for format conversions)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "\n",
    "## Part 1: Creating canvas widgets and frames in widgets and coordinates\n",
    "\n",
    "To create and use the widgets you need to import the `dual_canvas` module in an IPython notebook\n",
    "and you probably also will want to use `IPython.display.display`.\n",
    "\n",
    "### Creating a `dual_canvas.DualCanvasWidget`\n",
    "\n",
    "A dual canvas is a space on the IPython notebook to draw on using\n",
    "drawing operations specified using (x,y) coordinates.\n",
    "A newly created dual canvas initially has width and height given in device pixels.\n",
    "The `dual_canvas.DualCanvasWidget`\n",
    "constructor may optionally specify a default font.  The initial lower left corner is at (0,0)\n",
    "and the upper right corner is at (width, height)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 2,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "application/vnd.jupyter.widget-view+json": {
       "model_id": "3507e8e51b0249feb7a4fb94e363cef2",
       "version_major": 2,
       "version_minor": 0
      },
      "text/plain": [
       "DualCanvasWidget(status='Not yet rendered')"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    },
    {
     "data": {
      "text/html": [
       "<img src=\"make_a_canvas.png\"/>"
      ],
      "text/plain": [
       "<IPython.core.display.HTML object>"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    }
   ],
   "source": [
    "def make_a_canvas():\n",
    "    \n",
    "    # Create a canvas with pixel coordinates (0...420, 0...120)\n",
    "    demo = dual_canvas.DualCanvasWidget(width=420, height=120, font=\"italic 12px Courier\",)\n",
    "    \n",
    "    # Put some reference marks on the canvas to illustrate the coordinate space.\n",
    "    demo.text(x=0, y=0, text=\"0,0\", color=\"red\", background=\"yellow\", )\n",
    "    demo.text(x=410, y=110, text=\"410,110\", align=\"right\", color=\"red\", background=\"yellow\", )\n",
    "    demo.lower_left_axes(min_x=10, min_y=10, max_x=410, \n",
    "                         max_y=110, x_anchor=150, y_anchor=40, max_tick_count=7, color=\"blue\")\n",
    "    eg.show(demo)  # replace with display(demo)\n",
    "\n",
    "make_a_canvas()"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### Create a reference frame inside a dual canvas\n",
    "\n",
    "Pixel coordinates are rarely the most convenient coordinate systems to\n",
    "use for scientific visualizations.  Reference frames allow drawing using\n",
    "transformed coordinates.  The `frame_region` method creates a frame\n",
    "by mapping reference points in the pixel space to reference\n",
    "points in the reference frame coordinate space.  Objects can then\n",
    "be drawn on the reference frame and the underlying coordinates will be\n",
    "converted automatically."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 3,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "application/vnd.jupyter.widget-view+json": {
       "model_id": "b0a68cf478e94718bb21040887e1968f",
       "version_major": 2,
       "version_minor": 0
      },
      "text/plain": [
       "DualCanvasWidget(status='Not yet rendered')"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    },
    {
     "data": {
      "text/html": [
       "<img src=\"make_a_reference_frame.png\"/>"
      ],
      "text/plain": [
       "<IPython.core.display.HTML object>"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    }
   ],
   "source": [
    "def make_a_reference_frame():\n",
    "    demo = dual_canvas.DualCanvasWidget(width=420, height=120)\n",
    "    \n",
    "    # Map pixel coords (10,10) and (400,100)\n",
    "    #  to frame coords (-1, 0) and (1, 2)\n",
    "    frame = demo.frame_region(\n",
    "        minx=10, miny=10, maxx=400, maxy=100,\n",
    "        frame_minx=-1, frame_miny=0, frame_maxx=1, frame_maxy=2,\n",
    "    )\n",
    "    # Put some reference marks on the frame to indicate the coordinates.\n",
    "    frame.text(x=-1, y=0, text=\"-1,0\", color=\"red\", background=\"yellow\", )\n",
    "    frame.text(x=1, y=2, text=\"1,2\", align=\"right\", color=\"red\", background=\"yellow\", )\n",
    "    frame.lower_left_axes(min_x=-1, min_y=0, max_x=1,\n",
    "                         max_y=2, x_anchor=0, y_anchor=1, max_tick_count=7, color=\"blue\")\n",
    "    \n",
    "    # also draw axes in canvas/pixel coordinates\n",
    "    demo.lower_left_axes(min_x=10, min_y=10, max_x=410,\n",
    "                         max_y=110, x_anchor=100, y_anchor=40, max_tick_count=7, color=\"pink\")\n",
    "    eg.show(demo)  # replace with display(demo)\n",
    "\n",
    "make_a_reference_frame()"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "###  Create two reference frames inside a dual canvas\n",
    "\n",
    "It is possible to create many reference frames inside a dual canvas each with a different\n",
    "coordinate transform."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 4,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "application/vnd.jupyter.widget-view+json": {
       "model_id": "1165f062d88243f185abd63d8b73f840",
       "version_major": 2,
       "version_minor": 0
      },
      "text/plain": [
       "DualCanvasWidget(status='Not yet rendered')"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    },
    {
     "data": {
      "text/html": [
       "<img src=\"make_2_reference_frames.png\"/>"
      ],
      "text/plain": [
       "<IPython.core.display.HTML object>"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    }
   ],
   "source": [
    "def make_2_reference_frames():\n",
    "    demo = dual_canvas.DualCanvasWidget(width=420, height=120)\n",
    "    # draw pink axes in canvas/pixel coordinates behind the other figures.\n",
    "    demo.lower_left_axes(min_x=10, min_y=10, max_x=410,\n",
    "                         max_y=110, x_anchor=40, y_anchor=80, max_tick_count=7, color=\"pink\")\n",
    "    \n",
    "    # Map pixel coords (10,10) and (190,100)\n",
    "    #  to frame1 coords (-1, 0) and (1, 2)\n",
    "    frame1 = demo.frame_region(\n",
    "        minx=10, miny=10, maxx=190, maxy=100,\n",
    "        frame_minx=-1, frame_miny=0, frame_maxx=1, frame_maxy=2,\n",
    "    )\n",
    "    # Put some reference marks on the frame1 to indicate the coordinates.\n",
    "    frame1.text(x=-1, y=1.8, text=\"frame1\", color=\"blue\", background=\"white\", )\n",
    "    frame1.text(x=-1, y=0, text=\"-1,0\", color=\"red\", background=\"yellow\", )\n",
    "    frame1.text(x=1, y=2, text=\"1,2\", align=\"right\", color=\"red\", background=\"yellow\", )\n",
    "    frame1.lower_left_axes(min_x=-1, min_y=0, max_x=1,\n",
    "                         max_y=2, x_anchor=0, y_anchor=1, max_tick_count=7, color=\"blue\")\n",
    "                         \n",
    "    # Map pixel coords (210,10) and (400,100)\n",
    "    #  to frame coords (-1, 0) and (1, 2)\n",
    "    frame2 = demo.frame_region(\n",
    "        minx=210, miny=10, maxx=400, maxy=100,\n",
    "        frame_minx=-1, frame_miny=0, frame_maxx=1, frame_maxy=2,\n",
    "    )\n",
    "    # Put some reference marks on the frame2 to indicate the coordinates.\n",
    "    frame2.text(x=-1, y=1.8, text=\"frame2\", color=\"green\", background=\"white\", )\n",
    "    frame2.text(x=-1, y=0, text=\"-1,0\", color=\"white\", background=\"magenta\", )\n",
    "    frame2.text(x=1, y=2, text=\"1,2\", align=\"right\", color=\"white\", background=\"magenta\", )\n",
    "    frame2.lower_left_axes(min_x=-1, min_y=0, max_x=1,\n",
    "                         max_y=2, x_anchor=0, y_anchor=1, max_tick_count=7, color=\"green\")\n",
    "                         \n",
    "    eg.show(demo)  # replace with display(demo)\n",
    "\n",
    "make_2_reference_frames()"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "###  Get a simplified frame using `swatch`\n",
    "\n",
    "The `swatch` convenience helper is useful to create square canvases with a single frame\n",
    "where the X and Y coordinates have the same scale."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 5,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "application/vnd.jupyter.widget-view+json": {
       "model_id": "d2d7545943c64326899453f5da44e08a",
       "version_major": 2,
       "version_minor": 0
      },
      "text/plain": [
       "DualCanvasWidget(status='Not yet rendered')"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    },
    {
     "data": {
      "text/html": [
       "<img src=\"make_a_swatch.png\"/>"
      ],
      "text/plain": [
       "<IPython.core.display.HTML object>"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    }
   ],
   "source": [
    "def make_a_swatch():\n",
    "    \n",
    "    # Create a frame with pixel coordinates 200 by 200 using swatch:\n",
    "    frame = dual_canvas.swatch(\n",
    "        pixels=200,       # width and height of 200 pixels\n",
    "        model_height=4.5, # width and height in frame coordinates\n",
    "        cx=4,\n",
    "        cy=-3,            # center of canvas at (4, -3) in frame coordinates (default (0, 0))\n",
    "        snapfile=None,    # if this is set to a file path the widget will be a snapshot widget (default None)\n",
    "        show=False,       # automatically display the widget if true (default True)\n",
    "    )\n",
    "    # Put some reference marks on the canvas to indicate the coordinates.\n",
    "    frame.text(x=2, y=-5, text=\"2,-5\", color=\"red\", background=\"yellow\", )\n",
    "    frame.text(x=6, y=-1, text=\"6,-1\", align=\"right\", color=\"red\", background=\"yellow\", )\n",
    "    frame.lower_left_axes(min_x=2, min_y=-5, max_x=6, \n",
    "                         max_y=-1, x_anchor=4, y_anchor=-3, max_tick_count=7, color=\"blue\")\n",
    "    eg.show(frame)  # replace with display(frame)\n",
    "\n",
    "make_a_swatch()"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "The return value for `swatch` is a reference frame.  The underlying canvas widget associated\n",
    "with the frame is available as `frame.get_canvas()`.\n",
    "\n",
    "###  Simplified coordinates using the `fit()` method\n",
    "\n",
    "It is often convenient to draw objects on a canvas or frame and then use the `fit` method to automatically\n",
    "adjust the coordinate conversions so the visible objects are visible in the frame.  Fit will compute the\n",
    "maximum and minimum coordinate values drawn and automatically adjust the canvas coordinate conversion\n",
    "so that the objects are in view and \"fill\" the canvas in either the X or Y dimension (or both).\n",
    "\n",
    "**Warning:** Buggy code that uses `fit()` may make objects that are so far apart\n",
    "that they are too small to be seen after the `fit()` operation.\n",
    "\n",
    "*Note:* Below we do not explicitly choose the center of the frame or the\n",
    "endpoints of the axes because they are derived from the coordinate system\n",
    "chosen by `fit` automatically."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 6,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "application/vnd.jupyter.widget-view+json": {
       "model_id": "97250782b41d4b4cb5f17761fa98e556",
       "version_major": 2,
       "version_minor": 0
      },
      "text/plain": [
       "DualCanvasWidget(status='Not yet rendered')"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    },
    {
     "data": {
      "text/html": [
       "<img src=\"fit_a_swatch.png\"/>"
      ],
      "text/plain": [
       "<IPython.core.display.HTML object>"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    }
   ],
   "source": [
    "def fit_a_swatch():\n",
    "    \n",
    "    # Create a canvas with pixel coordinates 200 by 200 using swatch:\n",
    "    #   Note: we don't specify the center because fit() below will chose the appropriate center.\n",
    "    frame = dual_canvas.swatch(200, 4.5, show=False)\n",
    "    # Put some reference marks on the canvas to indicate the coordinates.\n",
    "    frame.text(x=2, y=-5, text=\"2,-5\", color=\"red\", background=\"yellow\", )\n",
    "    frame.text(x=6, y=-1, text=\"6,-1\", align=\"right\", color=\"red\", background=\"yellow\", )\n",
    "    # fit the text objects into the canvas\n",
    "    frame.fit()\n",
    "    \n",
    "    # Draw axes using the coordinate system chosen by the fit operation above\n",
    "    #   Note: the max and min coordinates are not specified because they are inferred from the fit.\n",
    "    frame.lower_left_axes(max_tick_count=5, x_anchor=4, y_anchor=-3, color=\"blue\")\n",
    "    \n",
    "    # Fit the objects drawn into the canvas again allowing a margin of 20 pixels\n",
    "    frame.fit(margin=20)\n",
    "    eg.show(frame)  # replace with display(frame)\n",
    "\n",
    "fit_a_swatch()"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### 1.6 Create a \"Snapshot canvas\"\n",
    "\n",
    "```Python\n",
    "widget = dual_canvas.SnapshotCanvas(filename=\"snapshot_image_file.png\", width=420, height=120)\n",
    "widget.display_all()  # Show the canvas inside the snapshot tab.\n",
    "```\n",
    "\n",
    "# Part 2: Drawing on canvases and frames\n",
    "\n",
    "\n",
    "Dual canvases and reference frames on dual canvases support a number of drawing operations\n",
    "described below.\n",
    "\n",
    "The discussion makes use of the helper module to present the draw operations\n",
    "and their visual results shown with a reference axis without having to repeat boilerplate\n",
    "code (like creating a canvas and an axis over and over and over....).\n",
    "\n",
    "Objects may be drawn directly using the canvas (in which case the canvas is also\n",
    "the reference frame) or with respect to a reference frame derived from the canvas.\n",
    "\n",
    "Note that some objects (`text`, `circle`, and, `rect`) are sized relative to the\n",
    "canvas, not relative to any reference frame, in order to allow consistent mark sizes\n",
    "across all frames of a canvas.  The `frame_rect` and `frame_circle` variants\n",
    "are sized relative to the current frame.  All objects are positioned relative\n",
    "to the current frame,"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 7,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/markdown": [
       "\n",
       "### Drawing lines\n",
       "\n",
       "The `line` method draws a line segment between two end points.\n"
      ],
      "text/plain": [
       "<IPython.core.display.Markdown object>"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    },
    {
     "data": {
      "text/markdown": [
       "```Python\n",
       "\n",
       "    widget.line(\n",
       "        x1=50, y1=10,   # One end point of the line\n",
       "        x2=320, y2=30,  # The other end point of the line\n",
       "        color=\"cyan\",   # Optional color (default: \"black\")\n",
       "        lineWidth=4,    # Optional line width\n",
       "        lineDash=[5,2,1], # Optional line dash pattern\n",
       "    )\n",
       "\n",
       "```"
      ],
      "text/plain": [
       "<IPython.core.display.Markdown object>"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    },
    {
     "data": {
      "application/vnd.jupyter.widget-view+json": {
       "model_id": "b05bdc46952a4fe7a772568e516d4a46",
       "version_major": 2,
       "version_minor": 0
      },
      "text/plain": [
       "DualCanvasWidget(status='Not yet rendered')"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    },
    {
     "data": {
      "text/html": [
       "<img src=\"py_line_example.png\"/>"
      ],
      "text/plain": [
       "<IPython.core.display.HTML object>"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    }
   ],
   "source": [
    "eg.py_line_example()"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 8,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/markdown": [
       "\n",
       "### Drawing arrows\n",
       "\n",
       "The `arrow` method draws an arrow between a head position and a tail position.\n"
      ],
      "text/plain": [
       "<IPython.core.display.Markdown object>"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    },
    {
     "data": {
      "text/markdown": [
       "```Python\n",
       "\n",
       "    widget.arrow(\n",
       "        head_length=30,\n",
       "        x1=50, y1=10,   # The tail end point of the line\n",
       "        x2=320, y2=70,  # The head end point of the line\n",
       "        color=\"red\",   # Optional color (default: \"black\")\n",
       "        lineWidth=4,    # Optional line width\n",
       "        lineDash=[2,2], # Optional line dash pattern\n",
       "        head_angle=45,  # Optional head segment angle in degrees (default 45)\n",
       "        head_offset=10,  # Optional offset of head from endpoint\n",
       "        symmetric=True, # If true draw two arrow head segments (default False)\n",
       "    )\n",
       "\n",
       "```"
      ],
      "text/plain": [
       "<IPython.core.display.Markdown object>"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    },
    {
     "data": {
      "application/vnd.jupyter.widget-view+json": {
       "model_id": "29c074cd87614698aebe78d5dfd48383",
       "version_major": 2,
       "version_minor": 0
      },
      "text/plain": [
       "DualCanvasWidget(status='Not yet rendered')"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    },
    {
     "data": {
      "text/html": [
       "<img src=\"py_arrow_example.png\"/>"
      ],
      "text/plain": [
       "<IPython.core.display.HTML object>"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    }
   ],
   "source": [
    "eg.py_arrow_example()"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 9,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/markdown": [
       "\n",
       "### Drawing double arrows\n",
       "\n",
       "The `double_arrow` method draws an arrow between a head position and a tail position\n",
       "with head marks at both ends.\n"
      ],
      "text/plain": [
       "<IPython.core.display.Markdown object>"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    },
    {
     "data": {
      "text/markdown": [
       "```Python\n",
       "\n",
       "    widget.double_arrow(\n",
       "        head_length=30,\n",
       "        x1=50, y1=10,   # The tail end point of the line\n",
       "        x2=320, y2=70,  # The head end point of the line\n",
       "        color=\"red\",   # Optional color (default: \"black\")\n",
       "        back_color=\"blue\",  # Optional color of back arrow\n",
       "        lineWidth=4,    # Optional line width\n",
       "        lineDash=[2,2], # Optional line dash pattern\n",
       "        head_angle=45,  # Optional head segment angle in degrees (default 45)\n",
       "        back_angle=90,   # Optional back head segment angle\n",
       "        head_offset=10,  # Optional offset of head from endpoint\n",
       "        back_offset=0,   # Optional, offset of back pointing head mark\n",
       "        symmetric=False, # If true draw two arrow head segments (default False)\n",
       "        line_offset=5,  # offset of back arrow from forward arros\n",
       "    )\n",
       "\n",
       "```"
      ],
      "text/plain": [
       "<IPython.core.display.Markdown object>"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    },
    {
     "data": {
      "application/vnd.jupyter.widget-view+json": {
       "model_id": "f0c08db093af4b0cac76cf7b0f8ff3d5",
       "version_major": 2,
       "version_minor": 0
      },
      "text/plain": [
       "DualCanvasWidget(status='Not yet rendered')"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    },
    {
     "data": {
      "text/html": [
       "<img src=\"py_double_arrow_example.png\"/>"
      ],
      "text/plain": [
       "<IPython.core.display.HTML object>"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    }
   ],
   "source": [
    "eg.py_double_arrow_example()"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 10,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/markdown": [
       "\n",
       "### Drawing polylines\n",
       "\n",
       "The `polyline` method draws sequence of connected line segments.\n"
      ],
      "text/plain": [
       "<IPython.core.display.Markdown object>"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    },
    {
     "data": {
      "text/markdown": [
       "```Python\n",
       "\n",
       "    points = [(50,20), (40, 60), (140, 111), (300,4), (100,70)]\n",
       "    widget.polyline(\n",
       "        points=points, # The vertices of the polyline path\n",
       "        color=\"green\",   # Optional color (default: \"black\")\n",
       "        lineWidth=3,    # Optional line width\n",
       "        lineDash=[5,5], # Optional line dash pattern\n",
       "    )\n",
       "\n",
       "```"
      ],
      "text/plain": [
       "<IPython.core.display.Markdown object>"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    },
    {
     "data": {
      "application/vnd.jupyter.widget-view+json": {
       "model_id": "2e8b159f57ec4efeba909105c2d0553f",
       "version_major": 2,
       "version_minor": 0
      },
      "text/plain": [
       "DualCanvasWidget(status='Not yet rendered')"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    },
    {
     "data": {
      "text/html": [
       "<img src=\"py_polyline_example.png\"/>"
      ],
      "text/plain": [
       "<IPython.core.display.HTML object>"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    }
   ],
   "source": [
    "eg.py_polyline_example()"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 11,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/markdown": [
       "\n",
       "### Drawing polygons\n",
       "\n",
       "The `polygon` method draws closed sequence of connected line segments.\n"
      ],
      "text/plain": [
       "<IPython.core.display.Markdown object>"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    },
    {
     "data": {
      "text/markdown": [
       "```Python\n",
       "\n",
       "    points = [(50,20), (40, 60), (140, 111), (300,4), (100,70)]\n",
       "    widget.polygon(\n",
       "        points=points, # The vertices of the polyline path\n",
       "        color=\"green\",   # Optional color (default: \"black\")\n",
       "        lineWidth=3,    # Optional line width\n",
       "        lineDash=[5,5], # Optional line dash pattern\n",
       "        fill=False,     # Optional, if True (default) fill interior\n",
       "    )\n",
       "\n",
       "```"
      ],
      "text/plain": [
       "<IPython.core.display.Markdown object>"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    },
    {
     "data": {
      "application/vnd.jupyter.widget-view+json": {
       "model_id": "4720f4a4b9234153b83fba5060320835",
       "version_major": 2,
       "version_minor": 0
      },
      "text/plain": [
       "DualCanvasWidget(status='Not yet rendered')"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    },
    {
     "data": {
      "text/html": [
       "<img src=\"py_polygon_example.png\"/>"
      ],
      "text/plain": [
       "<IPython.core.display.HTML object>"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    }
   ],
   "source": [
    "eg.py_polygon_example()"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 12,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/markdown": [
       "\n",
       "### Drawing circles with canvas relative radius\n",
       "\n",
       "The `circle` method draws a circle sized relative to the canvas\n",
       "coordinate system.  Circles on two frames with the same radius\n",
       "will have the same size.\n"
      ],
      "text/plain": [
       "<IPython.core.display.Markdown object>"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    },
    {
     "data": {
      "text/markdown": [
       "```Python\n",
       "   \n",
       "    frame = widget.frame_region(\n",
       "        minx=10, miny=10, maxx=100, maxy=100,\n",
       "        frame_minx=-3, frame_miny=0, frame_maxx=3, frame_maxy=6,\n",
       "    )\n",
       "    # Draw a circle positioned relative to the frame and sized relative to the canvas.\n",
       "    frame.circle(\n",
       "        x=4,\n",
       "        y=2.5,\n",
       "        r=20,  # radius \"r\" is in canvas coordinates, not frame coordinates\n",
       "        color=\"blue\",\n",
       "        fill=False,\n",
       "        lineWidth=5,\n",
       "        lineDash=[5,5],\n",
       "    )\n",
       "\n",
       "```"
      ],
      "text/plain": [
       "<IPython.core.display.Markdown object>"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    },
    {
     "data": {
      "application/vnd.jupyter.widget-view+json": {
       "model_id": "eb094e327c9646fca082e160f4c6869d",
       "version_major": 2,
       "version_minor": 0
      },
      "text/plain": [
       "DualCanvasWidget(status='Not yet rendered')"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    },
    {
     "data": {
      "text/html": [
       "<img src=\"py_circle_example.png\"/>"
      ],
      "text/plain": [
       "<IPython.core.display.HTML object>"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    }
   ],
   "source": [
    "eg.py_circle_example()"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 13,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/markdown": [
       "\n",
       "### Drawing circles with frame relative radius\n",
       "\n",
       "The `frame_circle` method draws a circle sized relative to the current reference frame\n",
       "coordinate system.  Frame circles on two frames with the same radius\n",
       "may have different sizes if the scaling differs between the frames.\n"
      ],
      "text/plain": [
       "<IPython.core.display.Markdown object>"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    },
    {
     "data": {
      "text/markdown": [
       "```Python\n",
       "   \n",
       "    frame = widget.frame_region(\n",
       "        minx=10, miny=10, maxx=100, maxy=100,\n",
       "        frame_minx=-3, frame_miny=0, frame_maxx=3, frame_maxy=6,\n",
       "    )\n",
       "    # Draw a circle positioned and sized relative to the frame.\n",
       "    frame.frame_circle(\n",
       "        x=4,\n",
       "        y=2.5,\n",
       "        r=3,  # radius \"r\" is in frame coordinates\n",
       "        color=\"blue\",\n",
       "        fill=True,\n",
       "    )\n",
       "\n",
       "```"
      ],
      "text/plain": [
       "<IPython.core.display.Markdown object>"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    },
    {
     "data": {
      "application/vnd.jupyter.widget-view+json": {
       "model_id": "0e72cdec6cc64208b3cd74003cab8417",
       "version_major": 2,
       "version_minor": 0
      },
      "text/plain": [
       "DualCanvasWidget(status='Not yet rendered')"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    },
    {
     "data": {
      "text/html": [
       "<img src=\"py_frame_circle_example.png\"/>"
      ],
      "text/plain": [
       "<IPython.core.display.HTML object>"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    }
   ],
   "source": [
    "eg.py_frame_circle_example()"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 14,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/markdown": [
       "\n",
       "### Drawing stars\n",
       "\n",
       "The `star` method draws a star on the canvas.\n"
      ],
      "text/plain": [
       "<IPython.core.display.Markdown object>"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    },
    {
     "data": {
      "text/markdown": [
       "```Python\n",
       "   \n",
       "    # Draw a star (always positioned and sized relative to the frame)\n",
       "    widget.star(\n",
       "        x=40, y=25, radius=30,\n",
       "        points=5,   # optional number of points\n",
       "        point_factor=2.1,  # optional scale factor for outer radius\n",
       "        color=\"magenta\",\n",
       "        fill=False,\n",
       "        lineWidth=5,\n",
       "        lineDash=[5,5],\n",
       "    )\n",
       "\n",
       "```"
      ],
      "text/plain": [
       "<IPython.core.display.Markdown object>"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    },
    {
     "data": {
      "application/vnd.jupyter.widget-view+json": {
       "model_id": "168dcf6d551e476e919e71454a72653b",
       "version_major": 2,
       "version_minor": 0
      },
      "text/plain": [
       "DualCanvasWidget(status='Not yet rendered')"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    },
    {
     "data": {
      "text/html": [
       "<img src=\"py_star_example.png\"/>"
      ],
      "text/plain": [
       "<IPython.core.display.HTML object>"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    }
   ],
   "source": [
    "eg.py_star_example()"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 15,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/markdown": [
       "\n",
       "### Drawing rectangles with canvas relative size\n",
       "\n",
       "The `rect` method draws a rectangle sized relative to the canvas\n",
       "coordinate system.  `rect`s on two frames with the same width and height\n",
       "will have the same size.\n"
      ],
      "text/plain": [
       "<IPython.core.display.Markdown object>"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    },
    {
     "data": {
      "text/markdown": [
       "```Python\n",
       " \n",
       "    frame = widget.frame_region(\n",
       "        minx=10, miny=10, maxx=100, maxy=100,\n",
       "        frame_minx=-3, frame_miny=0, frame_maxx=3, frame_maxy=6,\n",
       "    )\n",
       "\n",
       "    # Draw a rectangle positioned and sized relative to the frame.\n",
       "    (x,y) = (4, 2.5)\n",
       "    frame.rect(\n",
       "        x=x, y=y,  # rectangle position relative to the frame\n",
       "        w=50, h=40,  # width and height relative to the canvas\n",
       "        dx=-10, dy=-10,  # offset of lower left corner from (x,y) relative to the canvas\n",
       "        color=\"green\",\n",
       "        degrees=10,  # optional rotation in degrees\n",
       "        fill=False,\n",
       "        lineWidth=5,\n",
       "        lineDash=[5,5],\n",
       "    )\n",
       "    # Draw a reference point at (x, y)\n",
       "    frame.circle(x, y, 5, \"red\")\n",
       "    frame.lower_left_axes(color=\"pink\")\n",
       "\n",
       "```"
      ],
      "text/plain": [
       "<IPython.core.display.Markdown object>"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    },
    {
     "data": {
      "application/vnd.jupyter.widget-view+json": {
       "model_id": "684708607b044be998c20a45738ad597",
       "version_major": 2,
       "version_minor": 0
      },
      "text/plain": [
       "DualCanvasWidget(status='Not yet rendered')"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    },
    {
     "data": {
      "text/html": [
       "<img src=\"py_rect_example.png\"/>"
      ],
      "text/plain": [
       "<IPython.core.display.HTML object>"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    }
   ],
   "source": [
    "eg.py_rect_example()"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 16,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/markdown": [
       "\n",
       "### Drawing rectangles with frame relative size\n",
       "\n",
       "The `frame_rect` method draws a rectangle sized relative to the current reference frame\n",
       "coordinate system.  `frame_rect`s on two frames with the same width and height\n",
       "may have the different sizes.\n"
      ],
      "text/plain": [
       "<IPython.core.display.Markdown object>"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    },
    {
     "data": {
      "text/markdown": [
       "```Python\n",
       "    \n",
       "    frame = widget.frame_region(\n",
       "        minx=10, miny=10, maxx=100, maxy=100,\n",
       "        frame_minx=-3, frame_miny=0, frame_maxx=3, frame_maxy=6,\n",
       "    )\n",
       "    # Draw a rectangle positioned and sized relative to the frame.\n",
       "    (x,y) = (4, 2.5)\n",
       "    frame.frame_rect(\n",
       "        x=x, y=y,  # rectangle position\n",
       "        w=5, h=4,  # width and height relative to frame\n",
       "        dx=-1, dy=-1,  # offset of lower left corner from (x,y) relative to frame\n",
       "        color=\"green\",\n",
       "        fill=False,\n",
       "        degrees=10,  # optional rotation in degrees\n",
       "        lineWidth=5,\n",
       "        lineDash=[5,5],\n",
       "    )\n",
       "    # Draw a reference point at (x, y)\n",
       "    frame.circle(x, y, 5, \"red\")\n",
       "    frame.lower_left_axes(color=\"pink\")\n",
       "\n",
       "```"
      ],
      "text/plain": [
       "<IPython.core.display.Markdown object>"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    },
    {
     "data": {
      "application/vnd.jupyter.widget-view+json": {
       "model_id": "a25552201a9d404d938c1a67b2e53ebc",
       "version_major": 2,
       "version_minor": 0
      },
      "text/plain": [
       "DualCanvasWidget(status='Not yet rendered')"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    },
    {
     "data": {
      "text/html": [
       "<img src=\"py_canvas_rect_example.png\"/>"
      ],
      "text/plain": [
       "<IPython.core.display.HTML object>"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    }
   ],
   "source": [
    "eg.py_canvas_rect_example()"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 17,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/markdown": [
       "\n",
       "### Drawing text\n",
       "\n",
       "The `text` method draws a text screen on the canvas.\n",
       "The position of the text is determined by the current reference frame\n",
       "but the text font parameters are relative to the shared canvas coordinate space.\n"
      ],
      "text/plain": [
       "<IPython.core.display.Markdown object>"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    },
    {
     "data": {
      "text/markdown": [
       "```Python\n",
       "   \n",
       "    (x, y) = (50,20)\n",
       "    widget.text(\n",
       "        x=x, y=y, \n",
       "        text=\"We the people\",\n",
       "        color=\"white\",   # Optional color (default: \"black\")\n",
       "        font=\"italic 52px Courier\",   # optional\n",
       "        background=\"#a00\",  # optional\n",
       "        degrees=-15,  # optional rotation in degrees\n",
       "        align=\"center\", # or \"left\" or \"right\", optional\n",
       "        valign=\"center\",  # or \"bottom\", optional\n",
       "    )\n",
       "    # Draw a reference point at (x, y)\n",
       "    widget.circle(x, y, 5, \"magenta\")\n",
       "\n",
       "```"
      ],
      "text/plain": [
       "<IPython.core.display.Markdown object>"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    },
    {
     "data": {
      "application/vnd.jupyter.widget-view+json": {
       "model_id": "2559d9da69994b64af9cd61075fdb382",
       "version_major": 2,
       "version_minor": 0
      },
      "text/plain": [
       "DualCanvasWidget(status='Not yet rendered')"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    },
    {
     "data": {
      "text/html": [
       "<img src=\"py_text_example.png\"/>"
      ],
      "text/plain": [
       "<IPython.core.display.HTML object>"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    }
   ],
   "source": [
    "eg.py_text_example()"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 18,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/markdown": [
       "\n",
       "### Drawing whole images\n",
       "\n",
       "Before an image can be drawn on a canvas\n",
       "the image must be loaded.  The `name_imagea_url` methodß\n",
       "loads an image from a file or a remote resource.\n",
       "After the image has been loaded and named the `named_image`\n",
       "draws the loaded image.  If no subimage is specified\n",
       "the whole image is drawn into the rectangular region.\n",
       "A loaded image may be drawn any number of times.\n"
      ],
      "text/plain": [
       "<IPython.core.display.Markdown object>"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    },
    {
     "data": {
      "text/markdown": [
       "```Python\n",
       "   \n",
       "    # load the image from a remote resource\n",
       "    mandrill_url = \"http://sipi.usc.edu/database/preview/misc/4.2.03.png\"\n",
       "    widget.name_image_url(\n",
       "        image_name=\"mandrill\",\n",
       "        url=mandrill_url,\n",
       "    )\n",
       "    # draw the named image (any number of times)\n",
       "    (x, y) = (50,20)\n",
       "    widget.named_image(  # Draw the *whole* image (don't specify the s* parameters)\n",
       "        image_name=\"mandrill\",\n",
       "        x=x, y=y,  # rectangle position relative to the canvas\n",
       "        w=150, h=140,  # width and height relative to the frame\n",
       "        dx=-30, dy=-50,  # optional offset of lower left corner from (x,y) relative to the canvas\n",
       "        degrees=10,  # optional rotation in degrees\n",
       "    )\n",
       "    # Draw a reference point at (x, y)\n",
       "    widget.circle(x, y, 5, \"magenta\")\n",
       "\n",
       "```"
      ],
      "text/plain": [
       "<IPython.core.display.Markdown object>"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    },
    {
     "data": {
      "application/vnd.jupyter.widget-view+json": {
       "model_id": "d6398a567ee64df1887cd2b40983e3a2",
       "version_major": 2,
       "version_minor": 0
      },
      "text/plain": [
       "DualCanvasWidget(status='Not yet rendered')"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    }
   ],
   "source": [
    "eg.py_full_image_example()"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "**Note:** The canvas created above is marked \"tainted\" \n",
    "because it loads an image from a remote origin and security restrictions in the browser\n",
    "prevent the canvas from being converted to an image.  Here is a screen capture of the\n",
    "live canvas when executed:\n",
    "\n",
    "<img src=\"py_full_mandrill.png\" width=\"400\"/>"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 19,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/markdown": [
       "\n",
       "### Drawing parts of images\n",
       "\n",
       "The `named_image`\n",
       "draws part of a loaded image if the subimage parameters\n",
       "sx, sy, sWidth, and sHeight are specified.\n"
      ],
      "text/plain": [
       "<IPython.core.display.Markdown object>"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    },
    {
     "data": {
      "text/markdown": [
       "```Python\n",
       " \n",
       "    # load the image from a remote resource\n",
       "    mandrill_url = \"http://sipi.usc.edu/database/preview/misc/4.2.03.png\"\n",
       "    widget.name_image_url(\n",
       "        image_name=\"mandrill\",\n",
       "        url=mandrill_url,\n",
       "    )\n",
       "    # draw the named image (any number of times)\n",
       "    (x, y) = (50,20)\n",
       "    widget.named_image(  # Draw just the eyes (by specifying the subimage)\n",
       "        image_name=\"mandrill\",\n",
       "        x=x, y=y,  # rectangle position relative to the canvas\n",
       "        w=150, h=40,  # width and height relative to the frame\n",
       "        dx=-30, dy=-10,  # optional offset of lower left corner from (x,y) relative to the canvas\n",
       "        degrees=10,  # optional rotation in degrees\n",
       "        sx=30, sy=15, # subimage upper left corner in image coordinates\n",
       "        sWidth=140, sHeight=20,  # subimage extent in image coordinates\n",
       "    )\n",
       "    # Draw a reference point at (x, y)\n",
       "    widget.circle(x, y, 5, \"magenta\")\n",
       "\n",
       "```"
      ],
      "text/plain": [
       "<IPython.core.display.Markdown object>"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    },
    {
     "data": {
      "application/vnd.jupyter.widget-view+json": {
       "model_id": "53844de3b1574f7f83cad99852893f17",
       "version_major": 2,
       "version_minor": 0
      },
      "text/plain": [
       "DualCanvasWidget(status='Not yet rendered')"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    }
   ],
   "source": [
    "eg.py_part_image_example()"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "**Note:** The canvas created above is marked \"tainted\" \n",
    "because it loads an image from a remote origin and security restrictions in the browser\n",
    "prevent the canvas from being converted to an image.  Here is a screen capture of the\n",
    "live canvas when executed:\n",
    "\n",
    "<img src=\"py_part_mandrill.png\" width=\"400\"/>"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 20,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/markdown": [
       "\n",
       "### Drawing black and white images from arrays\n",
       "\n",
       "The `name_image_array`\n",
       "can load a black and white image from a\n",
       "2 dimensional `numpy` array.  The numeric values in the\n",
       "array should be in the range from 0 to 255.\n"
      ],
      "text/plain": [
       "<IPython.core.display.Markdown object>"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    },
    {
     "data": {
      "text/markdown": [
       "```Python\n",
       " \n",
       "    # Make a \"black and white\" array.\n",
       "    import numpy as np\n",
       "    checkerboard = np.zeros((8,8))\n",
       "    for i in range(8):\n",
       "        for j in range(8):\n",
       "            if (i + j) % 2 == 0:\n",
       "                checkerboard[i,j] = 64 + 3*i*j\n",
       "    # Load the image from the array.\n",
       "    widget.name_image_array( \n",
       "        image_name=\"checkerboard\",\n",
       "        np_array=checkerboard,\n",
       "    )\n",
       "    # draw the named image (any number of times)\n",
       "    (x, y) = (50,20)\n",
       "    widget.named_image(  # Draw just the eyes (by specifying the subimage)\n",
       "        image_name=\"checkerboard\",\n",
       "        x=x, y=y,  # rectangle position relative to the canvas\n",
       "        w=150, h=140,  # width and height relative to the frame\n",
       "        dx=-30, dy=-10,  # offset of lower left corner from (x,y) relative to the canvas\n",
       "        degrees=10,  # optional rotation in degrees\n",
       "    )\n",
       "    # Draw a reference point at (x, y)\n",
       "    widget.circle(x, y, 5, \"magenta\")\n",
       "\n",
       "```"
      ],
      "text/plain": [
       "<IPython.core.display.Markdown object>"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    },
    {
     "data": {
      "application/vnd.jupyter.widget-view+json": {
       "model_id": "deddf997f3b547d68d6de7efecf03e31",
       "version_major": 2,
       "version_minor": 0
      },
      "text/plain": [
       "DualCanvasWidget(status='Not yet rendered')"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    },
    {
     "data": {
      "text/html": [
       "<img src=\"py_bw_image_example.png\"/>"
      ],
      "text/plain": [
       "<IPython.core.display.HTML object>"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    }
   ],
   "source": [
    "eg.py_bw_image_example()"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 21,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/markdown": [
       "\n",
       "### Drawing color images from arrays\n",
       "\n",
       "The `name_image_array`\n",
       "can load a color image from a\n",
       "3 dimensional `numpy` array of shape \"width by height by 3\"\n",
       "or \"width by height by 4\".  The values at `array[:,:,1:3]` represent\n",
       "the red, green, and blue color values for the pixel and should be in the range 0 to 255.\n",
       "If provided the values at `array[:,:,3]` represent the opacity of the\n",
       "pixel and should be in the range 0 (transparent) to 1.0 (fully opaque).\n"
      ],
      "text/plain": [
       "<IPython.core.display.Markdown object>"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    },
    {
     "data": {
      "text/markdown": [
       "```Python\n",
       " \n",
       "    # Make a \"color\" numpy array\n",
       "    import numpy as np\n",
       "    checkerboard = np.zeros((8,8,3))\n",
       "    R = G = B = 255\n",
       "    for i in range(8):\n",
       "        for j in range(8):\n",
       "            if (i + j) % 2 == 0:\n",
       "                checkerboard[i,j] = (R, G, B)\n",
       "                R = (G + 123) % 256\n",
       "            else:\n",
       "                checkerboard[i,j] = (G, R, R)\n",
       "                G = (R + 201) % 256\n",
       "    # Load the image from the array     \n",
       "    widget.name_image_array(\n",
       "        image_name=\"checkerboard\",\n",
       "        np_array=checkerboard,\n",
       "    )\n",
       "    # draw the named image (any number of times)\n",
       "    (x, y) = (50,20)\n",
       "    widget.named_image(  # Draw just the eyes (by specifying the subimage)\n",
       "        image_name=\"checkerboard\",\n",
       "        x=x, y=y,  # rectangle position relative to the canvas\n",
       "        w=150, h=140,  # width and height relative to the frame\n",
       "        dx=-30, dy=-10,  # offset of lower left corner from (x,y) relative to the canvas\n",
       "        degrees=-50,  # optional rotation in degrees\n",
       "    )\n",
       "    # Draw a reference point at (x, y)\n",
       "    widget.circle(x, y, 10, \"yellow\")\n",
       "\n",
       "```"
      ],
      "text/plain": [
       "<IPython.core.display.Markdown object>"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    },
    {
     "data": {
      "application/vnd.jupyter.widget-view+json": {
       "model_id": "4adbeca50ab2488ea3ebe1cc56048679",
       "version_major": 2,
       "version_minor": 0
      },
      "text/plain": [
       "DualCanvasWidget(status='Not yet rendered')"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    },
    {
     "data": {
      "text/html": [
       "<img src=\"py_color_image_example.png\"/>"
      ],
      "text/plain": [
       "<IPython.core.display.HTML object>"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    }
   ],
   "source": [
    "eg.py_color_image_example()"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### Drawing axes\n",
    "\n",
    "The `left_axis`, `right_axis`, `bottom_axis`, `top_axis`, and `lower_left_axis` methods\n",
    "draw axes on the canvas."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 22,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "application/vnd.jupyter.widget-view+json": {
       "model_id": "44607291e33c4fe99ff5bd6d3a6bcb8a",
       "version_major": 2,
       "version_minor": 0
      },
      "text/plain": [
       "DualCanvasWidget(status='Not yet rendered')"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    },
    {
     "data": {
      "text/html": [
       "<img src=\"axes_demos.png\"/>"
      ],
      "text/plain": [
       "<IPython.core.display.HTML object>"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    }
   ],
   "source": [
    "def axes_demos():\n",
    "    widget = dual_canvas.DualCanvasWidget(width=420, height=120, font=\"italic 12px Courier\",)\n",
    "\n",
    "    widget.left_axis(\n",
    "        min_value=10,\n",
    "        max_value=80,\n",
    "        axis_origin=dict(x=40, y=0),\n",
    "        max_tick_count=3,\n",
    "        color=\"green\",\n",
    "        add_end_points=True\n",
    "    )\n",
    "    widget.right_axis(\n",
    "        min_value=10,\n",
    "        max_value=80,\n",
    "        axis_origin=dict(x=240, y=0),\n",
    "        max_tick_count=7,\n",
    "        color=\"red\"\n",
    "    )\n",
    "    widget.bottom_axis(\n",
    "        min_value=60,\n",
    "        max_value=110,\n",
    "        axis_origin=dict(x=0, y=20),\n",
    "        max_tick_count=5,\n",
    "        color=\"blue\"\n",
    "    )\n",
    "    widget.top_axis(\n",
    "        min_value=130,\n",
    "        max_value=180,\n",
    "        axis_origin=dict(x=0, y=100),\n",
    "        max_tick_count=5,\n",
    "        color=\"orange\"\n",
    "    )\n",
    "\n",
    "    widget.lower_left_axes(\n",
    "        min_x=50, \n",
    "        min_y=30, \n",
    "        max_x=210, \n",
    "        max_y=90, \n",
    "        x_anchor=130, \n",
    "        y_anchor=66, \n",
    "        max_tick_count=4, \n",
    "        color=\"brown\")\n",
    "\n",
    "    widget.fit(margin=10)\n",
    "    eg.show(widget)  # replace with display(demo)\n",
    "\n",
    "axes_demos()"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# Part 3: Events and mutations\n",
    "\n",
    "Objects which have been explicitly named can be changed (moved, resized, deleted, transitioned, etcetera)\n",
    "and unless events are disabled for the object the object can respond to mouse events (mouse over,\n",
    "click, etcetera).\n",
    "\n",
    "### Attaching event callbacks\n",
    "\n",
    "The `object.on(etype, callback)`\n",
    "attaches a `callback` to be called when the object\n",
    "recieves an event of type `etype`."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 23,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "application/vnd.jupyter.widget-view+json": {
       "model_id": "b5595d84e5e14a27bc57b0017918d610",
       "version_major": 2,
       "version_minor": 0
      },
      "text/plain": [
       "DualCanvasWidget(status='Not yet rendered')"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    },
    {
     "data": {
      "text/html": [
       "<img src=\"py_event_example.png\"/>"
      ],
      "text/plain": [
       "<IPython.core.display.HTML object>"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    }
   ],
   "source": [
    "def py_event_example():\n",
    "    widget = dual_canvas.DualCanvasWidget(width=120, height=120)\n",
    "\n",
    "    # this circle cannot be mutated and does not respond to events because it is not named.\n",
    "    widget.circle(x=0, y=0, r=100, color=\"#e99\")\n",
    "\n",
    "    # this text is named and can be mutated and can respond to events\n",
    "    txt1 = widget.text(x=0, y=0, text=\"Click me please\", degrees=45, name=True,\n",
    "               font= \"40pt Arial\", color=\"#e3e\", background=\"#9e9\", align=\"center\", valign=\"center\")\n",
    "\n",
    "    # add a click event bound to the txt which transitions the text rotation\n",
    "    def on_click(*ignored):\n",
    "        txt1.transition(text=\"That tickles\", degrees=720, color=\"#f90\", background=\"#009\", seconds_duration=5)\n",
    "\n",
    "    txt1.on(\"click\", on_click)\n",
    "\n",
    "    widget.fit()\n",
    "    eg.show(widget)  # replace with display(demo)\n",
    "\n",
    "py_event_example()"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### Unnamed objects are invisible to events\n",
    "\n",
    "If an object is not named it will not respond to events\n",
    "but a named object drawn undernieth the unnamed object may\n",
    "receive the event.\n",
    "A named object may also disable events by setting `events=False`\n",
    "-- the resulting object can be changed or deleted but it will not respond to events:\n",
    "```Python\n",
    "widget.circle(x=0, y=0, r=100, color=\"#e99\", name=True, events=False)\n",
    "```\n",
    "Below the circle obscures the text but clicks in the\n",
    "center of the circle are recieved by the text."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 24,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "application/vnd.jupyter.widget-view+json": {
       "model_id": "02c77125388640a68157ea56a8469a98",
       "version_major": 2,
       "version_minor": 0
      },
      "text/plain": [
       "DualCanvasWidget(status='Not yet rendered')"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    },
    {
     "data": {
      "text/html": [
       "<img src=\"py_no_name_no_event.png\"/>"
      ],
      "text/plain": [
       "<IPython.core.display.HTML object>"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    }
   ],
   "source": [
    "def py_no_name_no_event():\n",
    "    widget = dual_canvas.DualCanvasWidget(width=120, height=120)\n",
    "\n",
    "    # this text is named and can be mutated and can respond to events\n",
    "    txt2 = widget.text(x=0, y=0, text=\"CLICK THE CENTER\", degrees=45, name=True,\n",
    "               font= \"40pt Arial\", color=\"#E3E\", background=\"#9e9\", align=\"center\", valign=\"center\")\n",
    "\n",
    "    # this circle cannot be mutated and does not respond to events because it is not named.\n",
    "    # Clicks on the circle above the underlying text will propagate to the text object.\n",
    "    widget.circle(x=0, y=0, r=100, color=\"#e99\")\n",
    "\n",
    "    # add a click event bound to the txt which transitions the text rotation\n",
    "    def on_click(*ignored):\n",
    "        txt2.transition(text=\"That tickles\", degrees=720, color=\"#f90\", background=\"#009\", seconds_duration=5)\n",
    "\n",
    "    txt2.on(\"click\", on_click)\n",
    "\n",
    "    widget.fit()\n",
    "    eg.show(widget)  # replace with display(demo)\n",
    "    \n",
    "py_no_name_no_event()"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### Only the top named object responds to events\n",
    "\n",
    "Only the top named object under an event receives the event even if\n",
    "it is drawn using a transparent color.\n",
    "Any object underneith the top object will not receive the event."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 25,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "application/vnd.jupyter.widget-view+json": {
       "model_id": "29f4b99dddfd49498071efa10cf68fc5",
       "version_major": 2,
       "version_minor": 0
      },
      "text/plain": [
       "DualCanvasWidget(status='Not yet rendered')"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    },
    {
     "data": {
      "text/html": [
       "<img src=\"py_top_object_event.png\"/>"
      ],
      "text/plain": [
       "<IPython.core.display.HTML object>"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    }
   ],
   "source": [
    "def py_top_object_event():\n",
    "    widget = dual_canvas.DualCanvasWidget(width=120, height=120)\n",
    "\n",
    "    # this text is named and can be mutated and can respond to events\n",
    "    txt3 = widget.text(x=0, y=0, text=\"TRY CLICKING CENTER\", degrees=45, name=True,\n",
    "               font= \"40pt Arial\", color=\"#E3E\", background=\"#9e9\", align=\"center\", valign=\"center\")\n",
    "\n",
    "    # this circle CAN be mutated and DOES respond to events because it is named.\n",
    "    # and clicks on the circle will NOT \"propagate\" to the text object underneith.\n",
    "    circ3 = widget.circle(x=0, y=0, r=100, color=\"#e99\",\n",
    "                 name=True)\n",
    "\n",
    "    # add a click event bound to the txt which transitions the text rotation\n",
    "    def on_click(*ignored):\n",
    "        txt3.transition(text=\"That tickles\", degrees=720, color=\"#f90\", background=\"#009\", seconds_duration=5)\n",
    "        circ3.change(color=\"red\")\n",
    "\n",
    "    txt3.on(\"click\", on_click)\n",
    "\n",
    "    widget.fit()\n",
    "    eg.show(widget)  # replace with display(demo)\n",
    "    \n",
    "py_top_object_event()"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### Changing, transitioning, forgetting, and hiding named objects\n",
    "\n",
    "Named objects have methods which allow them to be modified or related to interactive events.\n",
    "\n",
    "```Python\n",
    "# Change the object options.\n",
    "object.change(**changed_options)\n",
    "\n",
    "# Transition the object options over a time period.\n",
    "object.transition(seconds_duration, **changed_options)\n",
    "\n",
    "# Make the object invisible and unresponsive to events\n",
    "object.visible(False)\n",
    "\n",
    "# Make the object visible and enable event bindings.\n",
    "object.visible(True)\n",
    "\n",
    "# Remove the object from the canvas and dispose of it.\n",
    "object.forget()\n",
    "```\n",
    "\n",
    "### Binding and unbinding event callbacks to named objects\n",
    "\n",
    "```Python\n",
    "# Attach an event handler to call when event_type effects the object.\n",
    "object.on(event_type, handler)\n",
    "\n",
    "# Detach any event handler associated with event_type for the object.\n",
    "object.off(event_type)\n",
    "```\n",
    "\n",
    "Event types include `click`, `mousedown`, `mouseup`, `mouseout`, `mouseover`, `mousemove`, `keydown`\n",
    "among others.  Please see \n",
    "<a href=\"https://developer.mozilla.org/en-US/docs/Web/Events\">https://developer.mozilla.org/en-US/docs/Web/Events</a>\n",
    "and <a href=\"https://api.jquery.com/on/\">https://api.jquery.com/on/</a>\n",
    "for more information about events.\n",
    "\n",
    "### Addressing objects by name\n",
    "\n",
    "Objects can be identified by name and modified using methods attached to the canvas widget.\n",
    "\n",
    "```Python\n",
    "# Change object properties by object name.\n",
    "canvas.change(name, **changed_options)\n",
    "\n",
    "# Destroy objects with a sequence of names.\n",
    "canvas.forget_objects(names)\n",
    "\n",
    "# Show or hide objects identified by a name sequence.\n",
    "canvas.set_visibilities(names, visibility)\n",
    "\n",
    "# Add an event binding to an object by name or the whole canvas if for_name is None.\n",
    "canvas.on_canvas_event(event_type, callback, for_name=None, abbreviated=True, delay=True)\n",
    "\n",
    "# Remove an event binding from an object by name or from the whole canvas if for_name is None.\n",
    "canvas.off_canvas_event(event_type, for_name=None)\n",
    "```\n",
    "\n",
    "### The event callback\n",
    "\n",
    "Event callbacks receive a dictionary argument `event` describing the event.\n",
    "Descriptive slots include:\n",
    "\n",
    "- `event[\"type\"]` gives the type of the event (like `click`).\n",
    "- `event[\"canvas_name\"]` give the name of the object under the event, if any (some events are associated to the canvas and have no target object on the canvas).\n",
    "- `event[\"model_location\"]` gives the coordinate position on the canvas or reference frame associated with\n",
    "the event as a dictionary like `{'x': -0.21, 'y': 0.28}`.\n",
    "- `event[\"reference_frame\"][\"name\"]` gives the name of the reference frame for the canvas if the event\n",
    "is associated with a reference frame."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 26,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "application/vnd.jupyter.widget-view+json": {
       "model_id": "da98aefa5faa4cedb888c81a61cb0cb9",
       "version_major": 2,
       "version_minor": 0
      },
      "text/plain": [
       "DualCanvasWidget(status='Not yet rendered')"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    },
    {
     "data": {
      "text/html": [
       "<img src=\"event_callback_example.png\"/>"
      ],
      "text/plain": [
       "<IPython.core.display.HTML object>"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    }
   ],
   "source": [
    "event = None\n",
    "\n",
    "def event_callback_example():\n",
    "    widget = dual_canvas.DualCanvasWidget(width=220, height=220)\n",
    "\n",
    "    frame = widget.frame_region(\n",
    "        minx=10, miny=10, maxx=200, maxy=200,\n",
    "        frame_minx=-1, frame_miny=-1, frame_maxx=1, frame_maxy=1,\n",
    "        name=\"EVENT_REFERENCE_FRAME\"\n",
    "    )\n",
    "    frame.lower_left_axes(min_x=-1, min_y=-1, max_x=1, max_y=1, color=\"pink\", max_tick_count=4)\n",
    "    txte = frame.text(-0.5, 0.25, \"CLICK ME\", name=\"EVENT_EXAMPLE_TEXT\", background=\"#eea\")\n",
    "\n",
    "    def callback(e):\n",
    "        global event\n",
    "        event = e\n",
    "        txte.change(text=\"Thanks!\", background=\"#aee\")\n",
    "\n",
    "    txte.on(\"click\", callback)\n",
    "    \n",
    "    eg.show(widget)  # replace with display(demo)\n",
    "    \n",
    "event_callback_example()"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 27,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "The object has not been clicked\n"
     ]
    }
   ],
   "source": [
    "if event is None:\n",
    "    print(\"The object has not been clicked\")\n",
    "else:\n",
    "    print(\"The event was of type\", event[\"type\"])\n",
    "    print(\"Clicked object named\", event[\"canvas_name\"])\n",
    "    print(\"Click was positioned in the reference frame coordinates at\", event[\"model_location\"])\n",
    "    print(\"The reference frame for the click was named\", event[\"reference_frame\"][\"name\"])\n",
    "#event"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "When the previous cell runs after the `txte` object is clicked the cell prints eomething similar to the following:\n",
    "```\n",
    "The event was of type click\n",
    "Clicked object named EVENT_EXAMPLE_TEXT\n",
    "Click was positioned in the reference frame coordinates at {'x': -0.2302634791324013, 'y': 0.2726244474712171}\n",
    "The reference frame for the click was named EVENT_REFERENCE_FRAME\n",
    "```\n",
    "\n",
    "### Selecting named objects by surrounding them with a lasso\n",
    "\n",
    "The `widget.do_lasso(callback)` method allows the user to select named objects\n",
    "by surrounding them with a graphical loop.  After the loop is complete the callback\n",
    "receives a dictionary mapping the names of the selected objects to their descriptions."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 28,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "application/vnd.jupyter.widget-view+json": {
       "model_id": "b13553bc88fa45afaef9ad06592be242",
       "version_major": 2,
       "version_minor": 0
      },
      "text/plain": [
       "DualCanvasWidget(status='Not yet rendered')"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    },
    {
     "data": {
      "text/html": [
       "<img src=\"py_lasso_demo.png\"/>"
      ],
      "text/plain": [
       "<IPython.core.display.HTML object>"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    }
   ],
   "source": [
    "mapping = None\n",
    "\n",
    "widget = dual_canvas.DualCanvasWidget(width=420, height=150)\n",
    "\n",
    "def py_lasso_demo():\n",
    "    info = widget.text(10, 10, \"Mouse down and draw lasso to encircle elements.\", name=\"info\")\n",
    "    left = widget.text(50, 50, \"Left\", name=\"left\", background=\"#ffe\", color=\"red\")\n",
    "    center = widget.text(100, 50, \"Center\", name=\"center\", background=\"#ffe\", color=\"blue\")\n",
    "    above = widget.text(100, 75, \"Above\", name=\"above\", background=\"#ffe\", color=\"green\")\n",
    "    below = widget.text(100, 25, \"Below\", name=\"below\", background=\"#ffe\", color=\"brown\")\n",
    "    right = widget.text(150, 50, \"Right\", name=\"right\", background=\"#ffe\")\n",
    "\n",
    "    def callback(m):\n",
    "        global mapping\n",
    "        mapping = m\n",
    "        info.change(text=\"selected: \" + str(list(mapping.keys())) + \". Play again!\")\n",
    "        # set up the lasso again\n",
    "        widget.do_lasso(callback)\n",
    "\n",
    "    widget.fit()\n",
    "\n",
    "    widget.do_lasso(callback)\n",
    "    \n",
    "    eg.show(widget)  # replace with display(demo)\n",
    "\n",
    "py_lasso_demo()"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 29,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Lasso was not completed.\n"
     ]
    }
   ],
   "source": [
    "if mapping is None:\n",
    "    print (\"Lasso was not completed.\")\n",
    "else:\n",
    "    print (\"Lassoed\", len(mapping), \"objects.\")\n",
    "    for name in mapping:\n",
    "        info = mapping[name]\n",
    "        print(\"   name:\", name, \"at\", info[\"x\"], info[\"y\"], \"shape\", info[\"shape_name\"], \"color\", info[\"color\"])"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "After encircling \"Above\" and \"Center\" the cell above prints\n",
    "\n",
    "```\n",
    "Lassoed 2 objects.\n",
    "   name: above at 100 75 shape text color green\n",
    "   name: center at 100 50 shape text color blue\n",
    "```\n",
    "\n",
    "#### Adding a floating tooltip for named elements\n",
    "\n",
    "The `widget.enable_tooltip(tooltip_attribute=\"tip\", background=\"cyan\")`\n",
    "causes named objects to pop up a tooltip showing the value of the\n",
    "`tip` attribute when the mouse is over the object."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 30,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "application/vnd.jupyter.widget-view+json": {
       "model_id": "a8405b2090824e24975daf769c6e09e7",
       "version_major": 2,
       "version_minor": 0
      },
      "text/plain": [
       "DualCanvasWidget(status='Not yet rendered')"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    },
    {
     "data": {
      "text/html": [
       "<img src=\"py_tooltip_demo.png\"/>"
      ],
      "text/plain": [
       "<IPython.core.display.HTML object>"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    }
   ],
   "source": [
    "def py_tooltip_demo():\n",
    "    widget = dual_canvas.DualCanvasWidget(width=420, height=150)\n",
    "\n",
    "    info = widget.text(10, 10, \"Mouse over named elements to see tooltip.\", tip=\"this unnamed element will not respond!\")\n",
    "    left = widget.text(50, 50, \"Left\", name=\"left\", background=\"#ff7\", tip=\"the left most <br> named element\")\n",
    "    center = widget.text(100, 50, \"Center\", name=\"center\", background=\"#ff7\", tip=\"the central <br> named element\")\n",
    "    above = widget.text(100, 75, \"Above\", name=\"above\", background=\"#ff7\", tip=\"the upper most <br> named element\")\n",
    "    below = widget.text(100, 25, \"Below\", name=\"below\", background=\"#ff7\", tip=\"the lower most <br> named element\")\n",
    "    right = widget.text(150, 50, \"Right\", name=\"right\", background=\"#ff7\", tip=\"the right most <br> named element\")\n",
    "\n",
    "    widget.fit()\n",
    "\n",
    "    widget.enable_tooltip(tooltip_attribute=\"tip\", background=\"cyan\", font=\"bold 10px Arial\")\n",
    "    widget.element.jp_doodle_tooltip.css({\"border-radius\": \"5px\", \"padding\": \"4px\"})\n",
    "\n",
    "    eg.show(widget)  # replace with display(demo)\n",
    "    \n",
    "py_tooltip_demo()"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## Part 4: Other canvas and frame methods\n",
    "\n",
    "\n",
    "### Preventing redraws during complex updates.\n",
    "\n",
    "```Python\n",
    "# Do not redraw the widget until both update operations are complete.\n",
    "with widget.delay_redraw():\n",
    "    complex_update1(widget)\n",
    "    complex_update2(widget)\n",
    "```\n",
    "\n",
    "### Remove all objects and reset internal data structures\n",
    "\n",
    "The following will remove and destroy all objects from a canvas and reset\n",
    "the canvas to its initial configuration.\n",
    "\n",
    "```Python\n",
    "widget.reset_canvas()\n",
    "```\n",
    "\n",
    "The following will remove and destroy all objects from a canvas and reset\n",
    "a frame to its initial configuration.\n",
    "\n",
    "```Python\n",
    "frame.reset_frame()\n",
    "```\n",
    "\n",
    "### Pop out dialog\n",
    "\n",
    "The `in_dialog` method places the canvas in a floating JQueryUI dialog.\n",
    "\n",
    "```Python\n",
    "widget.in_dialog()\n",
    "```\n",
    "\n",
    "### Execute callback at next animation frame\n",
    "\n",
    "The `requestAnimationFrame` method calls the\n",
    "callback when the screen refreshes.\n",
    "\n",
    "```Python\n",
    "widget.requestAnimationFrame(callback)\n",
    "```\n",
    "\n",
    "### Recalibrate a frame\n",
    "\n",
    "The following will reposition and rescale a frame\n",
    "\n",
    "```Python\n",
    "frame.set_region(\n",
    "    minx, miny, maxx, maxy, \n",
    "    frame_minx, frame_miny, frame_maxx, frame_maxy)\n",
    "```\n",
    "\n",
    "### Show debug output area\n",
    "\n",
    "The `widget.debugging_display()` method generates a composite widget\n",
    "which provides verbose debugging information that may provide information\n",
    "about exceptions or other problems which occur during the development\n",
    "of a canvas viaualization.\n",
    "\n",
    "```Python\n",
    "widget.debugging_display()\n",
    "```"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": []
  }
 ],
 "metadata": {
  "kernelspec": {
   "display_name": "Python 3",
   "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.6.8"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 2
}