简体   繁体   中英

D3 Line Graph with Dates on one Axis: What's Missing

...I'm working on a project that intends to present a D3 line chart, but my data model seems wonky.

The axes for the chart seem to come up fine, so I'd think the data model is good, but there's no line draw, and the function stops with an error that implies bad data.

(Tired and I want to go to the airport... so forgive me if there's something obvious about how I'm processing the data here...)

Here's the salient code snippet:

<svg id="chart_space" width="800" height="400"></svg>

<script>

var ymd =  d3.timeParse('%Y-%m-%d');

DrawChart(); // everything in that function

function DrawChart() {

    var static_data = {
        "currency": "GBP",
        "prices": [
            {
                "date": "2015-02-28",
                "marketPrice": 392
            },
            {
                "date": "2015-03-31",
                "marketPrice": 394
            }
        ]
    };

var priceHistory = static_data['prices'];

var vis = d3.select("#chart_space"),
    WIDTH = 800,
    HEIGHT = 400,
    MARGINS = {
      top: 18,
      right: 18,
      bottom: 18,
      left: 35
    },
    xRange = d3.time.scale().range([MARGINS.left, WIDTH - MARGINS.right]).domain([d3.min(priceHistory, function (d) {
        var dd = ymd(d.date);
        return dd;
      }),
      d3.max(priceHistory, function (d) {
        return ymd(d.date);
      })
    ]),

    yRange = d3.scale.linear().range([HEIGHT - MARGINS.top, MARGINS.bottom]).domain([d3.min(priceHistory, function (d) {
        return d.marketPrice;
      }),
      d3.max(priceHistory, function (d) {
        return d.marketPrice;
      })
    ]),

    // the axes on this chart draw okay. I have to think xRange is okay
    xAxis = d3.svg.axis()
      .scale(xRange)
      .tickSize(5)
      .tickSubdivide(true),

    yAxis = d3.svg.axis()
      .scale(yRange)
      .tickSize(5)
      .orient("left")
      .tickSubdivide(true);

  vis.append("svg:g")
    .attr("class", "x axis")
    .attr("transform", "translate(0," + (HEIGHT - MARGINS.bottom) + ")")
    .call(xAxis);

  vis.append("svg:g")
    .attr("class", "y axis")
    .attr("transform", "translate(" + (MARGINS.left) + ",0)")
    .call(yAxis);

// this is where mayhem begins -- we get NaN in the log traces here
var lineFunc = d3.svg.line()
  .x(function (d) {
    var xd = xRange(d.date);
    //console.log('X data to be plotted is: ' + xd); // emits NaN
    return xRange(d.date);
  })
  .y(function (d) {
    var yd = yRange(d.date); // (EDIT) okay, this is an error!
    //console.log('Y data to be plotted is: ' + yd);          
    return yRange(d.marketPrice);
  })
  .interpolate('linear');

vis.append("svg:path")
  .attr("d", lineFunc(priceHistory))
  .attr("stroke", "blue")
  .attr("stroke-width", 2)
  .attr("fill", "none");

}
</script>

There is a screen shot of the console for this:

控制台条件

I suspect it's related to the date information in the model, but I can't understand why the numeric data is showing up as NaN also. (EDIT: because of the error annotated in the code)

Pretty sure I'm doing something off-color, but can't see what and my eyesight is fading.

Ideas?

First of all, this is not D3 v3:

var ymd =  d3.timeParse('%Y-%m-%d');

It should be:

var ymd =  d3.time.format('%Y-%m-%d');
ymd.parse(string);

Back to the question: the problem of your code is that you're parsing the dates only when computing the domain. The data array remains with strings.

So, the solution is parsing the dates in the data array:

priceHistory.forEach(function(d) {
    d.date = ymd.parse(d.date)
});

Here is your code with that change:

 var ymd = d3.time.format('%Y-%m-%d'); DrawChart(); // everything in that function function DrawChart() { var static_data = { "currency": "GBP", "prices": [{ "date": "2015-02-28", "marketPrice": 392 }, { "date": "2015-03-31", "marketPrice": 394 } ] }; var priceHistory = static_data['prices']; priceHistory.forEach(function(d) { d.date = ymd.parse(d.date) }); var vis = d3.select("#chart_space"), WIDTH = 800, HEIGHT = 400, MARGINS = { top: 18, right: 18, bottom: 18, left: 35 }, xRange = d3.time.scale().range([MARGINS.left, WIDTH - MARGINS.right]).domain([d3.min(priceHistory, function(d) { return d.date; }), d3.max(priceHistory, function(d) { return d.date; }) ]), yRange = d3.scale.linear().range([HEIGHT - MARGINS.top, MARGINS.bottom]).domain([d3.min(priceHistory, function(d) { return d.marketPrice; }), d3.max(priceHistory, function(d) { return d.marketPrice; }) ]), // the axes on this chart draw okay. I have to think xRange is okay xAxis = d3.svg.axis() .scale(xRange) .tickSize(5) .tickSubdivide(true), yAxis = d3.svg.axis() .scale(yRange) .tickSize(5) .orient("left") .tickSubdivide(true); vis.append("svg:g") .attr("class", "x axis") .attr("transform", "translate(0," + (HEIGHT - MARGINS.bottom) + ")") .call(xAxis); vis.append("svg:g") .attr("class", "y axis") .attr("transform", "translate(" + (MARGINS.left) + ",0)") .call(yAxis); // this is where mayhem begins -- we get NaN in the log traces here var lineFunc = d3.svg.line() .x(function(d) { var xd = xRange(d.date); //console.log('X data to be plotted is: ' + xd); // emits NaN return xRange(d.date); }) .y(function(d) { var yd = yRange(d.date); // (EDIT) okay, this is an error! //console.log('Y data to be plotted is: ' + yd); return yRange(d.marketPrice); }) .interpolate('linear'); vis.append("svg:path") .attr("d", lineFunc(priceHistory)) .attr("stroke", "blue") .attr("stroke-width", 2) .attr("fill", "none"); } 
 <script src="https://d3js.org/d3.v3.min.js"></script> <svg id="chart_space" width="800" height="400"></svg> 

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

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