Trying to print/export BokehJS plot, how can I do this..? How to use export_png()?

Hi,

I’m create a graphing web app. Development is just on my computer with 1 .js, 1 .html file.
I’m trying to print out web page (which includes the graph + other stuff). I would like to be able to format the printing so it prints the same every time.

I’ve tried a few random js libraries that allow printing of DOM/HTML elements.
printjs can print the div the Plot is in, but will not print the plot itself, which I guess makes sense.

So that approach failed, and I’m now trying to use export_png()
But this doesnt seem to exist in BokehJS??? There is a save button on the plot toolbar so surely it is possible to export the plot with code instead of the button?
If it does exist, how would I call it? I’ve been trying

Bokeh.io.export_png(plot, filename = "bokeh_plot.png");

I also tried other variations of calling it, Bokeh.IO, Bokeh.Io,…
This gives
Uncaught TypeError: Bokeh.io is undefined

I tried looking in the source code on GitHub but I couldn’t find the export_png() for JavaScript.

So, my overall question is: Can I use export_png() in BokehJS, if so how? If not, are there alternatives?

Thanks

export_png is Python-only, it does not exist in BokehJS.

You could do what the SaveTool does, yourself:

Here, this.parent is the Plot object. Please be aware that this only allows for saving a single plot canvas, and not an entire page or layout. Please also be aware the browsers sometimes have different behaviors with respect to file dialogs and saving off files. There’s nothing we can do about that.

Thanks for the quick reply,

I’m trying to implement this now.

When I change that first line to:

const blob = await plot.export().to_blob();

It is giving an error:

TypeError: plot.export is not a function

How can I fix this? How exactly should I call that export() function? Thanks

This is what I changed the code to

    const blob = await plot.export().to_blob();
    const link = document.createElement("a");
    link.href = URL.createObjectURL(blob);
    link.download = "soosk"; // + ".png" | "svg" (inferred from MIME type)
    link.target = "_blank";
    link.dispatchEvent(new MouseEvent("click"));

This is how my plot is constructed, and how I was calling it’s functions/attributes

const plot = Bokeh.Plotting.figure({
        //title: 'Example of random data',
        tools: "pan,wheel_zoom,box_zoom,reset,save,hover",
        toolbar_location: "right",
        toolbar_sticky: false,
        height: 600,
        width: 700,
        x_range: [1, 1000000],
        y_range: [-180, -70],
        x_axis_type: "log",
        x_axis_label: "Offset Frequency (Hz)",
        //y_axis_type: "linear",
        y_axis_label: "Phase Noise (dBc/Hz)",
        extra_y_ranges: { "y2_range": y2_range },
        extra_y_scales: { "y2_range": new Bokeh.LogScale() },
    });

plot.line({ field: "x" }, { field: "y" }, {...

Actually I guess this.parent is the PlotView, not the Plot model. BokehJS views are not as publicly accessible, at present I think you will have to search through the global Bokeh.index to find the view object for the plot that you need. Also you have not mentioned any versions (please always specify a version in OSS help questions). I mention because I think PlotView.export is only present in Bokeh 3.0+

Ah apologies, I’m on version 3.0.3.

logging Bokeh.index to the console gives:

Object {  }
​
E6346ADE05324C4B904BD938D7BBDB91: Object { removed: {…}, _removed: false, _idle_notified: true, … }
​
<prototype>: Object { … }

I only have the 1 plot, so I assume this one entry is my plot.
How do I get the PlotView from this?

In my js file:

Object.keys(Bokeh.index); //returned empty array
Object.values(Bokeh.index); //returned empty array
Bokeh.index[0]; //returned undefined
Bokeh.index.toString(); //returned [object Object]

When I run Object.keys(Bokeh.index) in the browser (Chrome) console, it correctly prints out

Array [ "DC572550235F4541AFB693288C7E925F" ]
​
0: "DC572550235F4541AFB693288C7E925F"
​
length: 1
​
<prototype>: Array []

But as above, when I do it in my js file, it returns an empty array. Would you know what the issue is here?

Edit: I figured out why I was getting different results in console and js file. Bokeh.Index I guess had not updated. I set a timeout for 5 secs and seems to be working now

Thanks

If you only have the one plot then the value for the single key will be the plot view. E.g. from one of the gallery examples:

> Object.values(Bokeh.index)[0].export

export(e="auto",t=!0){const i=(()=>{switch(e){case"auto":return this.canvas_view.model.output_backend;case"png":return"canvas";case"svg":return"svg"}})(),s=new k.CanvasLayer(i,t),{width:n,height:a}=t…

Thanks very much for the help, Bryan.
Works now. No way I would’ve figure that out by myself lol

BokehJS started out as a private implementation detail. We’d like to keep pushing on it to be a useful JS-only project on its own, but it didn’t start out that way, and it will take time and effort to get things to the same level as the Python API.

1 Like

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