4

I have a shapefile with some polygons and I'd like to create a graph that assigns vertices to polygons and creates edges between vertices if the corresponding polygons share a border. Since I'm using networkx, a Python graph library, I was thinking of using GeoPandas to convert from the shapefile to a nx graph. Does anyone have any idea how to do this?

(networkx has a built-in read_shp method, but I don't think that's what I want; I'm pretty sure (but not confident) that that translates points to vertices and lines to edges, not polygons and borders.)

3

You could use pysal to create a contiguity matrix. This can be done from a data frame using pysal.weights.Rook.from_dataframe(args), or direct from a shapefile. You could then use this to add nodes (these are the keys in both dictionaries dictionary) and edges (a list of tuples of each key paired with each neighbour from it's value list. Something like:

import networkx as nx
import pysal

#build contiguity matrix - uses rook contiguity - queen is available
path_to_shp = r'come/path/to/file.shp'
my_keys = 'name_of_id_for_your_features'
contig_matrix = pysal.weights.Rook.from_shapefile(path_to_shp,idVariable = my_keys)

#build list of edges - this will create edges going both ways from connected nodes, so you might need to remove duplicates
nodes = contig_matrix.weights.keys() # to get dict of keys, alternatively use contig_matrix.id2i.keys()
edges = [(node,neighbour) for node in nodes for neighbour in contig_matrix[node]]
my_graph = nx.Graph(edges)
  • This is cool -- I hadn't heard of pysal! I ended up coming up with a (pretty hacky) solution, but nonetheless one that works, by creating a bunch of shapely objects and using the builtin obj.touches(other) method. – rohan Jun 21 '17 at 17:04
  • Great, always good to discover new things. Why not add your solution as an answer for others. As an aside I think pysal implements graphs too. – RoperMaps Jun 21 '17 at 20:14
1

I figured it out! The gist of the solution is this: use fiona to read in the shapefile, shapely to convert them into shapes that can be analyzed, and the shape.touches(other) method shapely provides to build the graph, as follows:

import fiona
from shapely.geometry import shape
import networkx as nx

# Converts a shapefile located at indir/infile to a networkx graph.
# If draw_graph is set to True, the graph is drawn using matplotlib.
def create_graph(indir, infile, draw_shapefile=False, draw_graph=False):
  G = nx.Graph()
  i = 1

  with cd(indir):
    with fiona.open(infile) as blocks:
      for shp in blocks:
        # the geometry property here may be specific to my shapefile
        block = shape(shp['geometry'])

        G.add_node(i)
        i += 1

  for n in G.nodes(data=True):
    state = n[1]['block']
    for o in G.nodes(data=True):
      other = o[1]['block']
      if state is not other and state.touches(other):
        G.add_edge(n[0], o[0])

  return G

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.