coder1
coder1

Reputation: 65

How to display the value (sum) rather than count of markers in a dc.leaflet.js

I want to use crossfilter's reduceSum function dc.leaflet.js, and display the sum instead of the number of clustered markers.

The first example for dc.leaflet.js uses reduceCount. Additionally it doesn't use the reduced value; it just displays the number of markers in the cluster.

I want to use the sum of data using reduceSum.

Here is my data as tsv:

type geo say
wind 38.45330,28.55529 10
wind 38.45330,28.55529 10
solar 39.45330,28.55529 10

Here is my code:

<script type="text/javascript" src="../js/d3.js"></script>
<script type="text/javascript" src="../js/crossfilter.js"></script>
<script type="text/javascript" src="../js/dc.js"></script>
<script type="text/javascript" src="../js/leaflet.js"></script>
<script type="text/javascript" src="../js/leaflet.markercluster.js"></script>
<script type="text/javascript" src="../js/dc.leaflet.js"></script>


<script type="text/javascript">
    /*     Markers      */

d3.csv("demo1.csv", function(data) {
  drawMarkerSelect(data);
});

function drawMarkerSelect(data) {
  var xf = crossfilter(data);

    var facilities = xf.dimension(function(d) { return d.geo; });
    var facilitiesGroup = facilities.group().reduceSum(function(d){return d.say});

  dc.leafletMarkerChart("#demo1 .map")
      .dimension(facilities)
      .group(facilitiesGroup)
      .width(1100)
        .height(600)
      .center([39,36])
      .zoom(6)
      .cluster(true);  

    var types = xf.dimension(function(d) { return d.type; });
    var typesGroup = types.group().reduceSum(function(d){return d.say});    


  dc.pieChart("#demo1 .pie")
      .dimension(types)
      .group(typesGroup)
      .width(200) 
        .height(200)
        .renderLabel(true)
        .renderTitle(true)
      .ordering(function (p) {
        return -p.value;
      });

    dc.renderAll();
} 



</script>

Upvotes: 2

Views: 1502

Answers (2)

Gordon
Gordon

Reputation: 20120

I have rewritten the question because it was very unclear. I agree with @Kees that the intention was probably to display the sum in a clustered marker chart, rather than "reduceSum doesn't work".

@Kees also pointed out a Leaflet.markercluster issue which gives basic information about how to display a sum inside a marker cluster.

The question becomes, how to apply these customizations to dc.leaflet.js?

First, I've created a version of the example data with another column rnd:

type    geo rnd
wind    43.45330,28.55529   1.97191
wind    43.44930,28.54611   3.9155
wind    43.45740,28.54814   3.9922
...

We can use reduceSum like this:

  var facilitiesGroup = facilities.group().reduceSum(d => +d.rnd);

And annotate each marker with its value by overriding .marker(), wrapping the default callback:

  const old_marker_function = marker.marker();
  marker.marker(function(d, map) {
    const m = old_marker_function(d, map);
            m.value = d.value;
    return m;
  });

And we can specify a different rendering of the icon using .clusterOptions():

  marker.clusterOptions({
    iconCreateFunction: function(cluster) {
      var children = cluster.getAllChildMarkers();
        var sum = 0;
        for (var i = 0; i < children.length; i++) {
        sum += children[i].value;
      }
      sum = sum.toFixed(0);
      var c = ' marker-cluster-';
      if (sum < 10) {
        c += 'small';
      } else if (sum < 100) {
        c += 'medium';
      } else {
        c += 'large';
      }
      return new L.DivIcon({ html: '<div><span>' + sum + '</span></div>', className: 'marker-cluster' + c, iconSize: new L.Point(40, 40) });
    }
  });

The example given in the above issue was missing any styling, so I copied the implementation of _defaultIconCreateFunction from the Leaflet.markercluster sources, and modified it.

number clusters Demo fiddle

As expected, the numbers are close to 2.5 times the original numbers (since the new column is a random number from 0 to 5).

Putting numbers on the individual markers

marker.icon() allows you change the icon for individual markers, so you can use DivIcon with similar styling to display the numbers:

  marker.icon(function(d, map) {
    return new L.DivIcon({
      html: '<div><span>' + d.value.toFixed(0) + '</span></div>',
      className: 'marker-cluster-indiv marker-cluster',
      iconSize: new L.Point(40, 40) });
  });

This introduces a new class .marker-cluster-indiv to distinguish it from the others; in the new fiddle I've colored them blue with

.marker-cluster-indiv {
    background-color: #9ecae1;
}
.marker-cluster-indiv div {
    background-color: #6baed6;
}

with blue individuals

The interaction is perhaps less clear since clicking blue dots brings up a popup instead of expanding. Perhaps a different icon should be used.

Upvotes: 2

Gordon
Gordon

Reputation: 20120

The reduceSum part should work fine, since that is just a different crossfilter function.

Are you sure that your data is getting read correctly? You state that it is a tsv file, and show code that looks like it is tab-separated, but then you use d3.csv to load it, which would have pretty bad effects considering there is a comma in the middle of the second field.

Please try console.log(data) after your data is loaded, and verify that it is loading correctly.

Also, you do not state what problem you encounter. "It doesn't work" does not help us help you.

Upvotes: 0

Related Questions