8 votos

Agregación del resultado de la unión muchos-muchos de los puntos más cercanos a la línea en QGIS

Tengo una capa de puntos y una segunda capa de líneas. El objetivo es saber para cada línea, cuántos y qué puntos (por "ID" ) están más cerca de esa línea, para luego exportar esta información para su posterior análisis.

Points and lines.

He utilizado un Spatial join para asociar cada punto con la línea más cercana (es decir, mis puntos tienen ahora la información de la carretera en su tabla de atributos), pero ahora no entiendo cómo puedo utilizar esto para añadir el punto "ID" s a las líneas. La operación regular de unión de QGIS es sólo 1->1 y por lo tanto me da sólo un punto "ID" aunque es evidente que existen múltiples puntos. ¿Cómo puedo almacenar el "ID" s de todos los puntos como atributo en la línea de correspondencia?

He buscado bastante en Google, pero parece que tengo problemas para encontrar los términos adecuados para describir lo que quiero hacer. También he intentado utilizar la función de relaciones de QGIS, pero no he obtenido resultados satisfactorios. Tal vez la funcionalidad de las relaciones no es adecuado para las exportaciones.

10voto

nitinsavant Puntos 6

Darle sólo un identificador de punto es sensato. De lo contrario, la operación de unión generaría cientos/miles de columnas en la capa de líneas para cada punto cercano.

Una solución sería añadir todos los ids de los puntos cercanos a un único campo de tipo cadena utilizando el siguiente script PyQGIS.

point_layer_name = "Point_Layer"
line_layer_name = "Line_Layer"

# reference of layers
point_layer = QgsProject.instance().mapLayersByName(point_layer_name)[0]
line_layer = QgsProject.instance().mapLayersByName(line_layer_name)[0]

# check if field storing ids exists. if not add a new field
if line_layer.dataProvider().fieldNameIndex("POINT_IDS") == -1:
    line_layer.dataProvider().addAttributes([QgsField("POINT_IDS", QVariant.String, len=100)])
    line_layer.updateFields()

field_idx = line_layer.fields().indexOf('POINT_IDS')
with edit(line_layer):

    # reset POINT_IDS values
    for feature in line_layer.getFeatures():
       line_layer.changeAttributeValue(feature.id(), field_idx, '')

    # iterate over points
    for point in point_layer.getFeatures():

        distances = {line.id(): point.geometry().distance(line.geometry()) 
                                for line in line_layer.getFeatures()}

        # find the nearest line id
        nearest_line_id = min(distances, key=distances.get)
        # get the line by id
        line = line_layer.getFeature(nearest_line_id)    
        # append the point id to the line's POINT_IDS 
        line["POINT_IDS"] += str(point.id()) + " " # you can use comma instead of space

        line_layer.updateFeature(line)

Resultado:
enter image description here

7voto

chhh Puntos 1154

Una solución utilizando expresiones de QGIS:

  1. Ve a la capa de puntos para crear un atributo que contenga el id de la línea más cercana utilizando esta expresión

     array_first (
         overlay_nearest (
             'line', 
             line_id
         )
     )
  2. En la capa de líneas, cree un nuevo atributo concatenando los id de los puntos más cercanos a la característica actual:

    with_variable (
        'lineid',
        $id,
        aggregate (
            'point',
            'concatenate',
            to_string(pointid),
            filter:=closest_line=@lineid,
            concatenator:=','
        )
    )

enter image description here

5voto

ARUNBALAN NV Puntos 101

Otra solución utiliza un "Capa virtual" a través de Layer > Add Layer > Add/Edit Virtual Layer... .

Supongamos que hay dos capas prueba_puntos_aleatorios (10 funciones) y líneas_prueba (tres características), véase la imagen siguiente.

input

Con la siguiente consulta (incluye GROUP_CONCAT() , ST_Within() y ST_Buffer() ), es posible para almacenar el "ID" s de todos los puntos como atributo en la línea de correspondencia .

SELECT
    lines.*,
    GROUP_CONCAT(poi."id") AS "poi_ids"
FROM
    "lines_test" AS lines
LEFT JOIN
    "random_points_test" AS poi
WHERE
    st_within(poi.geometry, st_buffer(lines.geometry, 100000))
GROUP BY
    lines."id"

La capa virtual de salida tendrá el siguiente aspecto

result1

Nota: Valor de 100000 en el st_buffer() corresponde a la distancia máxima de una característica lineal a los puntos.

Para obtener cuántos puntos están más cerca de esa línea, añade la siguiente cadena COUNT(*) AS "poi_n" en la consulta:

SELECT
    lines.*,
    GROUP_CONCAT(poi."id") AS "poi_ids",
    COUNT(*) AS "poi_n"
FROM
    "lines_test" AS lines
LEFT JOIN
    "random_points_test" AS poi
WHERE
    st_within(poi.geometry, st_buffer(lines.geometry, 100000))
GROUP BY
    lines."id"

Por lo tanto, ahora la salida tendrá el siguiente aspecto

result2


Otra consulta similar (incluye GROUP_CONCAT() , ST_ShortestLine() y ST_Length() ):

SELECT
    lines.*,
    GROUP_CONCAT(poi."id") AS "poi_ids"
FROM
    "lines_test" AS lines
LEFT JOIN
    "random_points_test" AS poi
WHERE
    ST_Length(ST_ShortestLine(poi.geometry, lines.geometry)) < 100000
GROUP BY
    lines."id"

i-Ciencias.com

I-Ciencias es una comunidad de estudiantes y amantes de la ciencia en la que puedes resolver tus problemas y dudas.
Puedes consultar las preguntas de otros usuarios, hacer tus propias preguntas o resolver las de los demás.

Powered by:

X