Edit GeoJSON without QGIS native support

This article was inspired by the question below on Twitter from Nathaniel V. KELSO, the main guy behind "Natural Earth Data" ;) (Thanks for your work!)

We choose to demonstrate a way to make GeoJSON content editable possible via a workaround.

OGR/GDAL, the library used by QGIS to read geographic data, does not support GeoJSON update (a crowdfounding to pay someone to do could be a good idea IMO!)

The workflow most people uses: Save GeoJSON as shapefile, edit the shapefile, save edit, convert new shapefile to GeoJSON, then repeat for each edit. In simple case, they use GeoJSON.io website

One alternate and simpler way to manage this issue is to use "Memory provider" layer. We quote the Python QGIS cookbook to define it.

Memory provider is intended to be used mainly by plugin or 3rd party app developers. It does not store data on disk, allowing developers to use it as a fast backend for some temporary layers.

The big picture is to transfer content from GeoJSON to this type of layer, editable (contrary to GeoJSON), as a workaround.

We can copy the GeoJSON content to a Memory provider Layer with below code (go to Extension > Python console and copy/paste)

# Select the GeoJSON layer in the legend then get the current active layer
layer = qgis.utils.iface.activeLayer()

# Get info from the GeoJSON layer to reuse later
provider = layer.dataProvider()
fields = provider.fields()

# Specify layer type for editing GeoJSON content
# It can be "Point", "LineString", "Polygon", "MultiPoint",
# "MultiLineString", or "MultiPolygon". Forget about mixed geometries here
type_layer = 'Point'

# Create layer
vl = QgsVectorLayer("%s?crs=epsg:4326&index=yes" % type_layer, "temporary_points", "memory")
pr = vl.dataProvider()

# Prepare fields to copy fields from GeoJSON layer to "Memory provider" layer
new_fields = [QgsField(f.name(), f.type(), f.typeName(), f.length(), \
f.precision(), f.comment()) for f in fields]  # Python Comprehension list

# Copy attribute to the "Memory provider" layer
pr.addAttributes(new_field)

vl.updateFields()

pr.addFeatures([f for f in provider.getFeatures()])

# Update extent
vl.updateExtents()

# Add layer to current canvas
QgsMapLayerRegistry.instance().addMapLayer(vl)

To avoid to do this operation in the Python console each time for the same layer, you have to save your current project. Then, you can save the not so temporary "Memory provider" layer with extension "Memory plugin saver" in your current project and reopen it later. You can now edit the "Memory provider" layer with the "GeoJSON content as you wish and if you really want GeoJSON again, just do a "Save as" right clicking on the temporary layer legend to overwrite your GeoJSON layer.

The "save, edit" workflow is working like if you were using a shapefile in QGIS.

If you need remote editing, a possibility could be to create a button to update the file if a web service to update remote content was available.

Enjoy and feel free to make us a feedback here or via Twitter.

PS: As stated by Antonio Locandro, it could be also possible to code to adapt the sample plugin for editing CSV from "Faking a Data Provider with Python" for GeoJSON. We just didn't want to code here ;)

Commentaires