【问题标题】:Rendering D3 data from CSV从 CSV 渲染 D3 数据
【发布时间】:2018-09-15 18:03:36
【问题描述】:

这更像是对代码审查的请求,但我这辈子都无法让这个 .csv 数据在 D3 中正确呈现为折线图...

下面是我写的代码。

到目前为止,我只能渲染 y 轴和轴标题,但我似乎无法渲染数据。也许我做错了什么,但根本看不到。

非常感谢您的帮助和建议。

JavaScript 文件

// ./weather-app/d3/testing-dsky-d3.js
const fname_forecast =  'forecast-hourly-temp.csv';
const path2File = './csv/';

const parseDateTime = d3.timeParse('%Y-%m-%d %H:%M:%S');

d3.csv(path2File + fname_forecast)
  .row((data) => {
    return {
      date: parseDateTime(data.datetime),
      temp: +data.temperature
    }
  })
  .get((err, data) => {
    if (err) {
      console.log('\nErrors!\n', err)
    } else {
      console.log(data);

      const minDate = d3.min(data, (d) => { return d.date; });
      const maxDate = d3.max(data, (d) => { return d.date; });

      const minTemp = d3.min(data, (d) => { return d.temp; });
      const maxTemp = d3.max(data, (d) => { return d.temp; });

      const svg = d3.select('svg'),
            margin = { top: 20, right: 20, bottom: 30, left: 50 },
            width = +svg.attr('width') - margin.left - margin.right,
            height = +svg.attr('height') - margin.top - margin.bottom,
            g = svg.append('g')
                      .attr('transform', 'translate(' + margin.left +   ',' + margin.top + ')');

      const x = d3.scaleTime()
                  .rangeRound([minDate, maxDate])
                  .domain([minDate, maxDate]);
      const y = d3.scaleLinear()
                  .rangeRound([height, 0])
                  .domain([height, 0])

      const line = d3.line()
                     .x((d) => { return x(d.date); })
                     .y((d) => { return y(d.temp); });

      g.append('g')
          .attr('transform', 'translate(0,' + height + ')')
          .call(d3.axisBottom(x))
        .select('.domain')
          .remove();

      g.append('g')
          .call(d3.axisLeft(y))
        .append('text')
          .attr('fill', '#000')
          .attr('transform', 'rotate(-90)')
          .attr('y', 6)
          .attr('dy', '0.71em')
          .attr('text-anchor', 'end')
          .text('Temperature (degC)');

      g.append('path')
          .datum(data)
          .attr('fill', 'none')
          .attr('stroke', 'steelblue')
          .attr('stroke-linejoin', 'round')
          .attr('stroke-linecap', 'round')
          .attr('stroke-width', 1.5)
          .attr('d', line);

       }
     });

HTML 文件:

<!DOCTYPE html>
<html>


<head>
  <meta charset='utf-8'>
  <title>Test: Rendering DarkSky Data w/ D3</title>
  <script type='text/javascript' src='./learn/d3.v4.js'></script>
</head>

<body>

  <h1>Test: Rendering DarkSky API Temperature Data w/   <code>D3.js</code></h1>
  <hr><br>
  <div id='container'>
    <svg width='960' height='500'></svg>
  </div>
  <script type='text/javascript' src='testing-dsky-d3.js'></script>

</body>

然后是一些示例.csv 文件

datetime,temperature

2018-04-04 12:00:00,46.98

2018-04-04 13:00:00,48.43

2018-04-04 14:00:00,49.63

2018-04-04 15:00:00,49.85

2018-04-04 16:00:00,48.98

2018-04-04 17:00:00,47.95

2018-04-04 18:00:00,47.35

2018-04-04 19:00:00,47.08

2018-04-04 20:00:00,46.79

2018-04-04 21:00:00,46.62

【问题讨论】:

  • 嗨,你能把它改造成fiddle
  • jsfiddle.net 是否支持 D3,是否可以加载外部 csv 文件?

标签: javascript html csv d3.js


【解决方案1】:

您需要正确设置秤的域和范围,

这里:

 const x = d3.scaleTime()
    .rangeRound([minDate, maxDate])
    .domain([minDate, maxDate]);

您正在设置一个比例,以获取从 minDate 到 maxDate(域)的值,并将它们映射到从 minDate 到 maxDate(范围)的值。你需要修改这个:

 const x = d3.scaleTime()
    .rangeRound([0,width])       // values to map to (x coordinate values)
    .domain([minDate, maxDate]); // extent of input values/values needing scaling

y 轴也一样:

  const y = d3.scaleLinear()
              .rangeRound([height, 0])
              .domain([height, 0])

您需要区分您的范围和域。上面的比例只是取一个介于 0 和 height 之间的值并返回相同的值。


要修复您的图表,您需要正确设置:

  • 域到数据集中输入值的范围(温度、日期等)
  • 输出值的范围,通常是 x 或 y(或颜色、半径等)的坐标值。

像这样应用这些更改(我将 [40,50] 的域硬编码为温度):

  const x = d3.scaleTime()
              .rangeRound([0,width])
              .domain([minDate, maxDate]);
  const y = d3.scaleLinear()
              .domain([40, 50])
              .rangeRound([height, 0])

否则使用您的代码和数据,我得到:

【讨论】:

  • 太棒了!感谢您的提示和建议!我会玩弄代码。 :)
  • 好的!我已经更改了代码并得到了一个静态 HTML 页面,
  • 一切正常吗?
  • 确实如此!非常感谢!我阅读了您的建议并参考了 M.Bostock 中的一个示例,并在
  • 这是我的新问题的链接:stackoverflow.com/questions/49682823/…
猜你喜欢
  • 2021-06-11
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2022-12-01
  • 2017-08-11
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多