Skip to content

Instantly share code, notes, and snippets.

Show Gist options
  • Star 12 You must be signed in to star a gist
  • Fork 4 You must be signed in to fork a gist
  • Save chriddyp/9827cb5086cfab8da092 to your computer and use it in GitHub Desktop.
Save chriddyp/9827cb5086cfab8da092 to your computer and use it in GitHub Desktop.
A Collection of Plotly and IPython Widgets
Display the source blob
Display the rendered blob
Raw
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Display the source blob
Display the rendered blob
Raw
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Display the source blob
Display the rendered blob
Raw
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Display the source blob
Display the rendered blob
Raw
{
"metadata": {
"name": "",
"signature": "sha256:c8531c61678477c4b9d3cd30455f394cff74d191579fa1ff7f38178708ad8d1a"
},
"nbformat": 3,
"nbformat_minor": 0,
"worksheets": [
{
"cells": [
{
"cell_type": "markdown",
"metadata": {},
"source": [
"# Fractal Trees\n",
"#### Plotly and IPython Notebook Widgets"
]
},
{
"cell_type": "code",
"collapsed": false,
"input": [
"from IPython.display import Image\n",
"Image(url='http://i.imgur.com/l9Yzfcs.gif')"
],
"language": "python",
"metadata": {},
"outputs": [
{
"html": [
"<img src=\"http://i.imgur.com/l9Yzfcs.gif\"/>"
],
"metadata": {},
"output_type": "pyout",
"prompt_number": 7,
"text": [
"<IPython.core.display.Image at 0x1075db4d0>"
]
}
],
"prompt_number": 7
},
{
"cell_type": "code",
"collapsed": false,
"input": [
"from math import pi as PI\n",
"from math import sin, cos\n",
"import random\n",
"\n",
"from plotly.widgets import GraphWidget\n",
"from plotly.graph_objs import *\n",
"import plotly.plotly as py\n",
"import plotly.tools as tls\n",
"\n",
"from IPython.html import widgets \n",
"from IPython.display import display, clear_output\n",
"\n",
"root = 12"
],
"language": "python",
"metadata": {},
"outputs": [
{
"output_type": "stream",
"stream": "stderr",
"text": [
"/Users/chris/anaconda/lib/python2.7/site-packages/pandas/computation/expressions.py:21: UserWarning: The installed version of numexpr 2.0.1 is not supported in pandas and will be not be used\n",
"The minimum supported version is 2.1\n",
"\n",
" \"version is 2.1\\n\".format(ver=ver), UserWarning)\n"
]
},
{
"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",
"require([\"widgets/js/widget\"], function(WidgetManager){\n",
"\n",
" var GraphView = IPython.DOMWidgetView.extend({\n",
" render: function(){\n",
"\n",
" console.log('render!');\n",
"\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 = $(['<iframe id=\"'+graphId+'\"',\n",
" 'src=\"'+_graph_url+'.embed\"',\n",
" 'seamless',\n",
" 'style=\"border: none;\"',\n",
" 'width=\"100%\"',\n",
" 'height=\"600\">',\n",
" '</iframe>'].join(' '));\n",
" that.$graph.appendTo(that.$el);\n",
"\n",
" that.$loading = $('<div id=\"'+loadingId+'\">Initializing...</div>')\n",
" .appendTo(that.$el);\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",
" console.log('posting ping: ', plotlyDomain);\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",
" console.log('message: ', e.data);\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",
" }\n",
" }\n",
" that.send({event: message.type, message: message, graphId: graphId});\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",
" var plot = $('#'+message.graphId)[0].contentWindow;\n",
" plot.postMessage(message, window.plotlyDomains[message.graphId]);\n",
" }\n",
"\n",
" return GraphView.__super__.update.apply(this);\n",
" }\n",
" });\n",
"\n",
" // Register the GraphView with the widget manager.\n",
" WidgetManager.register_widget_view('GraphView', GraphView);\n",
"});\n",
"\n",
"//@ sourceURL=graphWidget.js\n"
],
"metadata": {},
"output_type": "display_data",
"text": [
"<IPython.core.display.Javascript at 0x1075d5f10>"
]
}
],
"prompt_number": 1
},
{
"cell_type": "code",
"collapsed": false,
"input": [
"# color the tree with a gradient from root_col to tip_col\n",
"# interpolate linearly to get color at a given position in the gradient\n",
"def get_col(root_col, tip_col, iterat):\n",
" r = ((iterat*1.0/root)*(root_col[0]-tip_col[0]))+tip_col[0]\n",
" g = ((iterat*1.0/root)*(root_col[1]-tip_col[1]))+tip_col[1]\n",
" b = ((iterat*1.0/root)*(root_col[2]-tip_col[2]))+tip_col[2]\n",
" return '#%02x%02x%02x' % (r,g,b)\n",
" \n",
"def tree_graph(iterat=12, branch_angle=18.0):\n",
" # angle to radian factor\n",
" ang2rad = PI/180.0\n",
" # experiment with trunk length (try 120)\n",
" t = 120\n",
" # experiment with factor to contract the trunk each iteratation (try 0.7)\n",
" r = 0.7\n",
" # starting orientation (initial 90 deg)\n",
" theta = 90.0 * ang2rad\n",
" # experiment with angle of the branch (try 18 deg)\n",
" dtheta = branch_angle * ang2rad\n",
" # experiment with gradient color choices\n",
" root_col = (40,40,40)\n",
" tip_col = (250,250,250)\n",
" # experiment with factor to increase random angle variation as child branches get smaller\n",
" iterscale = 6.0\n",
" # center of bottom\n",
" origin = (250, 500)\n",
" root=iterat\n",
" # make the tree\n",
" \n",
" def fractal_tree(lines, iterat, origin, t, r, theta, dtheta, root_col, tip_col, randomize=False):\n",
" \"\"\"\n",
" draws branches\n",
" iterat: iteratation number, stop when iterat == 0\n",
" origin: x,y coordinates of the start of this branch\n",
" t: current trunk length\n",
" r: factor to contract the trunk each iteratation\n",
" theta: starting orientation\n",
" dtheta: angle of the branch\n",
" \"\"\"\n",
" if iterat == 0:\n",
" return lines\n",
" # render the branch\n",
" x0, y0 = origin\n",
"\n",
" # randomize the length\n",
" randt = random.random()*t\n",
" if randomize:\n",
" x, y = x0 + randt * cos(theta), y0 - randt * sin(theta)\n",
" else:\n",
" x, y = x0 + cos(theta), y0 - sin(theta)\n",
" # color the branch according to its position in the tree\n",
" col = get_col(root_col, tip_col, iterat)\n",
" # add to traces\n",
" lines.append(Scatter(x=[x0, x], y=[y0, y], mode='lines', line=Line(color=col, width=1)))\n",
" # recursive calls\n",
" if randomize:\n",
" fractal_tree(lines, iterat-1, (x,y), t * r, r, theta + (random.random())*(iterscale/(iterat+1))*dtheta, dtheta, root_col, tip_col, randomize)\n",
" fractal_tree(lines, iterat-1, (x,y), t * r, r, theta - (random.random())*(iterscale/(iterat+1))*dtheta, dtheta, root_col, tip_col, randomize) \n",
" else: \n",
" fractal_tree(lines, iterat-1, (x,y), t * r, r, theta + dtheta, dtheta, root_col, tip_col, randomize)\n",
" fractal_tree(lines, iterat-1, (x,y), t * r, r, theta - dtheta, dtheta, root_col, tip_col, randomize)\n",
" \n",
" lines = []\n",
" fractal_tree(lines, iterat, origin, t, r, theta, dtheta, root_col, tip_col, True)\n",
" \n",
" # group the lines by similar color\n",
" branches = {}\n",
" for line in lines:\n",
" color = line['line']['color']\n",
" if color not in branches:\n",
" branches[color] = line\n",
" else:\n",
" branches[color]['x'].extend(line['x'])\n",
" branches[color]['y'].extend(line['y'])\n",
" branches[color]['x'].append(None)\n",
" branches[color]['y'].append(None)\n",
" \n",
" \n",
" branch_data = [branches[c] for c in branches]\n",
" \n",
" return branch_data"
],
"language": "python",
"metadata": {},
"outputs": [],
"prompt_number": 2
},
{
"cell_type": "code",
"collapsed": false,
"input": [
"g = GraphWidget('https://plot.ly/~chris/4103')\n",
"\n",
"iterations = widgets.IntSliderWidget()\n",
"iterations.min= 2\n",
"iterations.max= 14\n",
"iterations.value = 12\n",
"iterations.description = 'iterations'\n",
"\n",
"branch_angle = widgets.IntSliderWidget()\n",
"branch_angle.min = 5\n",
"branch_angle.max = 90\n",
"branch_angle.value = 18\n",
"branch_angle.description = 'branch angle'\n",
"\n",
"seed = widgets.ButtonWidget()\n",
"seed.description = 'Grow a new tree'\n",
"\n",
"def regraph_tree(_):\n",
" branch_data = tree_graph(iterations.value, branch_angle.value)\n",
"\n",
" g.restyle({'x': [[]], 'y': [[]]})\n",
" g.add_traces(branch_data)\n",
"\n",
"iterations.on_trait_change(regraph_tree, 'value')\n",
"branch_angle.on_trait_change(regraph_tree, 'value')\n",
"seed.on_click(regraph_tree)\n",
" \n",
"display(iterations)\n",
"display(branch_angle)\n",
"display(seed)\n",
"display(g)"
],
"language": "python",
"metadata": {},
"outputs": [],
"prompt_number": 3
},
{
"cell_type": "code",
"collapsed": false,
"input": [
"layout = Layout(yaxis=YAxis(autorange='reversed'), width=500, showlegend=False)\n",
"\n",
"g.relayout(layout)"
],
"language": "python",
"metadata": {},
"outputs": [],
"prompt_number": 4
},
{
"cell_type": "code",
"collapsed": false,
"input": [
"# CSS styling within IPython notebook - feel free to re-use\n",
"from IPython.core.display import HTML\n",
"import urllib2\n",
"\n",
"HTML(urllib2.urlopen('http://bit.ly/1Bf5Hft').read())"
],
"language": "python",
"metadata": {},
"outputs": [
{
"html": [
"<style>\n",
"\n",
"html {\n",
" font-size: 62.5% !important; }\n",
"body {\n",
" font-size: 1.5em !important; /* currently ems cause chrome bug misinterpreting rems on body element */\n",
" line-height: 1.6 !important;\n",
" font-weight: 400 !important;\n",
" font-family: \"Raleway\", \"HelveticaNeue\", \"Helvetica Neue\", Helvetica, Arial, sans-serif !important;\n",
" color: #222 !important; }\n",
"\n",
"div{ border-radius: 0px !important; }\n",
"div.CodeMirror-sizer{ background: rgb(244, 244, 248) !important; }\n",
"div.input_area{ background: rgb(244, 244, 248) !important; }\n",
"\n",
"div.out_prompt_overlay:hover{ background: rgb(244, 244, 248) !important; }\n",
"div.input_prompt:hover{ background: rgb(244, 244, 248) !important; }\n",
"\n",
"h1, h2, h3, h4, h5, h6 {\n",
" color: #333 !important;\n",
" margin-top: 0 !important;\n",
" margin-bottom: 2rem !important;\n",
" font-weight: 300 !important; }\n",
"h1 { font-size: 4.0rem !important; line-height: 1.2 !important; letter-spacing: -.1rem !important;}\n",
"h2 { font-size: 3.6rem !important; line-height: 1.25 !important; letter-spacing: -.1rem !important; }\n",
"h3 { font-size: 3.0rem !important; line-height: 1.3 !important; letter-spacing: -.1rem !important; }\n",
"h4 { font-size: 2.4rem !important; line-height: 1.35 !important; letter-spacing: -.08rem !important; }\n",
"h5 { font-size: 1.8rem !important; line-height: 1.5 !important; letter-spacing: -.05rem !important; }\n",
"h6 { font-size: 1.5rem !important; line-height: 1.6 !important; letter-spacing: 0 !important; }\n",
"\n",
"@media (min-width: 550px) {\n",
" h1 { font-size: 5.0rem !important; }\n",
" h2 { font-size: 4.2rem !important; }\n",
" h3 { font-size: 3.6rem !important; }\n",
" h4 { font-size: 3.0rem !important; }\n",
" h5 { font-size: 2.4rem !important; }\n",
" h6 { font-size: 1.5rem !important; }\n",
"}\n",
"\n",
"p {\n",
" margin-top: 0 !important; }\n",
" \n",
"a {\n",
" color: #1EAEDB !important; }\n",
"a:hover {\n",
" color: #0FA0CE !important; }\n",
" \n",
"code {\n",
" padding: .2rem .5rem !important;\n",
" margin: 0 .2rem !important;\n",
" font-size: 90% !important;\n",
" white-space: nowrap !important;\n",
" background: #F1F1F1 !important;\n",
" border: 1px solid #E1E1E1 !important;\n",
" border-radius: 4px !important; }\n",
"pre > code {\n",
" display: block !important;\n",
" padding: 1rem 1.5rem !important;\n",
" white-space: pre !important; }\n",
" \n",
"button{ border-radius: 0px !important; }\n",
".navbar-inner{ background-image: none !important; }\n",
"select, textarea{ border-radius: 0px !important; }\n",
"\n",
"</style>"
],
"metadata": {},
"output_type": "pyout",
"prompt_number": 5,
"text": [
"<IPython.core.display.HTML at 0x1075db690>"
]
}
],
"prompt_number": 5
}
],
"metadata": {}
}
]
}
Display the source blob
Display the rendered blob
Raw
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Display the source blob
Display the rendered blob
Raw
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Display the source blob
Display the rendered blob
Raw
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment