I want to display a chart created using Python Plotly in my front-end (written in JavaScript). The chart is created in my back-end (running on Python Flask) and has the following structure:
#document // chartDoc
<div> // outerDiv
<div></div> // innerDiv
<script> innerScriptText </script> // innerScript
</div>
I send it as a string inside a JSON file: {"chart": my_chart_str}
.
The problem: I receive the chart in my JS, I create a new <script>
element, I fill it with the code to display the chart (otherwise the browser doesn't execute the script, only prints it as plaintext) and I get the following error:
Uncaught TypeError: Cannot read property 'setProperty' of undefined
at Element.<anonymous> (plotly-latest.min.js:20)
at plotly-latest.min.js:20
at ut (plotly-latest.min.js:20)
at Array.Y.each (plotly-latest.min.js:20)
at Array.Y.style (plotly-latest.min.js:20)
at lt (plotly-latest.min.js:61)
at Object.r.plot (plotly-latest.min.js:61)
at Object.r.newPlot (plotly-latest.min.js:61)
at <anonymous>:1:210
at code.js:38
which comes from the plotly.js library and is caused by a div
component that evaluates this.style
as undefined
.
But if I take the received chart code and manually paste it inside an .html
file, the chart is displayed fine.
Basically what I'm trying to do is automating the procedure described in this answer.
This is the minimal code to reproduce my error:
index.html
<html>
<head>
<script src="https://cdn.plot.ly/plotly-latest.min.js"></script>
<script src="./code.js"></script>
</head>
<body>
<div id="graph-container">
</div>
</body>
</html>
code.js
window.onload = function () {
displayChart();
}
function displayChart() {
fetch("http://127.0.0.1:5000/chart", {
headers: { 'Accept': 'application/json', 'Content-Type': 'application/json' },
method: "GET"
})
.then(response => response.json())
.then(response => {
let chartString = response.chart;
let chartDoc = new DOMParser().parseFromString(chartString, "text/xml"); // #document
// get elements from received graph
let outerDiv = chartDoc.firstElementChild;
let innerDiv = outerDiv.firstElementChild.cloneNode();
let innerScriptText = outerDiv.lastElementChild.innerHTML;
// recreate same structure with new component and old content
let newOuterDiv = document.createElement("div");
let newInnerScript = document.createElement("script");
newInnerScript.setAttribute("type", "text/javascript");
let newInnerScriptText = document.createTextNode(innerScriptText);
newInnerScript.appendChild(newInnerScriptText);
newOuterDiv.appendChild(innerDiv);
newOuterDiv.appendChild(newInnerScript);
// insert graph in the page
document.getElementById("graph-container").appendChild(newOuterDiv);
});
}
server.py
from flask import Flask
from flask_restful import Api, Resource
from flask_cors import CORS
app = Flask(__name__)
api = Api(app)
CORS(app)
class Chart(Resource):
def get(self):
my_chart_str = str(get_chart())
return {"chart": my_chart_str}
def get_chart():
# taken from dash "getting started" guide
import plotly.graph_objs as go
from plotly.offline import plot
x = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
y1 = [9, 6, 2, 1, 5, 4, 6, 8, 1, 3]
y2 = [19, 36, 12, 1, 35, 4, 6, 8, 1, 3]
trace1 = go.Bar(x=x,
y=y1,
name='Boats')
trace2 = go.Bar(x=x,
y=y2,
name='Cars')
data = [trace1, trace2]
layout = go.Layout(title='Title',
xaxis=dict(title='X axis',
tickfont=dict(size=14,
color='rgb(107, 107, 107)'),
tickangle=-45),
yaxis=dict(title='Y axis',
titlefont=dict(size=16,
color='rgb(107, 107, 107)'),
tickfont=dict(size=14,
color='rgb(107, 107, 107)')),)
fig = go.Figure(data=data, layout=layout)
return plot(fig,
include_plotlyjs=False,
output_type='div')
api.add_resource(Chart, "/chart")
if __name__ == "__main__":
app.run(debug=True, host="127.0.0.1", port=5000)
Start the server (I'm on Windows) with python server.py
, open index.html
in your browser (double click on it, not via localhost), open the developer console and you should see the error.
Any idea on how to solve it?