简体   繁体   中英

Line graph in d3 rendering but not displaying

I'm trying to build a line graph using D3 (in a React app built with webpack and react-faux-dom) and have everything except the line(s) displaying. Checking the dev tools there is a path rendering, but it seems to be off screen to the right (hovering the path pops path.line 141523000000 x 742.33 up, right correct height for data and what appears to be UTC milliseconds for the width) and I'm not sure why.

The x-axis is a time scale

const x = d3.scaleTime().range([0, width]);
const xAxis = d3.axisBottom(x).ticks(10).tickFormat(d3.timeFormat('%b %d, %Y'));

using

const parseTime = d3.timeParse('%Y-%m-%d');

for both the data

data.stocks.forEach((d) => {
  d.date = parseTime(d.date);
  d['GOOG'] = +d['GOOG'];
});

and the domain of the axis

x.domain(d3.extent(data.stocks, (d) => parseTime(d.date)));

If the x-axis is being set for a domain with numbers much smaller than the UTC milliseconds times I could the line being too far to the right to see on the chart, but they all convert with parseTime() and the examples I've looked only use d3.timeFormat() so I haven't found the problem. Using a bunch of console logs it appears the data is getting through properly with

const valueline = d3.line()
  .x((d) => d.date)
  .y((d) => d['GOOG']);

svg.append('path')
  .data([data.stocks])
  .attr('class', 'line')
  .attr('d', valueline);

but I can't seem to change anything to get the lines on the chart. Anyone familiar with this and/or far more experienced with D3 to spot what's going on?

In case it's not glaringly obvious in the above, the full component is

import React from 'react';
import ReactFauxDOM from 'react-faux-dom';
import * as d3 from 'd3';

export default class StockChart extends React.Component {
  render() {
    const div = new ReactFauxDOM.Element('div');
    let stockMax;
    const rawData = this.props.data; // see below if needed
    const smallestDataSetSize = d3.min(rawData.map((stock) => stock.closingValues.length));
    const restrictingDataSet = rawData.filter((stock) => stock.closingValues.length === smallestDataSetSize)[0];
    const parseTime = d3.timeParse('%Y-%m-%d');
    const margin = {top: 20, right: 40, bottom: 70, left: 40}
    const width = window.innerWidth - margin.left - margin.right;
    const height = window.innerHeight - margin.top - margin.bottom - 75*2;
    const x = d3.scaleTime().range([0, width]);
    const y = d3.scaleLinear().range([height, 0]);
    const xAxis = d3.axisBottom(x).ticks(10).tickFormat(d3.timeFormat('%b %d, %Y'));
    const yAxis = d3.axisLeft(y).ticks(5);

    // Get prelimiary data to set up chart
    stockMaximums = rawData.map((stock) => d3.max(stock.closingValues.map((d) => parseInt(d.price))));
    stockMax = d3.max(stockMaximums);

    // Fromat data into a JSON format that can be used with D3
    const data = { stocks: []};
    for (let i = smallestDataSetSize - 1; i > -1; i--) {
      const date = restrictingDataSet.closingValues[i].date;
      data.stocks.push({
        'date': date
      });
      rawData.map((stock) => {
        const stockData = stock.closingValues.filter((stockData) => stockData.date === date);
        data.stocks[data.stocks.length - 1][stock.name] = parseFloat(stockData[0].price);
      });
    }

    // Draw the plot
    let svg = d3.select(div).append('svg')
      .attr('width', width + margin.left + margin.right)
      .attr('height', height + margin.bottom + margin.top)
      .append('g')
      .attr('transform', `translate(${margin.left}, ${margin.top})`);

    x.domain(d3.extent(data.stocks, (d) => parseTime(d.date)));
    y.domain([0, stockMax*11/10]);

    svg.append('g')
      .attr('transform', `translate(0, ${height})`)
      .call(xAxis)
      .selectAll('text')
        .style('text-anchor', 'end')
        .attr('dx', '-1rem')
        .attr('dy', '-.2rem')
        .attr('transform', 'rotate(-65)');

    svg.append('g')
      .call(yAxis);

    // Just trying one line right now while debugging
    const valueline = d3.line()
      .x((d) => d.date)
      .y((d) => d['GOOG']);

    data.stocks.forEach((d) => {
      d.date = parseTime(d.date);
      d['GOOG'] = +d['GOOG'];
    });

    svg.append('path')
      .data([data.stocks])
      .attr('class', 'line')
      .attr('d', valueline);

    return div.toReact();
  }
}

and the only CSS at the moment

.line {
    fill: none;
    stroke: steelblue;
    stroke-width: 2;
}

with sample data

const rawData = {
    closingValues: [
        { date: "2018-09-28", price: "1193.4700" },
        { date: "2018-09-21", price: "1166.0900" },
        { date: "2018-09-14", price: "1172.5300" },
        { date: "2018-09-07", price: "1164.8300" },
        { date: "2018-08-31", price: "1218.1900" },
        { date: "2018-08-24", price: "1220.6500" },
        { date: "2018-08-17", price: "1200.9600" },
        { date: "2018-08-10", price: "1237.6100" },
        { date: "2018-08-03", price: "1223.7100" },
        { date: "2018-07-27", price: "1238.5000" },
        { date: "2018-07-20", price: "1184.9100" },
        { date: "2018-07-13", price: "1188.8200" },
        { date: "2018-07-06", price: "1140.1700" },
        { date: "2018-06-29", price: "1115.6500" },
        { date: "2018-06-22", price: "1155.4800" },
        { date: "2018-06-15", price: "1152.2600" },
        { date: "2018-06-08", price: "1120.8700" },
        { date: "2018-06-01", price: "1119.5000" },
        { date: "2018-05-25", price: "1075.6600" },
        { date: "2018-05-18", price: "1066.3600" },
        { date: "2018-05-11", price: "1098.2600" },
        { date: "2018-05-04", price: "1048.2100" },
        { date: "2018-04-27", price: "1030.0500" },
        { date: "2018-04-20", price: "1072.9600" },
        { date: "2018-04-13", price: "1029.2700" },
        { date: "2018-04-06", price: "1007.0400" },
        { date: "2018-03-29", price: "1031.7900" },
        { date: "2018-03-23", price: "1021.5700" },
        { date: "2018-03-16", price: "1135.7300" },
        { date: "2018-03-09", price: "1160.0400" },
        { date: "2018-03-02", price: "1078.9200" },
        { date: "2018-02-23", price: "1126.7900" },
        { date: "2018-02-16", price: "1094.8000" },
        { date: "2018-02-09", price: "1037.7800" },
        { date: "2018-02-02", price: "1111.9000" },
        { date: "2018-01-26", price: "1175.8400" },
        { date: "2018-01-19", price: "1137.5100" },
        { date: "2018-01-12", price: "1122.2600" },
        { date: "2018-01-05", price: "1102.2300" },
        { date: "2017-12-29", price: "1046.4000" },
        { date: "2017-12-22", price: "1060.1200" },
        { date: "2017-12-15", price: "1064.1900" },
        { date: "2017-12-08", price: "1037.0500" },
        { date: "2017-12-01", price: "1010.1700" },
        { date: "2017-11-24", price: "1040.6100" },
        { date: "2017-11-17", price: "1019.0900" },
        { date: "2017-11-10", price: "1028.0700" },
        { date: "2017-11-03", price: "1032.4800" },
        { date: "2017-10-27", price: "1019.2700" },
        { date: "2017-10-20", price: "988.2000" },
        { date: "2017-10-13", price: "989.6800" },
        { date: "2017-10-06", price: "978.8900" },
        { date: "2017-09-29", price: "959.1100" },
        { date: "2017-09-22", price: "928.5300" },
        { date: "2017-09-15", price: "920.2900" },
        { date: "2017-09-08", price: "926.5000" },
        { date: "2017-09-01", price: "937.3400" },
        { date: "2017-08-25", price: "915.8900" },
        { date: "2017-08-18", price: "910.6700" },
        { date: "2017-08-11", price: "914.3900" },
        { date: "2017-08-04", price: "927.9600" },
        { date: "2017-07-28", price: "941.5300" },
        { date: "2017-07-21", price: "972.9200" },
        { date: "2017-07-14", price: "955.9900" },
        { date: "2017-07-07", price: "918.5900" },
        { date: "2017-06-30", price: "908.7300" },
        { date: "2017-06-23", price: "965.5900" },
        { date: "2017-06-16", price: "939.7800" },
        { date: "2017-06-09", price: "949.8300" },
        { date: "2017-06-02", price: "975.6000" },
        { date: "2017-05-26", price: "971.4700" },
        { date: "2017-05-19", price: "934.0100" },
        { date: "2017-05-12", price: "932.2200" },
        { date: "2017-05-05", price: "927.1300" },
        { date: "2017-04-28", price: "905.9600" },
        { date: "2017-04-21", price: "843.1900" },
        { date: "2017-04-13", price: "823.5600" },
        { date: "2017-04-07", price: "824.6700" },
        { date: "2017-03-31", price: "829.5600" },
        { date: "2017-03-24", price: "814.4300" },
        { date: "2017-03-17", price: "852.1200" },
        { date: "2017-03-10", price: "843.2500" },
        { date: "2017-03-03", price: "829.0800" },
        { date: "2017-02-24", price: "828.6400" },
        { date: "2017-02-17", price: "828.0700" },
        { date: "2017-02-10", price: "813.6700" },
        { date: "2017-02-03", price: "801.4900" },
        { date: "2017-01-27", price: "823.3100" },
        { date: "2017-01-20", price: "805.0200" },
        { date: "2017-01-13", price: "807.8800" },
        { date: "2017-01-06", price: "806.1500" },
        { date: "2016-12-30", price: "771.8200" },
        { date: "2016-12-23", price: "789.9100" },
        { date: "2016-12-16", price: "790.8000" },
        { date: "2016-12-09", price: "789.2900" },
        { date: "2016-12-02", price: "750.5000" },
        { date: "2016-11-25", price: "761.6800" },
        { date: "2016-11-18", price: "760.5400" },
        { date: "2016-11-11", price: "754.0200" },
        { date: "2016-11-04", price: "762.0200" }
    ],
    id: "-LNgk1Gxv0RFmJbiYgnx",
    lastUpdated: "2018-09-28",
    name: "GOOG"
};

the problem with the code is the use of the scales and the parsing of the data.

  • best to do the parsing as soon as possible so you only have to do it once.
  • apply the x and y scales in the calculation of the line

     const valueline = d3.line() .x((d) => x(d.date)) .y((d) => y(d['GOOG'])); 

the whole code is (only the inner part because I used an HTML file to debug)

const smallestDataSetSize = d3.min(rawData.map((stock) => stock.closingValues.length));
const restrictingDataSet = rawData.filter((stock) => stock.closingValues.length === smallestDataSetSize)[0];
const parseTime = d3.timeParse('%Y-%m-%d');
let svgWidth = window.innerWidth;
let svgHeight = window.innerHeight - 75*2;
const margin = {top: 20, right: 40, bottom: 70, left: 40}
const width = svgWidth - margin.left - margin.right;
const height = svgHeight - margin.top - margin.bottom;
const x = d3.scaleTime().range([0, width]);
const y = d3.scaleLinear().range([height, 0]);
const xAxis = d3.axisBottom(x).ticks(10).tickFormat(d3.timeFormat('%b %d, %Y'));
const yAxis = d3.axisLeft(y).ticks(5);

// Get prelimiary data to set up chart
var stockMaximums = rawData.map((stock) => d3.max(stock.closingValues.map((d) => parseInt(d.price))));
var stockMax = d3.max(stockMaximums);

// Fromat data into a JSON format that can be used with D3
const data = { stocks: []};
for (let i = smallestDataSetSize - 1; i > -1; i--) {
  const date = restrictingDataSet.closingValues[i].date;
  data.stocks.push({
    'date': date
  });
  rawData.map((stock) => {
    const stockData = stock.closingValues.filter((stockData) => stockData.date === date);
    data.stocks[data.stocks.length - 1][stock.name] = parseFloat(stockData[0].price);
  });
}

data.stocks.forEach((d) => {
  d.date = parseTime(d.date);
  d['GOOG'] = +d['GOOG'];
});

// Draw the plot
let svg = d3.select(div).append('svg')
  .attr('width', svgWidth)
  .attr('height', svgHeight)
  .append('g')
  .attr('transform', `translate(${margin.left}, ${margin.top})`);

// x.domain(d3.extent(data.stocks, (d) => parseTime(d.date)));
x.domain(d3.extent(data.stocks, (d) => d.date));
y.domain([0, stockMax*11/10]);

svg.append('g')
  .attr('class', 'x axis')
  .attr('transform', `translate(0, ${height})`)
  .call(xAxis)
  .selectAll('text')
    .style('text-anchor', 'end')
    .attr('dx', '-1rem')
    .attr('dy', '-.2rem')
    .attr('transform', 'rotate(-65)');

svg.append('g')
  .attr('class', 'y axis')
  .call(yAxis);

// Just trying one line right now while debugging
const valueline = d3.line()
  .x((d) => x(d.date))
  .y((d) => y(d['GOOG']));

svg.append('path')
  .attr('class', 'line')
  .attr('d', valueline(data.stocks));

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