Skip to content

Instantly share code, notes, and snippets.

@m-kuhn
Last active June 25, 2019 07:24
Show Gist options
  • Save m-kuhn/20438ef2379fa28c036185498ab40811 to your computer and use it in GitHub Desktop.
Save m-kuhn/20438ef2379fa28c036185498ab40811 to your computer and use it in GitHub Desktop.
processing_geocode
from qgis.processing import alg
from qgis.core import QgsFeature, QgsGeometry, QgsPoint, QgsField, QgsFeatureSink, QgsNetworkAccessManager, QgsWkbTypes, QgsExpression, QgsExpressionContextUtils, QgsCoordinateReferenceSystem
from PyQt5.QtCore import QUrl, QVariant
from PyQt5.QtNetwork import QNetworkRequest
import json
class NominatimGeocoder():
"""A geocoder for nominatim"""
def __init__(self):
pass
def request_uri(self, address):
return 'https://nominatim.openstreetmap.org/search?format=json&q={address}'.format(address=address)
def process_response(self, response):
res = []
for rec in response['results']:
res.append((rec['display_name'], QgsPoint(float(rec['lon']), float(rec['lat']))))
return res
class GoogleGeocoder():
"""a geocoder for google. Needs an API key"""
def __init__(self, api_key):
self.api_key=api_key
def request_uri(self, address):
return 'https://maps.googleapis.com/maps/api/geocode/json?address={address}&key={key}'.format(address=address, key=self.api_key)
def process_response(self, response):
res = []
for rec in response['results']:
res.append((rec['formatted_address'], QgsPoint(float(rec['geometry']['location']['lng']), float(rec['geometry']['location']['lat']))))
return res
@alg(name="geocode", label=alg.tr("GeoCode"), group="examplescripts", group_label=alg.tr("GeoCode"))
@alg.input(type=alg.SOURCE, name="INPUT", label="Adress layer", default="asdf")
@alg.input(type=alg.EXPRESSION, name="EXPRESSION", label="Address expression", parentLayerParameterName="INPUT", default=" 'Bnei Brak ' || \"Field3\" || ' ' || \"Field1\" ")
@alg.input(type=alg.ENUM, name="SERVICE", label="Service", options=['Google', 'Nominatim'], default="Google")
@alg.input(type=alg.STRING, name="API_KEY", label="Google API key", default="AIzaSyDFyl_TY4QMBEmthl2m2DKCUmv1hL0yqF8")
@alg.input(type=alg.SINK, name="OUTPUT", label="Output layer")
def geocode(instance, parameters, context, feedback, inputs):
"""
Geocode locations. Addresses in, points out.
May produce multiple points for an address if ambiguous.
"""
source = instance.parameterAsSource(parameters, "INPUT", context)
exp = instance.parameterAsExpression(parameters, "EXPRESSION", context)
service = instance.parameterAsExpression(parameters, "SERVICE", context)
api_key = instance.parameterAsExpression(parameters, "API_KEY", context)
fields = source.fields()
fields.append(QgsField('DisplayName', QVariant.String))
(sink, dest_id) = instance.parameterAsSink(
parameters, "OUTPUT", context,
fields, QgsWkbTypes.Point, QgsCoordinateReferenceSystem(4326))
total = 100.0 / source.featureCount() if source.featureCount() else 0
features = source.getFeatures()
exp_context = context.expressionContext()
exp_context.appendScope(source.createExpressionContextScope())
expression = QgsExpression(exp)
expression.prepare(exp_context)
if service == 'Nominatim':
geocoder = NominatimGeocoder(api_key)
else:
geocoder = GoogleGeocoder(api_key)
for current, feature in enumerate(features):
if feedback.isCanceled():
break
exp_context.setFeature(feature)
address = expression.evaluate(exp_context)
request = QNetworkRequest(QUrl(geocoder.request_uri(address)))
reply = QgsNetworkAccessManager.blockingGet(request)
response = json.loads(str(reply.content().data(), encoding='utf-8'))
out_feature = QgsFeature(fields)
for field in source.fields():
out_feature[field.name()] = feature[field.name()]
for result in geocoder.process_response(response):
out_feature.setGeometry(QgsGeometry(result[1]))
out_feature['DisplayName'] = result[0]
sink.addFeature(out_feature, QgsFeatureSink.FastInsert)
feedback.setProgress(int(current * total))
return {"OUTPUT": dest_id}
@mbernasocchi
Copy link

mbernasocchi commented Jun 25, 2019

demo data (.csv)

name, address, city
PostFinance-Filiale Zürich Rennweg, Rennweg 35, 8001 Zürich
PostFinance Affoltern am Albis, Bahnhofplatz 11, 8910 Affoltern am Albis
PostFinance Muri, Kirchenfeldstrasse 6, 5630 Muri AG
PostFinance-Filiale Dietikon, Neumattstrasse 22, 8953 Dietikon
PostFinance-Filiale Winterthur, Bahnhofplatz 8, 8400 Winterthur
PostFinance-Filiale Zug, Baarerstrasse 38, 6300 Zug
PostFinance-Filiale Horgen, Bahnhofstrasse 6, 8810 Horgen
PostFinance Bülach, Sonnenhof 1, 8180 Bülach
PostFinance Meilen, Dorfstrasse 73, 8706 Meilen
PostFinance Reinach AG, Postplatz 4, 5734 Reinach AG
PostFinance-Filiale Zürich Oerlikon, Edisonstrasse 3, 8050 Zürich
PostFinance-Filiale Uster, Bahnhofstrasse 9, 8610 Uster
PostFinance-Filiale Zürich Enge, Gutenbergstrasse 1, 8002 Zürich
PostFinance Kloten, Bahnhofstrasse 6, 8302 Kloten
PostFinance Küsnacht, Kohlrainstrasse 16, 8700 Küsnacht ZH
PostFinance-Filiale Baden, Nordhaus 3, 5400 Baden
PostFinance Würenlingen, Dorfstrasse 6, 5303 Würenlingen
PostFinance-Filiale Vevey, Avenue du Général-Guisan 17, 1800 Vevey
PostFinance Montreux, Avenue des Alpes 70, 1820 Montreux
PostFinance-Filiale Lausanne, Place Saint-François 15, 1003 Lausanne
PostFinance Aigle, Rue de la Gare 27, 1860 Aigle
PostFinance Bussigny, Route de Renens 1, 1030 Bussigny
PostFinance Monthey, Rue de Venise 3B, 1870 Monthey
PostFinance Morges, Grand-Rue 73, 1110 Morges
PostFinance-Filiale Sitten, Place de la Gare 7, 1950 Sion
PostFinance Martigny, Avenue de la Gare 34, 1920 Martigny
PostFinance Zweisimmen, Montreuxstrasse 5, 3770 Zweisimmen
PostFinance Sierre, Avenue Général-Guisan 2, 3960 Sierre
PostFinance Glarus, Schweizerhofstrasse 8, 8750 Glarus
PostFinance Ilanz, Via S. Clau Sura 11, 7130 Ilanz
PostFinance Wattwil, Grüenaustrasse 4, 9630 Wattwil
PostFinance Amriswil, Kirchstrasse 18, 8580 Amriswil
PostFinance Kreuzlingen, Löwenstrasse 16, 8280 Kreuzlingen
PostFinance Pfäffikon ZH, Kempttalstrasse 26, 8330 Pfäffikon ZH
PostFinance-Filiale Wil, Lerchenfeldstrasse 10, 9500 Wil SG
PostFinance Herisau, Gossauerstrasse 2, 9100 Herisau
PostFinance-Filiale Rapperswil, Untere Bahnhofstrasse 2, 8640 Rapperswil SG
PostFinance-Filiale Frauenfeld, Rheinstrasse 5, 8500 Frauenfeld
PostFinance Chêne-Bourg, Rue du Gothard 22, 1225 Chêne-Bourg
PostFinance-Filiale Genf Carouge, Rue des Allobroges 5, 1227 Carouge GE
PostFinance-Filiale Nyon, Place Bel-Air 5, 1260 Nyon
PostFinance-Filiale Genf Mont Blanc, Rue du Mont-Blanc 18, 1201 Genève
PostFinance Davos, Promenade 111, 7270 Davos Platz
PostFinance-Filiale Chur, Bahnhofplatz 3, 7000 Chur
PostFinance St. Moritz, Bahnhofplatz 3, 7000 Chur
PostFinance-Filiale Luzern, Bahnhofplatz 4, 6003 Luzern
PostFinance Stans, Stansstaderstrasse 90, 6370 Stans
PostFinance Seewen, Bahnhofstrasse 128, 6423 Seewen SZ
PostFinance Altdorf (Uri), Bahnhofstrasse 9, 6460 Altdorf UR
PostFinance Solothurn, Kronengasse 12, 4500 Solothurn
PostFinance-Filiale Biel, Bahnhofstrasse 49, 2502 Biel/Bienne
PostFinance Grenchen, Solothurnstrasse 32, 2540 Grenchen
PostFinance Laufen, Bahnhofstrasse 4, 4242 Laufen
PostFinance Tramelan, Grand-Rue 126, 2720 Tramelan
PostFinance Porrentruy, Rue du Jura 6, 2900 Porrentruy
PostFinance-Filiale Basel Clara Shopping, Greifengasse 36, 4058 Basel
PostFinance-Filiale Basel Steinenberg, Elisabethenstrasse 2, 4051 Basel
PostFinance-Filiale Fribourg, Rue Saint-Pierre 3, 1700 Fribourg
PostFinance Bern Aarbergergasse, Aarbergergasse 5, 3011 Bern
PostFinance Münsingen, Bernstrasse 5, 3110 Münsingen
PostFinance Murten, Schaalgasse 2, 3280 Murten
PostFinance Lyss, Bahnhofstrasse 10, 3250 Lyss
PostFinance-Filiale Bern PostParc, Bogenschützenstrasse 9B, 3008 Bern
PostFinance-Filiale St. Gallen, Bahnhofplatz 5, 9000 St. Gallen
PostFinance St. Margrethen, Bahnhofplatz 12, 9430 St. Margrethen SG
PostFinance Buchs, Bahnhofplatz 2, 9470 Buchs SG
PostFinance Langnau, Alleestrasse 11, 3550 Langnau im Emmental
PostFinance-Filiale Thun, Aarefeldstrasse 16, 3600 Thun
PostFinance Interlaken, Marktgasse 16, 3800 Interlaken
PostFinance-Filiale Bern Land, Kirchbergstrasse 23, 3400 Burgdorf
PostFinance Frutigen, Kanderstegstrasse 11, 3714 Frutigen
PostFinance Rheinfelden, Kaiserstrasse 6, 4310 Rheinfelden
PostFinance Frick, Widengasse 14, 5070 Frick
PostFinance Sursee, Centralstrasse 8A, 6210 Sursee
PostFinance Lenzburg, Brättligäu 6, 5600 Lenzburg
PostFinance-Filiale Aarau, Poststrasse 24, 5000 Aarau
PostFinance Liestal, Poststrasse 3, 4410 Liestal
PostFinance Sissach, Bahnhofstrasse 11, 4450 Sissach
PostFinance Langenthal, Jurastrasse 41, 4900 Langenthal
PostFinance-Filiale Olten, Frohburgstrasse 10, 4600 Olten
PostFinance La Chaux-de-Fonds, Avenue Léopold-Robert 63, 2300 La Chaux-de-Fonds
PostFinance-Filiale Neuenburg, Place du Port 2, 2000 Neuchâtel
PostFinance Payerne, Rue des Granges 20, 1530 Payerne
PostFinance Romont, Place Saint-Jacques 61, 1680 Romont FR
PostFinance-Filiale Yverdon, Avenue de la Gare 6, 1400 Yverdon-les-Bains
PostFinance Biasca, Via A. e M. Pini 14, 6710 Biasca
PostFinance-Filiale Lugano, Via della Posta 7, 6900 Lugano
PostFinance-Filiale Locarno, Piazza Grande 3, 6600 Locarno
PostFinance-Filiale Bellinzona, Viale Stazione 15, 6500 Bellinzona
PostFinance Ponte Tresa, Via della Posta 7, 6900 Lugano
PostFinance-Filiale Mendrisio, Viale Stefano Franscini 7, 6850 Mendrisio
PostFinance Saignelégier, Rue de la Gare 6, 2350 Saignelégier
PostFinance-Filiale Schaffhausen, Bahnhofstrasse 34, 8200 Schaffhausen

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment