2016-12-28 19 views
4

私はFlaskにとって全く新しいので、d3js強制レイアウトでnetworkxグラフデータを表示する方法を理解しようとしています。ここFlaskでサーバからクライアントへのJSONデータの受け渡し

@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ファイルされる:ここでは、関連するPythonコードがあるので、はっきりd3.json

<!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> 

()関数は、静的なJSONファイルの場所、で望んでいますこの場合、リクエストURLに基​​づいて動的に生成しようとしています。

ここで私が見つけたアプローチが約12件ありました。そのままテンプレートのindex.htmlで

@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) 

、とに「http://localhost/thread?thread_id=12345」ナビゲートが、それはページID 12345のためのJSONを印刷する代わりに、JavaScriptをレンダリングされたため、これは失敗しました:以下の提案あたり、私が試してみました。

私の現在の目標は、Pythonメソッドでパラメータを指定することです( ".../showgraph?threadid = whatever ...")、Pythonコードでjsonを生成し、それをhtml/jsに戻します。これをどのように達成するのですか?

答えて

5

あなたは本当に近いです!

まず、「d3.json()関数が静的なJSONファイルの場所を必要としていることを明示的に示しています」という記述が正しくありません。

d3.json()(例えば、静的data.jsonようなJSONはなく、リテラルJSONデータとすることができるURLを、期待する)d3-requestライブラリの一部であり、など、XHR方法です。

私は関数として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パラメータを送信するためにビットを呼び出して調整します:

このような何かをする必要がありますdは
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 
}); 

これは問題ありません。 FYI

また、あなたはあなたが2つのフィルタを使用する必要がJavaScriptオブジェクトにオブジェクトを "読む" ためにJinja2のを使用する場合:{{ data|tojson|safe }}

+0

d3.json()はURL(つまり、静的ファイルやREST APIの何か)を受け入れることを確認していますが、そのためには別のメソッドを呼び出す必要がありますどういうわけか実際にテンプレートをレンダリングするのですか?最初のスニペット候補を 'requests.get'の代わりに少し変更した'request.args.get'を試してみましたが、JSをレンダリングする代わりに、ページ上に未処理のJSONを表示しています。これは私が繰り返し遭遇した別の問題でした... – stuart

+0

はい、それは非同期メソッドなので、任意の有効なhttp URLを受け入れます。 requests.getはエラー、良いキャッチでした。あなたは何が起こっているかをより詳細に説明できますか?おそらくより多くのコードを共有するでしょう。 – abigperson

+0

ほとんどすべてのコードを貼り付けました(インポートは省略され、if __name__ == '__main__'ビット)、私は私のアプローチで何か間違っているかもしれないと思います...私がURLに行くとき[ domain]/thread?thread_id = 12345'それはバックエンドのものをすべて処理しますが、そのJSONをレンダリングする代わりに文字通り{"source":1、 "target":2}などを印刷します。たぶん私はURLに直接行くべきではないでしょうか? – stuart

3

解決した

のPython:

@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 json.dumps(s) 


@app.route("/showgraph") 
def showgraph(): 
    thread_id = request.args.get("thread_id", 3532967, type=int) 
    return render_template("index.html", threadid=thread_id) 

HTML/Jinja2の:

<!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?thread_id={{ threadid }}", function (json) { 
     var force = d3.layout.force() 
      .charge(-120) 
      .linkDistance(30) 
      .nodes(json.nodes) 
      .links(json.links) 
      .size([w, h]) 
      .start(); 

     // irrelevant stuff 
    }); 
</script> 
</body> 
</html> 

必要な別の方法JSONを返してページをレンダリングします。まだthread_id argを2回解析する必要があるのは馬鹿馬鹿しいようです。それが問題の99%だったので、PJの答えを受け入れました!

関連する問題