Localizando la Instalación Más Cercana con Matriz Origen-Destino (QGIS3)

En el tutorial previo, Visualización y Enrutamiento Básico de Red (QGIS3), aprendimos como construir una red y calcular la ruta más corta entre 2 puntos. Podemos aplicar esa técnica para varios tipos diferentes de análisis basado en red. Una de esas aplicaciones es el cálculo Matriz Origen-Destino o Matriz OD. Dado un conjunto de puntos de origen y otro conjunto de puntos destino, podemos calcular la ruta más corta entre cada par de origen-destino y averiguar la distancia/tiempo de viaje entre ellos. Tal análisis es útil para ubicar la instalación más cercana a un punto dado. Por ejemplo, la empresa de logística puede usar este análisis para encontrar el almacen más cercano a sus clientes para optimizar las rutas de entrega. Aquí usaremos el algoritmo Matriz de Distancia del complemento QGIS Network Analysis Toolbox (QNEAT3) para encontrar la instalación de salud más cercana a cada dirección en la ciudad.

Nota

Este tutorial muestra como usar tus propios datos de red para calcular una matriz origen-destino. Si no tienes tus propios datos de red, puedes usar Complemento ORS Tools y el algoritmo ORS Tools ‣ Matriz ‣ Matriz desde Capas para hacer el análisis similar usando datos OpenStreetMap. Vea Análisis de Área de Servicio usando Openrouteservice (QGIS3) para aprender como usar el complemento ORS Tools.

Vista general de la tarea

Tomaremos 2 capas para Washington DC - una con puntos que representan direcciones y otra con puntos que representan instalaciones de salud mental - y averiguaremos la instalación con la menor distancia de viaje para cada dirección.

Otras habilidades que aprenderá

  • Extraer una muestra aleatoria de una capa punto.

  • Usar Capas Virtuales para ejecutar una consulta SQL en una capa QGIS.

Obtener los datos

El gobierno del Distrito de Columbia comparte libremente cientos de conjuntos de datos en el Catálogo de Datos Abiertos.

Descargue las siguientes capas de datos como archivos shape.

Para su comodidad, puede descargar directamente una copia de los conjuntos de datos de los enlaces abajo:

Roadway_Block-shp.zip

Address_Points.zip

Adult_Mental_Health_Providers.zip

Fuente de Datos: [DCOPENDATA]

Configuración

Visite Complementos ‣ Administrar e Instalar complementos. Seleccione :guilabel:` Todos` Busque el complemento QNEAT3 e instálelo. Clic en Cerrar.

../../_images/setup11.png

Procedimiento

  1. Localice el archivo descargado Roadway_Block-shp.zip en el panel Explorador. Expándalo y arrastre el archivo Roadway_Block.shp al lienzo. De forma similar, localice el archivo Adult_Mental_Health_Providers.zip, expándalo y agregue Adult_Mental_Health_Providers.shp al lienzo.

../../_images/1101.png
  1. A continuación, localice el archivo Address_Points.zip, expándalo y agregue Address_Points.shp. Verá bastantes puntos alrededor de la ciudad. Cada punto representa una dirección válida. Seleccionaremos 1000 puntos al azar. Esta técnica es llamada muestreo aleatorio. Vaya a Procesos ‣ Caja de Herramientas.

../../_images/260.png
  1. Busque y localice el algoritmo Selección de Vector ‣ Extracción aleatoria

../../_images/334.png
  1. Seleccione Address_Points como la Capa de Entrada, Number of feature como el Método e, ingrese 1000 en Número/porcentaje de objetos espaciales. En el Extraído (aleatorio) elija el ... y clic Guardar a un archivo. Ahora elija el directorio e ingrese el nombre address_point_subset.shp y clic Ejecutar.

../../_images/415.png

Nota

Como el algoritmo extraerá 1000 puntos aleatorios del conjunto de datos dado, para replicar los puntos exactos usados en este ejercicio puede descargar el archivo de subconjunto que obtuvimos durante la ejecución del algoritmo aquí address_point_subset.zip. Después de descargar, cargue la capa address_point_subset.shp en QGIS.

  1. Se agregará una nueva capa address_point_subset al panel Capas, pueden deshabilitar la visibilidad de la capa de puntos de direcciones Address_Points.

../../_images/515.png
  1. Clic-derecho en la capa address_point_subset y seleccione Renombrar capa.

../../_images/615.png
  1. Renombremos esta capa como origin_points. De forma similar, renombre la capa Adult_Mental_Health_Providers que representa las instalaciones sanitarias como destination_points. Nombrando de esta manera las capas facilita identificarlas en el procesamiento posterior.

../../_images/714.png
  1. Localice el algoritmo QNEAT3 ‣ Matrices de distancia ‣ OD Matrix from Layers as Line (m:n). Si no ve este algoritmo en la caja de herramientas, asegúrese que tiene instalado el complemento QNEAT3.

../../_images/814.png
  1. Este algoritmo ayuda a encontrar las distancias a lo largo de la red entre el origen seleccionado y las capas destino. Seleccione Roadway_Block como la Capa de red. Seleccione origin_points como la Capa de puntos Desde y OBJECTID_1 como el Campo ID único de punto. De forma similar, defina destination_points como la Capa de punto Hacia y OBJECTID como el Campo ID único de punto. Defina el Criterio de Optimización como Ruta más corta (optimización de distancia).

../../_images/914.png
  1. Como muchas calles en la red son de un solo sentido, necesitamos definir los Parámetros avanzados para especificar la dirección. Vea Visualización y Enrutamiento Básico de Red (QGIS3) para más detalles sobre cómo están estructurados estos atributos. Elija SUMMARYDIR como el Campo dirección. Ingrese OB como el Valor para la dirección adelante, IB como el Valor para dirección atrás, y BD como el Valor para ambas direcciones. Defina la Tolerancia de topología como 0.0000150. Mantenga las otras opciones en sus valores predeterminados y clic en Ejecutar.

../../_images/1021.png
  1. Será agregada una nueva tabla llamada Output OD Matrix al panel Capas. Clic-derecho y seleccione Abrir Tabla de Atributos. Verá que la tabla contiene 13000 filas. Teníamos 13 puntos de origen y 1000 puntos destino - por lo que la salida contiene 13x1000 = 13000 pares de orígenes y destinos. La columna total_cost contiene distancia en metros entre cada punto de origen y cada punto destino.

../../_images/1124.png
  1. Para este tutorial, estamos interesados sólo en el punto de destino con la distancia más corta. Podemos crear una consulta SQL para escoger el destino con el total_cost menor entre todos los destinos. Vaya a Procesos ‣ Caja de Herramientas

../../_images/1222.png
  1. Busque y localice Vector general ‣ Ejecutar SQL, seleccione ... en Fuentes de entrada de datos adicionales marque el Matriz OD Saluda y, clic Aceptar. Ahora clic el Summation bajo Consulta SQL.

../../_images/1320.png
  1. Ingrese la siguiente consulta en la caja de diálogo consulta SQL. Ingrese geometry como el Campo geometría y, seleccione LineString como el Tipo de Geometría. Clic en Ejecutar.

select origin_id, destination_id, min(total_cost) as shortest_distance, geometry
from input1 group by origin_id
../../_images/1418.png
  1. Se agregará una capa virtual SQL Output al panel Capas. Esta Capa tiene el resultado de nuestro análisis. El centro de salud de adultos más cercano para cada uno de los 1000 puntos de origen. Intentemos unas pocas maneras diferentes de visualizar y validar estos resultados.

../../_images/1516.png
  1. Para validar esto construyamos la ruta Más Corta. El punto (OBJECTID_1 = 853046) está visualmente cerca al Centro de salud (OBJECTID = 3), pero de la consulta SQL está conectada al centro de salud (OBJECTID = 9). Validemos esto encontrando la distancia real entre estos orígenes y destino. Primero, ejecutemos el algoritmo de ruta más corta en 1 par. Localice el algoritmo QNEAT3 ‣ Enrutamiento ‣ Ruta más corta (punto a punto) y inícielo.

../../_images/1615.png
  1. Seleccione Roadway_Block como la Capa de Red. Para elegir un punto de inicio y final. Puedes hacer clic en el botón junto al Punto de inicio y clic en el punto origen (OBJECTID_1 = 853046) en el lienzo. Similarmente, seleccione el punto de inicio (OBJECTID = 3) como el Punto final. Mantenga el Criterio de optimización como Ruta más corta (optimización de distancia). Expanda la sección Parámetro avanzado. Elija SUMMARYDIR como el Campo de dirección. Ingrese OB como el Valor para dirección adelante y IB como Valor para dirección atrás. Defina la Tolerancia de topología como 0,0000150. Mantenga las otras opciones en sus valores predeterminados y clic en Ejecutar. Ahora cambie el punto destino (OBJECTID = 9) en el Punto final y clic en Ejecutar

../../_images/1716.png
  1. Dos nuevas capas Shortest Path Layer será agregada al panel Capas. Usted verá que aunque el punto destino (OBJECTID = 9) visualmente está cerrado al punto de origen, la distancia actual es mayor cuando se compara al punto destino (OBJECTID = 3).

../../_images/1814.png
  1. Note que a pesar de que las líneas que conectan el origen y el destino son rectas, el destino fue encontrado usando la distancia a lo largo de la red. Será una visualización más útil mostrar la ruta más corta real entre cada origen-destino. Al momento, no existe una manera fácil para general la ruta más corta entre múltiples pares origen-destino de la manera como generamos la matriz de distancia. Pero demostraré una manera para usar algo de script python para generar esta visualización. Primero, ejecutemos el algoritmo de la ruta más corta en 1 par. Localice el algoritmo QNEAT3 ‣ Enrutamiento ‣ Ruta más corta (punto a punto) e inícielo.

../../_images/1912.png
  1. En el diálogo Ruta más corta (Punto a Punto), seleccione Roadway_Block como la Capa de red. Mantenga el Criterio de optimización como Ruta más corta (optimización de distancia). A continuación necesitamos elegir un punto de inicio y final. Puede hacer clic en el botón junto a Punto de inicio y clic en el punto de origen en el lienzo. De forma similar seleccione el punto de destino como el Punto final. Expanda la sección Parámetro avanzado. Elija SUMMARYDIR como el Campo dirección. Ingrese OB como el Valor para dirección adelante y IB como el Valor para dirección atrás. En la Tolerancia de topología ingrese 0,000015. Mantenga otras opciones en sus valores predeterminados y clic Ejecutar.

../../_images/2012.png
  1. Una nueva capa Shortest Path Layer se agregará al panel Capas. Verá que esta ruta sigue la red en vez de conectar el origen y destino con una línea recta. La razón que ejecutamos el algoritmo en 1 para es para identificar fácilemente los valores parámetro que podemos usar en nuestro script. Seleccione Shortest Path layer, clic-derecho y seleccione Quitar capa. Clic el botón Historia en la Caja de herramientas Procesos.

../../_images/2115.png
  1. En el diálogo Historia, Seleccione el último comando (comando usado para Ruta más corta). Este comando muestra todos los parámetros y los valores que usamos. Ahora podemos tomar estos valores y ponerlos en un script que nos puede permitir ejecutar este comando en muchos pares origen-destino. Clic Cerrar.

../../_images/2214.png
  1. En la Caja de Herramientas Procesos, clic el botón scripts y seleccion Crear Nuevo script.

../../_images/2313.png
  1. En el Editor Script de Procesos, copie/pegue el código de abajo. Guarde el archivo como get_routes_from_matrix.py. Ahora cierre el Editor Script de Procesos. Si está usando un conjunto de datos diferente que aquel usado en este tutorial, tendrá que actualizar el script con los valores de parámetro del paso 22.

import requests
import processing
from PyQt5.QtCore import QCoreApplication
from qgis.core import (QgsProcessing, QgsProcessingAlgorithm, 
    QgsProcessingParameterFeatureSource, QgsProcessingParameterFeatureSink,
    QgsFeatureSink)


class MatrixToRoutes(QgsProcessingAlgorithm):
    """Creats Routes from Distance Matrix"""
    NETWORK = 'NETWORK'
    MATRIX = 'MATRIX'
    OUTPUT = 'OUTPUT'

    
    def initAlgorithm(self, config=None):
        self.addParameter(
            QgsProcessingParameterFeatureSource(
                'NETWORK',
                self.tr('Network Layer'),
                types=[QgsProcessing.TypeVectorLine]
            )
        )
        
        self.addParameter(
            QgsProcessingParameterFeatureSource(
                'MATRIX',
                self.tr('Distance Matrix Layer'),
                types=[QgsProcessing.TypeVectorLine]
            )
        )
        
        
        self.addParameter(
            QgsProcessingParameterFeatureSink(
                self.OUTPUT,
                'Network Routes',
                QgsProcessing.TypeVectorLine
            )
        )

    def processAlgorithm(self, parameters, context, feedback):
        network = self.parameterAsString(parameters, self.NETWORK, context)
        matrix = self.parameterAsSource(parameters, self.MATRIX, context)
        
        sink, dest_id = self.parameterAsSink(
            parameters,
            self.OUTPUT,
            context,
            matrix.fields(),
            matrix.wkbType(),
            matrix.sourceCrs()
            )
        
        # Compute the number of steps to display within the progress bar and
        # get features from source
        total = 100.0 / matrix.featureCount() if matrix.featureCount() else 0
        features = matrix.getFeatures()
        
        coordinate_list = []
        for current, f in enumerate(features):
            # Stop the algorithm if cancel button has been clicked
            if feedback.isCanceled():
                break
            line = f.geometry().asPolyline()
            origin_coords = line[0].x(), line[0].y()
            destination_coords = line[1].x(), line[1].y()

            feedback.setProgress(int(current * total))

            params = {
            'INPUT':network,
            'START_POINT':'{},{}'.format(origin_coords[0], origin_coords[1]),
            'END_POINT':'{},{}'.format(destination_coords[0], destination_coords[1]),
            'STRATEGY':0,
            'ENTRY_COST_CALCULATION_METHOD':0,
            'DIRECTION_FIELD':'SUMMARYDIR',
            'VALUE_FORWARD':'OB',
            'VALUE_BACKWARD':'IB',
            'VALUE_BOTH':'',
            'DEFAULT_DIRECTION':2,
            'SPEED_FIELD':None,
            'DEFAULT_SPEED':5,
            'TOLERANCE':0,
            'OUTPUT':'memory:'}
            
            route_layer = processing.run("qneat3:shortestpathpointtopoint", params)['OUTPUT']
            
            if route_layer:
                # We expect only 1 feature in the output, so use next() to get the first item
                route_f = next(route_layer.getFeatures())
                output_geom = route_f.geometry()
                f.setGeometry(output_geom)
                sink.addFeature(f, QgsFeatureSink.FastInsert)
            feedback.setProgressText('Processed feature {}'.format(current))

  
        return {self.OUTPUT: sink} 

    def name(self):
        return 'routes_from_matrix'

    def displayName(self):
        return self.tr('Get Routes from Matrix')
        
    def shortHelpString(self):
        return self.tr('Creates Route Layer from the result of Distance Matrix algorithm')

    def group(self):
        return self.tr(self.groupId())

    def groupId(self):
        return ''

    def tr(self, string):
        return QCoreApplication.translate('Processing', string)

    def createInstance(self):
        return MatrixToRoutes()
../../_images/2412.png
  1. Ahora podemos probar el script. Seleccione unas pocas conexiones para la capa SQL Output para la que quiere que se calculen las rutas actuales. En la Caja de Herramientas de Procesos, se agregará un nueva lista desplegable Scripts. Clic en ella y seleccione Obtener Rutas de la Matriz.

../../_images/2510.png

Nota

Este script necesita calcular el grafo de red para cada iteración y es por lo tanto bastante lento. Si tiene bastantes pares origen-destino, puede tomar tiempo.

  1. En la Capa de Red seleccione Roadway_Block y en la capa Matriz Distancia seleccione SQL Output luego marque solo objetos seleccionados. Clic Ejecutar.

../../_images/269.png
  1. Una nueva capa Network Routes será agregada al panel Capas. Esto contendrá la ruta actual al destino.

../../_images/2710.png
comments powered by Disqus