如何在 JS 客户端上正确显示使用 Python Plotly 在服务器上创建的图表?
Posted
技术标签:
【中文标题】如何在 JS 客户端上正确显示使用 Python Plotly 在服务器上创建的图表?【英文标题】:How to correctly display a chart on JS client, created on server using Python Plotly? 【发布时间】:2021-09-03 08:23:37 【问题描述】:我想在我的前端(用 javascript 编写)显示使用 Python Plotly 创建的图表。该图表是在我的后端(在 Python Flask 上运行)创建的,具有以下结构:
#document // chartDoc
<div> // outerDiv
<div></div> // innerDiv
<script> innerScriptText </script> // innerScript
</div>
我将它作为 JSON 文件中的字符串发送:"chart": my_chart_str
。
问题: 我在我的 JS 中收到图表,我创建了一个新的 <script>
元素,我用代码填充它以显示图表(否则浏览器不执行脚本,仅将其打印为纯文本)并且我收到以下错误:
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
它来自 plotly.js 库,由 div
组件引起,该组件将 this.style
评估为 undefined
。
但是,如果我将收到的图表代码手动粘贴到.html
文件中,则图表显示正常。
基本上我想做的是自动化this answer中描述的过程。
这是重现我的错误的最少代码:
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)
使用python server.py
启动服务器(我在Windows 上),在浏览器中打开index.html
(双击它,而不是通过本地主机),打开开发者控制台,您应该会看到错误。
你知道如何解决吗?
【问题讨论】:
只是一个问题。为什么不直接使用破折号呢?要求了解实际用例 我无法控制此项目中使用的技术。此外,它必须由 JS 的前端开发人员和后端的 pyhton 数据科学家管理。 我明白了。我认为这是不正确的做法。只需使用 FE 库来绘制图表,如 charts.js 或 high-charts 或 w/e,您的 BE 应该只发送数据来填充图表。 我明白你的意思,但图表是可能数百万个数据点的固定大小结果,在这种情况下,发送图表比发送数据点更方便。 【参考方案1】:我终于找到了解决方法。
我没有将图表作为 JSON 字符串发送,而是执行以下操作:
-
从
index.html
一个 JQuery 函数调用服务器。
服务器创建图表(以div
的形式)并将其保存在一个名为chart.html
的文件中。
服务器将chart.html
文件返回给JQuery。
JQuery 接收文件并将其插入到 index.html
(this answer 帮助我弄清楚如何将 html 文件嵌入到另一个文件中)。
我的工作代码:
index.html
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<script src="https://cdn.plot.ly/plotly-latest.min.js"></script>
<script src="https://ajax.googleapis.com/ajax/libs/jquery/3.5.1/jquery.min.js"></script>
<script src="./index.js"></script>
</head>
<body>
<p>CHART WILL BE SHOWN BELOW</p>
<div id="chart-container"></div>
</body>
</html>
index.js
(function ()
window.onload = function ()
getChart();
function getChart()
$("#chart-container").load("get_chart"); // chart will be inserted in "chart-container"
)();
server.py
from flask import Flask, render_template
from flask_cors import CORS
app = Flask(__name__, static_url_path="", static_folder='', template_folder='')
CORS(app)
def create_chart():
# sample graph
import plotly.express as px
fig = px.imshow([[1, 20, 30],
[20, 1, 60],
[30, 60, 1]])
fig.write_html("./chart.html", include_plotlyjs=False, full_html=False)
@app.route("/")
def index():
return render_template("/index.html") # return "index.html" without chart
@app.route("/get_chart")
def get_chart():
create_chart() # create "chart.html" file
return render_template("/chart.html") # return chart to jquery
if __name__ == "__main__":
app.run(debug=True, host="127.0.0.1", port=5000)
要运行它,首先启动服务器(windows:python server.py
)然后打开浏览器并导航到127.0.0.1:5000
。
【讨论】:
以上是关于如何在 JS 客户端上正确显示使用 Python Plotly 在服务器上创建的图表?的主要内容,如果未能解决你的问题,请参考以下文章
如何使用 Python、PyQt5 和 Pyinstaller 修复未正确显示的按钮
不和谐.JS |如何使用 **channel.client** 功能而不显示机器人客户端信息?
Clickhouse 客户端无法在 linux 屏幕上正确显示数据