from IPython.display import Image Image(url='http://i.imgur.com/2Wbbo6l.gif') import plotly.plotly as py from plotly.graph_objs import * import plotly.tools as tls import json import numpy as np import math from IPython.display import display from plotly.widgets import GraphWidget contour_plot = GraphWidget('https://plot.ly/~bronsolo/63') line_plot = GraphWidget('https://plot.ly/~chris/2150') display(contour_plot) display(line_plot) contour_fig = py.get_figure('https://plot.ly/~bronsolo/63') def march(x0, y0, x1, y1): ''' Return the closest path of integer coordinates between (x0, y0) and (x1, y1) ''' if abs(x1-x0) > abs(y1-y0): if x1>x0: x = range(int(x0), int(x1)+1) else: x = range(int(x0), int(x1)+1, -1) y = [] tanth = (y1-y0)/(x1-x0) for xi in x: y.append(round(y0+(xi-x0)*tanth)) else: if y1>y0: y = range(int(y0), int(y1)+1) else: y = range(int(y0), int(y1)+1, -1) x = [] tanth = (x1-x0)/(y1-y0) for yi in y: x.append(round(x0+(yi-y0)*tanth)) return (x, y) class Responder(object): ''' Stateful object that stores and computes the elevation and distance data of the line plot. The 'click' method is executed on `click` events of the contour map. ''' def __init__(self, data): self.clicks = 0 self.x = [] self.y = [] self.xp = [] self.yp = [] self.z = [] self.d = [] self.data = data def append_point(self, point): xp = point['pointNumber'][1] yp = point['pointNumber'][0] self.xp.append(xp) self.yp.append(yp) if 'x' in self.data[0]: x = self.data[0]['x'][xp] else: x = xp if 'y' in self.data[0]: y = self.data[0]['y'][xp] else: y = yp self.x.append(x) self.y.append(y) self.z.append(point['z']) if len(self.x) == 1: self.d.append(0) else: self.d.append(math.sqrt((y-self.y[-2])**2+(x-self.x[-2])**2)) def click(self, contour_widget, click_obj): point = click_obj[0] if self.clicks==0 or self.clicks > 5: self.__init__(self.data) self.append_point(point) else: (xpath, ypath) = march(self.xp[-1], self.yp[-1], point['pointNumber'][1], point['pointNumber'][0]) d = [] z = [] for i in range(1, len(xpath)): xpi = xpath[i] ypi = ypath[i] if 'x' in self.data[0]: xi = self.data[0]['x'][xpi] else: xi = xpi if 'y' in self.data[0]: yi = self.data[0]['y'][ypi] else: yi = ypi self.d.append(self.d[-1]+math.sqrt((yi-self.y[-1])**2+(xi-self.x[-1])**2)) self.z.append(self.data[0]['z'][int(ypi)][int(xpi)]) self.x.append(xi) self.y.append(yi) self.xp.append(xpi) self.yp.append(ypi) self.clicks+=1 line_plot.restyle({'x': [self.d], 'y': [self.z]}) r = Responder(contour_fig['data']) contour_plot.on_click(r.click) # CSS styling within IPython notebook - feel free to re-use from IPython.core.display import HTML import urllib2 HTML(urllib2.urlopen('http://bit.ly/1Bf5Hft').read())