26 votos

Encontrar todos los vecinos utilizando GeoPandas

Me pregunto si es posible identificar a todos los vecinos de cada polígono utilizando sólo Python (con, por ejemplo, GeoPandas) de la misma manera que se puede hacer con Python en QGIS ( Encontrar vecinos polígono ).

0 votos

36voto

nitinsavant Puntos 6

El siguiente script encuentra y añade vecinos como un nuevo valor de campo unido por coma.

import geopandas as gpd

file = "C:/path/to/shapefile.shp"    

# open file
gdf = gpd.read_file(file)

# add NEIGHBORS column
gdf["NEIGHBORS"] = None  

for index, country in gdf.iterrows():   

    # get 'not disjoint' countries
    neighbors = gdf[~gdf.geometry.disjoint(country.geometry)].NAME.tolist()

    # remove own name of the country from the list
    neighbors = [ name for name in neighbors if country.NAME != name ]

    # add names of neighbors as NEIGHBORS value
    gdf.at[index, "NEIGHBORS"] = ", ".join(neighbors)

# save GeoDataFrame as a new file
gdf.to_file("c:/path/to/newfile.shp")

enter image description here

0 votos

Para más información esta gran respuesta , "la iteración en Pandas es un anti-patrón y es algo que sólo debes hacer cuando hayas agotado todas las demás opciones".

1 votos

@Taras Sí, es una gran respuesta. Si mi inglés fuera bueno, me gustaría dar respuestas así, pero me llevaría un día (tal vez días) responder a tales respuestas en inglés.

0 votos

No te preocupes @_@ Probablemente sepa a qué te refieres exactamente, esto es solo una referencia para tener en cuenta >_<

18voto

George Puntos 31

Esta es una adición a la respuesta de @Kadir (que funciona muy bien).

Por un lado, en lugar de utilizar not disjoint puede utilizar touches directamente, que hace lo mismo pero es más fácil de leer.

Si, como pregunta el OP, quieres buscar internamente para encontrar todas las geometrías vecinas en un único GeoDataFrame:

for index, row in df.iterrows():  
    neighbors = df[df.geometry.touches(row['geometry'])].name.tolist() 
    neighbors = neighbors.remove(row.name)
    df.at[index, "my_neighbors"] = ", ".join(neighbors)

Para una función relacionada, es posible que desee determinar si cada fila de un DataFrame bordea alguna otra forma en particular, potencialmente de un DataFrame diferente o de algún valor de entrada (convertido en un GeoDataFrame).

someSpecialGeometry = GEOdataframeRow['geometry'].values[0] 
df['isNeighbor'] = df.apply(lambda row: row['geometry'].touches(someSpecialGeometry), axis=1)

Esto crea una columna con valores booleanos para saber si cada fila bordea la forma de interés.

6voto

Ahmer Puntos 9

Esta es una adición adicional relacionada con el comentario de @Aaron.

Si encuentra que 'touches' no encuentra todos los polígonos vecinos como debería, es probable que se deba a la resolución de los bordes de sus polígonos, que de hecho pueden intersecarse, por lo que 'touches' los ignora.

He resuelto este problema utilizando overlaps adicionalmente a touches .

neighbors = np.array(df[df.geometry.touches(row['geometry'])].name)
#overlapping neighbors use if discrepances found with touches
overlap = np.array(df[df.geometry.overlaps(row['geometry'])].name)

neighbors = np.union1d(neighbors, overlap)

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