Esta es una solución en Python. Debes pegar este código en la consola de Python de QGIS.
Este es mi setup: Tengo dos capas vectoriales GIS_SE_POINT
y GIS_SE_POLY
cada una con un campo (atributo) llamado name
(para describir un punto como Punto 1
y un polígono como A
).
![enter image description here]()
![enter image description here]()
Canvas:
![enter image description here]()
Este es el código:
EDITADO
import collections
from operator import itemgetter
from itertools import groupby
def grouping_intersection(point_layer, point_attribute, polygon_layer, group_by_attribute, buffer, segments, state):
if QgsMapLayerRegistry.instance().mapLayersByName(point_layer):
point = QgsMapLayerRegistry.instance().mapLayersByName(point_layer)[0]
else:
print('{}{}{}'.format('Layer ', point_layer, ' does not exist.'))
return False
index = point.fieldNameIndex(point_attribute)
if index == -1:
print('{}{}{}'.format('Field ', point_attribute, ' does not exist.'))
return False
else:
pass
if QgsMapLayerRegistry.instance().mapLayersByName(polygon_layer):
poly = QgsMapLayerRegistry.instance().mapLayersByName(polygon_layer)[0]
else:
print('{}{}{}'.format('Layer ', polygon_layer, ' does not exist.'))
return False
index = poly.fieldNameIndex(group_by_attribute)
if index == -1:
print('{}{}{}'.format('Field ', group_by_attribute, ' does not exist.'))
return False
else:
pass
list = []
for b in poly.getFeatures():
for a in point.getFeatures():
if buffer >0:
if a.geometry().buffer(buffer, segments).intersects(b.geometry()):
list.append([a[point_attribute], b[group_by_attribute]])
elif buffer == 0:
if a.geometry().intersects(b.geometry()):
list.append([a[point_attribute], b[group_by_attribute]])
for points, polygons in groupby(sorted(list, key=itemgetter(0)), itemgetter(0)):
item_list=[]
for i in polygons:
item_list.append((i)[1])
counter=collections.Counter(item_list)
if state == 0:
print('{}{}{}'.format(points, ': ', ','.join(sorted(item_list))))
elif state == 1:
print('{}{}{}'.format(points, ': ', ','.join(sorted(counter.keys())))
elif state == 2:
print('{}{}{}'.format(points, ': ', ','.join('{}{}{}{}'.format(key, '(', val, ')') for key, val in sorted(counter.items()))))
else:
print('{}{}{}'.format('State ', state, ' does not exist'))
return False
Cómo obtener el resultado:
Debes llamar a la función con 6 parámetros.
- nombre de tu capa de puntos
- campo (atributo) con los nombres de los puntos
- nombre de la capa de polígonos
- campo (atributo) con los nombres de los polígonos
- tamaño del buffer en metros (aumenta/disminuye el valor según desees)
- segmentos del buffer (aumentar la cantidad de segmentos aumenta el tiempo de procesamiento)
- alternando el estado:
0
sin agrupar ni contar, 1
agrupando, 2
agrupando y contando.
>>>grouping_intersection('GIS_SE_POINT', 'name', 'GIS_SE_POLY', 'name', 1000, 20, 0)
Point 1: A,A,A,B,C
Point 2: A,A,B,C,D
Point 3: B,B
Point 4: A,A,B,C,C,D,D
>>>grouping_intersection('GIS_SE_POINT', 'name', 'GIS_SE_POLY', 'name', 1000, 20, 1)
Point 1: A,B,C
Point 2: A,B,C,D
Point 3: B
Point 4: A,B,C,D
>>>grouping_intersection('GIS_SE_POINT', 'name', 'GIS_SE_POLY', 'name', 1000, 20, 2)
Point 1: A(3),B(1),C(1)
Point 2: A(2),B(1),C(1),D(1)
Point 3: B(2)
Point 4: A(2),B(1),C(2),D(2)
ACTUALIZACIÓN
Para una pequeña cantidad de datos, el resultado del enfoque anterior es razonable en términos de tiempo. Para conjuntos de datos más grandes, el siguiente script utiliza un índice espacial para los polígonos. -- Atención -- Probé varias capas y noté que si la capa de polígonos no es un shapefile, no se puede establecer el índice espacial.
import collections
from operator import itemgetter
from itertools import groupby
def grouping_intersection_spIndex(point_layer, point_attribute, polygon_layer, group_by_attribute, buffer, segments, state):
if QgsMapLayerRegistry.instance().mapLayersByName(point_layer):
point = QgsMapLayerRegistry.instance().mapLayersByName(point_layer)[0]
else:
print('{}{}{}'.format('Layer ', point_layer, ' does not exist.'))
return False
index = point.fieldNameIndex(point_attribute)
if index == -1:
print('{}{}{}'.format('Field ', point_attribute, ' does not exist.'))
return False
else:
pass
if QgsMapLayerRegistry.instance().mapLayersByName(polygon_layer):
poly = QgsMapLayerRegistry.instance().mapLayersByName(polygon_layer)[0]
else:
print('{}{}{}'.format('Layer ', polygon_layer, ' does not exist.'))
return False
index = poly.fieldNameIndex(group_by_attribute)
if index == -1:
print('{}{}{}'.format('Field ', group_by_attribute, ' does not exist.'))
return False
else:
pass
points = [feature for feature in point.getFeatures()]
polygons = [feature for feature in poly.getFeatures()]
polygon_spIndex = QgsSpatialIndex()
for feat in polygons:
polygon_spIndex.insertFeature(feat)
list = []
for a in points:
if buffer >0:
pt = a.geometry().buffer(buffer,segments)
if buffer == 0:
pt = a.geometry()
for id in polygon_spIndex.intersects(pt.boundingBox()):
if pt.intersects(polygons[id].geometry()):
list.append([a[point_attribute], polygons[id][group_by_attribute]])
for points, polygons in groupby(sorted(list, key=itemgetter(0)), itemgetter(0)):
item_list=[]
for i in polygons:
item_list.append((i)[1])
counter=collections.Counter(item_list)
if state == 0:
print('{}{}{}'.format(points, ': ', ','.join(sorted(item_list))))
elif state == 1:
print('{}{}{}'.format(points, ': ', ','.join(sorted(counter.keys()))))
elif state == 2:
print('{}{}{}'.format(points, ': ', ','.join('{}{}{}{}'.format(key, '(', val, ')') for key, val in sorted(counter.items()))))
else:
print('{}{}{}'.format('State ', state, ' does not exist'))
return False
Con el índice espacial realmente puedes acelerar tu tiempo de procesamiento.
Caso de prueba:
Capa de puntos con 2250 elementos y una capa de polígonos con 600 elementos. Pruebas del tiempo de procesamiento sin imprimir.
Sin usar un índice espacial: 65seg
Usando un índice espacial: 0.35seg
¡Más de 180 veces más rápido!