Relacionar tablas y actualizar datos sin usar las herramientas de Join y Field Calculator

2826
0
02-28-2023 04:53 PM
OscarSolis1
Esri Contributor
5 0 2,826

Me ha pasado y creo que tal vez a otras personas que necesito relacionar tablas para actualizar una capa o servicio, sin embargo, por algún macabro designio del destino no se actualiza, pues que me dirían que con simplemente 31 líneas de código podemos resolver el problema, y esto porque en realidad muchas líneas son comentarios, al menos 13 líneas son comentarios. Pues bueno dicho lo anterior se los voy a mostrar.

A continuación voy a mostrar una imagen con el script completo, también lo voy a adjuntar y dejar acceso a mi GitHub, para que también puedan verlo e interactuar con este.OscarSolis1_0-1677628444472.png

En este caso este script en particular usa únicamente una sola librería de python, que sería arcpy, esta se encuentra disponible únicamente si usan ArcGIS Pro o ArcMap, sin embargo, lo implementado acá puede aplicarse por ejemplo con pandas, y el acceso a la información puede cambiar, pero el método es muy similar, básicamente es considerar dos cosas, la primera es crear un diccionario con la tabla que tiene la nueva información o los datos que queremos traernos. y lo segundo es crear un iterador para que en la tabla o capa a actualizar, se ingrese la nueva información, en este caso como uso ArcGIS Pro, usaré cursores para acceder a las tablas.

Cabe destacar, que podemos encontrar tres tipos de cursores en arcpy: uno es SearchCursor, otro InsertCursor y UpdateCursor.

Cada uno tiene diferentes usos:

  • SearchCursor: simplemente nos sirve para mostrar datos y recorrer tablas.
  • InsertCursor: agrega nuevos datos en la tabla que estemos usando.
  • UpdateCursor: actualiza la tabla que usemos.

Dicho lo anterior voy a explicar por partes:

Importar librerías o paquetes de python

import arcpy

Con esto se llama a la librería de python para poder acceder a las herramientas de geoprocesamiento de ArcGIS Pro.

Parámetros de la herramienta

En esta sección se encuentran los parámetros que definí para la herramienta, donde tenemos:

  1. Tabla de con los nuevos datos: tabla = arcpy.GetParameterAsText(0)
  2. Campo de relacion de la tabla con los datos nuevos: cam_tabla=arcpy.GetParameterAsText(1)
  3. Campo con la nueva información de la tabla con los datos nuevos: cam_tab_traer=arcpy.GetParameterAsText(2)
  4. Capa o tabla a actualizar: CAPA= arcpy.GetParameterAsText(3)
  5. Campo de relacion de la tabla a actualizar: campo=arcpy.GetParameterAsText(4)
  6. Campo a actualizar de la tabla a actualizar: camp_reemp=arcpy.GetParameterAsText(5)

Como podrán observar ya le establecí que son parámetros de ArcGIS, pero si requieren ejecutarlo como simple script pueden escribir la dirección de la tabla por ejemplo r"C:/Datos/tabla.dbf", escribir los nombres de los campos "campo_relacion", "campo_datos_nuevos"; obviamente lo mismo con la capa o tabla a actualizar, por ejemplo: r"C:/Datos/tabla.shp" y con los nombres de los campos correspondientes "campo_relacion", "campo_a_actualizar".

Diccionario de datos de la tabla con los datos nuevos

dct = {r[0]: r[1] for r in arcpy.da.SearchCursor(tabla, (cam_tabla,cam_tab_traer))}

Al haber parametrizado todo, pues en este diccionario, se llama a la tabla, el campo de relación, y el campo con los datos nuevos. También como logran observar estoy usando el SearchCursor, lo que quiere decir es que dentro del diccionario está tenemos un cursor y estamos iterando dentro de este, es como una versión resumida de una iteración de tabla con el SearchCursor, sin embargo, al estar dentro de un diccionario se vuelve muy rápido.

Otra cosa y es que esto r[0]: r[1]  indica para r[0] el parámetro cam_tabla (campo de relación) y r[1] representa el parámetro cam_tab_traer (campo con la nueva información.

Cursor de actualización

with arcpy.da.UpdateCursor(CAPA, (campo,camp_reemp)) as curs:

Con lo anterior abrimos el cursor de actualización, de esta forma luego podemos iterar en la tabla o capa a actualizar de la siguiente forma:

for row in curs:

Nótese que creamos un objeto llamado row y que estamos llamando al cursor de actualización como el objeto curs.

Luego definimos un par de variables para que sea más amigable:

oid = row[0]
cam_actuali = row[1]

Donde oid es el campo de relación de la tabla o capa a actualizar y cam_actuali es el campo que vamos a actualizar que puede tener datos desactualizados o estar vacío, nótese que llaman al objeto row que creamos anteriormente y tienen un valor númérico, estos se relacionan con el orden a lo que tenemos acá en esta línea en negrita: with arcpy.da.UpdateCursor(CAPA, (campo,camp_reemp)) as curs:. Como pueden observar, campo está de primero, esto significa que es el row[0] y camp_reemp es row[1] al ser el segundo. Recuerden que en todo lo que tiene que ver de informática el primer valor es 0 y no el 1.

Consulta para que se actualice únicamente lo que deseamos

Ahora es necesario decirle que vamos a actualizar, por eso tenemos dos cosas, un diccionario con la nueva información y un cursor para iterar entre todos los registros pero no le hemos dicho cuando o que va a actualizar, por ello tenemos la siguiente consulta:

if oid in dct:

Lo que quiere decir es si la variable que definimos como oid, que es el campo a relacionar de la capa o tabla a actualizar se encuentra dentro de la lista de valores del diccionario y de ser verdadera, se comparará con la tupla del diccionario.

Actualización

Ya que se hizo la consulta, le vamos a decir que hacer y pues es decirle que el valor del campo a actualizar, es igual al campo con la nueva información, esto por medio de la tupla del diccionario obviamente.

cam_actuali = dct[oid]

Donde, cam_actuali es la variable que contiene el campo a actualizar, dct es el diccionario que definimos, [oid] es la tupla que se relaciona con el campo a relacionar y se encuentra dentro del diccionario, por ende, trayendo el nuevo registro al campo a actualizar.

Imprimir un mensaje

A veces necesitamos imprimir un mensaje, por ejemplo en este caso, justo debajo de la línea donde le decíamos al script que el campo a actualizar era igual a lo relacionado en la tupla, pues se captura un mensaje solamente para saber qué está haciendo o en qué registro va.

arcpy.AddMessage(cam_actuali)

Cabe destacar que esta línea no es necesaria, pero puede ser que les interese ver por qué parte de la tabla se encuentra ejecutándose el script.

Acción de actualizar

Ya casi terminamos, y acá es donde le decimos que una vez que encuentre la relación y luego que queremos actualizar, pues le decimos ahora que actualice la tabla. De esta forma tenemos lo siguiente:

curs.updateRow(row)

como pueden observar la línea anterior usa dos objetos, uno es curs en este caso, y el otro es row, por lo que cuando hagan sus scripts, si nombran a un cursor digamos actualizacion, en ese caso en vez de curs, sería actualizacion, si en vez de row crearon fila, pues en vez de row sería fila.

Eliminar el cursor de actualización

Casi listo, de hecho ya con esto se debió actualizar la tabla o capa a partir de una relación, pero como abrimos un cursor, debemos borrarlo para evitar bloqueos en la tabla o capa que estamos editando, y es que los cursores de InsertCursor o UpdateCursor realizan ediciones sobre las capas que estemos usando.

Para esto, y en este caso se tiene lo siguiente:

del curs

Como podrán observar volvemos a llamar al objeto creado anteriormente llamado curs, así vuelvo a indicar que si llaman a sus cursores de forma diferente pues acá también lo llamen de esa forma.

Y listo, ya tienen un script para actualizar elementos a partir de una relación sin usar las herramientas de join y Field Calculator, en otra ocasión les mostraré como hacerlo con pandas, o con listas y diccionarios en excel, csv o dbf sin usar cursores.

Pueden acceder a mi GitHub donde encontrarán este y otros ejemplos, ya que también con esto podemos actualizar o mover una geometría también, lo cual más adelante también les mostraré, puesto que hay muchas posibilidades. De la misma forma adjunto el toolbox que es para ArcGIS Pro versión 3x, si disponene de una versión anterior pueden visitar este post