Making a join between a table and many Feature classes and being able to export them

103
1
3 weeks ago
JuanManuelCruzHerrera
New Contributor III

Hola . Llevo días intentando hacer un join entre Feature Class y una tabla para que los datos de la tabla se queden en la FC, primero intenté creando los campos vacíos en la FC y al hacer el join los datos de la tabla pasaran a la FC antes de quitar el Join pero no me daba la información y luego intenté crear una nueva FC con el join pero sigue sin coger la tabla. Lo último que intenté fue arcpy.management.MakeFeatureLayer y luego arcpy.conversion.ExportFeatures pero tampoco funcionó y finalmente hice arcpy.management.AddJoin(fc_name, "Codigo_Municipal_Catastral", table, "Codigo_Municipal_Catastral", "KEEP_ALL")
print(f"Join hecho entre '{fc_name}' y '{table}' con tipo 'KEEP_ALL'")

# Crear una capa temporal
arcpy.management.MakeFeatureLayer(fc_name, layer_name)
print(f"Capa temporal '{layer_name}' creada a partir de la clase de entidad")

# Guarde la capa temporal como un archivo de capa (.lyrx)
arcpy.management.SaveToLayerFile(layer_name, layer_file, "RELATIVE")
print(f"Capa guardada como archivo de capa '{layer_file}'")
pero tampoco me da los datos de la tabla en la nueva clase de entidad.

Dejo algunos de los guiones aquí

importar arcpy
importar sistema operativo

def realizar_join_y_exportar(gdb_destino, prefijo, sufijo, dataset, tabla):
"""
Realiza un join entre los feature classes y la tabla 'cod_catastrales' y exporta el resultado a un nuevo feature class.
"""
arcpy.env.workspace = f"{gdb_destino}\\{dataset}"
feature_classes = arcpy.ListFeatureClasses(f"{sufijo}*")

for fc in feature_classes:
nombre_fc = f"{gdb_destino}\\{dataset}\\{fc}"
nuevo_fc = f"{gdb_destino}\\{dataset}\\{prefijo}{fc[len(sufijo):]}"
layer_name = f"layer_{fc}"
layer_file = os.path.join(gdb_destino, f"{layer_name}.lyrx")

if arcpy.Exists(nombre_fc):
# Realizar Join con la opción KEEP_ALL
arcpy.management.AddJoin(nombre_fc, "Codigo_Municipal_Catastral", tabla, "Codigo_Municipal_Catastral", "KEEP_ALL")
print(f"Join realizado entre '{nombre_fc}' y '{tabla}' con tipo 'KEEP_ALL'")

# Crear una capa temporal
arcpy.management.MakeFeatureLayer(nombre_fc, layer_name)
print(f"Capa temporal '{layer_name}' creada desde el feature class")

# Guardar la capa temporal como archivo de capa (.lyrx)
arcpy.management.SaveToLayerFile(layer_name, layer_file, "RELATIVE")
print(f"Capa guardada como archivo de capa '{layer_file}'")

# Cargar la capa desde el archivo de capa y exportarla a un nuevo feature class
arcpy.management.MakeFeatureLayer(layer_file, layer_name)
arcpy.conversion.FeatureClassToFeatureClass(layer_name, os.path.dirname(nuevo_fc), os.path.basename(nuevo_fc))
print(f"Feature class exportado a '{nuevo_fc}'")

def verificar_elementos(gdb_destino, prefijo, sufijo, dataset):
"""
Verifica la cantidad de elementos en los feature classes originales y los nuevos feature classes.
"""
arcpy.env.workspace = f"{gdb_destino}\\{dataset}"
feature_classes_orig = arcpy.ListFeatureClasses(f"{sufijo}*")
feature_classes_new = arcpy.ListFeatureClasses(f"{prefijo}*")

for fc_orig, fc_new in zip(feature_classes_orig, feature_classes_new):
nombre_fc_orig = f"{gdb_destino}\\{dataset}\\{fc_orig}"
nombre_fc_new = f"{gdb_destino}\\{dataset}\\{fc_new}"

if arcpy.Exists(nombre_fc_orig) and arcpy.Exists(nombre_fc_new):
count_orig = arcpy.management.GetCount(nombre_fc_orig)[0]
count_new = arcpy.management.GetCount(nombre_fc_new)[0]
print(f"Feature class original: '{nombre_fc_orig}' - Elementos: {count_orig}")
print(f"Feature class nuevo: '{nombre_fc_new}' - Elementos: {count_new}")
if count_orig == count_new:
print(f"Verificación exitosa: La cantidad de elementos coincide entre '{nombre_fc_orig}' y '{nombre_fc_new}'.\n")
else:
print(f"Error de verificación: La cantidad de elementos NO coincide entre '{nombre_fc_orig}' y '{nombre_fc_new}'.\n")

if __name__ == "__main__":
# Solicita al usuario la ruta de la geodatabase de destino
gdb_destino = input("Ingrese la ruta de la geodatabase de destino: ")

# Ruta de la tabla cod_catastrales
tabla_cod_catastrales = f"{gdb_destino}\\cod_catastrales"

# Realizar join y exportar para rustico
realizar_join_y_exportar(gdb_destino, "rA_", "r_", "rustico", tabla_cod_catastrales)

# Realizar join y exportar para urbano
realizar_join_y_exportar(gdb_destino, "uA_", "u_", "urbano", tabla_cod_catastrales)

# Verificar elementos rústicos
verificar_elementos(gdb_destino, "rA_", "r_", "rustico")

# Verificar elementos para urbano
verificar_elementos(gdb_destino, "uA_", "u_", "urbano")

 

 

alguien sabe como resolverlo?

 

Gracias

 

 

Tags (3)
0 Kudos
1 Reply
HaydenWelch
Occasional Contributor II

Here's an implementation of a FeatureJoiner class that should help:

import arcpy
import os 
from typing import Self

class FeatureJoiner():
    def __init__(self, path: os.PathLike):
        self.path = path
        self.describe = arcpy.Describe(path)
        self.name = self.describe.name
        self.fields = self.describe.fields
        self.field_names = [field.name for field in self.fields]
        self._join_field = None
    
    @property
    def join_field(self):
        return self._join_field
    
    @join_field.setter
    def join_field(self, field_name: str):
        if field_name not in self.field_names:
            raise ValueError(f"The field '{field_name}' does not exist in the feature class")
        self._join_field = field_name
    
    @join_field.deleter
    def join_field(self):
        self._join_field = None           
    
    def create_join_features(self, other: Self, out_table: os.PathLike) -> object:
        """Create a table with the joined features.
        
        Parameters:
            other: FeatureJoiner The other FeatureJoiner object to join with.
            out_table: os.PathLike The path to the output table.
        
        Returns:
            object["FeatureClass"] The result of the join.
        """
        join = self + other
        new_features = arcpy.management.CopyFeatures(join, out_table)[0]
        return new_features
    
    def __str__(self) -> str:
        return f"{self.name}:\n\tElements: {len(self)}\n\tJoin Field: {self.join_field}"
    
    def __eq__(self, other: Self) -> bool:
        return len(self) == len(other)
    
    def __len__(self) -> int:
        return int(arcpy.management.GetCount(self.path)[0])
        
    def __add__(self, other: Self) -> arcpy.Result:
        # Make sure a join is possible
        if not self.join_field:
            raise ValueError(f"The join field has not been set for {self.name}!")
        if not isinstance(other, FeatureJoiner):
            raise TypeError(f"Unsupported operand type(s) for +: 'FeatureClass' and '{type(other)}'")
        if not other.join_field:
            raise ValueError(f"The join field has not been set for {other.name}!")
        if self != other:
            raise ValueError(f"The number of elements in {self.name} and {other.name} do not match!")
        
        # Perform the join and return the result
        layer = arcpy.management.AddJoin(self.path, self.join_field, other.path, other.join_field, "KEEP_ALL")[0]
        return layer
    
if __name__ == "__main__":
    # Get database path
    database = input("Enter the path to the geodatabase: ")
    
    # Set workspace
    arcpy.env.workspace = database
    
    # Join field
    JOIN_FIELD = "Codigo_Municipal_Catastral"
    
    # Set join table path
    tabla_cod_catastrales = FeatureJoiner(os.path.join(database, "cod_catastrales"))
    tabla_cod_catastrales.join_field = JOIN_FIELD
    
    # Suffixes
    suffixes = ["_r", "_u"]
    # Prefixes
    prefixes = ["rA_", "uA_"]
    # Datasets
    datasets = ["rustico", "urban"]
    
    for suffix, prefix, dataset in zip(suffixes, prefixes, datasets):
        for fc in arcpy.ListFeatureClasses(wildcard=f"{suffix}*", feature_dataset=dataset):
            feature = FeatureJoiner(os.path.join(database, dataset, fc))
            feature.join_field = JOIN_FIELD
            out_features = os.path.join(database, f"{prefix}{fc[len(suffix):]}")
            
            try:
                join_features = feature.create_join_features(tabla_cod_catastrales, out_features)
            except Exception as e:
                print(f"Error creating {os.path.basename(out_features)}: {e}")
                
            print(f"Created {os.path.basename(out_features)}")
            
            # Do something with the output features (join_features) here like adding them
            # to a map using arcpy.mp.<Map>.AddDataFromPath() or arcpy.management.MakeFeatureLayer()
        
0 Kudos