MapStore is an Open Source highly modular web gis framework developed by GeoSolutions to create, manage and share securely in a simple and intuitive way maps created by mixing geospatial contents served from servers like Google Maps, OpenStreetMap, Bing or from server adhering to OGC standards like WFS, CSW, WMS and WMTS.

Although it is possible to make layers editable within MapStore, the annotation functionality is a much more accessible functionality to sketch on a map and save the results of these sketches. The annotations provide a simple, yet powerful tool that can be very useful e.g.. in data reviewing or stakeholder engagement sessions.

Annotations in MapStore

However, if one wants to use the annotations in another context (spatial analysis in a desktop GIS, show in other web maps, etc.), things become more difficult. The annotations can be downloaded as a .json file, however this is a custom json format which can only be imported in MapStore itself.

Download MapStore Annotations

A while ago I had already created some functionality to load these annotations into QGIS and when a posts was made onto the MapStore developers mailinglist, I decided to share this efforts1.

The complete workflow should be as simple as:

  1. Download MapStore annotation file
  2. Copy-paste the Python code below into a text editor
  3. Change the input file path in the Python code
  4. Open QGIS and open the Python console (Plugins Python Console )
  5. Copy-paste the modified Python code into the QGIS Python console
  6. Notice the annotations showing up as a group layer.

Annotations in QGIS

Python code:

# !/usr/bin/env python
# -*- coding: utf-8 -*-

import json

from PyQt5.QtGui import QColor, QFont

from qgis.core import QgsPalLayerSettings, QgsTextFormat
from qgis.core import QgsTextBufferSettings, QgsVectorLayerSimpleLabeling

# Replace with the path to the downloaded .json file with annotations
input_file_path = unicode(r"C:\Users\NL01031\Downloads\Sample Map.json")

def turnOnLabels(layer, expression):
    layer_settings = QgsPalLayerSettings()
    text_format = QgsTextFormat()

    text_format.setFont(QFont("Arial", 10))
    text_format.setSize(10)

    buffer_settings = QgsTextBufferSettings()
    buffer_settings.setEnabled(True)
    buffer_settings.setSize(0.10)
    buffer_settings.setColor(QColor("black"))

    text_format.setBuffer(buffer_settings)
    layer_settings.setFormat(text_format)

    layer_settings.fieldName = expression
    layer_settings.isExpression = True
    layer_settings.placement = 4

    layer_settings.enabled = True

    layer_settings = QgsVectorLayerSimpleLabeling(layer_settings)
    layer.setLabelsEnabled(True)
    layer.setLabeling(layer_settings)
    layer.triggerRepaint()

groupName ="Annotations"
project = QgsProject.instance()
root = project.layerTreeRoot()
group = root.addGroup(groupName)
lineLayer = QgsVectorLayer("linestring?crs=epsg:4326&field=id:string(36)&field=title:string&field=description:string&index=yes", "PolyLines", "memory")
project.addMapLayer(lineLayer, False)
group.addLayer(lineLayer)
pointLayer = QgsVectorLayer("point?crs=epsg:4326&field=id:string(36)&field=title:string&field=description:string&field=textvalue:string&&index=yes", "Points", "memory")
project.addMapLayer(pointLayer, False)
group.addLayer(pointLayer)
polygonLayer = QgsVectorLayer("polygon?crs=epsg:4326&field=id:string(36)&field=title:string&field=description:string&index=yes", "Polygons", "memory")
project.addMapLayer(polygonLayer, False)
group.addLayer(polygonLayer)

annotationFile = open(input_file_path)
annotations = json.loads(annotationFile.read())
features = annotations['features']
for feature in features:
    attributeId = feature['properties']['id']
    attributeTitle = feature['properties']['title']
    try:
        attributeDescription = feature['properties']['description']
    except KeyError:
        attributeDescription = None
    
    subParts = feature['features']
    for subPart in subParts:
        featureType = subPart['geometry']['type']
        if featureType == 'LineString':
            vertices = []
            for coord in subPart['geometry']['coordinates']:
                vertex = QgsPoint(coord[0], coord[1])
                vertices.append(vertex)
            geom = QgsGeometry.fromPolyline(vertices)
            feat = QgsFeature(lineLayer.fields())
        elif featureType == 'Point':
            coord = subPart['geometry']['coordinates']
            pointXY = QgsPointXY(coord[0], coord[1]) 
            geom = QgsGeometry.fromPointXY(pointXY)
            feat = QgsFeature(pointLayer.fields())
            try:
                attributeTextValue = subPart['properties']['valueText']
            except KeyError:
                attributeTextValue = ''
            feat.setAttribute('textvalue', attributeTextValue)
        elif featureType == 'Polygon':
            vertices = []
            for coord in subPart['geometry']['coordinates'][0]:
                vertex = QgsPointXY(coord[0], coord[1])
                vertices.append(vertex)
            geom = QgsGeometry.fromPolygonXY([vertices])
            geom.addRing(vertices)
            feat = QgsFeature(polygonLayer.fields())
    
        feat.setGeometry(geom)
        feat.setAttribute('id', attributeId)
        feat.setAttribute('title', attributeTitle)
        feat.setAttribute('description', attributeDescription)
        if featureType == 'LineString':
            (res, outFeats) = lineLayer.dataProvider().addFeatures([feat])
        elif featureType == 'Point':
            (res, outFeats) = pointLayer.dataProvider().addFeatures([feat])
        elif featureType == 'Polygon':
            (res, outFeats) = polygonLayer.dataProvider().addFeatures([feat])


turnOnLabels(pointLayer, '"title" ||  \' - \'  ||  "textvalue"')
turnOnLabels(lineLayer, '"title"')
turnOnLabels(polygonLayer, '"title"')

  1. An issue has already been created on GitHub to make it possible to download annotations as proper geojson as well, so the code in this posts may be obsolete shortly. [return]