Hello,
This is a post redirected from Extending Bokeh with JS library for heatmap · Issue #7377 · bokeh/bokeh · GitHub to this forum.
I’m trying to extend Bokeh by wrapping a JavaScript library for heatmaps (https://github.com/pa7/heatmap.js).
Based on the documentation, I’ve created a CoffeeScript in a separate file named bokeh_extension_heatmap.coffee with the following contents:
import * as p from "core/properties"
import {LayoutDOM, LayoutDOMView} from "models/layouts/layout_dom"
export class HeatmapGeoView extends LayoutDOMView
initialize: (options) ->
super(options)
url = "https://cdnjs.cloudflare.com/ajax/libs/heatmap.js/2.0.2/heatmap.js"
script = document.createElement('script')
script.src = url
script.async = false
script.onreadystatechange = script.onload = () => @_init()
document.querySelector("head").appendChild(script)
_init: () ->
@_graph = h337.create({container: @el, radius: 10, blur: .75, maxOpacity: .5, minOpacity: 0});
@_graph.setData({ max: 10, data: @populate_data()})
@connect(@model.data_source.change, () =>
@_graph.setData({ max: 10, data: @populate_data()})
@_graph.repaint()
)
populate_data: () ->
list_points = []
source = @model.data_source
for i in [0...source.get_length()]
list_points.push({
x: source.get_column(@model.x_m)[i]
y: source.get_column(@model.y_m)[i]
value: source.get_column(@model.val)[i]
})
return list_points
export class HeatmapGeo extends LayoutDOM
#the view defined above
default_view: HeatmapGeoView
#the current wrapping Python class name
type: "HeatmapGeo"
#The @define block adds corresponding "properties" to the JS model. These
# should basically line up 1-1 with the Python model class.
@define {
x_m: [ p.String ]
y_m: [ p.String ]
val: [ p.String ]
data_source: [ p.Instance ]
}
Then, the Python model (in file bokeh_extension_heatmap.py):
from bokeh.core.properties import Instance, String
from bokeh.models import ColumnDataSource, LayoutDOM
from bokeh.util.compiler import FromFile
class HeatmapGeo(LayoutDOM):
__javascript__ = "https://cdnjs.cloudflare.com/ajax/libs/heatmap.js/2.0.2/heatmap.js"
__implementation__ = FromFile('bokeh_extension_heatmap.coffee')
# This is a Bokeh ColumnDataSource that can be updated in the Bokeh
# server by Python code
#the names should be the same as in HeatmapGeo class (in the coffeescript script)
data_source = Instance(ColumnDataSource)
# strings representing names of useful columns
x_m = String
y_m = String
val = String
I want to be able to add an HeatmapGeo instance on top of a Bokeh figure, but here I’m not sure which approach to implement.
The goal is to be able to add this heatmap layer on top of a map (Bokeh figure with tileset from some Web Map Tile Service).
import bokeh.tile_providers as tp
from bokeh.io import (
curdoc
)
from bokeh.plotting import (
figure
)
from bokeh.models import (
ColumnDataSource,
Range1d
)
import logging
from bokeh_extension_heatmap import HeatmapGeo
import numpy as np
#----------------------- logging for debug
logging.basicConfig(level=logging.DEBUG)
x = np.arange(11529166.0546, 11539166.0546, 1000)
y = np.arange( 125839.385417, 135838.385417, 1000)
values = np.ones(x.shape[0])
source = ColumnDataSource(data=dict(x=x, y=y, values=values))
x_range = Range1d(11529166.0546, 11588007.5559)
y_range = Range1d(125839.385417, 164456.343591)
WHITE = "#FFFFFF"
PLOT_FORMATS = dict(
toolbar_location='right',
outline_line_color=WHITE,
title_location='above',
tools="tap,box_zoom,pan,wheel_zoom,reset"
)
my_map = figure(x_range=x_range, y_range=y_range, title="Plot",
plot_width=600, plot_height=600, output_backend="webgl", **PLOT_FORMATS)
my_map.axis.visible = False
#add the desired tileset
my_map.add_tile(tp.STAMEN_TONER)
myheatmap = HeatmapGeo(x_m="x", y_m="y", val="values", data_source=source)
##### NEXT COMES THE ISSUE:
my_map.add_layout(obj=myheatmap,place='center')
#ValueError: expected an element of List(Instance(Renderer)), got seq with invalid items
# [HeatmapGeo(id='5ee18c4f-214f-4c56-94ce-b98636a82d72', ...)]
curdoc().add_root(my_map)
#MOREOVER, if instead of the last 2 lines of code, I add the custom layout as root directly
#then I get another error
#curdoc().add_root(myheatmap)
The referred screenshot is shown at Extending Bokeh with JS library for heatmap · Issue #7377 · bokeh/bokeh · GitHub
The Bokeh app is served by Bokeh server.
When this first part will get working, I’ll have to address the task of synchronizing the displayed heatmap with the current map view (e.g. on box_zoom, wheel_zoom, pan). Any suggestions on that topic would be very helpful, too.
Thank you in advance for your advice!
Camelia