bokeh-plot
Table of Contents
1 DONE Interactive Bokeh plots in HTML
In our last post we examined the use of plotly to generate interactive plots in HTML. Today we expand the idea, and use Bokeh. One potential issue with plotly is the need for an account and API-key, some limitations on how many times a graph can be viewed per day (although I should aspire to have my graphs viewed 1000+ times a day!), and who knows what happens to the graphs if plotly ever goes out of business. While the static images we usually use have limited utility, at least they stick around.
So, today we look at Bokeh which allows you to embed some json data in your HTML, which is made interactive by your browser with more javascript magic. We get straight to the image here so you can see what this is all about. Briefly, this data shows trends (or lack of) in the adsorption energies of some atoms on the atop and fcc sites of several transition metals as a function of adsorbate coverage xu-2014-probin-cover. The code to do this is found here.
Using Bokeh does not integrate real smoothly with my blog workflow, which only generates the body of HTML posts. Bokeh needs some javascript injected into the header to work. To get around that, I show the plot in a frame here. You can see a full HTML version here: ./bokeh-plot.html.
This is somewhat similar to the plotly concept. The data is embedded in the html in this case, which is different. For very large plots, I actually had some trouble exporting the blog post! I suspect that is a limitation of the org-mode exporter though, because I could save the html files from Python and view them fine.
Note to make this work, we need these lines in our HTML header:
#+HTML_HEAD: <link rel="stylesheet" href="http://cdn.pydata.org/bokeh/release/bokeh-0.11.1.min.css" type="text/css" /> #+HTML_HEAD: <script type="text/javascript" src="http://cdn.pydata.org/bokeh/release/bokeh-0.11.1.min.js"></script>
Since we do not host those locally, if they ever disappear, our plots will not show ;(
1.1 The data and code
We will get the data from our paper on coverage dependent adsorption energies xu-2014-probin-cover. There are some data rich figures there that would benefit from some interactivity. You can get the data here: http://pubs.acs.org/doi/suppl/10.1021/jp508805h. Extract out the supporting-information.org and energies.json file to follow here. We will make Figure 2a in the SI document here, and make it interactive with hover tooltips.
import json from collections import OrderedDict from bokeh import mpl from bokeh.plotting import * from bokeh.models import HoverTool from bokeh.embed import components with open('/users/jkitchin/Desktop/energies.json', 'r') as f: data = json.load(f) # color for metal # letter symbol for adsorbate colors = {'Cu':'Orange', 'Ag':'Silver', 'Au':'Yellow', 'Pd':'Green', 'Pt':'Red', 'Rh':'Blue', 'Ir':'Purple'} all_ads = ['O', 'S'] TOOLS="crosshair,pan,wheel_zoom,box_zoom,reset,hover,previewsave" p = figure(title="Correlation between atop and fcc sites", tools=TOOLS) for metal in ['Rh', 'Pd', 'Cu', 'Ag']: for adsorbate in all_ads: E1, E2 = [], [] for coverage in '0.25', '0.5', '0.75', '1.0': if (isinstance(data[metal][adsorbate]['ontop'][coverage], float) and isinstance(data[metal][adsorbate]['fcc'][coverage], float)): E1.append(data[metal][adsorbate]['ontop'][coverage]) E2.append(data[metal][adsorbate]['fcc'][coverage]) labels = ['{0}-{1} {2} ML'.format(metal, adsorbate, x) for x in ['0.25', '0.5', '0.75', '1.0']] p.line('x', 'y', color=colors[metal], source=ColumnDataSource(data={'x': E1, 'y': E2, 'label': labels})) p.circle('x', 'y', color=colors[metal], source=ColumnDataSource(data={'x': E1, 'y': E2, 'label': labels})) hover =p.select({'type': HoverTool}) hover.tooltips = OrderedDict([("(atop,fcc)", "(@x, @y)"), ("label", "@label")]) p.xaxis.axis_label = 'Adsorption energy on the atop site' p.yaxis.axis_label = 'Adsorption energy on the fcc site' script, div = components(p) script = '\n'.join(['#+HTML_HEAD_EXTRA: ' + line for line in script.split('\n')]) print '''{script} #+BEGIN_HTML <a name="figure"></a> {div} #+END_HTML '''.format(script=script, div=div)