2

I'm trying to display a heatmap from some data in CSV format. I'm trying to get the data from the CSV file into a JavaScript variable, but I don't know how to do that.

I use the following Leaflet plugins:

<script src="http://cdn.leafletjs.com/leaflet-0.7.3/leaflet.js"></script>

<script src="heatmap.js"></script>

<script src="leaflet-heatmap.js"></script>

My code is below:

<script>

  window.onload = function() {

    var baseLayer = L.tileLayer(
      'http://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png',{
        attribution: 'Map data &copy; <a href="http://openstreetmap.org">OpenStreetMap</a> contributors, <a href="http://creativecommons.org/licenses/by-sa/2.0/">CC-BY-SA</a>, Imagery © <a href="http://cloudmade.com">CloudMade</a>',
        maxZoom: 18
      }
    );
    var testData = {
      max: 8,
      data: [
        {lat: 24.6408, lng:46.7728, count: 3},
        {lat: 50.75, lng:-1.55, count: 1},
        {lat: 52.6333, lng:1.75, count: 1}
      ]
    };
    var cfg = {
      "radius": 2,
      "maxOpacity": .8, 
      "scaleRadius": true, 
      "useLocalExtrema": true,
      latField: 'lat',
      lngField: 'lng',
      valueField: 'count'
    };
    var heatmapLayer = new HeatmapOverlay(cfg);
    var map = new L.Map('map', {
      center: new L.LatLng(25.6586, -80.3568),
      zoom: 4,
      layers: [baseLayer, heatmapLayer]
    });
    heatmapLayer.setData(testData);
    layer = heatmapLayer;
  };
</script>

The CSV file looks like this:

id;Código postal;Localidad;Valoracion;lat;lng
1;46100;Burjassot;8;39.51;-0.425055
2;18005;Granada;7;37.169266;-3.597161
IvanSanchez
  • 18,272
  • 3
  • 30
  • 45
Ruben Llorens
  • 31
  • 1
  • 4

3 Answers3

4

There are a lot of different approaches to the problem. What I'm going to describe is just one of them.


First off, I'm gonna use the latest available version of Leaflet:

<link rel="stylesheet" href="https://unpkg.com/leaflet@1.0.2/dist/leaflet.css" />
<script src="https://unpkg.com/leaflet@1.0.2/dist/leaflet.js"></script>

And just one heatmap plugin. There is no reason on earth why you should need two heatmap plugins at the same time.

<script src="https://unpkg.com/leaflet.heat@0.2.0/dist/leaflet-heat.js"></script>

Next off is reading the contents of a text file into a JS variable. There are several methods, but I'm particularly fond of the fetch API:

fetch('http://something/something/data.csv').then(function(response){
    return response.text();
}).then(function(text){
    // Handling of the text contents goes here
}).catch(function(err){
    // Error handling goes here (e.g. the network request failed, etc)
})

Split the text into lines...

var lines = text.split("\n");

...iterate through the lines, except the first one...

for (var i=1; i<lines.length; i++) {

...split the line into the comma-separated parts (in this case, semicolon-separated); I'm assuming a trivial CSV format (things can get a bit more complicated with some CSV files)...

var parts = lines[i].split(";");

...get the data you want to show on the heatmap, in a form that the heatmap plugin will like, keeping in mind that parts is a 0-indexed array...

var heatData = []
for(...){
   ...
   // heatData.push( lat, lng, weight )
   heatData.push( [ parts[4], parts[5], parts[3] ] )

...and once the loop over the lines is over and heatData is ready, init the heatmap:

var heat = L.heatLayer(heatData, {radius: 25}).addTo(map);

And put it all together:

    var map = new L.Map('map').fitWorld();

    var positron = L.tileLayer('http://{s}.basemaps.cartocdn.com/light_all/{z}/{x}/{y}.png', {
        attribution: '&copy; <a href="http://www.openstreetmap.org/copyright">OpenStreetMap</a> contributors, &copy; <a href="http://cartodb.com/attributions">CartoDB</a>'
    }).addTo(map);

    // I'll just ignore the network request and fake some data.

//    fetch('http://something/something/data.csv').then(function(response){
//        return response.text();
//    }).then(function(text){

          text = "id;Código postal;Localidad;Valoracion;lat;lng\n1;46100;Burjassot;8;39.51;-0.425055\n2;18005;Granada;7;37.169266;-3.597161";

          var lines = text.split("\n");
          var heatData = [];
          for (var i=1; i<lines.length; i++) {
            var parts = lines[i].split(";");
            heatData.push( [ parts[4], parts[5], parts[3] ] );
          }

          var heat = L.heatLayer(heatData, {radius: 25}).addTo(map);

//    }).catch(function(err){
//        // Error handling for the fetch goes here (e.g. the network request failed, etc)
//    })

See a working example here.


Please do not blindly copy-paste the code. Every time you copy-paste code, the stackoverflow gods kill a kitten and somebody cooks rice with peas and fish on it and calls it paella. Think on the kittens. And the paella.

Please note that I've split the problem is several, smaller problems:

  • Choose the right tools (leaflet version, heatmap implementation)
  • Read a text file (fetch/ajax/XHR/etc)
  • Parse the CSV (split lines from the file, and fields form the lines)
  • Create a data structure for the heatmap (loop, choose fields)

Depending on your specific scenario, you might have to modify any of these smaller problems.

IvanSanchez
  • 18,272
  • 3
  • 30
  • 45
  • Thanks Ivan, I understand that the code below is for pass the csv file from the web: fetch('http://something/something/data.csv').then(function(response){ return response.text(); }).then(function(text){ But it is necessary that I introduce all the lines of csv in the text? – Ruben Llorens Nov 22 '16 at 16:36
  • No. You should just use the fetch API, that will populate the `text` variable with the contents of the file. Copy-pasting the contents of the CSV in my code is just an example. – IvanSanchez Nov 22 '16 at 17:39
  • BTW, the `fetch(...)` code is not «for pass» the CSV file. That code *makes your browser fetch a remote resource*, in this case a csv file. There's a difference there. – IvanSanchez Nov 22 '16 at 17:40
  • HI, think you might have meant to say: of the kittens, vs on the kittens. But I could be wrong. :-) Great write up by the way. Awesome! – Edward Potter Apr 22 '20 at 15:47
0

Try this. In practice, you'll need an AJAX call to load your CSV file. In the success function, assign it to a variable (rather than using a textarea, as I have here, for illustration).

mapData = [];
CSV = $('#input').val();
var lines = CSV.split("\n");
var result = [];
var headers = lines[0].split(";");
for (var i = 1; i < lines.length; i++) {
  var obj = {};
  var nextline = lines[i].split(";");
  for (var j = 0; j < headers.length; j++) {
    obj[headers[j]] = nextline[j];
  }
  result.push(obj);
}
$.each(result, function(i, el) {
  lat = el.lat;
  lng = el.lng;
  newData = {
    lat: lat,
    lng: lng
  };
  mapData.push(newData);
});
console.log(mapData);
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<textarea id="input">
id;Código postal;Localidad;Valoracion;lat;lng
1;46100;Burjassot;8;39.51;-0.425055 
2;18005;Granada;7;37.169266;-3.597161</textarea>
sideroxylon
  • 4,338
  • 1
  • 22
  • 40
0

There are many ways to do it but I prefer to read CSV files using D3.js library. It may be useful where you can do more calculations on your data or maybe just read it!!

after installing d3:

<script src="https://d3js.org/d3.v4.js" charset="utf-8"></script>

then simply:

d3.csv(url, function(data) {
console.log(data)
})

url refer to your data source it may be something like this

url = 'http://something/something/data.csv'
Abdallah Ali
  • 69
  • 1
  • 6