{ "cells": [ { "cell_type": "code", "execution_count": 2, "metadata": { "collapsed": false }, "outputs": [ { "name": "stderr", "output_type": "stream", "text": [ "/Library/Frameworks/Python.framework/Versions/2.7/lib/python2.7/site-packages/IPython/html.py:14: ShimWarning:\n", "\n", "The `IPython.html` package has been deprecated. You should import from `notebook` instead. `IPython.html.widgets` has moved to `ipywidgets`.\n", "\n", "/Library/Frameworks/Python.framework/Versions/2.7/lib/python2.7/site-packages/IPython/utils/traitlets.py:5: UserWarning:\n", "\n", "IPython.utils.traitlets has moved to a top-level traitlets package.\n", "\n" ] }, { "data": { "application/javascript": [ "window.genUID = function() {\n", " return 'xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx'.replace(/[xy]/g, function(c) {\n", " var r = Math.random()*16|0, v = c == 'x' ? r : (r&0x3|0x8);\n", " return v.toString(16);\n", " });\n", "};\n", "\n", "var IPYTHON_VERSION = '3';\n", "\n", "require([\"widgets/js/widget\", \"widgets/js/manager\"], function (widget, manager) {\n", " if (!('DOMWidgetView' in widget)) {\n", "\n", " // we're in IPython2, things moved a bit from 2 --> 3.\n", " // construct the expected IPython3 widget API\n", " IPYTHON_VERSION = '2';\n", " manager = {WidgetManager: widget};\n", " widget = {DOMWidgetView: IPython.DOMWidgetView};\n", " }\n", "\n", " var GraphView = widget.DOMWidgetView.extend({\n", " render: function(){\n", " var that = this;\n", "\n", " var graphId = window.genUID();\n", " var loadingId = 'loading-'+graphId;\n", "\n", "\n", " var _graph_url = that.model.get('_graph_url');\n", "\n", " // variable plotlyDomain in the case of enterprise\n", " var url_parts = _graph_url.split('/');\n", " var plotlyDomain = url_parts[0] + '//' + url_parts[2];\n", "\n", " if(!('plotlyDomains' in window)){\n", " window.plotlyDomains = {};\n", " }\n", " window.plotlyDomains[graphId] = plotlyDomain;\n", "\n", " // Place IFrame in output cell div `$el`\n", " that.$el.css('width', '100%');\n", " that.$graph = $([''].join(' '));\n", " that.$graph.appendTo(that.$el);\n", "\n", " that.$loading = $('
Initializing...
')\n", " .appendTo(that.$el);\n", "\n", " // for some reason the 'width' is being changed in IPython 3.0.0\n", " // for the containing `div` element. There's a flicker here, but\n", " // I was unable to fix it otherwise.\n", " setTimeout(function () {\n", " if (IPYTHON_VERSION === '3') {\n", " $('#' + graphId)[0].parentElement.style.width = '100%';\n", " }\n", " }, 500);\n", "\n", " // initialize communication with the iframe\n", " if(!('pingers' in window)){\n", " window.pingers = {};\n", " }\n", "\n", " window.pingers[graphId] = setInterval(function() {\n", " that.graphContentWindow = $('#'+graphId)[0].contentWindow;\n", " that.graphContentWindow.postMessage({task: 'ping'}, plotlyDomain);\n", " }, 200);\n", "\n", " // Assign a message listener to the 'message' events\n", " // from iframe's postMessage protocol.\n", " // Filter the messages by iframe src so that the right message\n", " // gets passed to the right widget\n", " if(!('messageListeners' in window)){\n", " window.messageListeners = {};\n", " }\n", "\n", " window.messageListeners[graphId] = function(e) {\n", " if(_graph_url.indexOf(e.origin)>-1) {\n", " var frame = document.getElementById(graphId);\n", "\n", " if(frame === null){\n", " // frame doesn't exist in the dom anymore, clean up it's old event listener\n", " window.removeEventListener('message', window.messageListeners[graphId]);\n", " clearInterval(window.pingers[graphId]);\n", " } else if(frame.contentWindow === e.source) {\n", " // TODO: Stop event propagation, so each frame doesn't listen and filter\n", " var frameContentWindow = $('#'+graphId)[0].contentWindow;\n", " var message = e.data;\n", "\n", " if('pong' in message && message.pong) {\n", " $('#loading-'+graphId).hide();\n", " clearInterval(window.pingers[graphId]);\n", " that.send({event: 'pong', graphId: graphId});\n", " } else if (message.type==='hover' ||\n", " message.type==='zoom' ||\n", " message.type==='click' ||\n", " message.type==='unhover') {\n", "\n", " // click and hover events contain all of the data in the traces,\n", " // which can be a very large object and may take a ton of time\n", " // to pass to the python backend. Strip out the data, and require\n", " // the user to call get_figure if they need trace information\n", " if(message.type !== 'zoom') {\n", " for(var i in message.points) {\n", " delete message.points[i].data;\n", " delete message.points[i].fullData;\n", " }\n", " }\n", " that.send({event: message.type, message: message, graphId: graphId});\n", " } else if (message.task === 'getAttributes') {\n", " that.send({event: 'getAttributes', response: message.response});\n", " }\n", " }\n", " }\n", " };\n", "\n", " window.removeEventListener('message', window.messageListeners[graphId]);\n", " window.addEventListener('message', window.messageListeners[graphId]);\n", "\n", " },\n", "\n", " update: function() {\n", " // Listen for messages from the graph widget in python\n", " var jmessage = this.model.get('_message');\n", " var message = JSON.parse(jmessage);\n", "\n", " // check for duplicate messages\n", " if(!('messageIds' in window)){\n", " window.messageIds = {};\n", " }\n", "\n", " if(!(message.uid in window.messageIds)){\n", " // message hasn't been received yet, do stuff\n", " window.messageIds[message.uid] = true;\n", "\n", " if (message.fadeTo) {\n", " this.fadeTo(message);\n", " } else {\n", " var plot = $('#' + message.graphId)[0].contentWindow;\n", " plot.postMessage(message, window.plotlyDomains[message.graphId]);\n", " }\n", " }\n", "\n", " return GraphView.__super__.update.apply(this);\n", " },\n", "\n", " /**\n", " * Wrapper for jquery's `fadeTo` function.\n", " *\n", " * @param message Contains the id we need to find the element.\n", " */\n", " fadeTo: function (message) {\n", " var plot = $('#' + message.graphId);\n", " plot.fadeTo(message.duration, message.opacity);\n", " }\n", " });\n", "\n", " // Register the GraphView with the widget manager.\n", " manager.WidgetManager.register_widget_view('GraphView', GraphView);\n", "\n", "});\n", "\n", "//@ sourceURL=graphWidget.js\n" ], "text/plain": [ "" ] }, "metadata": {}, "output_type": "display_data" } ], "source": [ "import plotly.plotly as py\n", "from plotly.graph_objs import *\n", "from IPython.display import Image, display\n", "from plotly.widgets import GraphWidget" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "### Initialize a Graph widget with a Plotly URL" ] }, { "cell_type": "code", "execution_count": 3, "metadata": { "collapsed": false }, "outputs": [], "source": [ "# get graph data\n", "contour_data = py.get_figure('https://plotly.com/~bronsolo/63')" ] }, { "cell_type": "code", "execution_count": 1, "metadata": { "collapsed": false }, "outputs": [ { "ename": "NameError", "evalue": "name 'GraphWidget' is not defined", "output_type": "error", "traceback": [ "\u001b[0;31m---------------------------------------------------------------------------\u001b[0m", "\u001b[0;31mNameError\u001b[0m Traceback (most recent call last)", "\u001b[0;32m\u001b[0m in \u001b[0;36m\u001b[0;34m()\u001b[0m\n\u001b[0;32m----> 1\u001b[0;31m \u001b[0mgraph\u001b[0m \u001b[0;34m=\u001b[0m \u001b[0mGraphWidget\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0;34m'https://plotly.com/~bronsolo/63'\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m\u001b[1;32m 2\u001b[0m \u001b[0mg\u001b[0m \u001b[0;34m=\u001b[0m \u001b[0mgraph\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 3\u001b[0m \u001b[0;31m#line_plot = GraphWidget('https://plotly.com/~chris/2150')\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 4\u001b[0m \u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 5\u001b[0m \u001b[0mdisplay\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mg\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n", "\u001b[0;31mNameError\u001b[0m: name 'GraphWidget' is not defined" ] } ], "source": [ "graph = GraphWidget('https://plotly.com/~bronsolo/63')\n", "g = graph\n", "#line_plot = GraphWidget('https://plotly.com/~chris/2150')\n", "\n", "display(g)\n", "# display(line_plot)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "### Assign handlers to 'click', 'hover', and 'zoom' events" ] }, { "cell_type": "code", "execution_count": 12, "metadata": { "collapsed": false }, "outputs": [], "source": [ "from IPython.display import display, clear_output\n", "def message_handler(widget, msg):\n", " clear_output()\n", " print widget._graph_url\n", " display(msg)\n", " \n", "\n", "g.on_click(message_handler)\n", "# g.on_zoom(message_handler)" ] }, { "cell_type": "code", "execution_count": 17, "metadata": { "collapsed": false }, "outputs": [], "source": [ "def march(x0, y0, x1, y1):\n", " '''\n", " Return the closest path of integer coordinates \n", " between (x0, y0) and (x1, y1)\n", " '''\n", " if abs(x1-x0) > abs(y1-y0): \n", " if x1>x0:\n", " x = range(int(x0), int(x1)+1)\n", " else:\n", " x = range(int(x0), int(x1)+1, -1)\n", " y = []\n", " tanth = (y1-y0)/(x1-x0)\n", " for xi in x:\n", " y.append(round(y0+(xi-x0)*tanth))\n", " else:\n", " if y1>y0:\n", " y = range(int(y0), int(y1)+1)\n", " else:\n", " y = range(int(y0), int(y1)+1, -1)\n", " x = []\n", " tanth = (x1-x0)/(y1-y0)\n", " for yi in y:\n", " x.append(round(x0+(yi-y0)*tanth))\n", "\n", " return (x, y)\n", "\n", "class Responder(object):\n", " '''\n", " Stateful object that stores and computes the \n", " elevation and distance data of the \n", " line plot. The 'click' method is executed\n", " on `click` events of the contour map.\n", " '''\n", " def __init__(self, data):\n", " self.clicks = 0\n", " self.x = []\n", " self.y = []\n", " self.xp = []\n", " self.yp = []\n", " self.z = []\n", " self.d = []\n", " self.data = data\n", "\n", " def append_point(self, point):\n", " print point\n", " xp = point['pointNumber'][1]\n", " yp = point['pointNumber'][0]\n", " self.xp.append(xp)\n", " self.yp.append(yp)\n", "\n", " if 'x' in self.data[0]:\n", " x = self.data[0]['x'][xp]\n", " else:\n", " x = xp\n", " if 'y' in self.data[0]:\n", " y = self.data[0]['y'][xp]\n", " else:\n", " y = yp\n", "\n", " self.x.append(x)\n", " self.y.append(y)\n", " self.z.append(point['z'])\n", " \n", " if len(self.x) == 1:\n", " self.d.append(0)\n", " else:\n", " self.d.append(math.sqrt((y-self.y[-2])**2+(x-self.x[-2])**2))\n", " \n", " \n", " def click(self, contour_widget, click_obj):\n", " print \"This is the clickobj\"\n", " print click_obj\n", " point = click_obj[0]\n", " if self.clicks==0 or self.clicks > 5:\n", " self.__init__(self.data)\n", " self.append_point(point)\n", " else:\n", " \n", " (xpath, ypath) = march(self.xp[-1], self.yp[-1],\n", " point['pointNumber'][1], point['pointNumber'][0])\n", " \n", " d = []\n", " z = []\n", " for i in range(1, len(xpath)):\n", " xpi = xpath[i]\n", " ypi = ypath[i]\n", "\n", " if 'x' in self.data[0]:\n", " xi = self.data[0]['x'][xpi]\n", " else:\n", " xi = xpi\n", " if 'y' in self.data[0]:\n", " yi = self.data[0]['y'][ypi]\n", " else:\n", " yi = ypi\n", " \n", " self.d.append(self.d[-1]+math.sqrt((yi-self.y[-1])**2+(xi-self.x[-1])**2))\n", " self.z.append(self.data[0]['z'][int(ypi)][int(xpi)])\n", " self.x.append(xi)\n", " self.y.append(yi)\n", " self.xp.append(xpi)\n", " self.yp.append(ypi)\n", " \n", "\n", " self.clicks+=1\n", " \n", " line_plot.restyle({'x': [self.d], 'y': [self.z]})\n", "\n", " \n", "r = Responder(contour_data['data'])" ] }, { "cell_type": "code", "execution_count": 18, "metadata": { "collapsed": false }, "outputs": [], "source": [ "g.on_click(r.click)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "### Manual hover over points" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "collapsed": false }, "outputs": [], "source": [ "g.hover({'xval': 2, 'yval': 8})" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "collapsed": false }, "outputs": [], "source": [ "from IPython.display import display, HTML\n", "\n", "display(HTML(''))\n", "display(HTML(''))\n", "\n", "! pip install publisher --upgrade\n", "import publisher\n", "publisher.publish(\n", " 'plotly_widgets.ipynb', 'python/ipython-widgets//', 'IPython Notebook Widgets | plotly',\n", " 'How to make IPython Notebook Widgets in Python with Plotly.',\n", " name = 'IPython Notebook Widgets',\n", " thumbnail='thumbnail/ipython_widgets.jpg', language='python',\n", " page_type='example_index', has_thumbnail='true', display_as='chart_events', order=0) " ] }, { "cell_type": "code", "execution_count": null, "metadata": { "collapsed": 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.9" } }, "nbformat": 4, "nbformat_minor": 0 }