File Output
File output
If you are using Bokeh just to enable interactive data exploration, you might not need to save any output. Or perhaps you have used Bokeh server to carry out some data processing or to prepare a custom visualization, in which case you might just need to use the Save tool attached to a plot to download a png-formatted copy of the figure. (There are additional mechanisms for exporting png and svg versions of figures described in the Bokeh documentation.)
In some cases, however, you might use Bokeh server to process and/or transform data and would like to download the processed data. For example, with the data plotted on the page on file input, you might want to have a callback to optionally subtract off the mean background (which has a value of approximately -0.06), and to re-plot the ColumnDataSource with the background-subtracted data. As with the file input issue, the processed data reside in memory (and are stored in a ColumnDataSource object), and need to be sent back from the server to your local machine. Unfortunately, there is not currently any "FileOutput" widget that is analogous to the FileInput widget that we used on the previous page to upload a data file. Instead, one must resort to writing a CustomJS
callback function in JavaScript to download the processed data to a file. Thus, even though an overarching goal of the design of Bokeh is to allow you to write Python code instead of JavaScript, sometimes it is necessary to write some JS code.
The code that follows is an extension of the file input example from the previous page.
Here, we have added two more widgets to the application:
- a Button that triggers a "Subtract background" calculation and a subsequent re-plot of the background-subtracted data, through the use of the callback function
subtract_mean_background
- a Button that triggers a "Download processed data" download of the data to the user's filesystem, through the use of a CustomJS callback that is encoded in the string named
jscode
A screenshot of this application in action is shown below, after the mean background has been subtracted so that the signal is centered around 0.0 rather than -0.06 as on the previous page.
We highlight a few more aspects of the code above:
- If you want to run the code above, you could copy it to a file named "bokeh_read_and_write_file.py" and then run it using Bokeh server via
bokeh serve --show bokeh_read_and_write_file.py
. - Lines 44-74: The callback code stored in
jscode
and passed to theCustomJS
constructor is written in JavaScript, not Python. - The purpose of the CustomJS callback code is to take the data that are stored in the ColumnDataSource named
datasource
and to write it back out to a text-based csv file that can be downloaded. That conversion to csv is done by iterating over each x,y pair of the data and creating a comma-separated row for each pair, which are then joined with intervening newline characters. The code at the bottom (lines 59-73) is somewhat inscrutable JS code that enables the file to be downloaded from the browser to a file named "data_result.csv". - An alternative to encoding the JavaScript directly in a Python multi-line string within the Python application is to store the unquoted code in its own separate JS file (e.g., download.js), which can then be read as part of the call to CustomJS. This is the approach taken in the export_csv example at bokeh.org.
- One advantage to encoding the JS into its own file is that there are subtleties involved in embedding the JS code in a Python string. In particular, some special characters, such as the newline character '\n', need to be escaped if one is embedding the JS in a Python string (see line 57, where the newline characters we need to insert after each row in the csv file are escaped as '\\\\n').