Trigger a SaveTool action via CustomJS? Other ways?

What am I trying to do?

Accomplish the ‘save’ action of a saveTool on a figure/plot via CustomJS (e.g. when the user clicks a button, I need to do execute a series of things, including a png export of the current view.

What I’ve set up/sketched out → three (not working) ideas in the CustomJS code:

from bokeh.plotting import figure, save
from bokeh.models import CustomJS, Button
from bokeh.layouts import column
f = figure()
f.scatter(x=[1,2,3],y=[1,2,3])
btn = Button(label='Click me to save image of f??')

cb = CustomJS(args=dict(f=f
                        ,st=f.tools[3] #the saveTool instance attached to the figure
                        )
              ,code='''
              console.log(f)
              console.log(st)
              
              //IDEA 1 --> st seems to have a "do"/"doit" method?
              st.do({action:'save'}) // ???
              
              //IDEA 2 --> "trigger_event" on figure?
              
              f.trigger_event({'event_name':'save'}) //?? doesn't seem to be a "save" event etc?
              
              
              //IDEA 3 --> mimic SaveTool.ts source code? --> Lines 16-21 here  https://github.com/bokeh/bokeh/blob/branch-3.1/bokehjs/src/lib/models/tools/actions/save_tool.ts
              
              const blob = this.parent.export().to_blob() 
              // "this.parent" in the source code is I believe something to do with the figure's "PlotView" 
              // but I don't know how to access that from here
              const link = document.createElement("a")
              //the rest of the source code i think i understand/can use?
              link.href = URL.createObjectURL(blob)
              link.download = 'yourimage' // + ".png" | "svg" (inferred from MIME type)
              link.target = "_blank"
              link.dispatchEvent(new MouseEvent("click"))
              
              
              ''')
btn.js_on_click(cb)
save(column([btn,f]))

I’m not sure which of the three ideas is best approach/possible or if any of them will accomplish what I’m shooting for. I am also (evidently) very lost on syntax/proper querying of what I need to query for all three… Any guidance much appreciated!

Thanks…

1 Like

Simultaneously frustrating but satisfying… as soon as you post the question you find the answer yourself.

I needed to read into “do” a bit more. st.do.emit() will execute the save action. The only other tricky part was that you need to initialize the savetool with a dummy filename (“stuff” in my example below). That way you can update its filename property freely in the CustomJS, which will then let you bypass the filenaming prompts you may get.

from bokeh.plotting import figure, save,show
from bokeh.models import CustomJS, Button
from bokeh.layouts import column
f = figure()
f.scatter(x=[1,2,3],y=[1,2,3])
btn = Button(label='Click me to save image of f??')
f.tools[3].filename = 'stuff'
cb = CustomJS(args=dict(f=f
                        ,st=f.tools[3] #the saveTool instance attached to the figure
                        )
              ,code='''             
              st.filename = 'stuff_but_different'
              st.do.emit()
              ''')
btn.js_on_click(cb)
show(column([btn,f]))
1 Like

This topic was automatically closed 90 days after the last reply. New replies are no longer allowed.