Host a Jupyter / Python generated Plotly chart

One thing I do often is generating charts with Jupyter. Common ways to do that with a Python kernel is to use Matplotlib or Plotly. I'm a Plotly user.

The challenge today was to host a Python generated chart for usage in a website. In this particular case it is a S3 bucket, but it could be any webserver.
The easiest way to achieve that is to use static images like .png or .svg, but since Plotly comes with the feature of being interactive via Plotly.js, it's not what I wanted to do. Another example of Plotly can be found on my Abuse statistics page.

The problem in this case was that nearly all Plotly.js examples do the data preparation or generating part in Javascript. But what if you are a Python / Pandas user and have already done that.
What needs to be done if the data is already there?

The answer is to use the .json export feature in Plotly and import it via Plotly.js.

Basic example directory structure of the webserver document_root:

- index.html
- plot.js
- plots/
-- my_plot.json

index.html

<html>
  <head>
    <meta charset="utf-8"/>
    <script src="https://cdn.plot.ly/plotly-latest.min.js"></script>
    <script src="plot.js"></script>
  </head>
  <body>
    <div id="my_plot"></div>
  </body>
</html>

The <div> element(s) is getting referenced by name in plot.js and is actually the location of the chart(s) in the DOM.

plot.js

"use strict";
var plots = ['my_plot'];
var _loop = function _loop() {
  var plot = _plots[_i];
  Plotly.d3.json('plots/' + plot + ".json", function (error, data) {
    if (error) return console.warn(error);
    Plotly.newPlot(plot, data.data, data.layout, {
      responsive: true
    });
  });
};

for (var _i = 0, _plots = plots; _i < _plots.length; _i++) {
  _loop();
}

Since the .json document my_plot.json was used inside Jupyterlab it contains all information which are needed to generate a graph. The data and layout just needs to be loaded and re-used with Plotly.js
Responsive mode is turned on, no idea why it's not default :-)

That's it for the web part. All that's missing is a valid my_plot.json file. This can be stored via Jupyter or directly uploaded to S3 in case if you host via S3 or run the Python script with Lambda.

Generate my_plot.json

# Store locally
import plotly.graph_objects as go

animals=['giraffes', 'orangutans', 'monkeys']
fig = go.Figure(data=[
    go.Bar(name='SF Zoo', x=animals, y=[20, 14, 23]),
    go.Bar(name='LA Zoo', x=animals, y=[12, 18, 29])
])
fig.update_layout(barmode='group')
fig.show()
# save
fig.write_json('plots/my_plot.json')
# Alternative upload to S3
import boto3
s3 = boto3.resource('s3', region_name='eu-central-1')
s3_object = s3.Object('my_bucket', 'plots/my_plot.json')
s3_object.put(Body=fig.to_json())

That's it. Now the interactive Plotly chart get's displayed in the browser as it was before in Jupyterlab.

Schreibe einen Kommentar