While following along a tutorial on choropleth maps in Leaflet I realized that a Shapefile > GeoJSON conversion generated a very large file. TopoJSON proved a better alternative, except for being unable to access the properties for each geometry. I merged data from https://github.com/centraldedados/violencia-domestica into a TopoJSON file converted from a Shapefile, structured like so:
{
"transform": {
"scale": [
0.0025081552497290688,
0.0012125352320998587
],
"translate": [
-31.26818656921381,
30.03017616271984
]
},
"objects": {"PRT_adm1": {
"geometries": [
{
"type": "Polygon",
"arcs": [[
0,
1,
2,
3,
4
]],
"properties": {
"ENGTYPE_1": "District",
"ISO": "PRT",
"NL_NAME_1": null,
"HASC_1": "PT.EV",
"ID_0": 182,
"NAME_0": "Portugal",
"TYPE_1": "Distrito",
"ID_1": 1,
"NAME_1": "Évora",
"CCN_1": 0,
"CCA_1": null,
"dgai_violencia_domestica_2008_2014": {
"Valores": [
{
"Ano": "2009",
"Entidade": [
{"GNR": "216"},
{"PSP": "171"}
]
},
{
"Ano": "2010",
"Entidade": [
{"GNR": "247"},
{"PSP": "162"}
]
},
{
"Ano": "2011",
"Entidade": [
{"GNR": "248"},
{"PSP": "181"}
]
},
{
"Ano": "2012",
"Entidade": [
{"GNR": "277"},
{"PSP": "150"}
]
},
{
"Ano": "2013",
"Entidade": [
{"GNR": "207"},
{"PSP": "169"}
]
},
{
"Ano": "2014",
"Entidade": [
{"GNR": "226"},
{"PSP": "137"}
]
}
],
"Distrito": "Évora",
"Factor_amostra": 0.020521270111203194,
"Somatorio_amostra": 2391
},
"VARNAME_1": null
}
},
...
and would like to access the "dgai_violencia_domestica_2008_2014.Factor_amostra" property of each object, so as to encode a color value.
Is this possible with Leaflet+Omnivore, or would d3 or another library be needed?
A current, broken version of the map lives here, with the relevant code being:
L.mapbox.accessToken = '...';
var map = L.mapbox.map('map', 'mapbox.streets').setView([39.5, -8.60], 7);
// Omnivore will AJAX-request this file behind the scenes and parse it:
// note that there are considerations:
// - The file must either be on the same domain as the page that requests it,
// or both the server it is requested from and the user's browser must
// support CORS.
// Internally this function uses the TopoJSON library to decode the given file
// into GeoJSON.
function getColor(d) {
return d > 0.75 ? '#800026' :
d > 0.50 ? '#FC4E2A' :
d > 0.25 ? '#FD8D3C' :
'#FFEDA0';
}
var pt = omnivore.topojson('dgai_violencia_domestica_2008_2014.topo.json');
function style(geometry) {
return {
fillColor: getColor(geometry.properties.dgai_violencia_domestica_2008_2014.Peso_na_duracao_da_amostra),
weight: 1,
opacity: 1,
color: 'white',
dashArray: '3',
fillOpacity: 1
};
}
pt.setStyle(style);
pt.addTo(map);
A nudge in the right direction, anyone?
Thanks in advance.
Did some testing and as it turns out, the setStyle function won't execute:
pt.setStyle(function (feature) {
console.log('Yay, i am executed!');
return {
'color': 'red'
}
});
Using that Yay, i am executed!
never gets logged to the console. Which made me suspect that there's something wrong with the setStyle
method of Omnivore. So i tried it with a custom layer:
var geojson = new L.GeoJSON(null);
var pt = omnivore.topojson(url, null, geojson).addTo(map);
geojson.setStyle(function (feature) {
console.log('Yay, i am executed!');
return {
'color': 'red'
};
});
Same thing, Yay, i am executed!
never get logged to the console. One thing left to try was the style
option of L.GeoJSON
:
var geojson = new L.GeoJSON(null, {
'style': function (feature) {
console.log('Yay, i am executed!');
return {
'color': 'red'
};
}
});
var pt = omnivore.topojson(url, null, geojson).addTo(map);
And lo and behold, that does what it's supposed to do. So i tried it with your style and color function and dataset:
function getColor(d) {
return d > 0.75 ? '#800026' :
d > 0.50 ? '#FC4E2A' :
d > 0.25 ? '#FD8D3C' :
'#FFEDA0';
}
function getStyle (feature) {
return {
fillColor: getColor(feature.properties.dgai_violencia_domestica_2008_2014.Peso_na_duracao_da_amostra),
weight: 1,
opacity: 1,
color: 'white',
dashArray: '3',
fillOpacity: 1
};
}
var geojson = new L.GeoJSON(null, {
'style': getStyle
});
var pt = omnivore.topojson(url, null, geojson).addTo(map);
This gives me the following error:
Uncaught TypeError: Cannot read property 'Peso_na_duracao_da_amostra' of undefined
That's because on the third feature, that property is missing. So your dataset is corrupt or incomplete. Hopefully this will help you along, good luck, here's a Plunker of my experiment which works (so far):