-
-
Save ewsterrenburg/b579e1f6c053050112a2e89f9811408d to your computer and use it in GitHub Desktop.
# -*- coding: utf-8 -*- | |
import json | |
from PyQt5.QtGui import QColor, QFont | |
from qgis.core import QgsPalLayerSettings, QgsTextFormat | |
from qgis.core import QgsTextBufferSettings, QgsVectorLayerSimpleLabeling | |
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 | |
# Line below is the original version | |
# Can't figure out anymore what the exact meaning of the magic 4 is... | |
# Could be replaced with a proper placement if required | |
# layer_settings.placement = 4 | |
layer_settings.enabled = True | |
layer_settings = QgsVectorLayerSimpleLabeling(layer_settings) | |
layer.setLabelsEnabled(True) | |
layer.setLabeling(layer_settings) | |
layer.triggerRepaint() | |
input_file_path = unicode(r"C:\Users\NL01031\Downloads\Annotations.json") | |
groupName ="Annotations" | |
project = QgsProject.instance() | |
root = project.layerTreeRoot() | |
group = root.addGroup(groupName) | |
# not the most elegant way to allow for longer descriptions, yet | |
# good enough for now. | |
# (for adding the fields in a more elegant way: https://anitagraser.com/pyqgis-101-introduction-to-qgis-python-programming-for-non-programmers/pyqgis101-creating-editing-a-new-vector-layer/ ) | |
lineLayer = QgsVectorLayer("linestring?crs=epsg:4326&field=id:string(36)&field=title:string&field=description:string(10000)&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(10000)&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(10000)&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 = [] | |
if len(subPart['geometry']['coordinates']) == 0: | |
iface.messageBar().pushMessage("Warning", f"Polygon without vertices encountered for feature with id {attributeId}.", level=Qgis.Warning) | |
continue | |
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"') |
This is great, and exactly the sort of thing I'm looking for to download annotations from mapstore and view in QGIS, for eventual export to Geoserver. I'm wondering if there is a limit to the number of annotations it can handle, I've got an annotations dataset with several hundred annotations (point, line, and polygon), and it only seems to output some of them (105 polygons, not points or lines). Wondering if you have any advice on how to handle such a large volume of data. Screenshot with error for reference:
@alex-myp good to see this gist is useful :)
Larger amounts of annotations should not be a problem, it seems that something else is not going as it should be (an annotation with empty geometry perhaps?). If you're ok with sharing the input data, I could have a check.
@ewsterrenburg than you for the reply! I have attached the input data, would really appreciate you taking a look. Thank you!
https://drive.google.com/file/d/119fNJiMeXBSQGjBoJ0jYrKyKTcXFGC28/view?usp=share_link
@alex-myp Thanks for your upload.
The good news: with some minor changes I'm able to see the large majority of your features.
The bad news:
- There are two empty (sub?)-geometries in your data that the script does not handle well. --> When looking at things, I doubt all geometry edge cases are handled well as is, at least I will add a check to ignore/log those occurrences.
- It is reporting some (≈100) cases of the text being longer than the default 255 characters --> I'll change this.
- Seems in current QGIS the syntax for the label placement has changed --> I'll change this.
@alex-myp made some changes, now it should also work with your dataset.
@ewsterrenburg thanks for the quick changes, my data is loading in QGIS now without issues. Appreciate the help with this, keep up the good work :)
Good morning! Appreciate for the code as JSON cannot be loaded directly in QGIS. I would like to inquire how to do it in the python console? What are the things I need to change in the code to be able to run them in the console? sorry another newbie in python. Thanks in advance!
@roelsantiago
Should be as simple as:
- Download this script
- Open the Python console
- Choose "Show editor"
- Open the script
- Change to path to where your json file is located
- Run
Success. great guide! Just a follow up, I notice in the python console, there's an option to "Add script Toolbox" Can this be implemented? then simply run the tools in the same manner like running a buffer? Big thanks!
@roelsantiago There's a few minor differences, yet indeed it can be implemented (in fact, this gist originally started as a plugin)
I included the improvements the current version and made it available here
https://drive.google.com/file/d/1vpJbGGb9Dq3U00u5rJ1bN5YGrcmg6BF3/view?usp=sharing
Thanks for the update! Tested the plugin in QGIS 3.32 and works perfectly fine.
hi, sorry for my ignorance, I was running it directly without the editor opening. I appreciate your willingness to help me. excuse my English. It works perfect. You helped me a lot. Oscar