2016-12-28 63 views
4

我完全是Flask的新手,正試圖弄清楚如何使用d3js強制佈局顯示networkx圖形數據。下面是相關Python代碼:使用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文件:

<!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」,但這種失敗,因爲它是在頁面上打印的JSON用於ID爲12345,而不是渲染的JavaScript。總結起來,我目前的目標是通過URL(「.../showgraph?threadid = whatever ...」)在Python方法中指定一個參數,並在Python代碼中生成一個json,並且把它傳回給html/js。我該如何做到這一點?

回答

5

你真的很接近!

首先,聲明:「顯然d3.json()函數需要一個靜態JSON文件的位置」是不正確的。

d3.json()d3-request庫的一部分,並且同樣地,是一種方法,XHR(例如期望的URL,這可能是一個靜態JSON像data.json,但不是字面JSON數據)。

我會調整自己的瓶路線接受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) 

我的意思在這裏,如果你想使用的功能參數你」是d需要做這樣的事情:

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

+0

所以從你的意思,我收集d3.json()接受一個URL(即靜態文件或從REST API的東西),但要做到這一點,我需要調用一個單獨的方法莫名其妙地呈現模板,不是嗎?我嘗試了第一個片段建議(稍微修改--request.args.get而不是'requests.get')版本,但它只是在頁面上打印原始JSON而不是渲染JS。這是我反覆遇到的另一個問題... – stuart

+0

是的,它是一種異步方法,因此接受任何有效的http URL。 requests.get是個錯誤,很好。你能更詳細地解釋發生了什麼嗎?也許分享更多的代碼。 – abigperson

+0

我粘貼了幾乎所有的代碼(省略導入和「if __name__ =='__main__'」位),我想我可能會在我的方法中做錯事情...當我去到網址'[[域] /線程?thread_id = 12345'它做所有正確的後端的東西,但它只是在頁面上打印{「source」:1,「target」:2}等,而不是呈現該JSON。也許我不應該直接去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兩次,但無論如何。接受PJ的回答,因爲這是99%的問題!

相關問題