python - 使用 Flask 将 JSON 数据从服务器传递到客户端

标签 python json d3.js flask

我是 Flask 的新手,正在尝试弄清楚如何使用 d3js 强制布局显示 networkx 图形数据。这是相关的 Python 代码:

@app.route("/")
def index():
    """
    When you request the root path, you'll get the index.html template.

    """
    return flask.render_template("index.html")


@app.route("/thread")
def get_graph_data(thread_id: int=3532967):
    """
    returns json of a network graph for the specified thread
    :param thread_id:
    :return:
    """
    pqdict, userdict = graphs.get_post_quote_dict(thread_id)
    G = graphs.create_graph(pqdict)
    s = graphs.graph_to_node_link(G, remove_singlets=True) # returns dict
    return flask.jsonify(s)

这是 index.html 文件:

<!DOCTYPE html>
<html>
<head>
    <title>Index thing</title>
    <script type="text/javascript" src="http://d3js.org/d3.v2.js"></script>
    <link type="text/css" rel="stylesheet" href="templates/graph.css"/>
</head>
<body>
<div id="chart"></div>
<script>
    var w = 1500,
        h = 1500,
        fill = d3.scale.category20();

    var vis = d3.select("#chart")
        .append("svg:svg")
        .attr("width", w)
        .attr("height", h);

    d3.json("/thread", function (json) {
        var force = d3.layout.force()
            .charge(-120)
            .linkDistance(30)
            .nodes(json.nodes)
            .links(json.links)
            .size([w, h])
            .start();

        var link = vis.selectAll("line.link")
            .data(json.links)
            .enter().append("svg:line")
            .attr("class", "link")
            .style("stroke-width", function (d) {
                return Math.sqrt(d.value);
            })
            .attr("x1", function (d) {
                return d.source.x;
            })
            .attr("y1", function (d) {
                return d.source.y;
            })
            .attr("x2", function (d) {
                return d.target.x;
            })
            .attr("y2", function (d) {
                return d.target.y;
            });

        var node = vis.selectAll("circle.node")
            .data(json.nodes)
            .enter().append("svg:circle")
            .attr("class", "node")
            .attr("cx", function (d) {
                return d.x;
            })
            .attr("cy", function (d) {
                return d.y;
            })
            .attr("r", 5)
            .style("fill", function (d) {
                return fill(d.group);
            })
            .call(force.drag);

        vis.style("opacity", 1e-6)
            .transition()
            .duration(1000)
            .style("opacity", 1);

        force.on("tick", function () {
            link.attr("x1", function (d) {
                return d.source.x;
            })
                .attr("y1", function (d) {
                    return d.source.y;
                })
                .attr("x2", function (d) {
                    return d.target.x;
                })
                .attr("y2", function (d) {
                    return d.target.y;
                });

            node.attr("cx", function (d) {
                return d.x;
            })
                .attr("cy", function (d) {
                    return d.y;
                });
        });
    });
</script>
</body>
</html>

很明显,d3.json() 函数需要一个静态 JSON 文件的位置,在本例中,我试图根据请求 URL 动态生成该文件。

我已经尝试了大约十二种我在这里发现的方法。根据以下建议,我尝试了:

@app.route("/")
def index():
    """
    When you request the root path, you'll get the index.html template.

    """
    return flask.render_template("index.html")


@app.route("/thread")
def get_graph_data():

    """
    returns json of a network graph for the specified thread
    :param thread_id:
    :return:
    """
    thread_id = request.args.get("thread_id", 3532967, type=int)
    pqdict, userdict = graphs.get_post_quote_dict(thread_id)
    G = graphs.create_graph(pqdict)
    s = graphs.graph_to_node_link(G, remove_singlets=True)
    return jsonify(s)

模板 index.html 不变,导航到“http://localhost/thread?thread_id=12345”,但这失败了,因为它在页面上打印 ID 12345 的 JSON 而不是呈现 javascript。

所以综上所述,我目前的目标是从URL(".../showgraph?threadid=whatever...")在Python方法中指定一个参数,在Python代码中生成一个json,并通过它回到 html/js。我该如何做到这一点?

最佳答案

你真的很接近!

首先,声明:“显然 d3.json() 函数需要一个静态 JSON 文件的位置”是不正确的。

d3.json()d3-request 库的一部分,因此是一个 XHR 方法(例如,需要一个 URL,它可以是一个静态 JSON,如 data.json,但不是文字 JSON 数据)。

我会调整您的 Flask 路由以接受 GET 参数,因为该函数将仅通过 URL 接受参数:

@app.route("/thread")
def get_graph_data():
    thread_id = request.args.get("thread_id", 3532967, type=int)
    pqdict, userdict = graphs.get_post_quote_dict(thread_id)
    G = graphs.create_graph(pqdict)
    s = graphs.graph_to_node_link(G, remove_singlets=True) # returns dict
    return flask.jsonify(s)

我的意思是如果你想使用你需要做这样的函数参数:

@app.route("/thread/<int:thread_id>")
def get_graph_data(thread_id):
    ...

然后,稍微调整您的 XHR 调用以发送 GET 参数:

var url = "/thread?thread_id=" + id.toString();
d3.json(url, function (json) {
    var force = d3.layout.force()
        .charge(-120)
        .linkDistance(30)
        .nodes(json.nodes)
        .links(json.links)
        .size([w, h])
        .start();

   // a bunch more js that i copied and pasted from a tutorial
});

应该没问题。

此外,仅供引用,如果您想使用 Jinja2 将对象“读”成 Javascript 对象,您需要使用 2 个过滤器:{{ data|tojson|safe }}

关于python - 使用 Flask 将 JSON 数据从服务器传递到客户端,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/41371214/

相关文章:

python - 生成一个有图案的 numpy 矩阵

python - 将多个元素(基于条件)移动到列表末尾

python - 人们通常如何处理 Django 中的类变量?

c++ - 无法在 Visual Studio 代码中启动 C++ 调试器

c# - Mono 不支持 System.Runtime.Serialization.DataMemberAttribute EmitDefaultValue 设置

javascript - 使用 d3.xml 而不是 d3.json 绘制可折叠缩进树

javascript - d3.js如何同时缩放多个图表

尝试按索引访问列表时出现 Python 错误 - "List indices must be integers, not str"

javascript - 我正在尝试使用 Tornado 数据制作旭日图

php - 如何在 CodeIgniter 中使用 AJAX 函数更改网页数据