{
 "cells": [
  {
   "cell_type": "code",
   "execution_count": 15,
   "metadata": {
    "collapsed": false,
    "deletable": true,
    "editable": true
   },
   "outputs": [],
   "source": [
    "from jp_doodle import doodle_files\n",
    "vf_js = doodle_files.vendor_path(\"js/canvas_2d_vector_field.js\")\n",
    "from jp_doodle import dual_canvas\n",
    "import jp_proxy_widget"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 16,
   "metadata": {
    "collapsed": false,
    "deletable": true,
    "editable": true
   },
   "outputs": [
    {
     "data": {
      "application/vnd.jupyter.widget-view+json": {
       "model_id": "22ce57770b1e44a286e0141ec05cd91c",
       "version_major": 2,
       "version_minor": 0
      },
      "text/html": [
       "<p>Failed to display Jupyter Widget of type <code>VBox</code>.</p>\n",
       "<p>\n",
       "  If you're reading this message in Jupyter Notebook or JupyterLab, it may mean\n",
       "  that the widgets JavaScript is still loading. If this message persists, it\n",
       "  likely means that the widgets JavaScript library is either not installed or\n",
       "  not enabled. See the <a href=\"https://ipywidgets.readthedocs.io/en/stable/user_install.html\">Jupyter\n",
       "  Widgets Documentation</a> for setup instructions.\n",
       "</p>\n",
       "<p>\n",
       "  If you're reading this message in another notebook frontend (for example, a static\n",
       "  rendering on GitHub or <a href=\"https://nbviewer.jupyter.org/\">NBViewer</a>),\n",
       "  it may mean that your frontend doesn't currently support widgets.\n",
       "</p>\n"
      ],
      "text/plain": [
       "VBox(children=(JSProxyWidget(status=u'Not yet rendered'), Text(value=u'Not yet rendered', description=u'status:'), Text(value=u'No error', description=u'error'), Output(layout=Layout(border=u'1px solid black'))))"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    }
   ],
   "source": [
    "w = jp_proxy_widget.JSProxyWidget()\n",
    "w.load_js_files([vf_js])\n",
    "dual_canvas.load_requirements(w)\n",
    "w.js_init(\"\"\"\n",
    "debugger;\n",
    "element.canvas_2d_vector_field.example(element);\n",
    "\"\"\")\n",
    "\n",
    "w.debugging_display()"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 3,
   "metadata": {
    "collapsed": false,
    "deletable": true,
    "editable": true
   },
   "outputs": [
    {
     "data": {
      "text/plain": [
       "element"
      ]
     },
     "execution_count": 3,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "w.element.reset_canvas()"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 17,
   "metadata": {
    "collapsed": false,
    "deletable": true,
    "editable": true
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "3.60555127546\n"
     ]
    },
    {
     "data": {
      "text/plain": [
       "(array([[ 0.30242086,  0.57327401,  0.87441002],\n",
       "        [ 0.8699484 ,  0.32549768,  0.29876122]]),\n",
       " array([[ 0.27784884,  0.52669488,  0.80336326],\n",
       "        [ 0.89160212,  0.33359958,  0.30619763]]))"
      ]
     },
     "execution_count": 17,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "import numpy as np\n",
    "print np.linalg.norm((2,3))\n",
    "x = np.random.random((2,3))\n",
    "\n",
    "def unitize(vectors):\n",
    "    (nr, nc) = vectors.shape\n",
    "    norms = np.linalg.norm(vectors, axis=1)\n",
    "    return vectors/norms.reshape((nr, 1))\n",
    "\n",
    "(x, unitize(x))\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 18,
   "metadata": {
    "collapsed": false,
    "deletable": true,
    "editable": true
   },
   "outputs": [],
   "source": [
    "# random motions from 1000 random positions\n",
    "npoints = 100\n",
    "duration = 1\n",
    "shape = (npoints, 2)\n",
    "points = np.random.random(shape) * 2.0 - 1.0\n",
    "max_movement = 0.2\n",
    "movement = max_movement * (np.random.random(shape) * 2.0 - 1.0)\n",
    "offsets = np.random.random((npoints,)) * duration\n",
    "motions = []\n",
    "for i in range(npoints):\n",
    "    (x, y) = points[i]\n",
    "    (dx, dy) = movement[i]\n",
    "    motion = {\n",
    "        \"sx\": x-dx, \"sy\": y-dy, \"ex\": x+dx, \"ey\": y+dy, \"dt\": offsets[i]\n",
    "    }\n",
    "    motions.append(motion)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 19,
   "metadata": {
    "collapsed": false,
    "deletable": true,
    "editable": true
   },
   "outputs": [
    {
     "data": {
      "application/vnd.jupyter.widget-view+json": {
       "model_id": "f5d113cb241b4215afa3110934a1a330",
       "version_major": 2,
       "version_minor": 0
      },
      "text/html": [
       "<p>Failed to display Jupyter Widget of type <code>Tab</code>.</p>\n",
       "<p>\n",
       "  If you're reading this message in Jupyter Notebook or JupyterLab, it may mean\n",
       "  that the widgets JavaScript is still loading. If this message persists, it\n",
       "  likely means that the widgets JavaScript library is either not installed or\n",
       "  not enabled. See the <a href=\"https://ipywidgets.readthedocs.io/en/stable/user_install.html\">Jupyter\n",
       "  Widgets Documentation</a> for setup instructions.\n",
       "</p>\n",
       "<p>\n",
       "  If you're reading this message in another notebook frontend (for example, a static\n",
       "  rendering on GitHub or <a href=\"https://nbviewer.jupyter.org/\">NBViewer</a>),\n",
       "  it may mean that your frontend doesn't currently support widgets.\n",
       "</p>\n"
      ],
      "text/plain": [
       "Tab(children=(VBox(children=(SnapshotCanvas(status=u'Not yet rendered'), JSProxyWidget(status=u'Not yet rendered'))), HTML(value=u'<img src=\"vector_field.png?id=snapshot_id_9_1539974981245\" id=\"snapshot_id_9_1539974981245\"/>\\n <div id=\"snapshot_id_10_1539974981246\">vector_field.png</div>')), _titles={u'1': 'Snapshot', u'0': 'Canvas'})"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    }
   ],
   "source": [
    "def show_motions(motions, duration=1, radius=0.01):    \n",
    "    #c2 = dual_canvas.DualCanvasWidget(width=800, height=800)\n",
    "    c2 = dual_canvas.SnapshotCanvas(\"vector_field.png\", width=800, height=800)\n",
    "    c2.js_init(\"\"\"\n",
    "            var frame0 = element.frame_region(50, 50, 300, 300, -1, -1, 1, 1);\n",
    "            element.frame0 = frame0;\n",
    "            frame0.frame_rect({x:-1, y:-1, w:2, h:2, color:\"#ddf\"});\n",
    "            frame0.lower_left_axes({min_x:-1, min_y:-1, max_x:1, max_y:1, max_tick_count:4});\n",
    "            var frame = element.frame_region(50, 50, 300, 300, -1, -1, 1, 1);\n",
    "            var f_options = {\n",
    "                frame: frame,\n",
    "                duration: duration,  // seconds\n",
    "                initial_color: \"red\",\n",
    "                final_color: \"red\",\n",
    "                radius: radius,\n",
    "                motions: motions,\n",
    "                shape: \"line\",\n",
    "            };\n",
    "            element.fit(null, 50)\n",
    "            element.canvas_2d_vector_field(f_options);\n",
    "    \"\"\", motions=motions, duration=duration, radius=radius)\n",
    "    #return c2.debugging_display()\n",
    "    return c2\n",
    "\n",
    "c2 = show_motions(motions, duration)\n",
    "c2.display_all()"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 20,
   "metadata": {
    "collapsed": false,
    "deletable": true,
    "editable": true
   },
   "outputs": [
    {
     "data": {
      "text/plain": [
       "element"
      ]
     },
     "execution_count": 20,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "c2.element.reset_canvas()"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 21,
   "metadata": {
    "collapsed": false,
    "deletable": true,
    "editable": true
   },
   "outputs": [],
   "source": [
    "#points"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 22,
   "metadata": {
    "collapsed": false,
    "deletable": true,
    "editable": true
   },
   "outputs": [],
   "source": [
    "#motions"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 23,
   "metadata": {
    "collapsed": false,
    "deletable": true,
    "editable": true
   },
   "outputs": [],
   "source": [
    "# attraction towards the center\n",
    "xc = 0.3\n",
    "yc = 0.4\n",
    "npoints = 100\n",
    "duration = 1\n",
    "shape = (npoints, 2)\n",
    "points = np.random.random(shape) * 2.0 - 1.0\n",
    "max_movement = 0.2\n",
    "shift = np.array([[xc, yc]]) - points\n",
    "movement = max_movement * shift\n",
    "offsets = np.random.random((npoints,)) * duration\n",
    "motions = []\n",
    "for i in range(npoints):\n",
    "    (x, y) = points[i]\n",
    "    (dx, dy) = movement[i]\n",
    "    motion = {\n",
    "        \"sx\": x-dx, \"sy\": y-dy, \"ex\": x+dx, \"ey\": y+dy, \"dt\": offsets[i]\n",
    "    }\n",
    "    motions.append(motion)\n",
    "    \n",
    "c3 = show_motions(motions, duration)\n",
    "#c3"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 24,
   "metadata": {
    "collapsed": false,
    "deletable": true,
    "editable": true
   },
   "outputs": [],
   "source": [
    "# motion around the center point\n",
    "xc = 0.3\n",
    "yc = 0.4\n",
    "npoints = 100\n",
    "duration = 1\n",
    "shape = (npoints, 2)\n",
    "points = np.random.random(shape) * 2.0 - 1.0\n",
    "max_movement = 0.2\n",
    "shift = np.array([[xc, yc]]) - points\n",
    "shift2 = np.zeros(shape)\n",
    "shift2[:,0] = shift[:,1]\n",
    "shift2[:,1] = -shift[:,0]\n",
    "movement = max_movement * shift2\n",
    "offsets = np.random.random((npoints,)) * duration\n",
    "motions = []\n",
    "for i in range(npoints):\n",
    "    (x, y) = points[i]\n",
    "    (dx, dy) = movement[i]\n",
    "    motion = {\n",
    "        \"sx\": x-dx, \"sy\": y-dy, \"ex\": x+dx, \"ey\": y+dy, \"dt\": offsets[i]\n",
    "    }\n",
    "    motions.append(motion)\n",
    "    \n",
    "c4 = show_motions(motions, duration)\n",
    "c4.js_init(\"\"\"\n",
    "debugger;\n",
    "element.frame0.frame_circle({x: xc, y:yc, r:max_movement, color:\"rgba(255,200,100,0.7)\"})\n",
    "\"\"\", xc=xc, yc=yc, max_movement=max_movement)\n",
    "#c4"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 25,
   "metadata": {
    "collapsed": false,
    "deletable": true,
    "editable": true
   },
   "outputs": [
    {
     "data": {
      "text/plain": [
       "element"
      ]
     },
     "execution_count": 25,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "c4.element.reset_canvas()"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 26,
   "metadata": {
    "collapsed": false,
    "deletable": true,
    "editable": true
   },
   "outputs": [
    {
     "data": {
      "application/vnd.jupyter.widget-view+json": {
       "model_id": "4992e17da5dd456c9daa3070f0667fed",
       "version_major": 2,
       "version_minor": 0
      },
      "text/html": [
       "<p>Failed to display Jupyter Widget of type <code>SnapshotCanvas</code>.</p>\n",
       "<p>\n",
       "  If you're reading this message in Jupyter Notebook or JupyterLab, it may mean\n",
       "  that the widgets JavaScript is still loading. If this message persists, it\n",
       "  likely means that the widgets JavaScript library is either not installed or\n",
       "  not enabled. See the <a href=\"https://ipywidgets.readthedocs.io/en/stable/user_install.html\">Jupyter\n",
       "  Widgets Documentation</a> for setup instructions.\n",
       "</p>\n",
       "<p>\n",
       "  If you're reading this message in another notebook frontend (for example, a static\n",
       "  rendering on GitHub or <a href=\"https://nbviewer.jupyter.org/\">NBViewer</a>),\n",
       "  it may mean that your frontend doesn't currently support widgets.\n",
       "</p>\n"
      ],
      "text/plain": [
       "SnapshotCanvas(status=u'Not yet rendered')"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    }
   ],
   "source": [
    "def attraction(cx, cy, points, factor=1.0):\n",
    "    shift = factor * (np.array([[cx, cy]]) - points)\n",
    "    return unitize(shift)\n",
    "\n",
    "def clockwise(cx, cy, points, factor=1.0):\n",
    "    shift = attraction(cx, cy, points, factor=1.0)\n",
    "    shift2 = np.zeros(shift.shape)\n",
    "    shift2[:,0] = shift[:,1]\n",
    "    shift2[:,1] = -shift[:,0]\n",
    "    return shift2\n",
    "\n",
    "npoints = 1000\n",
    "duration = 1\n",
    "shape = (npoints, 2)\n",
    "points = np.random.random(shape) * 2.0 - 1.0\n",
    "shift = 0.25 * (\n",
    "    #+ attraction(0.5, 0.5, points)\n",
    "    + 2* attraction(-0.5, -0.5, points)\n",
    "    + clockwise(0.5, -0.5, points, -1)\n",
    "    + 3*clockwise(-0.5, 0.5, points, -1)\n",
    ")\n",
    "#shift = unitize(shift)\n",
    "max_movement = 0.2\n",
    "movement = max_movement * shift\n",
    "offsets = np.random.random((npoints,)) * duration\n",
    "motions = []\n",
    "for i in range(npoints):\n",
    "    (x, y) = points[i]\n",
    "    (dx, dy) = movement[i]\n",
    "    motion = {\n",
    "        \"sx\": x-dx, \"sy\": y-dy, \"ex\": x+dx, \"ey\": y+dy, \"dt\": offsets[i]\n",
    "    }\n",
    "    motions.append(motion)\n",
    "    \n",
    "c4 = show_motions(motions, duration)\n",
    "c4"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 14,
   "metadata": {
    "collapsed": false,
    "deletable": true,
    "editable": true
   },
   "outputs": [
    {
     "data": {
      "text/plain": [
       "element"
      ]
     },
     "execution_count": 14,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "c4.element.reset_canvas()"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "collapsed": true,
    "deletable": true,
    "editable": true
   },
   "outputs": [],
   "source": [
    "# dump motions to file\n",
    "filename = \"motions.json\"\n",
    "f = open(filename, \"w\")\n",
    "f.write(\"[\\n\")\n",
    "for m in motions:\n",
    "    f.write(\"{\")\n",
    "    for k in m:\n",
    "        v = m[k]\n",
    "        f.write(\"%s:%2.2f,\" % (k, v))\n",
    "    f.write(\"},\\n\")\n",
    "f.write(\"]\\n\")\n",
    "f.close()"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "collapsed": false,
    "deletable": true,
    "editable": true
   },
   "outputs": [],
   "source": [
    "print(open(filename).read(3200))"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "collapsed": false,
    "deletable": true,
    "editable": true
   },
   "outputs": [],
   "source": [
    "motions[0]"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "collapsed": true,
    "deletable": true,
    "editable": true
   },
   "outputs": [],
   "source": []
  }
 ],
 "metadata": {
  "kernelspec": {
   "display_name": "Python 2",
   "language": "python",
   "name": "python2"
  },
  "language_info": {
   "codemirror_mode": {
    "name": "ipython",
    "version": 2
   },
   "file_extension": ".py",
   "mimetype": "text/x-python",
   "name": "python",
   "nbconvert_exporter": "python",
   "pygments_lexer": "ipython2",
   "version": "2.7.13"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 2
}