8

I'm new to d3.js so I know this might seem as a silly question to some so please bear with me. I'm trying to parse a csv file which a user uploads and print it's output in the console. I'm able to parse the CSV file when I provide the absolute path of the CSV file but when I try doing the same with file upload functionality I'm not getting any output in the console..

Working Javascript Code..

    var dataset = [];
    d3.csv("sample.csv", function(data) {
    dataset = data.map(function(d) { return [ d["Title"], d["Category"], d["ASIN/ISBN"], d["Item Total"] ]; });
    console.log(dataset[0]);
    console.log(dataset.length);
    }); 

Console Output...

["Men's Brooks Ghost 8 Running Shoe Black/High Risk Red/Silver Size 11.5 M US", "Shoes", "B00QH1KYV6", "$120.00 "]
 8

New HTML code..

    <input type="file" id="csvfile" name="uploadCSV"/>
    <br/>
    <button onclick="howdy()">submit</button>

Modified Javascript Code(not working)..

    var myfile = $("#csvfile").prop('files')[0];
    var reader = new FileReader();

    reader.onload = function(e) {
    var text = reader.result;
    }

    reader.readAsDataURL(myfile);

     var dataset = [];
    d3.csv(reader.result , function(data) {
    dataset = data.map(function(d) { return [ d["Title"], d["Category"], d["ASIN/ISBN"], d["Item Total"] ]; });
    console.log(dataset[0]);
    console.log(dataset.length);
    })

Since there was no official documentation on how to handle user uploaded CSV file I can't figure out where I'm going wrong..Is there a way I can use HTML5 file reader?? Please help..

5
  • The problem is that this line $("#csvfile")[0].files does not give you the content of the file. You need to upload your file to your server first, and return a URL of the uploaded file. You then need to update your client side code(javascript) to use the uploaded file URL and not just the content of the file upload input Commented Mar 18, 2016 at 8:26
  • Can't we use the HTML5 File Reader API to do that?? Commented Mar 18, 2016 at 8:44
  • Yes you can use the html5 Fie Reader API Commented Mar 18, 2016 at 8:48
  • I edited my code above to use file reader to get a url but still I'm not getting any output in the console. Could you please look at my edited code above and tell me where I'm going wrong? Commented Mar 18, 2016 at 10:28
  • please see developer.mozilla.org/en-US/docs/Web/API/FileReader/… you need to access the data in the onload callback. You set the text variable but you never used it. You might have to call the d3.csv() inside the callback when the content of the file is available. Commented Mar 18, 2016 at 10:38

3 Answers 3

9

You are close but you don't need to and can't call d3.csv on a reader.result. d3.csv makes an async AJAX call to retrieve a CSV file from a server. You already have the file contents and just want to parse, so use d3.csv.parse.

Full working example:

<!DOCTYPE html>
<html>

<head>
  <script data-require="[email protected]" data-semver="3.5.3" src="//cdnjs.cloudflare.com/ajax/libs/d3/3.5.3/d3.js"></script>
</head>

<body>
  <input type="file" onchange="loadFile()" />

  <script>
    var reader = new FileReader();  
    
    function loadFile() {      
      var file = document.querySelector('input[type=file]').files[0];      
      reader.addEventListener("load", parseFile, false);
      if (file) {
        reader.readAsText(file);
      }      
    }
    
    function parseFile(){
      var doesColumnExist = false;
      var data = d3.csv.parse(reader.result, function(d){
        doesColumnExist = d.hasOwnProperty("someColumn");
        return d;   
      });
      console.log(doesColumnExist);
    }
  </script>
</body>

</html>

Sign up to request clarification or add additional context in comments.

1 Comment

Is there a way to check whether a certain columns exist in CSV file inside parseFile() function??
1

This is for d3-csv@3

<!-- https://www.jsdelivr.com/package/npm/d3-dsv -->
<script src="https://cdn.jsdelivr.net/npm/[email protected]/dist/d3-dsv.min.js" integrity="sha256-IrzYc2a3nTkfvgAyowm/WKmIGdVCMCcccPtz+Y2y6VI=" crossorigin="anonymous"></script>
<input type="file" accept=".csv">
<button>test button</button>

<script>
const testData = `owner,repo,"branch name"
foo,demo,master
boo,"js awesome",sha1123456
`
document.querySelector(`input`).onchange = async e => {
  const input = e.target
  const file = input.files[0]
  const reader = new FileReader()
  reader.readAsText(new Blob(
    [file],
    {"type": file.type}
  ))
  const fileContent = await new Promise(resolve => {
    reader.onloadend = (event) => {
      resolve(event.target.result)
    }
  })
  const csvData = d3.csvParse(fileContent)
  console.log(csvData)
}

document.querySelector(`button`).onclick = e => {
  const csvData =  d3.csvParse(testData)
  console.log(csvData)
}
</script>


The below link may help you know the implementation of csvParse


If you just load the CSV only then do not import the whole JS. (instead of the d3-csv.js)

https://cdn.jsdelivr.net/npm/[email protected]/dist/d3.min.js

https://cdn.jsdelivr.net/npm/[email protected]/dist/d3-dsv.min.js

Comments

0

This is an old question and I think we have to clarify some points.

  1. How to load a local csv file
  2. How to link the loaded file with D3

1. Load a file is very simple just check this example:

const fileInput = document.getElementById('csv')
const readFile = e => {
  const reader = new FileReader()
  reader.onload = () => {
    document.getElementById('out').textContent = reader.result
  }
  reader.readAsBinaryString(fileInput.files[0])
}

fileInput.onchange = readFile
<div>
  <p>Select local CSV File:</p>
  <input id="csv" type="file" accept=".csv">
</div>
<pre id="out"><p>File contents will appear here</p></pre>

Here we have a simple input element with type="file" attribute, this lets us to pick a csv file. Then the readFile() function will be triggered whenever a file is selected and will call the onload function after reading the file as a binary string.

2. I recommend to use readAsDataURL() to integrate it with d3 like this:

const fileInput = document.getElementById('csv')
const previewCSVData = async dataurl => {
  const d = await d3.csv(dataurl)
  console.log(d)
}

const readFile = e => {
  const file = fileInput.files[0]
  const reader = new FileReader()
  reader.onload = () => {
    const dataUrl = reader.result;
    previewCSVData(dataUrl)
  }
  reader.readAsDataURL(file)
}

fileInput.onchange = readFile
<script src="https://cdnjs.cloudflare.com/ajax/libs/d3/5.7.0/d3.min.js"></script>
<div>
  <p>Select local CSV File:</p>
  <input id="csv" type="file" accept=".csv">
</div>
<pre id="out"><p>File contents will appear here</p></pre>

To integrate the loaded file we call previewCSVData() and pass the file then we parse it using d3.csv() method. Also lets use await because it is an asynchronous call.

Note:

d3.csv internally uses fetch and works for any type of URL, (httpURL, dataURL, blobURL, etc...)

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.