GetJSON 从 URL 到 d3.js 图表

Posted

技术标签:

【中文标题】GetJSON 从 URL 到 d3.js 图表【英文标题】:GetJSON from URL into d3.js chart 【发布时间】:2018-10-22 12:41:45 【问题描述】:

我正在尝试将 json 加载到我的 d3.js 图表中。我首先尝试使用静态硬编码的虚拟 json (freqData),它工作正常,但是当我尝试从 URL (freqData2) 复制 json 时,由于无法读取我的 json,因此未创建图表。我看不出结构或变量名称有什么不同。

你可以看看这个 jsfiddle(不要注意图表本身,我的 jsfiddle 有点乱,但在我的真实代码中,它可以正确处理正确的数据)。 https://jsfiddle.net/liostse/yfw3zgdL/2/

function dashboard(id, fData)  /*Creating dashboard for priorities*/
  var barColor = 'steelblue';

  function segColor(c) 
    return 
      P2: "#807dba",
      P3: "#e08214",
      P4: "#41ab5d",
      P5: "#1dc609",
      P6: "#f7f322"
    [c];
  
  // compute total for each state.
  fData.forEach(function(d) 
    console.log(d.freq.P2);
    d.total = d.freq.P2 + d.freq.P3 + d.freq.P4 + d.freq.P5 + d.freq.P6;
    console.log(d.total);
  );
  // function to handle histogram.
  function histoGram(fD) 
    var hG = ,
      hGDim = 
        t: 30,
        r: 30,
        b: 20,
        l: 50
      ;
    hGDim.w = 600 - hGDim.l - hGDim.r,
      hGDim.h = 300 - hGDim.t - hGDim.b;
    //create svg for histogram.
    var hGsvg = d3.select(id).append("svg")
      .attr("width", hGDim.w + hGDim.l + hGDim.r)
      .attr("height", hGDim.h + hGDim.t + hGDim.b).append("g")
      .attr("transform", "translate(" + hGDim.l + "," + hGDim.t + ")");
    // create function for x-axis mapping.
    var x = d3.scale.ordinal().rangeRoundBands([0, hGDim.w], 0.1)
      .domain(fD.map(function(d) 
        return d[0];
      ));
    // Add x-axis to the histogram svg.
    hGsvg.append("g").attr("class", "x axis")
      .attr("transform", "translate(0," + hGDim.h + ")")
      .call(d3.svg.axis().scale(x).orient("bottom"));
    // Create function for y-axis map.
    var y = d3.scale.linear().range([hGDim.h, 0])
      .domain([0, d3.max(fD, function(d) 
        return d[1];
      )]);
    // Create bars for histogram to contain rectangles and freq labels.
    var bars = hGsvg.selectAll(".bar").data(fD).enter()
      .append("g").attr("class", "bar");
    //create the rectangles.
    bars.append("rect")
      .attr("x", function(d) 
        return x(d[0]);
      )
      .attr("y", function(d) 
        return y(d[1]);
      )
      .attr("width", x.rangeBand())
      .attr("height", function(d) 
        return hGDim.h - y(d[1]);
      )
      .attr('fill', barColor)
      .on("mouseover", mouseover) // mouseover is defined below.
      .on("mouseout", mouseout); // mouseout is defined below.
    //Create the frequency labels above the rectangles.
    bars.append("text").text(function(d) 
        return d3.format(",")(d[1])
      )
      .attr("x", function(d) 
        return x(d[0]) + x.rangeBand() / 2;
      )
      .attr("y", function(d) 
        return y(d[1]) - 5;
      )
      .attr("text-anchor", "middle");

    function mouseover(d)  // utility function to be called on mouseover.
      // filter for selected state.
      var st = fData.filter(function(s) 
          return s.State == d[0];
        )[0],
        nD = d3.keys(st.freq).map(function(s) 
          return 
            type: s,
            freq: st.freq[s]
          ;
        );
      // call update functions of pie-chart and legend.    
      pC.update(nD);
      leg.update(nD);
    

    function mouseout(d)  // utility function to be called on mouseout.
      // reset the pie-chart and legend.    
      pC.update(tF);
      leg.update(tF);
    
    // create function to update the bars. This will be used by pie-chart.
    hG.update = function(nD, color) 
      // update the domain of the y-axis map to reflect change in frequencies.
      y.domain([0, d3.max(nD, function(d) 
        return d[1];
      )]);
      // Attach the new data to the bars.
      var bars = hGsvg.selectAll(".bar").data(nD);
      // transition the height and color of rectangles.
      bars.select("rect").transition().duration(500)
        .attr("y", function(d) 
          return y(d[1]);
        )
        .attr("height", function(d) 
          return hGDim.h - y(d[1]);
        )
        .attr("fill", color);
      // transition the frequency labels location and change value.
      bars.select("text").transition().duration(500)
        .text(function(d) 
          return d3.format(",")(d[1])
        )
        .attr("y", function(d) 
          return y(d[1]) - 5;
        );
    
    return hG;
  
  // function to handle pieChart.
  function pieChart(pD) 
    var pC = ,
      pieDim = 
        w: 250,
        h: 250
      ;
    pieDim.r = Math.min(pieDim.w, pieDim.h) / 2;
    // create svg for pie chart.
    var piesvg = d3.select(id).append("svg")
      .attr("width", pieDim.w).attr("height", pieDim.h).append("g")
      .attr("transform", "translate(" + pieDim.w / 2 + "," + pieDim.h / 2 + ")");
    // create function to draw the arcs of the pie slices.
    var arc = d3.svg.arc().outerRadius(pieDim.r - 10).innerRadius(0);
    // create a function to compute the pie slice angles.
    var pie = d3.layout.pie().sort(null).value(function(d) 
      return d.freq;
    );
    // Draw the pie slices.
    piesvg.selectAll("path").data(pie(pD)).enter().append("path").attr("d", arc)
      .each(function(d) 
        this._current = d;
      )
      .style("fill", function(d) 
        return segColor(d.data.type);
      )
      .on("mouseover", mouseover).on("mouseout", mouseout);
    // create function to update pie-chart. This will be used by histogram.
    pC.update = function(nD) 
      piesvg.selectAll("path").data(pie(nD)).transition().duration(500)
        .attrTween("d", arcTween);
    
    // Utility function to be called on mouseover a pie slice.
    function mouseover(d) 
      // call the update function of histogram with new data.
      hG.update(fData.map(function(v) 
        return [v.measure_code, v.freq[d.data.type]];
      ), segColor(d.data.type));
    
    //Utility function to be called on mouseout a pie slice.
    function mouseout(d) 
      // call the update function of histogram with all data.
      hG.update(fData.map(function(v) 
        return [v.measure_code, v.total];
      ), barColor);
    
    // Animating the pie-slice requiring a custom function which specifies
    // how the intermediate paths should be drawn.
    function arcTween(a) 
      var i = d3.interpolate(this._current, a);
      this._current = i(0);
      return function(t) 
        return arc(i(t));
      ;
    
    return pC;
  
  // function to handle legend.
  function legend(lD) 
    var leg = ;
    // create table for legend.
    var legend = d3.select(id).append("table").attr('class', 'legend');
    // create one row per segment.
    var tr = legend.append("tbody").selectAll("tr").data(lD).enter().append("tr");
    // create the first column for each segment.
    tr.append("td").append("svg").attr("width", '16').attr("height", '16').append("rect")
      .attr("width", '16').attr("height", '16')
      .attr("fill", function(d) 
        return segColor(d.type);
      );
    // create the second column for each segment.
    tr.append("td").text(function(d) 
      return d.type;
    );
    // create the third column for each segment.
    tr.append("td").attr("class", 'legendFreq')
      .text(function(d) 
        return d3.format(",")(d.freq);
      );
    // create the fourth column for each segment.
    tr.append("td").attr("class", 'legendPerc')
      .text(function(d) 
        return getLegend(d, lD);
      );
    // Utility function to be used to update the legend.
    leg.update = function(nD) 
      // update the data attached to the row elements.
      var l = legend.select("tbody").selectAll("tr").data(nD);
      // update the frequencies.
      l.select(".legendFreq").text(function(d) 
        return d3.format(",")(d.freq);
      );
      // update the percentage column.
      l.select(".legendPerc").text(function(d) 
        return getLegend(d, nD);
      );
    

    function getLegend(d, aD)  // Utility function to compute percentage.
      return d3.format("%")(d.freq / d3.sum(aD.map(function(v) 
        return v.freq;
      )));
    
    return leg;
  
  // calculate total frequency by segment for all state.
  var tF = ['P2', 'P3', 'P4', 'P5', 'P6'].map(function(d) 
    return 
      type: d,
      freq: d3.sum(fData.map(function(t) 
        return t.freq[d];
      ))
    ;
  );
  // calculate total frequency by state for all segment.
  var sF = fData.map(function(d) 
    return [d.measuer_code, d.total];
  );
  var hG = histoGram(sF), // create the histogram.
    pC = pieChart(tF), // create the pie-chart.
    leg = legend(tF); // create the legend.

freqData2 = [];
$.getJSON('http://88.99.13.199:3000/dashboarddata', function(mydata) 
  mydata.forEach(function(val) 
    var freqData1 = ;
    freqData1["measure_code"] = val.measure_code;
    freqData1["freq"] = 
      P2: val.p2,
      P3: val.p3,
      P4: val.p4,
      P5: val.p5,
      P6: val.p6
    ;
    freqData2.push(freqData1);
  );
  return freqData2;
);
var freqData = [
  measure_code: 'Μ1',
  freq: 
    P2: 47,
    P3: 19,
    P4: 29,
    P5: 20,
    P6: 100
  
, 
  measure_code: 'Μ2',
  freq: 
    P2: 11,
    P3: 42,
    P4: 74,
    P5: 15,
    P6: 10
  
, 
  measure_code: 'Μ3',
  freq: 
    P2: 93,
    P3: 21,
    P4: 48,
    P5: 10,
    P6: 10
  
, 
  measure_code: 'Μ4',
  freq: 
    P2: 82,
    P3: 11,
    P4: 12,
    P5: 50,
    P6: 20
  
, 
  measure_code: 'Μ5',
  freq: 
    P2: 44,
    P3: 34,
    P4: 98,
    P5: 10,
    P6: 14
  
, 
  measure_code: 'Μ6',
  freq: 
    P2: 19,
    P3: 17,
    P4: 13,
    P5: 10,
    P6: 10
  
, 
  measure_code: 'Μ7',
  freq: 
    P2: 18,
    P3: 27,
    P4: 12,
    P5: 50,
    P6: 18
  
, 
  measure_code: 'Μ8',
  freq: 
    P2: 48,
    P3: 38,
    P4: 42,
    P5: 15,
    P6: 17
  
, 
  measure_code: 'Μ9',
  freq: 
    P2: 77,
    P3: 18,
    P4: 15,
    P5: 50,
    P6: 14
  
, 
  measure_code: 'Μ10',
  freq: 
    P2: 162,
    P3: 39,
    P4: 41,
    P5: 40,
    P6: 10
  
, 
  measure_code: 'Μ11',
  freq: 
    P2: 62,
    P3: 39,
    P4: 41,
    P5: 15,
    P6: 20
  
, 
  measure_code: 'Μ12',
  freq: 
    P2: 12,
    P3: 39,
    P4: 41,
    P5: 15,
    P6: 12
  
, 
  measure_code: 'Μ13',
  freq: 
    P2: 162,
    P3: 39,
    P4: 71,
    P5: 30,
    P6: 10
  
, 
  measure_code: 'Μ14',
  freq: 
    P2: 62,
    P3: 79,
    P4: 41,
    P5: 15,
    P6: 12
  
, 
  measure_code: 'Μ16',
  freq: 
    P2: 12,
    P3: 39,
    P4: 41,
    P5: 10,
    P6: 10
  
, 
  measure_code: 'Μ19',
  freq: 
    P2: 16,
    P3: 379,
    P4: 41,
    P5: 10,
    P6: 10
  
, 
  measure_code: 'Μ20',
  freq: 
    P2: 16,
    P3: 39,
    P4: 41,
    P5: 50,
    P6: 32
  
, 
  measure_code: 'Μ97',
  freq: 
    P2: 62,
    P3: 379,
    P4: 47,
    P5: 50,
    P6: 10
  
];
console.log(typeof freqData2);
console.log(typeof freqData2);
dashboard('#dashboard', freqData);

任何帮助都会很棒!

【问题讨论】:

D3库中有json()方法。 【参考方案1】:

我可以看到 $.getJSON 方法的问题,您正在尝试从 HTTP 加载数据,因此您可能会在 jsfiddle 控制台中收到混合内容错误,但尝试使用 http 服务器从本地计算机运行它,您将获取数据。

【讨论】:

freqData和freqData2有区别吗? 不,我认为它是一样的,但是你正在使用 ajax 调用,所以你需要在回调中执行仪表板 func -> d3.json('88.99.13.199:3000/dashboarddata', function(err, mydata) mydata.forEach(function(val) var freqData1 = ; freqData1["measure_code"] = val.measure_code ; freqData1["freq"] = P2: val.p2, P3: val.p3, P4: val.p4, P5: val.p5, P6: val.p6 ; freqData2.push(freqData1); ); // 在此处调用仪表板 );【参考方案2】:

你的代码很好,但你有一些问题。

这是可以工作的代码。

查看 cmets 以了解您做错了什么。

var freqData2 = []; //You didn't declared a var

//Use d3.json instead of jquery.getJSON
//As also suggested by @Alexandra in the comments
d3.json('http://88.99.13.199:3000/dashboarddata', function(err, mydata) 

 console.log(err);

 if(mydata && mydata.length > 0) 
 //if mydata is defined and have data then loop

 mydata.forEach(function(val) 
    var freqData1 = ;
    freqData1["measure_code"] = val.measure_code;
    freqData1["freq"] = 
      P2: val.p2,
      P3: val.p3,
      P4: val.p4,
      P5: val.p5,
      P6: val.p6
    ;

    freqData2.push(freqData1);
  );
  
  return freqData2;
);

//Timeout? WHY? because it takes time for url to respond back 
//and then all that data manipulation on it. 
//So, we will wait 1 Second to get data back and then we will print it.

setTimeout(()=>
dashboard('#dashboard', freqData2);
,1000);

其他问题是您在 JSfiddle 中遇到混合内容错误。为什么?因为您试图从 HTTP 获取数据,而 JSFiddle 默认转到 HTTPS。

【讨论】:

以上是关于GetJSON 从 URL 到 d3.js 图表的主要内容,如果未能解决你的问题,请参考以下文章

d3.js ----面积图表

在d3.js时间轴图表中添加图像而不是点

有没有办法用 D3.js 修改 Vega 图表?

在Javascript中为d3.js创建来自URL的多字节JSON

D3.Js图表excel

D3.js系列——交互式操作和布局