5

I am trying to figure out why my polygons are not changing color based on a value I have in my GeoJSON. I've set up a hypothetical test here to replicate my issue here.

JSFIDDLE link here

My data snippet looks like so:

"properties": {
  "Name": "Chahar Burjak",
  "Province": "Nimroz",
  "Ethnic1": 25,
  "Ethnic2": 12,
  "Ethnic3": 3,
  "Ethnic4": 1,
  "Ethnic5": 0,
  "Ethnic6": 0
},

I have two polygons on a map that are a default blue. I want to style the polygons based on whether a value ('Ethnic1') is higher than a number like so:

Note: For brevity, this is just for "Ethnic Group 1". In my real world map, I have over 13 ethnic groups I am modeling

function setEthnic1Color(d) {
        return d > 100  ? '#FC4E2A' :
               d > 50   ? '#FD8D3C' :
               d > 20   ? '#FEB24C' :
               d > 10   ? '#FED976' :
                  '#FFEDA0';
        }

Then, we define a styling function for our GeoJSON layer so that its fillColor depends on feature.properties.Ethnic1 property, also adjusting the appearance a bit and adding a nice touch with dashed stroke.

function Ethnic1Style(feature) {
  return {
  fillColor: setEthnic1Color(feature.properties.Ethnic1),
  weight: 2,
  opacity: 1,
  color: 'white',
  dashArray: '3',
  fillOpacity: 0.7
 };
}

Then, since we will have more than one ethnic group to style, I will use a switch statement to style it:

L.geoJson(myData, {
   style: function(feature) {
      switch (feature.properties) {
        case 'Ethnic1': return { style: Ethnic1Style }
        // ...and others
      }
   }
}).addTo(map);

As you can see in the fiddle, it doesn't style the polygons. What am I doing wrong?

  • Styling the features based only on the value of Ethnic1 should be easy enough, but for multiple ethnic groups, it's a little unclear what your expected output would look like. Each of your features has properties for multiple ethnic groups, Ethnic1 through Ethnic6. Are you intending to only display one ethnic group at a time? And if so, do you want to use a different color scale depending on which ethnic group is chosen, or do you want to use the same scale for all (i.e. a value of 30 will produce the color #FEB24C regardless of which ethnic group is being displayed)? – nathansnider Mar 2 '16 at 6:29
  • feature.properties is an object. It will never match any string of type 'Ethnic1' in your switch statement. – ghybs Mar 2 '16 at 8:45
  • @nathansnider - yes that's exactly it: I want to only display one ethnic group at a time and use a different color scale (gradient like population density color except in this case it is ethnic group density) depending on what ethnic group is chosen. I want to also use a radio button to toggle (not checkmarks) so people can't toggle on more than one group at a time. – redshift Mar 2 '16 at 11:19
  • @ghybs, perhaps I need to use a filter option in my L.GeoJson? – redshift Mar 2 '16 at 11:22
  • I forgot to mention that I am basically using the Choropleth tutorial on the leaflet site to try to do what I want to do leafletjs.com/examples/choropleth.html – redshift Mar 2 '16 at 11:22
5
+50

As said in the question comments, unfortunately you cannot use feature.properties as is in your switch statement, because it is an object.

You have to provide before hand a way for the user to indicate which "ethnic" to use, so that you can apply the corresponding styling function.

Since you say you want to use radio inputs, you could have for example in your HTML page:

<input type="radio" name="ethnic" id="Ethnic1" checked />
<label for="Ethnic1">Ethnic1</label>

<input type="radio" name="ethnic" id="Ethnic2" />
<label for="Ethnic2">Ethnic2</label>

Then use a default styling function for the initial display (here I use Ethnic1), and attach listeners on your radio inputs to change that styling function when the user clicks on the radios:

var myGeoJson = L.geoJson(myData, {
  style: Ethnic1Style
}).addTo(map);

// Radio buttons to let the user choose the ethnic to use for colors.
assignClickListener("Ethnic1", onRadioClick);
assignClickListener("Ethnic2", onRadioClick);

function assignClickListener(id, listener) {
  document.getElementById(id).addEventListener("click", listener);
}

function onRadioClick(event) {
  var target = event.currentTarget,
    selectedEthnic = target.id;

  switch (selectedEthnic) {
    case "Ethnic1":
      myGeoJson.setStyle(Ethnic1Style);
      break;
    case "Ethnic2":
      myGeoJson.setStyle(Ethnic2Style);
      break;
  };
}

Updated JSFiddle: https://jsfiddle.net/69nkmdyw/2/

Reference:

You could even get rid of the switch statement by creating a mapping object:

var stylesMapping = {
  "Ethnic1": Ethnic1Style,
  "Ethnic2": Ethnic2Style
};

function onRadioClick(event) {
  var target = event.currentTarget,
    selectedEthnic = target.id;

  myGeoJson.setStyle(stylesMapping[selectedEthnic]);
}

Demo: https://jsfiddle.net/69nkmdyw/3/

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.