I have made an app using both bokeh and flask that queries a timestream database and renders the data using bokeh. The data is used to produce 4 dictionaries which store different resolutions of the data which are swapped into the columndatasource depending on the zoom level.
I have created a custom tool to download the raw data that is present in one of the 4 dictionaries but I would like for the tool to show as disabled when the column datasource is empty. Similar to the undo tool when the undo stack is empty:
Here is the implementation of my custom tool:
from bokeh.core.properties import Dict, Either, Float, List, Nullable, String
from bokeh.models import Tool
from bokeh.util.compiler import TypeScript
TS_CODE = r"""
import {ActionTool, ActionToolView} from "models/tools/actions/action_tool"
import * as p from "core/properties"
import * as t from "core/types"
export class DownloadDataToolView extends ActionToolView {
model: DownloadDataTool
doit(): void {
interface Data {
[key: string]: any[]
date: any[]
value: any[]
}
const data = <Data>this.model.source
if (data === null) {
return
}
const headers = Object.keys(data)
let csvContent = headers.join(",") + "\n"
const filename = "data.csv"
for (let i = 0; i < headers.map(header => data[header].length).reduce((a, b) => Math.max(a, b), 0); i++) {
const row = headers.map(header => (data[header][i] !== undefined ? data[header][i] : "")).join(",")
csvContent += row + "\n"
}
const blob = new Blob([csvContent], { type: "text/csv;charset=utf-8;" })
const link = document.createElement("a")
link.href = URL.createObjectURL(blob)
link.download = filename
link.target = "_blank"
link.style.visibility = 'hidden'
link.dispatchEvent(new MouseEvent('click'))
}
}
export namespace DownloadDataTool {
export type Attrs = p.AttrsOf<Props>
export type Props = ActionTool.Props & {
source: p.Property<t.Dict<t.Arrayable<number>> | null>
}
}
export interface DownloadDataTool extends DownloadDataTool.Attrs {}
export class DownloadDataTool extends ActionTool {
properties: DownloadDataTool.Props
__view_type__: DownloadDataToolView
constructor(attrs?: Partial<DownloadDataTool.Attrs>) {
super(attrs)
}
tool_name = "Download Data"
default_order = 1
static {
this.prototype.default_view = DownloadDataToolView
this.define<DownloadDataTool.Props>(({Dict, Arrayable, Nullable, Number}) => ({
source: [ Nullable(Dict(Arrayable(Number))), null ],
}))
}
}
"""
class DownloadDataTool(Tool):
__implementation__ = TypeScript(TS_CODE)
source = Nullable(Dict(String, List(Either(Float, String))))
Any help would be greatly appreciated!