node-mapnik
node-mapnik copied to clipboard
Features in FeatureSet lose their original ids
If I have a GeoJSON Feature with an id property, feed it into a Datasource, then read Mapnik Features out of that Datasource as JSON, that original id has been overwritten by an incrementing number that Mapnik adds to all the Features — so that information is lost.
I'm guessing Mapnik internally relies on this incrementing number as a unique id. I wonder, though, if there's a way to do this that doesn't overwrite the original information. Also, for my particular use-case I'd be better off if Mapnik didn't add any information that wasn't in the original Feature — I wonder if it would be possible to generate a unique id, used internally, that does not show up in output.
If a key exists inside the Feature.properties object named id Mapnik respects it and round-trips it correctly.
If a property named id exists at Feature.id then Mapnik ignores this, like it ingores all other properties that are not one of ["type", "geometry", "properties"]. Mapnik does this for both its geojson plugin (its internal, highly optimized GeoJSON datasource) and its OGR support. This is because Mapnik proposes globally unique ids after https://github.com/mapnik/mapnik/issues/753 and does the hard work to make this possible across the various formats it supports. We intentially ignore the Feature.id property of the JSON because it might not exist in all GeoJSON and when it does exist you cannot be guaranteed that it is a globally unique id.
I'm guessing Mapnik internally relies on this incrementing number as a unique id.
Correct, per above.
I wonder, though, if there's a way to do this that doesn't overwrite the original information.
Per above it is ignored not overwritten.
Also, for my particular use-case I'd be better off if Mapnik didn't add any information that wasn't in the original Feature — I wonder if it would be possible to generate a unique id, used internally, that does not show up in output.
The only thing Mapnik does is create a globally unique id and offers it in the output GeoJSON. To workaround this and use your own id you could put it in the properties and pull it from there?
@davidtheclark btw, you can play around with the Mapnik behavior with a script like:
var mapnik = require('mapnik');
var expected = {
type: "Feature",
id: "will be ignored",
properties: {id:2},
geometry: {
type: 'Polygon',
coordinates: [[[1,1],[2,1],[2,2],[1,2],[1,1]]]
}
};
var f = new mapnik.Feature.fromJSON(JSON.stringify(expected));
console.log(f.toJSON());
That outputs:
{"type":"Feature","id":1,"geometry":{"type":"Polygon","coordinates":[[[1,1],[2,1],[2,2],[1,2],[1,1]]]},"properties":{"id":2}}
If a key exists inside the Feature.properties object named id Mapnik respects it and round-trips it correctly.
We intentially ignore the Feature.id property of the JSON because it might not exist in all GeoJSON and when it does exist you cannot be guaranteed that it is a globally unique id.
That's the wrong reason. Feature.properties.id cannot be guaranteed to be unique, either. The correct reason is: because Feature.id can be a string ^^
Wouldn't it be better to name the generated Feature.mapnik_id so that it's obvious where it's coming from?
@springmeyer I've come across an issue related to this.
I want to use the new mapbox 'setFeatureState' function (https://www.mapbox.com/mapbox-gl-js/api/#map#setfeaturestate). This relies on the feature ID to change the state of an individual feature.
Because mapnik creates it's own IDs, it can be difficult to identify particular features. Also, because the ID's are only unique for each tile, I find that different features in the same layer can have the same ID in different tiles. This makes it pretty much impossible to use with mapnik generated tiles.
Could there be an option to use the passed in feature ID? Mine are created as unique constraints on a database so I know they are always unique.
@springmeyer I am in the same boat as @joedjc. I am very keen to use setFeatureState with my mapnik/postgis tiles. I would ask that such an option be provided so a unique constraint table field can come to use to deterministically id the features.
EDIT: this looks promising though.
EDIT-2: I tested key_field and it works great for mapnik's postgis datasource. As long as key_field is set to a value, which either the table / query's returned columns contain, the generated tiles have the correct featureId set, and I was successfully able to use feature-state api of mapbox-gl-js.
As another workaround to the problem @joedjc mentions, Tippecanoe preserves IDs on features in a GeoJSON into their .mbtiles files. Those IDs are also preserved through upload to Mapbox, as suggested in this issue.
We are facing the same problem as @charandas.
When using the feature-state with mapbox-gl-js with vector tiles produced with node-mapnik, features ids in tiles are unique by tile instead of by layer. We use the feature state for selection purpose, and the ids unique by tile cause feature selection collision.
When using the postgis plugin key_field parameter, the issue is solved.
But, with the OGR datasource, we don't have a such parameter. I've tried to set a _id_ parameter, but it doesn't work for vector tiles (maybe it's only for Grid).
I would like a a key_field parameter for all datasource types including OGR datasource.