Created
February 16, 2023 01:28
-
-
Save gmerritt123/8c8a40411c6977b9ca5d6be7e64faea4 to your computer and use it in GitHub Desktop.
d3 tricontour and bokeh
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
# -*- coding: utf-8 -*- | |
""" | |
Created on Wed Feb 15 19:24:01 2023 | |
Example demonstrating interoperability between d3 and bokeh for powerful CustomJS callbacks. | |
@author: Gaelen Merritt | |
""" | |
import numpy as np | |
from bokeh.plotting import figure | |
from bokeh.layouts import column | |
from bokeh.models import CustomJS, ColumnDataSource, PointDrawTool, Slider, ColorBar | |
from bokeh.palettes import Sunset8 | |
from bokeh.transform import linear_cmap | |
from bokeh.embed import components | |
from bokeh.resources import Resources | |
x = np.random.random(100)*3 | |
y = np.random.random(100)*2 | |
z = 1.3*np.exp(-2.5*((x-1.3)**2 + (y-0.8)**2)) - 1.2*np.exp(-2*((x-1.8)**2 + (y-1.3)**2)) | |
src = ColumnDataSource({'x':x,'y':y,'z':z}) | |
p = figure(width=800, height=400, x_range=(-.5, 3.5), y_range=(-0.5, 2.5) | |
,title='Move some points!') | |
cmap = linear_cmap(field_name='z',palette=Sunset8,low=-1,high=1) | |
r = p.scatter(x='x',y='y' | |
,fill_color=cmap | |
,line_alpha=cmap | |
,size=8 | |
,source=src) | |
color_bar = ColorBar(color_mapper=cmap.transform, label_standoff=12) | |
p.add_layout(color_bar, "right") | |
et = PointDrawTool(renderers=[r],num_objects=50) | |
p.add_tools(et) | |
p.toolbar.active_tap = et | |
csrc = ColumnDataSource(data={'xs':[],'ys':[],'z':[]}) | |
cr = p.multi_line(xs='xs',ys='ys',line_color=cmap,line_width=4,source=csrc) | |
sl = Slider(value=8,start=2,end=16,title='Desired Number of Contour Intervals') | |
cb = CustomJS(args=dict(src=src,csrc=csrc,sl=sl) | |
,code=''' | |
//transforms columndatasource data to array of objects | |
function cds_to_objarray(cds_data){ | |
var keys = Object.keys(cds_data) | |
var z = d3.transpose(Object.values(cds_data)) | |
var o = z.map(x=>Object.assign(...keys.map((k, i) => ({[k]: x[i]})))) | |
return o} | |
//translates a d3 contour result into multiline-ready CDS data | |
function contours_to_cds(d3_contour){ | |
var cxs = [] | |
var cys = [] | |
var cv = [] | |
for (var vi=0;vi<d3_contour.length;vi++){ | |
for (var pi=0; pi<d3_contour[vi].coordinates.length;pi++){ | |
for (var ppi = 0; ppi<d3_contour[vi].coordinates[pi].length;ppi++){ | |
var xy = d3.transpose(d3_contour[vi].coordinates[pi][ppi]) | |
cxs.push(xy[0]) | |
cys.push(xy[1]) | |
cv.push(d3_contour[vi].value) | |
} | |
} | |
} | |
return {'z':cv,'xs':cxs,'ys':cys} | |
} | |
var d = cds_to_objarray(src.data) | |
var tri = d3.tricontour().thresholds(sl.value) | |
var contours = tri(d.map(x=>[x.x,x.y,x.z])) | |
csrc.data = contours_to_cds(contours) | |
''') | |
src.js_on_change('data',cb) | |
sl.js_on_change('value',cb) | |
def save_html_wJSResources(bk_obj,fname,resources_list,html_title='Bokeh Plot'): | |
'''function to save a bokeh figure/layout/widget but with additional JS resources imported at the top of the html | |
resources_list is a list input of where to import additional JS libs so they can be utilized into CustomJS etc in bokeh work | |
e.g. ['http://d3js.org/d3.v6.js'] | |
''' | |
script, div = components(bk_obj) | |
resources = Resources() | |
# print(resources) | |
tpl = '''<!DOCTYPE html> | |
<html lang="en"> | |
<head> | |
<meta charset="utf-8"> | |
<title>'''+html_title+'''</title> | |
''' | |
tpl = tpl+resources.render_js() | |
for r in resources_list: | |
tpl = tpl +'''\n<script src="'''+r+'''"></script>''' | |
tpl = tpl+script+\ | |
''' | |
</head> | |
<body>'''\ | |
+div+\ | |
'''</body> | |
</html>''' | |
with open(fname,'w') as f: | |
f.write(tpl) | |
save_html_wJSResources(bk_obj=column([p,sl]),fname='d3Contouring.html' | |
,resources_list=['https://cdnjs.cloudflare.com/ajax/libs/d3/7.8.0/d3.min.js' | |
,'https://cdn.jsdelivr.net/npm/d3-tricontour@1'] | |
,html_title='d3 Contouring') | |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment