{
 "cells": [
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# Jupyter Canvas Widget - Rail Editor\n",
    "\n",
    "From - https://github.com/Who8MyLunch/Jupyter_Canvas_Widget/blob/master/notebooks/example%20mouse%20events.ipynb\n",
    "Follow his instructions to do a local dev install and enable the widget."
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## You need to run all cells before trying to edit the rails!"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 1,
   "metadata": {},
   "outputs": [],
   "source": [
    "%load_ext autoreload\n",
    "%autoreload 2"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 2,
   "metadata": {},
   "outputs": [],
   "source": [
    "import image_attendant as imat\n",
    "import ipywidgets\n",
    "import IPython\n",
    "import jpy_canvas\n",
    "import numpy as np\n",
    "from numpy import array\n",
    "import time\n",
    "from collections import deque\n",
    "from matplotlib import pyplot as plt\n",
    "import io\n",
    "from PIL import Image"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 3,
   "metadata": {},
   "outputs": [],
   "source": [
    "from ipywidgets import IntSlider, link, VBox, RadioButtons, HBox, interact"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 4,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "cpu\n"
     ]
    }
   ],
   "source": [
    "import flatland.core.env\n",
    "from flatland.envs.rail_env import RailEnv, random_rail_generator\n",
    "from flatland.core.transitions import RailEnvTransitions\n",
    "from flatland.core.env_observation_builder import TreeObsForRailEnv\n",
    "import flatland.utils.rendertools as rt\n",
    "from flatland.utils.editor import JupEditor"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 5,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/html": [
       "<style>.container { width:90% !important; }</style>"
      ],
      "text/plain": [
       "<IPython.core.display.HTML object>"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    }
   ],
   "source": [
    "from IPython.core.display import display, HTML\n",
    "display(HTML(\"<style>.container { width:90% !important; }</style>\"))"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 6,
   "metadata": {},
   "outputs": [],
   "source": [
    "oEnv = RailEnv(width=20,\n",
    "              height=20,\n",
    "              rail_generator=random_rail_generator(cell_type_relative_proportion=[1,1] + [0.5] * 6),\n",
    "              number_of_agents=0,\n",
    "              obs_builder_object=TreeObsForRailEnv(max_depth=2))\n",
    "obs = oEnv.reset()"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 7,
   "metadata": {},
   "outputs": [],
   "source": [
    "sfEnv = \"../flatland/env-data/tests/test1.npy\"\n",
    "if True:\n",
    "    oEnv.rail.load_transition_map(sfEnv)\n",
    "    oEnv.width = oEnv.rail.width\n",
    "    oEnv.height = oEnv.rail.height"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 8,
   "metadata": {},
   "outputs": [],
   "source": [
    "oRT = rt.RenderTool(oEnv)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 9,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "10"
      ]
     },
     "execution_count": 9,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "oEnv.width"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 10,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "['/home/jeremy/projects/heating',\n",
       " '/home/jeremy/projects/aicrowd/rl-trains/MAgent/python',\n",
       " '/home/jeremy/ve367/lib/python36.zip',\n",
       " '/home/jeremy/ve367/lib/python3.6',\n",
       " '/home/jeremy/ve367/lib/python3.6/lib-dynload',\n",
       " '/usr/lib/python3.6',\n",
       " '',\n",
       " '/home/jeremy/ve367/lib/python3.6/site-packages',\n",
       " '/home/jeremy/projects/aicrowd/rl-trains/torch-rl/torch_rl',\n",
       " '/home/jeremy/projects/aicrowd/rl-trains/gym-minigrid',\n",
       " '/home/jeremy/projects/aicrowd/rl-trains/flatland',\n",
       " '/home/jeremy/projects/aicrowd/rl-trains/Jupyter_Canvas_Widget',\n",
       " '/home/jeremy/ve367/lib/python3.6/site-packages/IPython/extensions',\n",
       " '/home/jeremy/.ipython']"
      ]
     },
     "execution_count": 10,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "import sys\n",
    "sys.path"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### Clear the rails"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 11,
   "metadata": {},
   "outputs": [],
   "source": [
    "oEnv.rail.grid[:,:] = 0"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### Render the env in the usual way, and take an image snapshot as numpy array\n",
    "If you have already edited the env in the cell below, these changes should be reflected here."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 12,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "<class 'numpy.ndarray'>\n"
     ]
    },
    {
     "data": {
      "text/plain": [
       "<Figure size 720x720 with 0 Axes>"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    }
   ],
   "source": [
    "oFig = plt.figure(figsize=(10,10))\n",
    "oRT.renderEnv(spacing=False, arrows=False, sRailColor=\"gray\", show=False)\n",
    "img = oRT.getImage()\n",
    "print(type(img))\n",
    "plt.clf()   # if you don't want the image to appear here\n",
    "pass\n",
    "\n",
    "wid_img = jpy_canvas.Canvas(img)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### Update the function - in case external code updated"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 13,
   "metadata": {},
   "outputs": [],
   "source": [
    "wid_img.unregister_all()\n",
    "oEditor = JupEditor(oEnv, wid_img)\n",
    "wid_img.register_move(oEditor.event_handler)\n",
    "wid_img.register_click(oEditor.on_click)\n"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### Some more widgets"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 14,
   "metadata": {},
   "outputs": [],
   "source": [
    "wid_drawMode = ipywidgets.RadioButtons(options=[\"Draw\", \"Erase\", \"Origin\", \"Destination\"])\n",
    "wid_drawMode.observe(oEditor.setDrawMode, names=\"value\")\n",
    "wid_debug = ipywidgets.Checkbox(description = \"Debug\")\n",
    "wid_debug.observe(oEditor.setDebug, names=\"value\")\n",
    "wid_debug_move = ipywidgets.Checkbox(description = \"Debug mouse move\")\n",
    "wid_debug_move.observe(oEditor.setDebugMove, names=\"value\")\n",
    "\n",
    "wid_output = ipywidgets.Output()\n",
    "oEditor.setOutput(wid_output)\n",
    "wid_filename = ipywidgets.Text(description = \"Filename\")\n",
    "wid_filename.value = sfEnv\n",
    "oEditor.setFilename(sfEnv)\n",
    "wid_filename.observe(oEditor.setFilename_event, names=\"value\")\n",
    "\n",
    "wid_size = ipywidgets.IntSlider(min=5, max=30, step=5, description=\"Regen Size\")\n",
    "wid_size.observe(oEditor.setRegenSize_event, names=\"value\")\n",
    "\n",
    "prog_steps = ipywidgets.IntProgress(value=0, min=0, max=20, step=1, description=\"Step\")\n",
    "#prog_steps.observe(oEditor.)\n",
    "\n",
    "\n",
    "ldButtons = [\n",
    "    dict(name = \"Refresh\", method = oEditor.redraw_event),\n",
    "    dict(name = \"Clear\", method = oEditor.clear),\n",
    "    dict(name = \"Regenerate\", method = oEditor.regenerate_event),\n",
    "    dict(name = \"Load\", method = oEditor.load),\n",
    "    dict(name = \"Save\", method = oEditor.save),\n",
    "    dict(name = \"Step\", method = oEditor.step_event),\n",
    "    dict(name = \"Run Steps\", method = oEditor.start_run_event),\n",
    "]\n",
    "\n",
    "lwid_buttons = []\n",
    "for dButton in ldButtons:\n",
    "    wid_button = ipywidgets.Button(description = dButton[\"name\"])\n",
    "    wid_button.on_click(dButton[\"method\"])\n",
    "    lwid_buttons.append(wid_button)\n",
    "    \n",
    "\n",
    "#wid_debug = interact(oEditor.setDebug, debug=False)\n",
    "vbox_controls = VBox([wid_filename, wid_drawMode, *lwid_buttons, wid_size, wid_debug, wid_debug_move])\n"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### Edit the map below here by dragging the mouse to create transitions\n",
    "You can create a dead-end by dragging foward and backward, ie Cell A -> Adjacent Cell B -> back to Cell A"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 15,
   "metadata": {
    "scrolled": false
   },
   "outputs": [
    {
     "data": {
      "application/vnd.jupyter.widget-view+json": {
       "model_id": "cddcd8e9e5fb48c185a129ff73b1ef40",
       "version_major": 2,
       "version_minor": 0
      },
      "text/plain": [
       "HBox(children=(Canvas(), VBox(children=(Text(value='../flatland/env-data/tests/test1.npy', description='Filena…"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    }
   ],
   "source": [
    "# wid_box\n",
    "wid_main = HBox([wid_img, vbox_controls])\n",
    "wid_output.clear_output()\n",
    "wid_main"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 32,
   "metadata": {
    "scrolled": true
   },
   "outputs": [
    {
     "data": {
      "application/vnd.jupyter.widget-view+json": {
       "model_id": "b4d521d96fc44ea6bf7cd9e4e299673b",
       "version_major": 2,
       "version_minor": 0
      },
      "text/plain": [
       "Output(outputs=({'output_type': 'stream', 'text': \"Set Debug: True\\ndebug: {'type': 'click', 'shiftKey': False…"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    }
   ],
   "source": [
    "wid_output.clear_output()\n",
    "wid_output"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### Experimental\n",
    "enable the thread.start below to try background stepping of the agents.  It tends to make a mess."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 17,
   "metadata": {},
   "outputs": [],
   "source": [
    "import threading\n",
    "def bgUpdate(editor):\n",
    "    for i in range(100):\n",
    "        editor.step_event()\n",
    "        time.sleep(0.2)\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 18,
   "metadata": {},
   "outputs": [],
   "source": [
    "thread = threading.Thread(target=bgUpdate, args = (oEditor,))"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 19,
   "metadata": {},
   "outputs": [],
   "source": [
    "if False:\n",
    "    thread.start()"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### Save the image (change the filename...)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 20,
   "metadata": {},
   "outputs": [],
   "source": [
    "if False: \n",
    "    oEnv.rail.save_transition_map(\"../flatland/env-data/tests/test-editor.npy\")"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## Junk below here"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 21,
   "metadata": {},
   "outputs": [],
   "source": [
    "def evListen(wid, ev):\n",
    "    x = ev[\"canvasX\"]\n",
    "    y=ev[\"canvasY\"]\n",
    "    yxBase = array([6, 21])\n",
    "    nPixCell = 35\n",
    "    rcCell = ((array([y, x]) - yxBase) / nPixCell).astype(int)\n",
    "    print(ev)\n",
    "    print(x, y, (x-21) / 35, (y-6) / 35, rcCell)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 22,
   "metadata": {},
   "outputs": [],
   "source": [
    "# wid_img.register_click(evListen)\n",
    "#wid_img.register(evListen)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 23,
   "metadata": {},
   "outputs": [],
   "source": [
    "#wid_img.unregister_all()"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 24,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "application/vnd.jupyter.widget-view+json": {
       "model_id": "adf698700a634775bfe4da0909912b96",
       "version_major": 2,
       "version_minor": 0
      },
      "text/plain": [
       "IntText(value=0)"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    }
   ],
   "source": [
    "ipywidgets.IntText(0)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 25,
   "metadata": {},
   "outputs": [],
   "source": [
    "from examples.play_model import Player"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 26,
   "metadata": {},
   "outputs": [],
   "source": [
    "oP = Player(oEnv)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 27,
   "metadata": {},
   "outputs": [],
   "source": [
    "oP.step()"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 28,
   "metadata": {},
   "outputs": [],
   "source": [
    "import asyncio\n",
    "def wait_for_change(widget, value):\n",
    "    future = asyncio.Future()\n",
    "    def getvalue(change):\n",
    "        # make the new value available\n",
    "        future.set_result(change.new)\n",
    "        widget.unobserve(getvalue, value)\n",
    "    widget.observe(getvalue, value)\n",
    "    return future"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 29,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "application/vnd.jupyter.widget-view+json": {
       "model_id": "e6bf851f84bd471f8f4a4771e9d9b668",
       "version_major": 2,
       "version_minor": 0
      },
      "text/plain": [
       "IntSlider(value=0)"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    }
   ],
   "source": [
    "slider = ipywidgets.IntSlider()\n",
    "\n",
    "async def f():\n",
    "    for i in range(10):\n",
    "        print('did work %s'%i)\n",
    "        x = await wait_for_change(slider, 'value')\n",
    "        print('async function continued with value %s'%x)\n",
    "asyncio.ensure_future(f())\n",
    "\n",
    "slider"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 30,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "application/vnd.jupyter.widget-view+json": {
       "model_id": "4de1e7a8162e460f8b1ecc732d3c1e2e",
       "version_major": 2,
       "version_minor": 0
      },
      "text/plain": [
       "FloatProgress(value=0.0, max=1.0)"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    }
   ],
   "source": [
    "\n",
    "import threading\n",
    "from IPython.display import display\n",
    "import time\n",
    "progress = ipywidgets.FloatProgress(value=0.0, min=0.0, max=1.0)\n",
    "\n",
    "def work(progress):\n",
    "    total = 100\n",
    "    for i in range(total):\n",
    "        time.sleep(0.2)\n",
    "        progress.value = float(i+1)/total\n",
    "\n",
    "thread = threading.Thread(target=work, args=(progress,))\n",
    "display(progress)\n",
    "thread.start()\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 31,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "['1000', '0000', '0010', '0000']"
      ]
     },
     "execution_count": 31,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "binTrans = format(32800, \"#016b\")\n",
    "[binTrans[i+2:i+6] for i in range(0, len(binTrans)-2, 4)]"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "\n"
   ]
  }
 ],
 "metadata": {
  "hide_input": false,
  "kernelspec": {
   "display_name": "ve367",
   "language": "python",
   "name": "ve367"
  },
  "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.7"
  },
  "latex_envs": {
   "LaTeX_envs_menu_present": true,
   "autoclose": false,
   "autocomplete": true,
   "bibliofile": "biblio.bib",
   "cite_by": "apalike",
   "current_citInitial": 1,
   "eqLabelWithNumbers": true,
   "eqNumInitial": 1,
   "hotkeys": {
    "equation": "Ctrl-E",
    "itemize": "Ctrl-I"
   },
   "labels_anchors": false,
   "latex_user_defs": false,
   "report_style_numbering": false,
   "user_envs_cfg": false
  },
  "toc": {
   "base_numbering": 1,
   "nav_menu": {},
   "number_sections": true,
   "sideBar": true,
   "skip_h1_title": false,
   "title_cell": "Table of Contents",
   "title_sidebar": "Contents",
   "toc_cell": false,
   "toc_position": {},
   "toc_section_display": true,
   "toc_window_display": false
  },
  "varInspector": {
   "cols": {
    "lenName": 16,
    "lenType": 16,
    "lenVar": 40
   },
   "kernels_config": {
    "python": {
     "delete_cmd_postfix": "",
     "delete_cmd_prefix": "del ",
     "library": "var_list.py",
     "varRefreshCmd": "print(var_dic_list())"
    },
    "r": {
     "delete_cmd_postfix": ") ",
     "delete_cmd_prefix": "rm(",
     "library": "var_list.r",
     "varRefreshCmd": "cat(var_dic_list()) "
    }
   },
   "types_to_exclude": [
    "module",
    "function",
    "builtin_function_or_method",
    "instance",
    "_Feature"
   ],
   "window_display": false
  }
 },
 "nbformat": 4,
 "nbformat_minor": 2
}