In [1]:
import numpy as np
from ipykernel.comm import Comm
import bokeh
from bokeh.plotting import figure, show
from bokeh.models import Range1d, ColumnDataSource
from bokeh.io import output_notebook
from ipywidgets import interact
output_notebook()
In [2]:
%%html
<script src="bokeh_update.js"></script>
In [3]:
update_bokeh_comm = Comm(target_name='bokeh_update_target',
target_module='bokeh_update', data={})
def replace_bokeh_data_source(ds):
update_bokeh_comm.send({"custom_type": "replace_bokeh_data_source",
"ds_id": ds.ref['id'], # Model Id
"ds_model": ds.ref['type'], # Collection Type
"ds_json": bokeh.protocol.serialize_json(ds.vm_serialize())
})
In [4]:
def compute_tree(levels=6, slope = 0.4, stem_width=0.2, baubles_n=20):
# Base shape of a tree level, parabolic slope
shape_x = np.linspace(-1,1,15)
shape_y = (shape_x>=0)*(shape_x-1)**2 + (shape_x<0)*(shape_x+1)**2
patch_colors = []
patch_x = []
patch_y = []
# Make a simple stem
patch_x.append([0,stem_width,-stem_width])
patch_y.append([0,-6,-6])
patch_colors.append("brown")
# Loop through the tree levels
for level in range(levels,0,-1):
width = level*slope
patch_x.append(shape_x*width)
patch_y.append(shape_y *5/levels - (level / levels*5))
patch_colors.append("green")
# Generate Baubles
#
# compensate for different level widths
probs = np.arange(0,levels+1)
probs = probs / np.sum(probs)
# draw random levels, according to the width
baubles_levels = np.random.choice(np.arange(0,levels+1), baubles_n, p=probs)
# x coordinates spread out, according to the levels
baubles_x = (np.random.uniform(-1,1,baubles_n) * baubles_levels * slope) *10 // 4 * 4 / 10 + np.random.normal(0,0.015,baubles_n)
# compute y coordinates from levels
baubles_y = -(baubles_levels / levels*5) - 0.2 + np.random.normal(0,0.015,baubles_n)
baubles_colors =["red"]*baubles_n
baubles_radius = np.ones(baubles_n)*0.1
return patch_x, patch_y, patch_colors, baubles_x, baubles_y, baubles_radius, baubles_colors
patch_x, patch_y, patch_colors, baubles_x, baubles_y, baubles_radius, baubles_color = compute_tree()
branches_ds = ColumnDataSource(data=dict(patch_x=patch_x, patch_y=patch_y, color=patch_colors))
baubles_ds = ColumnDataSource(data=dict(x=baubles_x, y=baubles_y, radius=baubles_radius, color=baubles_color))
In [5]:
def plot_tree():
p = figure(plot_width=800, plot_height=400)
p.y_range = Range1d(-6,1)
p.x_range = Range1d(-6,6)
p.patches(xs="patch_x",ys="patch_y",
color="color", source=branches_ds, alpha=0.9, line_width=2)
p.circle(x="x", y="y", radius="radius", color="color", source=baubles_ds)
p.axis.visible = False
p.grid.grid_line_color = None
show(p);
def update_tree(levels=6, slope = 0.4, stem_width=0.2, baubles_n=20):
patch_x, patch_y, patch_colors, baubles_x, \
baubles_y, baubles_radius, baubles_color = compute_tree(levels, slope, stem_width, baubles_n)
branches_ds.data['patch_x'] = patch_x
branches_ds.data['patch_y'] = patch_y
branches_ds.data['color'] = patch_colors
baubles_ds.data['x'] = baubles_x
baubles_ds.data['y'] = baubles_y
baubles_ds.data['color'] = baubles_color
baubles_ds.data['radius'] = baubles_radius
replace_bokeh_data_source(branches_ds)
replace_bokeh_data_source(baubles_ds)
In [6]:
plot_tree()
In [7]:
@interact(levels=[1,8,1], slope = [0.2,1,0.05], stem_width=[0.1,0.5,0.01], baubles_n=[5,30,1])
def plot(levels=6, slope = 0.4, stem_width=0.2, baubles_n=20):
update_tree(levels,slope,stem_width,baubles_n)