简体   繁体   English

使用 Django 后端将数据传递给 D3.js

[英]Passing Data to D3.js with Django Backend

I want to build a line chart following the code here .我想按照这里的代码构建一个折线图。 I've made slight change to the data being passed with contains epoch time and a closing price.我对包含纪元时间和收盘价的数据进行了轻微更改。 Following is the code以下是代码

{% load static %}
<html>
<script src="https://d3js.org/d3.v4.js"></script>

<body> 
    <h1> Hello! </h1>
    <div id="my_dataviz"></div>
</body>


<script>

    // set the dimensions and margins of the graph
    var margin = {top: 10, right: 30, bottom: 30, left: 60},
        width = 460 - margin.left - margin.right,
        height = 400 - margin.top - margin.bottom;
    
    // append the svg object to the body of the page
    var svg = d3.select("#my_dataviz")
      .append("svg")
        .attr("width", width + margin.left + margin.right)
        .attr("height", height + margin.top + margin.bottom)
      .append("g")
        .attr("transform",
              "translate(" + margin.left + "," + margin.top + ")");
    
    //Read the data
    var d = {
               "Date":{
                  "0":1641168000000,
                  "1":1641254400000,
                  "2":1641340800000
               },
               "Close":{
                  "0":182.01,
                  "1":179.7,
                  "2":174.92
               }
            };

    
    
    // When reading the csv, I must format variables:
    d3.json(d,
      function(d){
        return { date : d3.timeParse("%s")(d.Date), value : d.Close }
      },
    
      // Now I can use this dataset:
      function(data) {
    
        // Add X axis --> it is a date format
        var x = d3.scaleTime()
          .domain(d3.extent(data, function(d) { return d.date; }))
          .range([ 0, width ]);
        svg.append("g")
          .attr("transform", "translate(0," + height + ")")
          .call(d3.axisBottom(x));
    
        // Add Y axis
        var y = d3.scaleLinear()
          .domain([0, d3.max(data, function(d) { return +d.value; })])
          .range([ height, 0 ]);
        svg.append("g")
          .call(d3.axisLeft(y));
    
        // Add the line
        svg.append("path")
          .datum(data)
          .attr("fill", "none")
          .attr("stroke", "steelblue")
          .attr("stroke-width", 1.5)
          .attr("d", d3.line()
            .x(function(d) { return x(d.date) })
            .y(function(d) { return y(d.value) })
            )
    
    })
     
</script>
</html>

I am unable to generate the graph.我无法生成图表。 I've attached the console screenshot below.我在下面附上了控制台屏幕截图。

在此处输入图像描述

There seems to be an error passing data as seen in html file below传递数据似乎有错误,如下面的 html 文件所示

在此处输入图像描述

I can't figure out how to pass the data, what should be the correct way to do it?我不知道如何传递数据,正确的方法应该是什么?

Edit编辑

Applied suggested changes as follows应用建议的更改如下

{% load static %}
<html>
<script src="https://d3js.org/d3.v6.js"></script>
<body> 
    <h1> Hello! </h1>
    <div id="my_dataviz"></div>
    <!-- <canvas id="chart" width="100" height="100"></canvas>   -->
    <!-- <script src={% static "js\linechart.js" %}></script>  
    <script>
        var data = {{ AAPL|safe }};

        var chart = LineChart(data, {
        x: d => d.date,
        y: d => d.close,
        yLabel: "↑ Daily close ($)",
        width: 400,
        height: 400,
        color: "steelblue"
      });
    
    </script>     -->
</body>


<script>

    // set the dimensions and margins of the graph
    const margin = {top: 10, right: 30, bottom: 30, left: 60},
        width = 460 - margin.left - margin.right,
        height = 400 - margin.top - margin.bottom;
    
    // append the svg object to the body of the page
    const svg = d3.select("#my_dataviz")
      .append("svg")
        .attr("width", width + margin.left + margin.right)
        .attr("height", height + margin.top + margin.bottom)
      .append("g")
        .attr("transform", `translate(${margin.left},${margin.top})`);

    var d = [
       {
         "Date": 1641168000000,
         "Close": 182.01
       },
       {
         "Date": 1641254400000,
         "Close": 179.7
       },
       {
         "Date": 1641168000000,
         "Close": 174.92
       },
    ];

       d3.json(d,
    
      // When reading the csv, I must format variables:
      function(d){
        return { date : d3.timeParse("%s")(d.Date), value : d.Close }
      }).then(
    
      // Now I can use this dataset:
      function(data) {
    
        // Add X axis --> it is a date format
        const x = d3.scaleTime()
          .domain(d3.extent(data, function(d) { return d.date; }))
          .range([ 0, width ]);
        svg.append("g")
          .attr("transform", `translate(0, ${height})`)
          .call(d3.axisBottom(x));
    
        // Add Y axis
        const y = d3.scaleLinear()
          .domain([0, d3.max(data, function(d) { return +d.value; })])
          .range([ height, 0 ]);
        svg.append("g")
          .call(d3.axisLeft(y));
    
        // Add the line
        svg.append("path")
          .datum(data)
          .attr("fill", "none")
          .attr("stroke", "steelblue")
          .attr("stroke-width", 1.5)
          .attr("d", d3.line()
            .x(function(d) { return x(d.date) })
            .y(function(d) { return y(d.value) })
            )
    
    })
    </script>
</html>

I think there's two things happeningg here:我认为这里发生了两件事:

  1. When you call the funciton d3.json(data, parsingFunction) , d3 is expecting the data entry to be an array of elements, where each element contains all the information for that entry in your datum.当您调用d3.json(data, parsingFunction)时,d3 期望数据条目是一个元素数组,其中每个元素包含数据中该条目的所有信息。 What the parsingFunction does here, is recievee each element in the array and you have to write the logic of how to treat your data (in your case, parse the epoch and keep the close price as it was). parsingFunction 在这里所做的是接收数组中的每个元素,并且您必须编写如何处理数据的逻辑(在您的情况下,解析时期并保持收盘价不变)。

Therefore, what you should do is change the way your data is being sent so that it's an array where each entry is an object containing thee corresponding time and close price, ie:因此,您应该做的是更改数据的发送方式,使其成为一个数组,其中每个条目都是一个包含相应时间和收盘价的对象,即:

    var d = [
       {
         "Date": 1641168000000,
         "Close": 182.01
       },
       {
         "Date": 1641254400000,
         "Close": 179.7
       },
       {
         "Date": 1641168000000,
         "Close": 174.92
       },
    ];
  1. This is actually not what's causing your mistake, but I'll say it because i saw it in your code: d3.json return a promise .这实际上不是导致您的错误的原因,但我会这样说,因为我在您的代码中看到了它: d3.json return a promise Which means you have to wait for it to arrive.这意味着您必须等待它到达。 You can do this by either explicitely using var data = await d3.json(.., ..) and then using data to do whatever you want.你可以通过明确地使用var data = await d3.json(.., ..)来做到这一点,然后使用 data 来做任何你想做的事情。 OR, specify a callback function (which is what you were trying to do, I believe).或者,指定一个回调函数(我相信这是你想要做的)。 To do that though, you need too specify that you want to call that function when the promise has resolved, by using a .then(callback) statement.但是,要做到这一点,您还需要使用.then(callback)语句指定要在 promise 解决后调用该函数。

And by doing that, you can correctly parse the data with the code you sent above:通过这样做,您可以使用上面发送的代码正确解析数据:

d3.json(d, function(d){
    return { date : d3.timeParse("%s")(d.Date), value : d.Close }
    }
).then(function(data){
     // Use the data
})

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM