{
 "cells": [
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# Nuke\n",
    "\n",
    "Sometimes matplotlib just doesn't give us the tools we need to animate stuff. This block is a way to work around that.\n",
    "\n",
    "Matplotlib.axes.Axes.quiver does not have a way to dynamically set the location of arrows, only the angle. In this example, we work around that."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 1,
   "metadata": {},
   "outputs": [],
   "source": [
    "%matplotlib notebook\n",
    "import numpy as np\n",
    "import matplotlib.pyplot as plt\n",
    "import animatplot as amp"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Lets first construct our data. "
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 2,
   "metadata": {},
   "outputs": [],
   "source": [
    "E0 = np.array([1, 2])\n",
    "E0 = E0 / np.linalg.norm(E0)\n",
    "\n",
    "phi = np.array([0, np.pi / 7])\n",
    "\n",
    "f = 3\n",
    "t = np.linspace(0, 2 * np.pi, 100)\n",
    "\n",
    "ES = E0[:, np.newaxis] * np.exp(\n",
    "    1j * (t + phi[:, np.newaxis])\n",
    ")  # fancy array boardcasting"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Now, we animate the data."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 3,
   "metadata": {
    "scrolled": false
   },
   "outputs": [
    {
     "data": {
      "application/javascript": [
       "/* Put everything inside the global mpl namespace */\n",
       "window.mpl = {};\n",
       "\n",
       "\n",
       "mpl.get_websocket_type = function() {\n",
       "    if (typeof(WebSocket) !== 'undefined') {\n",
       "        return WebSocket;\n",
       "    } else if (typeof(MozWebSocket) !== 'undefined') {\n",
       "        return MozWebSocket;\n",
       "    } else {\n",
       "        alert('Your browser does not have WebSocket support.' +\n",
       "              'Please try Chrome, Safari or Firefox ≥ 6. ' +\n",
       "              'Firefox 4 and 5 are also supported but you ' +\n",
       "              'have to enable WebSockets in about:config.');\n",
       "    };\n",
       "}\n",
       "\n",
       "mpl.figure = function(figure_id, websocket, ondownload, parent_element) {\n",
       "    this.id = figure_id;\n",
       "\n",
       "    this.ws = websocket;\n",
       "\n",
       "    this.supports_binary = (this.ws.binaryType != undefined);\n",
       "\n",
       "    if (!this.supports_binary) {\n",
       "        var warnings = document.getElementById(\"mpl-warnings\");\n",
       "        if (warnings) {\n",
       "            warnings.style.display = 'block';\n",
       "            warnings.textContent = (\n",
       "                \"This browser does not support binary websocket messages. \" +\n",
       "                    \"Performance may be slow.\");\n",
       "        }\n",
       "    }\n",
       "\n",
       "    this.imageObj = new Image();\n",
       "\n",
       "    this.context = undefined;\n",
       "    this.message = undefined;\n",
       "    this.canvas = undefined;\n",
       "    this.rubberband_canvas = undefined;\n",
       "    this.rubberband_context = undefined;\n",
       "    this.format_dropdown = undefined;\n",
       "\n",
       "    this.image_mode = 'full';\n",
       "\n",
       "    this.root = $('<div/>');\n",
       "    this._root_extra_style(this.root)\n",
       "    this.root.attr('style', 'display: inline-block');\n",
       "\n",
       "    $(parent_element).append(this.root);\n",
       "\n",
       "    this._init_header(this);\n",
       "    this._init_canvas(this);\n",
       "    this._init_toolbar(this);\n",
       "\n",
       "    var fig = this;\n",
       "\n",
       "    this.waiting = false;\n",
       "\n",
       "    this.ws.onopen =  function () {\n",
       "            fig.send_message(\"supports_binary\", {value: fig.supports_binary});\n",
       "            fig.send_message(\"send_image_mode\", {});\n",
       "            if (mpl.ratio != 1) {\n",
       "                fig.send_message(\"set_dpi_ratio\", {'dpi_ratio': mpl.ratio});\n",
       "            }\n",
       "            fig.send_message(\"refresh\", {});\n",
       "        }\n",
       "\n",
       "    this.imageObj.onload = function() {\n",
       "            if (fig.image_mode == 'full') {\n",
       "                // Full images could contain transparency (where diff images\n",
       "                // almost always do), so we need to clear the canvas so that\n",
       "                // there is no ghosting.\n",
       "                fig.context.clearRect(0, 0, fig.canvas.width, fig.canvas.height);\n",
       "            }\n",
       "            fig.context.drawImage(fig.imageObj, 0, 0);\n",
       "        };\n",
       "\n",
       "    this.imageObj.onunload = function() {\n",
       "        fig.ws.close();\n",
       "    }\n",
       "\n",
       "    this.ws.onmessage = this._make_on_message_function(this);\n",
       "\n",
       "    this.ondownload = ondownload;\n",
       "}\n",
       "\n",
       "mpl.figure.prototype._init_header = function() {\n",
       "    var titlebar = $(\n",
       "        '<div class=\"ui-dialog-titlebar ui-widget-header ui-corner-all ' +\n",
       "        'ui-helper-clearfix\"/>');\n",
       "    var titletext = $(\n",
       "        '<div class=\"ui-dialog-title\" style=\"width: 100%; ' +\n",
       "        'text-align: center; padding: 3px;\"/>');\n",
       "    titlebar.append(titletext)\n",
       "    this.root.append(titlebar);\n",
       "    this.header = titletext[0];\n",
       "}\n",
       "\n",
       "\n",
       "\n",
       "mpl.figure.prototype._canvas_extra_style = function(canvas_div) {\n",
       "\n",
       "}\n",
       "\n",
       "\n",
       "mpl.figure.prototype._root_extra_style = function(canvas_div) {\n",
       "\n",
       "}\n",
       "\n",
       "mpl.figure.prototype._init_canvas = function() {\n",
       "    var fig = this;\n",
       "\n",
       "    var canvas_div = $('<div/>');\n",
       "\n",
       "    canvas_div.attr('style', 'position: relative; clear: both; outline: 0');\n",
       "\n",
       "    function canvas_keyboard_event(event) {\n",
       "        return fig.key_event(event, event['data']);\n",
       "    }\n",
       "\n",
       "    canvas_div.keydown('key_press', canvas_keyboard_event);\n",
       "    canvas_div.keyup('key_release', canvas_keyboard_event);\n",
       "    this.canvas_div = canvas_div\n",
       "    this._canvas_extra_style(canvas_div)\n",
       "    this.root.append(canvas_div);\n",
       "\n",
       "    var canvas = $('<canvas/>');\n",
       "    canvas.addClass('mpl-canvas');\n",
       "    canvas.attr('style', \"left: 0; top: 0; z-index: 0; outline: 0\")\n",
       "\n",
       "    this.canvas = canvas[0];\n",
       "    this.context = canvas[0].getContext(\"2d\");\n",
       "\n",
       "    var backingStore = this.context.backingStorePixelRatio ||\n",
       "\tthis.context.webkitBackingStorePixelRatio ||\n",
       "\tthis.context.mozBackingStorePixelRatio ||\n",
       "\tthis.context.msBackingStorePixelRatio ||\n",
       "\tthis.context.oBackingStorePixelRatio ||\n",
       "\tthis.context.backingStorePixelRatio || 1;\n",
       "\n",
       "    mpl.ratio = (window.devicePixelRatio || 1) / backingStore;\n",
       "\n",
       "    var rubberband = $('<canvas/>');\n",
       "    rubberband.attr('style', \"position: absolute; left: 0; top: 0; z-index: 1;\")\n",
       "\n",
       "    var pass_mouse_events = true;\n",
       "\n",
       "    canvas_div.resizable({\n",
       "        start: function(event, ui) {\n",
       "            pass_mouse_events = false;\n",
       "        },\n",
       "        resize: function(event, ui) {\n",
       "            fig.request_resize(ui.size.width, ui.size.height);\n",
       "        },\n",
       "        stop: function(event, ui) {\n",
       "            pass_mouse_events = true;\n",
       "            fig.request_resize(ui.size.width, ui.size.height);\n",
       "        },\n",
       "    });\n",
       "\n",
       "    function mouse_event_fn(event) {\n",
       "        if (pass_mouse_events)\n",
       "            return fig.mouse_event(event, event['data']);\n",
       "    }\n",
       "\n",
       "    rubberband.mousedown('button_press', mouse_event_fn);\n",
       "    rubberband.mouseup('button_release', mouse_event_fn);\n",
       "    // Throttle sequential mouse events to 1 every 20ms.\n",
       "    rubberband.mousemove('motion_notify', mouse_event_fn);\n",
       "\n",
       "    rubberband.mouseenter('figure_enter', mouse_event_fn);\n",
       "    rubberband.mouseleave('figure_leave', mouse_event_fn);\n",
       "\n",
       "    canvas_div.on(\"wheel\", function (event) {\n",
       "        event = event.originalEvent;\n",
       "        event['data'] = 'scroll'\n",
       "        if (event.deltaY < 0) {\n",
       "            event.step = 1;\n",
       "        } else {\n",
       "            event.step = -1;\n",
       "        }\n",
       "        mouse_event_fn(event);\n",
       "    });\n",
       "\n",
       "    canvas_div.append(canvas);\n",
       "    canvas_div.append(rubberband);\n",
       "\n",
       "    this.rubberband = rubberband;\n",
       "    this.rubberband_canvas = rubberband[0];\n",
       "    this.rubberband_context = rubberband[0].getContext(\"2d\");\n",
       "    this.rubberband_context.strokeStyle = \"#000000\";\n",
       "\n",
       "    this._resize_canvas = function(width, height) {\n",
       "        // Keep the size of the canvas, canvas container, and rubber band\n",
       "        // canvas in synch.\n",
       "        canvas_div.css('width', width)\n",
       "        canvas_div.css('height', height)\n",
       "\n",
       "        canvas.attr('width', width * mpl.ratio);\n",
       "        canvas.attr('height', height * mpl.ratio);\n",
       "        canvas.attr('style', 'width: ' + width + 'px; height: ' + height + 'px;');\n",
       "\n",
       "        rubberband.attr('width', width);\n",
       "        rubberband.attr('height', height);\n",
       "    }\n",
       "\n",
       "    // Set the figure to an initial 600x600px, this will subsequently be updated\n",
       "    // upon first draw.\n",
       "    this._resize_canvas(600, 600);\n",
       "\n",
       "    // Disable right mouse context menu.\n",
       "    $(this.rubberband_canvas).bind(\"contextmenu\",function(e){\n",
       "        return false;\n",
       "    });\n",
       "\n",
       "    function set_focus () {\n",
       "        canvas.focus();\n",
       "        canvas_div.focus();\n",
       "    }\n",
       "\n",
       "    window.setTimeout(set_focus, 100);\n",
       "}\n",
       "\n",
       "mpl.figure.prototype._init_toolbar = function() {\n",
       "    var fig = this;\n",
       "\n",
       "    var nav_element = $('<div/>')\n",
       "    nav_element.attr('style', 'width: 100%');\n",
       "    this.root.append(nav_element);\n",
       "\n",
       "    // Define a callback function for later on.\n",
       "    function toolbar_event(event) {\n",
       "        return fig.toolbar_button_onclick(event['data']);\n",
       "    }\n",
       "    function toolbar_mouse_event(event) {\n",
       "        return fig.toolbar_button_onmouseover(event['data']);\n",
       "    }\n",
       "\n",
       "    for(var toolbar_ind in mpl.toolbar_items) {\n",
       "        var name = mpl.toolbar_items[toolbar_ind][0];\n",
       "        var tooltip = mpl.toolbar_items[toolbar_ind][1];\n",
       "        var image = mpl.toolbar_items[toolbar_ind][2];\n",
       "        var method_name = mpl.toolbar_items[toolbar_ind][3];\n",
       "\n",
       "        if (!name) {\n",
       "            // put a spacer in here.\n",
       "            continue;\n",
       "        }\n",
       "        var button = $('<button/>');\n",
       "        button.addClass('ui-button ui-widget ui-state-default ui-corner-all ' +\n",
       "                        'ui-button-icon-only');\n",
       "        button.attr('role', 'button');\n",
       "        button.attr('aria-disabled', 'false');\n",
       "        button.click(method_name, toolbar_event);\n",
       "        button.mouseover(tooltip, toolbar_mouse_event);\n",
       "\n",
       "        var icon_img = $('<span/>');\n",
       "        icon_img.addClass('ui-button-icon-primary ui-icon');\n",
       "        icon_img.addClass(image);\n",
       "        icon_img.addClass('ui-corner-all');\n",
       "\n",
       "        var tooltip_span = $('<span/>');\n",
       "        tooltip_span.addClass('ui-button-text');\n",
       "        tooltip_span.html(tooltip);\n",
       "\n",
       "        button.append(icon_img);\n",
       "        button.append(tooltip_span);\n",
       "\n",
       "        nav_element.append(button);\n",
       "    }\n",
       "\n",
       "    var fmt_picker_span = $('<span/>');\n",
       "\n",
       "    var fmt_picker = $('<select/>');\n",
       "    fmt_picker.addClass('mpl-toolbar-option ui-widget ui-widget-content');\n",
       "    fmt_picker_span.append(fmt_picker);\n",
       "    nav_element.append(fmt_picker_span);\n",
       "    this.format_dropdown = fmt_picker[0];\n",
       "\n",
       "    for (var ind in mpl.extensions) {\n",
       "        var fmt = mpl.extensions[ind];\n",
       "        var option = $(\n",
       "            '<option/>', {selected: fmt === mpl.default_extension}).html(fmt);\n",
       "        fmt_picker.append(option)\n",
       "    }\n",
       "\n",
       "    // Add hover states to the ui-buttons\n",
       "    $( \".ui-button\" ).hover(\n",
       "        function() { $(this).addClass(\"ui-state-hover\");},\n",
       "        function() { $(this).removeClass(\"ui-state-hover\");}\n",
       "    );\n",
       "\n",
       "    var status_bar = $('<span class=\"mpl-message\"/>');\n",
       "    nav_element.append(status_bar);\n",
       "    this.message = status_bar[0];\n",
       "}\n",
       "\n",
       "mpl.figure.prototype.request_resize = function(x_pixels, y_pixels) {\n",
       "    // Request matplotlib to resize the figure. Matplotlib will then trigger a resize in the client,\n",
       "    // which will in turn request a refresh of the image.\n",
       "    this.send_message('resize', {'width': x_pixels, 'height': y_pixels});\n",
       "}\n",
       "\n",
       "mpl.figure.prototype.send_message = function(type, properties) {\n",
       "    properties['type'] = type;\n",
       "    properties['figure_id'] = this.id;\n",
       "    this.ws.send(JSON.stringify(properties));\n",
       "}\n",
       "\n",
       "mpl.figure.prototype.send_draw_message = function() {\n",
       "    if (!this.waiting) {\n",
       "        this.waiting = true;\n",
       "        this.ws.send(JSON.stringify({type: \"draw\", figure_id: this.id}));\n",
       "    }\n",
       "}\n",
       "\n",
       "\n",
       "mpl.figure.prototype.handle_save = function(fig, msg) {\n",
       "    var format_dropdown = fig.format_dropdown;\n",
       "    var format = format_dropdown.options[format_dropdown.selectedIndex].value;\n",
       "    fig.ondownload(fig, format);\n",
       "}\n",
       "\n",
       "\n",
       "mpl.figure.prototype.handle_resize = function(fig, msg) {\n",
       "    var size = msg['size'];\n",
       "    if (size[0] != fig.canvas.width || size[1] != fig.canvas.height) {\n",
       "        fig._resize_canvas(size[0], size[1]);\n",
       "        fig.send_message(\"refresh\", {});\n",
       "    };\n",
       "}\n",
       "\n",
       "mpl.figure.prototype.handle_rubberband = function(fig, msg) {\n",
       "    var x0 = msg['x0'] / mpl.ratio;\n",
       "    var y0 = (fig.canvas.height - msg['y0']) / mpl.ratio;\n",
       "    var x1 = msg['x1'] / mpl.ratio;\n",
       "    var y1 = (fig.canvas.height - msg['y1']) / mpl.ratio;\n",
       "    x0 = Math.floor(x0) + 0.5;\n",
       "    y0 = Math.floor(y0) + 0.5;\n",
       "    x1 = Math.floor(x1) + 0.5;\n",
       "    y1 = Math.floor(y1) + 0.5;\n",
       "    var min_x = Math.min(x0, x1);\n",
       "    var min_y = Math.min(y0, y1);\n",
       "    var width = Math.abs(x1 - x0);\n",
       "    var height = Math.abs(y1 - y0);\n",
       "\n",
       "    fig.rubberband_context.clearRect(\n",
       "        0, 0, fig.canvas.width, fig.canvas.height);\n",
       "\n",
       "    fig.rubberband_context.strokeRect(min_x, min_y, width, height);\n",
       "}\n",
       "\n",
       "mpl.figure.prototype.handle_figure_label = function(fig, msg) {\n",
       "    // Updates the figure title.\n",
       "    fig.header.textContent = msg['label'];\n",
       "}\n",
       "\n",
       "mpl.figure.prototype.handle_cursor = function(fig, msg) {\n",
       "    var cursor = msg['cursor'];\n",
       "    switch(cursor)\n",
       "    {\n",
       "    case 0:\n",
       "        cursor = 'pointer';\n",
       "        break;\n",
       "    case 1:\n",
       "        cursor = 'default';\n",
       "        break;\n",
       "    case 2:\n",
       "        cursor = 'crosshair';\n",
       "        break;\n",
       "    case 3:\n",
       "        cursor = 'move';\n",
       "        break;\n",
       "    }\n",
       "    fig.rubberband_canvas.style.cursor = cursor;\n",
       "}\n",
       "\n",
       "mpl.figure.prototype.handle_message = function(fig, msg) {\n",
       "    fig.message.textContent = msg['message'];\n",
       "}\n",
       "\n",
       "mpl.figure.prototype.handle_draw = function(fig, msg) {\n",
       "    // Request the server to send over a new figure.\n",
       "    fig.send_draw_message();\n",
       "}\n",
       "\n",
       "mpl.figure.prototype.handle_image_mode = function(fig, msg) {\n",
       "    fig.image_mode = msg['mode'];\n",
       "}\n",
       "\n",
       "mpl.figure.prototype.updated_canvas_event = function() {\n",
       "    // Called whenever the canvas gets updated.\n",
       "    this.send_message(\"ack\", {});\n",
       "}\n",
       "\n",
       "// A function to construct a web socket function for onmessage handling.\n",
       "// Called in the figure constructor.\n",
       "mpl.figure.prototype._make_on_message_function = function(fig) {\n",
       "    return function socket_on_message(evt) {\n",
       "        if (evt.data instanceof Blob) {\n",
       "            /* FIXME: We get \"Resource interpreted as Image but\n",
       "             * transferred with MIME type text/plain:\" errors on\n",
       "             * Chrome.  But how to set the MIME type?  It doesn't seem\n",
       "             * to be part of the websocket stream */\n",
       "            evt.data.type = \"image/png\";\n",
       "\n",
       "            /* Free the memory for the previous frames */\n",
       "            if (fig.imageObj.src) {\n",
       "                (window.URL || window.webkitURL).revokeObjectURL(\n",
       "                    fig.imageObj.src);\n",
       "            }\n",
       "\n",
       "            fig.imageObj.src = (window.URL || window.webkitURL).createObjectURL(\n",
       "                evt.data);\n",
       "            fig.updated_canvas_event();\n",
       "            fig.waiting = false;\n",
       "            return;\n",
       "        }\n",
       "        else if (typeof evt.data === 'string' && evt.data.slice(0, 21) == \"data:image/png;base64\") {\n",
       "            fig.imageObj.src = evt.data;\n",
       "            fig.updated_canvas_event();\n",
       "            fig.waiting = false;\n",
       "            return;\n",
       "        }\n",
       "\n",
       "        var msg = JSON.parse(evt.data);\n",
       "        var msg_type = msg['type'];\n",
       "\n",
       "        // Call the  \"handle_{type}\" callback, which takes\n",
       "        // the figure and JSON message as its only arguments.\n",
       "        try {\n",
       "            var callback = fig[\"handle_\" + msg_type];\n",
       "        } catch (e) {\n",
       "            console.log(\"No handler for the '\" + msg_type + \"' message type: \", msg);\n",
       "            return;\n",
       "        }\n",
       "\n",
       "        if (callback) {\n",
       "            try {\n",
       "                // console.log(\"Handling '\" + msg_type + \"' message: \", msg);\n",
       "                callback(fig, msg);\n",
       "            } catch (e) {\n",
       "                console.log(\"Exception inside the 'handler_\" + msg_type + \"' callback:\", e, e.stack, msg);\n",
       "            }\n",
       "        }\n",
       "    };\n",
       "}\n",
       "\n",
       "// from http://stackoverflow.com/questions/1114465/getting-mouse-location-in-canvas\n",
       "mpl.findpos = function(e) {\n",
       "    //this section is from http://www.quirksmode.org/js/events_properties.html\n",
       "    var targ;\n",
       "    if (!e)\n",
       "        e = window.event;\n",
       "    if (e.target)\n",
       "        targ = e.target;\n",
       "    else if (e.srcElement)\n",
       "        targ = e.srcElement;\n",
       "    if (targ.nodeType == 3) // defeat Safari bug\n",
       "        targ = targ.parentNode;\n",
       "\n",
       "    // jQuery normalizes the pageX and pageY\n",
       "    // pageX,Y are the mouse positions relative to the document\n",
       "    // offset() returns the position of the element relative to the document\n",
       "    var x = e.pageX - $(targ).offset().left;\n",
       "    var y = e.pageY - $(targ).offset().top;\n",
       "\n",
       "    return {\"x\": x, \"y\": y};\n",
       "};\n",
       "\n",
       "/*\n",
       " * return a copy of an object with only non-object keys\n",
       " * we need this to avoid circular references\n",
       " * http://stackoverflow.com/a/24161582/3208463\n",
       " */\n",
       "function simpleKeys (original) {\n",
       "  return Object.keys(original).reduce(function (obj, key) {\n",
       "    if (typeof original[key] !== 'object')\n",
       "        obj[key] = original[key]\n",
       "    return obj;\n",
       "  }, {});\n",
       "}\n",
       "\n",
       "mpl.figure.prototype.mouse_event = function(event, name) {\n",
       "    var canvas_pos = mpl.findpos(event)\n",
       "\n",
       "    if (name === 'button_press')\n",
       "    {\n",
       "        this.canvas.focus();\n",
       "        this.canvas_div.focus();\n",
       "    }\n",
       "\n",
       "    var x = canvas_pos.x * mpl.ratio;\n",
       "    var y = canvas_pos.y * mpl.ratio;\n",
       "\n",
       "    this.send_message(name, {x: x, y: y, button: event.button,\n",
       "                             step: event.step,\n",
       "                             guiEvent: simpleKeys(event)});\n",
       "\n",
       "    /* This prevents the web browser from automatically changing to\n",
       "     * the text insertion cursor when the button is pressed.  We want\n",
       "     * to control all of the cursor setting manually through the\n",
       "     * 'cursor' event from matplotlib */\n",
       "    event.preventDefault();\n",
       "    return false;\n",
       "}\n",
       "\n",
       "mpl.figure.prototype._key_event_extra = function(event, name) {\n",
       "    // Handle any extra behaviour associated with a key event\n",
       "}\n",
       "\n",
       "mpl.figure.prototype.key_event = function(event, name) {\n",
       "\n",
       "    // Prevent repeat events\n",
       "    if (name == 'key_press')\n",
       "    {\n",
       "        if (event.which === this._key)\n",
       "            return;\n",
       "        else\n",
       "            this._key = event.which;\n",
       "    }\n",
       "    if (name == 'key_release')\n",
       "        this._key = null;\n",
       "\n",
       "    var value = '';\n",
       "    if (event.ctrlKey && event.which != 17)\n",
       "        value += \"ctrl+\";\n",
       "    if (event.altKey && event.which != 18)\n",
       "        value += \"alt+\";\n",
       "    if (event.shiftKey && event.which != 16)\n",
       "        value += \"shift+\";\n",
       "\n",
       "    value += 'k';\n",
       "    value += event.which.toString();\n",
       "\n",
       "    this._key_event_extra(event, name);\n",
       "\n",
       "    this.send_message(name, {key: value,\n",
       "                             guiEvent: simpleKeys(event)});\n",
       "    return false;\n",
       "}\n",
       "\n",
       "mpl.figure.prototype.toolbar_button_onclick = function(name) {\n",
       "    if (name == 'download') {\n",
       "        this.handle_save(this, null);\n",
       "    } else {\n",
       "        this.send_message(\"toolbar_button\", {name: name});\n",
       "    }\n",
       "};\n",
       "\n",
       "mpl.figure.prototype.toolbar_button_onmouseover = function(tooltip) {\n",
       "    this.message.textContent = tooltip;\n",
       "};\n",
       "mpl.toolbar_items = [[\"Home\", \"Reset original view\", \"fa fa-home icon-home\", \"home\"], [\"Back\", \"Back to  previous view\", \"fa fa-arrow-left icon-arrow-left\", \"back\"], [\"Forward\", \"Forward to next view\", \"fa fa-arrow-right icon-arrow-right\", \"forward\"], [\"\", \"\", \"\", \"\"], [\"Pan\", \"Pan axes with left mouse, zoom with right\", \"fa fa-arrows icon-move\", \"pan\"], [\"Zoom\", \"Zoom to rectangle\", \"fa fa-square-o icon-check-empty\", \"zoom\"], [\"\", \"\", \"\", \"\"], [\"Download\", \"Download plot\", \"fa fa-floppy-o icon-save\", \"download\"]];\n",
       "\n",
       "mpl.extensions = [\"eps\", \"jpeg\", \"pdf\", \"png\", \"ps\", \"raw\", \"svg\", \"tif\"];\n",
       "\n",
       "mpl.default_extension = \"png\";var comm_websocket_adapter = function(comm) {\n",
       "    // Create a \"websocket\"-like object which calls the given IPython comm\n",
       "    // object with the appropriate methods. Currently this is a non binary\n",
       "    // socket, so there is still some room for performance tuning.\n",
       "    var ws = {};\n",
       "\n",
       "    ws.close = function() {\n",
       "        comm.close()\n",
       "    };\n",
       "    ws.send = function(m) {\n",
       "        //console.log('sending', m);\n",
       "        comm.send(m);\n",
       "    };\n",
       "    // Register the callback with on_msg.\n",
       "    comm.on_msg(function(msg) {\n",
       "        //console.log('receiving', msg['content']['data'], msg);\n",
       "        // Pass the mpl event to the overridden (by mpl) onmessage function.\n",
       "        ws.onmessage(msg['content']['data'])\n",
       "    });\n",
       "    return ws;\n",
       "}\n",
       "\n",
       "mpl.mpl_figure_comm = function(comm, msg) {\n",
       "    // This is the function which gets called when the mpl process\n",
       "    // starts-up an IPython Comm through the \"matplotlib\" channel.\n",
       "\n",
       "    var id = msg.content.data.id;\n",
       "    // Get hold of the div created by the display call when the Comm\n",
       "    // socket was opened in Python.\n",
       "    var element = $(\"#\" + id);\n",
       "    var ws_proxy = comm_websocket_adapter(comm)\n",
       "\n",
       "    function ondownload(figure, format) {\n",
       "        window.open(figure.imageObj.src);\n",
       "    }\n",
       "\n",
       "    var fig = new mpl.figure(id, ws_proxy,\n",
       "                           ondownload,\n",
       "                           element.get(0));\n",
       "\n",
       "    // Call onopen now - mpl needs it, as it is assuming we've passed it a real\n",
       "    // web socket which is closed, not our websocket->open comm proxy.\n",
       "    ws_proxy.onopen();\n",
       "\n",
       "    fig.parent_element = element.get(0);\n",
       "    fig.cell_info = mpl.find_output_cell(\"<div id='\" + id + \"'></div>\");\n",
       "    if (!fig.cell_info) {\n",
       "        console.error(\"Failed to find cell for figure\", id, fig);\n",
       "        return;\n",
       "    }\n",
       "\n",
       "    var output_index = fig.cell_info[2]\n",
       "    var cell = fig.cell_info[0];\n",
       "\n",
       "};\n",
       "\n",
       "mpl.figure.prototype.handle_close = function(fig, msg) {\n",
       "    var width = fig.canvas.width/mpl.ratio\n",
       "    fig.root.unbind('remove')\n",
       "\n",
       "    // Update the output cell to use the data from the current canvas.\n",
       "    fig.push_to_output();\n",
       "    var dataURL = fig.canvas.toDataURL();\n",
       "    // Re-enable the keyboard manager in IPython - without this line, in FF,\n",
       "    // the notebook keyboard shortcuts fail.\n",
       "    IPython.keyboard_manager.enable()\n",
       "    $(fig.parent_element).html('<img src=\"' + dataURL + '\" width=\"' + width + '\">');\n",
       "    fig.close_ws(fig, msg);\n",
       "}\n",
       "\n",
       "mpl.figure.prototype.close_ws = function(fig, msg){\n",
       "    fig.send_message('closing', msg);\n",
       "    // fig.ws.close()\n",
       "}\n",
       "\n",
       "mpl.figure.prototype.push_to_output = function(remove_interactive) {\n",
       "    // Turn the data on the canvas into data in the output cell.\n",
       "    var width = this.canvas.width/mpl.ratio\n",
       "    var dataURL = this.canvas.toDataURL();\n",
       "    this.cell_info[1]['text/html'] = '<img src=\"' + dataURL + '\" width=\"' + width + '\">';\n",
       "}\n",
       "\n",
       "mpl.figure.prototype.updated_canvas_event = function() {\n",
       "    // Tell IPython that the notebook contents must change.\n",
       "    IPython.notebook.set_dirty(true);\n",
       "    this.send_message(\"ack\", {});\n",
       "    var fig = this;\n",
       "    // Wait a second, then push the new image to the DOM so\n",
       "    // that it is saved nicely (might be nice to debounce this).\n",
       "    setTimeout(function () { fig.push_to_output() }, 1000);\n",
       "}\n",
       "\n",
       "mpl.figure.prototype._init_toolbar = function() {\n",
       "    var fig = this;\n",
       "\n",
       "    var nav_element = $('<div/>')\n",
       "    nav_element.attr('style', 'width: 100%');\n",
       "    this.root.append(nav_element);\n",
       "\n",
       "    // Define a callback function for later on.\n",
       "    function toolbar_event(event) {\n",
       "        return fig.toolbar_button_onclick(event['data']);\n",
       "    }\n",
       "    function toolbar_mouse_event(event) {\n",
       "        return fig.toolbar_button_onmouseover(event['data']);\n",
       "    }\n",
       "\n",
       "    for(var toolbar_ind in mpl.toolbar_items){\n",
       "        var name = mpl.toolbar_items[toolbar_ind][0];\n",
       "        var tooltip = mpl.toolbar_items[toolbar_ind][1];\n",
       "        var image = mpl.toolbar_items[toolbar_ind][2];\n",
       "        var method_name = mpl.toolbar_items[toolbar_ind][3];\n",
       "\n",
       "        if (!name) { continue; };\n",
       "\n",
       "        var button = $('<button class=\"btn btn-default\" href=\"#\" title=\"' + name + '\"><i class=\"fa ' + image + ' fa-lg\"></i></button>');\n",
       "        button.click(method_name, toolbar_event);\n",
       "        button.mouseover(tooltip, toolbar_mouse_event);\n",
       "        nav_element.append(button);\n",
       "    }\n",
       "\n",
       "    // Add the status bar.\n",
       "    var status_bar = $('<span class=\"mpl-message\" style=\"text-align:right; float: right;\"/>');\n",
       "    nav_element.append(status_bar);\n",
       "    this.message = status_bar[0];\n",
       "\n",
       "    // Add the close button to the window.\n",
       "    var buttongrp = $('<div class=\"btn-group inline pull-right\"></div>');\n",
       "    var button = $('<button class=\"btn btn-mini btn-primary\" href=\"#\" title=\"Stop Interaction\"><i class=\"fa fa-power-off icon-remove icon-large\"></i></button>');\n",
       "    button.click(function (evt) { fig.handle_close(fig, {}); } );\n",
       "    button.mouseover('Stop Interaction', toolbar_mouse_event);\n",
       "    buttongrp.append(button);\n",
       "    var titlebar = this.root.find($('.ui-dialog-titlebar'));\n",
       "    titlebar.prepend(buttongrp);\n",
       "}\n",
       "\n",
       "mpl.figure.prototype._root_extra_style = function(el){\n",
       "    var fig = this\n",
       "    el.on(\"remove\", function(){\n",
       "\tfig.close_ws(fig, {});\n",
       "    });\n",
       "}\n",
       "\n",
       "mpl.figure.prototype._canvas_extra_style = function(el){\n",
       "    // this is important to make the div 'focusable\n",
       "    el.attr('tabindex', 0)\n",
       "    // reach out to IPython and tell the keyboard manager to turn it's self\n",
       "    // off when our div gets focus\n",
       "\n",
       "    // location in version 3\n",
       "    if (IPython.notebook.keyboard_manager) {\n",
       "        IPython.notebook.keyboard_manager.register_events(el);\n",
       "    }\n",
       "    else {\n",
       "        // location in version 2\n",
       "        IPython.keyboard_manager.register_events(el);\n",
       "    }\n",
       "\n",
       "}\n",
       "\n",
       "mpl.figure.prototype._key_event_extra = function(event, name) {\n",
       "    var manager = IPython.notebook.keyboard_manager;\n",
       "    if (!manager)\n",
       "        manager = IPython.keyboard_manager;\n",
       "\n",
       "    // Check for shift+enter\n",
       "    if (event.shiftKey && event.which == 13) {\n",
       "        this.canvas_div.blur();\n",
       "        event.shiftKey = false;\n",
       "        // Send a \"J\" for go to next cell\n",
       "        event.which = 74;\n",
       "        event.keyCode = 74;\n",
       "        manager.command_mode();\n",
       "        manager.handle_keydown(event);\n",
       "    }\n",
       "}\n",
       "\n",
       "mpl.figure.prototype.handle_save = function(fig, msg) {\n",
       "    fig.ondownload(fig, null);\n",
       "}\n",
       "\n",
       "\n",
       "mpl.find_output_cell = function(html_output) {\n",
       "    // Return the cell and output element which can be found *uniquely* in the notebook.\n",
       "    // Note - this is a bit hacky, but it is done because the \"notebook_saving.Notebook\"\n",
       "    // IPython event is triggered only after the cells have been serialised, which for\n",
       "    // our purposes (turning an active figure into a static one), is too late.\n",
       "    var cells = IPython.notebook.get_cells();\n",
       "    var ncells = cells.length;\n",
       "    for (var i=0; i<ncells; i++) {\n",
       "        var cell = cells[i];\n",
       "        if (cell.cell_type === 'code'){\n",
       "            for (var j=0; j<cell.output_area.outputs.length; j++) {\n",
       "                var data = cell.output_area.outputs[j];\n",
       "                if (data.data) {\n",
       "                    // IPython >= 3 moved mimebundle to data attribute of output\n",
       "                    data = data.data;\n",
       "                }\n",
       "                if (data['text/html'] == html_output) {\n",
       "                    return [cell, data, j];\n",
       "                }\n",
       "            }\n",
       "        }\n",
       "    }\n",
       "}\n",
       "\n",
       "// Register the function which deals with the matplotlib target/channel.\n",
       "// The kernel may be null if the page has been refreshed.\n",
       "if (IPython.notebook.kernel != null) {\n",
       "    IPython.notebook.kernel.comm_manager.register_target('matplotlib', mpl.mpl_figure_comm);\n",
       "}\n"
      ],
      "text/plain": [
       "<IPython.core.display.Javascript object>"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    },
    {
     "data": {
      "text/html": [
       "<img src=\"data:image/png;base64,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\" width=\"640\">"
      ],
      "text/plain": [
       "<IPython.core.display.HTML object>"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    }
   ],
   "source": [
    "fig, ax = plt.subplots()\n",
    "\n",
    "\n",
    "def animate(i):\n",
    "    ax.set_title(\"Polarization\")\n",
    "    ax.set_aspect(\"equal\")\n",
    "    ax.set(xlim=(-1.2, 1.2), ylim=(-1.2, 1.2))\n",
    "\n",
    "    E = E0 * np.exp(1j * (f * t[i] + phi))\n",
    "\n",
    "    xx = np.array([0, E[0].real, 0])\n",
    "    yy = np.array([0, 0, 0])\n",
    "    uu = np.array([E[0].real, 0, E[0].real])\n",
    "    vv = np.array([0, E[1].real, E[1].real])\n",
    "\n",
    "    plax = ax.plot(ES[0].real, ES.real[1])\n",
    "    qax = ax.quiver(xx, yy, uu, vv, [0, 55, 200], scale_units=\"xy\", scale=1.0)\n",
    "\n",
    "\n",
    "animate(0)  # initialise the plot with the animate function\n",
    "\n",
    "timeline = amp.Timeline(t, units=\"ns\", fps=10)\n",
    "block = amp.blocks.Nuke(animate, length=len(timeline), ax=ax)\n",
    "anim = amp.Animation([block], timeline)\n",
    "\n",
    "anim.controls()\n",
    "anim.save_gif(\"nuke\")\n",
    "plt.show()"
   ]
  },
  {
   "cell_type": "raw",
   "metadata": {
    "raw_mimetype": "text/restructuredtext"
   },
   "source": [
    ".. image:: nuke.gif"
   ]
  }
 ],
 "metadata": {
  "celltoolbar": "Raw Cell Format",
  "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.5"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 2
}
