最新消息:雨落星辰是一个专注网站SEO优化、网站SEO诊断、搜索引擎研究、网络营销推广、网站策划运营及站长类的自媒体原创博客

javascript - Dynamic loading data using d3.csv in D3 v5 - Stack Overflow

programmeradmin3浏览0评论

I'm trying to build a dynamically loading bar chart in d3.js which will load data from back-end in parts. Using the d3.csv() function, is there any way to read only first n number of rows from a data for initial draw and then load subsequent data as per my JS logic?

tl;dr I want to selectively access my data inside the d3.csv() function.

I'm trying to run the below code for this :

var margin = {
            top: 20,
            bottom: 30,
            left: 40,
            right: 30
        },
        width = 600 - margin.left - margin.right,
        height = 500 - margin.top - margin.bottom;

    var loadData = function() {
        d3.csv("test_data.csv", function(data) {
            console.log(data.filter(function(d, i) {
                return i < 2;
            }));

            console.log(data.filter(function(d, i) {
                return i < 3;
            }))
        })
    }

    loadData();

However, I'm getting an error in the console:

Uncaught (in promise) TypeError: data.filter is not a function(…)

Which leads me to believe that this data is not an array. Is this the case or am i facing some other issue here?

Also, how do I access columns (inside csv file) inside this d3.csv function? (if for example, my csv data file contains two columns named a and b).

I'm trying to build a dynamically loading bar chart in d3.js which will load data from back-end in parts. Using the d3.csv() function, is there any way to read only first n number of rows from a data for initial draw and then load subsequent data as per my JS logic?

tl;dr I want to selectively access my data inside the d3.csv() function.

I'm trying to run the below code for this :

var margin = {
            top: 20,
            bottom: 30,
            left: 40,
            right: 30
        },
        width = 600 - margin.left - margin.right,
        height = 500 - margin.top - margin.bottom;

    var loadData = function() {
        d3.csv("test_data.csv", function(data) {
            console.log(data.filter(function(d, i) {
                return i < 2;
            }));

            console.log(data.filter(function(d, i) {
                return i < 3;
            }))
        })
    }

    loadData();

However, I'm getting an error in the console:

Uncaught (in promise) TypeError: data.filter is not a function(…)

Which leads me to believe that this data is not an array. Is this the case or am i facing some other issue here?

Also, how do I access columns (inside csv file) inside this d3.csv function? (if for example, my csv data file contains two columns named a and b).

Share Improve this question edited Apr 20, 2018 at 13:42 Gerardo Furtado 102k9 gold badges128 silver badges176 bronze badges asked Apr 20, 2018 at 12:25 D_S_XD_S_X 1,5697 gold badges18 silver badges38 bronze badges
Add a ment  | 

2 Answers 2

Reset to default 8

First, there is no way to load/parse just the first n rows of a CSV with d3.csv, I'm afraid that's not possible. Unfortunately you'll have to load/parse all the file, which may be inconvenient if the file is huge, meaning that the user will have to wait for the whole file to be loaded/parsed before the chart is painted. Also, it's worth mentioning that since d3.csv will load all the file the subsequent filter irrelevant: just use the rows of data you want, don't add even more unnecessary tasks to the browser, just use the rows you want for painting the chart.

Back to your main question:

Your data is an array. The problem here is just that you're using d3.csv as if it was a XHR, which was the case of D3 v4... However, in D3 v5, d3.csv is a promise.

So, it has to be:

d3.csv(url).then(callback);

Have a look at the demo below:

var csv = URL.createObjectURL(new Blob([
  `foo,bar,baz
12,43,21
45,54,21
87,13,17
98,69,17`
]));

d3.csv(csv).then(function(data) {
  console.log(data.filter(function(d, i) {
    return i < 2;
  }));
})
<script src="https://d3js/d3.v5.min.js"></script>

Regarding your second question, d3.csv exposes the columns in an array property named columns:

var csv = URL.createObjectURL(new Blob([
  `foo,bar,baz
12,43,21
45,54,21
87,13,17
98,69,17`
]));

d3.csv(csv).then(function(data) {
  console.log("columns are: " + data.columns)
})
<script src="https://d3js/d3.v5.min.js"></script>

One thing to add to Gerardo Furtado's answer: your example is structured like this:

d3.csv('some_file.csv', someFunction)

In d3.csv V5, if a function is passed as an argument like this here, it gets called once for each row, passed an object representing that row, its index, and an array of column keys, allowing the rows to be altered. So, the specific error is because the first arg in this callback is an object representing a row, not an array representing the data set.

Then, when they're all done, the promise is plete and a callback provided with .then(someFunction) is fired.

d3.csv('some_file.csv', transformRow).then(processData)

A transformRow function is optional; if one is provided, then whatever it returns for each row replaces that row in the data.

The processData callback then gets an array of rows, with a property columns which is an array of the original column names (so if transformRow returns an object with different property keys, the data.columns won't match the properties of each row).

So for example:

    var csv = URL.createObjectURL(new Blob([
     `name,start,end
      SOMETHING,123,321
      INVALID,321,123
      ANOTHER,111,333`
    ]));

    d3.csv(csv, processRow).then(processData)
    
    function processRow (row, index, columnKeys) {
      row[columnKeys[0]] = row[columnKeys[0]].trim().toLowerCase()
      row.duration = row.end - row.start // this new property doesn't change data.columns
      if (row.end > row.start) return row
    }
    
    function processData (data) {
      console.log(data, data.columns)
    }
<script src="https://d3js/d3.v5.min.js"></script>

发布评论

评论列表(0)

  1. 暂无评论