Last active
August 23, 2017 14:54
-
-
Save anthonydouc/7e5bb2a01972e29f82e4072304b539e9 to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
from __future__ import division | |
import numpy as np | |
from bokeh.core.properties import Instance, String, List, Either | |
from bokeh.models import ColumnDataSource, LayoutDOM | |
from bokeh.models.widgets import Button | |
from bokeh.layouts import column, row | |
from bokeh.io import curdoc | |
JS_CODE = """ | |
# These "require" lines are similar to python "import" statements | |
import * as p from "core/properties" | |
import {LayoutDOM, LayoutDOMView} from "models/layouts/layout_dom" | |
# This defines the layout options for a Plotly 3d graph. | |
layout = | |
title: 'Title' | |
autosize: false | |
width: 400 | |
height: 400 | |
scene: | |
aspectratio: | |
x: 0.85 | |
y: 0.85 | |
z: 0.85 | |
margin: | |
l: 0 | |
r: 0 | |
b: 0 | |
t: 0 | |
pad: 0 | |
# To create custom model extensions that will render on to the HTML canvas | |
# or into the DOM, we must create a View subclass for the model. Currently | |
# Bokeh models and views are based on BackBone. More information about | |
# using Backbone can be found here: | |
# | |
# http://backbonejs.org/ | |
# | |
# In this case we will subclass from the existing BokehJS ``LayoutDOMView``, | |
# corresponding to our | |
export class Surface3dView extends LayoutDOMView | |
initialize: (layout) -> | |
super(layout) | |
url = "https://cdn.plot.ly/plotly-latest.min.js" | |
script = document.createElement('script') | |
script.src = url | |
script.async = false | |
script.onreadystatechange = script.onload = () => @_init() | |
document.querySelector("head").appendChild(script) | |
_init: () -> | |
@_graph = new Plotly.newPlot(@el, @get_data(), layout) | |
# Set Backbone listener so that when the Bokeh data source has a change | |
# event, we can process the new data | |
# currently configured to bokeh 0.12.4 | |
@listenTo(@model.data_source, 'change', () => | |
Plotly.newPlot(@el, @get_data(), layout) | |
) | |
# This is the callback executed when the Bokeh data has an change. | |
# Plotly data is stored as a simple dict, so we can simply send this across. | |
get_data: () -> | |
source = @model.data_source | |
data= { | |
z: source.get_column(@model.z), | |
x: source.get_column(@model.x), | |
y: source.get_column(@model.y), | |
type: 'surface', | |
showscale: false | |
} | |
return [data] | |
# We must also create a corresponding JavaScript Backbone model sublcass to | |
# correspond to the python Bokeh model subclass. In this case, since we want | |
# an element that can position itself in the DOM according to a Bokeh layout, | |
# we subclass from ``LayoutDOM`` | |
export class Surface3d extends LayoutDOM | |
# This is usually boilerplate. In some cases there may not be a view. | |
default_view: Surface3dView | |
# The ``type`` class attribute should generally match exactly the name | |
# of the corresponding Python class. | |
type: "Surface3d" | |
# The @define block adds corresponding "properties" to the JS model. These | |
# should basically line up 1-1 with the Python model class. Most property | |
# types have counterparts, e.g. ``bokeh.core.properties.String`` will be | |
# ``p.String`` in the JS implementatin. Where the JS type system is not yet | |
# as rich, you can use ``p.Any`` as a "wildcard" property type. | |
@define { | |
x: [ p.String ] | |
y: [ p.String ] | |
z: [ p.String ] | |
data_source: [ p.Instance ] | |
} | |
""" | |
# This custom extension model will have a DOM view that should layout-able in | |
# Bokeh layouts, so use ``LayoutDOM`` as the base class. If you wanted to create | |
# a custom tool, you could inherit from ``Tool``, or from ``Glyph`` if you | |
# wanted to create a custom glyph, etc. | |
class Surface3d(LayoutDOM): | |
# The special class attribute ``__implementation__`` should contain a string | |
# of JavaScript (or CoffeeScript) code that implements the JavaScript side | |
# of the custom extension model. | |
__implementation__ = JS_CODE | |
# Below are all the "properties" for this model. Bokeh properties are | |
# class attributes that define the fields (and their types) that can be | |
# communicated automatically between Python and the browser. Properties | |
# also support type validation. More information about properties in | |
# can be found here: | |
# | |
# http://bokeh.pydata.org/en/latest/docs/reference/core.html#bokeh-core-properties | |
# This is a Bokeh ColumnDataSource that can be updated in the Bokeh | |
# server by Python code | |
data_source = Instance(ColumnDataSource) | |
# The vis.js library that we are wrapping expects data for x, y, z, and | |
# color. The data will actually be stored in the ColumnDataSource, but | |
# these properties let us specify the *name* of the column that should | |
# be used for each field. | |
x = String | |
y = String | |
z = String | |
x = np.arange(0, 300, 10) | |
y = np.arange(0, 300, 10) | |
xx, yy = np.meshgrid(x, y) | |
z = np.sin(xx/50) * np.cos(yy/50) * 50 + 50 | |
x1 = [list(x_i) for x_i in xx] | |
y1 = [list(x_i) for x_i in yy] | |
z1 = [list(x_i) for x_i in z] | |
source1 = ColumnDataSource(data=dict(x=x1, y=y1, z=z1)) | |
surface1 = Surface3d(x="x", y="y", z="z", data_source=source1) | |
# Applying the parametric equation.. | |
s = np.linspace(0, 2 * np.pi, 240) | |
t = np.linspace(0, np.pi, 240) | |
tGrid, sGrid = np.meshgrid(s, t) | |
r = 2 + np.sin(7 * sGrid + 5 * tGrid) # r = 2 + sin(7s+5t) | |
x = r * np.cos(sGrid) * np.sin(tGrid) # x = r*cos(s)*sin(t) | |
y = r * np.sin(sGrid) * np.sin(tGrid) # y = r*sin(s)*sin(t) | |
z = r * np.cos(tGrid) # z = r*cos(t) | |
x = [list(arr) for arr in x] | |
y = [list(arr) for arr in y] | |
z = [list(arr) for arr in z] | |
source2 = ColumnDataSource(data=dict(x=x, y=y, z=z)) | |
surface2 = Surface3d(x="x", y="y", z="z", data_source=source2) | |
curdoc().add_root(column(surface1, surface2)) |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment