summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJarrod Millman <jarrod.millman@gmail.com>2022-06-16 08:06:33 -0700
committerGitHub <noreply@github.com>2022-06-16 19:06:33 +0400
commit5aa82fe30ba50cd9ca7aa3759407a069f1631b57 (patch)
tree9fbad89020ddae5cdd213b76fa6bbe6d8c7e149e
parent19dbcfb672d3462f82640e3a9a9c56583e252f20 (diff)
downloadnetworkx-5aa82fe30ba50cd9ca7aa3759407a069f1631b57.tar.gz
Remove gdal dependency (#5766)
* Remove gdal dependency * [skip ci] Rm mention of gdal from roadmap. Co-authored-by: Ross Barnowski <rossbar@berkeley.edu> Co-authored-by: Mridul Seth <seth.mridul@gmail.com>
-rw-r--r--CONTRIBUTING.rst4
-rw-r--r--INSTALL.rst5
-rw-r--r--doc/developer/deprecations.rst1
-rw-r--r--doc/developer/roadmap.rst2
-rw-r--r--doc/reference/readwrite/index.rst1
-rw-r--r--doc/reference/readwrite/nx_shp.rst10
-rw-r--r--networkx/conftest.py12
-rw-r--r--networkx/readwrite/__init__.py1
-rw-r--r--networkx/readwrite/nx_shp.py350
-rw-r--r--networkx/readwrite/tests/test_shp.py288
10 files changed, 5 insertions, 669 deletions
diff --git a/CONTRIBUTING.rst b/CONTRIBUTING.rst
index 0ad02d92..7992323d 100644
--- a/CONTRIBUTING.rst
+++ b/CONTRIBUTING.rst
@@ -47,7 +47,7 @@ Development Workflow
# Install main development and runtime dependencies of networkx
pip install -r requirements/default.txt -r requirements/test.txt -r requirements/developer.txt
#
- # (Optional) Install pygraphviz, pydot, and gdal packages
+ # (Optional) Install pygraphviz and pydot packages
# These packages require that you have your system properly configured
# and what that involves differs on various systems.
# pip install -r requirements/extra.txt
@@ -68,7 +68,7 @@ Development Workflow
# Install main development and runtime dependencies of networkx
conda install -c conda-forge --file requirements/default.txt --file requirements/test.txt --file requirements/developer.txt
#
- # (Optional) Install pygraphviz, pydot, and gdal packages
+ # (Optional) Install pygraphviz and pydot packages
# These packages require that you have your system properly configured
# and what that involves differs on various systems.
# conda install -c conda-forge --file requirements/extra.txt
diff --git a/INSTALL.rst b/INSTALL.rst
index 792c099b..e52244dd 100644
--- a/INSTALL.rst
+++ b/INSTALL.rst
@@ -78,7 +78,7 @@ Extra packages
--------------
.. note::
- Some optional packages (e.g., `gdal`) may require compiling
+ Some optional packages may require compiling
C or C++ code. If you have difficulty installing these packages
with `pip`, please consult the homepages of those packages.
@@ -90,7 +90,6 @@ version requirements.
`pydot <https://github.com/erocarrera/pydot>`_ provide graph drawing
and graph layout algorithms via `GraphViz <http://graphviz.org/>`_.
- `PyYAML <http://pyyaml.org/>`_ provides YAML format reading and writing.
-- `gdal <http://www.gdal.org/>`_ provides shapefile format reading and writing.
- `lxml <http://lxml.de/>`_ used for GraphML XML format.
To install ``networkx`` and extra packages, do::
@@ -99,7 +98,7 @@ To install ``networkx`` and extra packages, do::
To explicitly install all optional packages, do::
- $ pip install pygraphviz pydot pyyaml gdal lxml
+ $ pip install pygraphviz pydot pyyaml lxml
Or, install any optional package (e.g., ``pygraphviz``) individually::
diff --git a/doc/developer/deprecations.rst b/doc/developer/deprecations.rst
index c24ce59f..e185752b 100644
--- a/doc/developer/deprecations.rst
+++ b/doc/developer/deprecations.rst
@@ -66,7 +66,6 @@ Version 3.0
``__getattr__`` definitions from ``networkx/__init__.py``,
``networkx/readwrite/__init__.py`` and ``networkx/readwrite/nx_yaml.py`` and
remove ``networkx/readwrite/tests/test_getattr_nxyaml_removal.py``
-* Remove ``readwrite/nx_shp.py`` and related tests (add info in alternatives).
* Remove ``copy`` method in the coreview Filtered-related classes and related tests.
* In ``algorithms/link_analysis/pagerank_alg.py`` replace ``pagerank`` with ``pagerank_scipy``.
* In ``algorithms/link_analysis/pagerank_alg.py`` rename ``pagerank_numpy`` as ``_pagerank_numpy``.
diff --git a/doc/developer/roadmap.rst b/doc/developer/roadmap.rst
index f0f1b1af..93dec061 100644
--- a/doc/developer/roadmap.rst
+++ b/doc/developer/roadmap.rst
@@ -15,7 +15,7 @@ Installation
------------
We aim to make NetworkX as easy to install as possible.
-Some of our dependencies (e.g., graphviz and gdal) can be tricky to install.
+Some of our dependencies (e.g., graphviz) can be tricky to install.
Other of our dependencies are easy to install on the CPython platform, but
may be more involved on other platforms such as PyPy.
Addressing these installation issues may involve working with the external projects.
diff --git a/doc/reference/readwrite/index.rst b/doc/reference/readwrite/index.rst
index 4601498b..ad852e3e 100644
--- a/doc/reference/readwrite/index.rst
+++ b/doc/reference/readwrite/index.rst
@@ -17,5 +17,4 @@ Reading and writing graphs
leda
sparsegraph6
pajek
- nx_shp
matrix_market
diff --git a/doc/reference/readwrite/nx_shp.rst b/doc/reference/readwrite/nx_shp.rst
deleted file mode 100644
index 47507624..00000000
--- a/doc/reference/readwrite/nx_shp.rst
+++ /dev/null
@@ -1,10 +0,0 @@
-GIS Shapefile
-=============
-.. automodule:: networkx.readwrite.nx_shp
-.. autosummary::
- :toctree: generated/
-
- read_shp
- write_shp
-
-
diff --git a/networkx/conftest.py b/networkx/conftest.py
index 600b3754..ad146c52 100644
--- a/networkx/conftest.py
+++ b/networkx/conftest.py
@@ -83,8 +83,6 @@ def set_warnings():
warnings.filterwarnings(
"ignore", category=DeprecationWarning, message="networkx.pagerank_scipy"
)
- warnings.filterwarnings("ignore", category=DeprecationWarning, message="write_shp")
- warnings.filterwarnings("ignore", category=DeprecationWarning, message="read_shp")
warnings.filterwarnings(
"ignore", category=DeprecationWarning, message="edges_from_line"
)
@@ -241,13 +239,6 @@ except ImportError:
has_pydot = False
try:
- import ogr
-
- has_ogr = True
-except ImportError:
- has_ogr = False
-
-try:
import sympy
has_sympy = True
@@ -303,7 +294,6 @@ needs_pandas = ["convert_matrix.py"]
needs_yaml = ["readwrite/nx_yaml.py"]
needs_pygraphviz = ["drawing/nx_agraph.py"]
needs_pydot = ["drawing/nx_pydot.py"]
-needs_ogr = ["readwrite/nx_shp.py"]
needs_sympy = ["algorithms/polynomials.py"]
if not has_numpy:
@@ -320,8 +310,6 @@ if not has_pygraphviz:
collect_ignore += needs_pygraphviz
if not has_pydot:
collect_ignore += needs_pydot
-if not has_ogr:
- collect_ignore += needs_ogr
if not has_sympy:
collect_ignore += needs_sympy
diff --git a/networkx/readwrite/__init__.py b/networkx/readwrite/__init__.py
index 85d4edd9..d6d4f532 100644
--- a/networkx/readwrite/__init__.py
+++ b/networkx/readwrite/__init__.py
@@ -54,6 +54,5 @@ from networkx.readwrite.graph6 import *
from networkx.readwrite.gml import *
from networkx.readwrite.graphml import *
from networkx.readwrite.gexf import *
-from networkx.readwrite.nx_shp import *
from networkx.readwrite.json_graph import *
from networkx.readwrite.text import *
diff --git a/networkx/readwrite/nx_shp.py b/networkx/readwrite/nx_shp.py
deleted file mode 100644
index dd487120..00000000
--- a/networkx/readwrite/nx_shp.py
+++ /dev/null
@@ -1,350 +0,0 @@
-"""
-*********
-Shapefile
-*********
-
-Generates a networkx.DiGraph from point and line shapefiles.
-
-"The Esri Shapefile or simply a shapefile is a popular geospatial vector
-data format for geographic information systems software. It is developed
-and regulated by Esri as a (mostly) open specification for data
-interoperability among Esri and other software products."
-See https://en.wikipedia.org/wiki/Shapefile for additional information.
-"""
-import warnings
-
-import networkx as nx
-
-__all__ = ["read_shp", "write_shp"]
-
-
-def read_shp(path, simplify=True, geom_attrs=True, strict=True):
- """Generates a networkx.DiGraph from shapefiles.
-
- .. deprecated:: 2.6
-
- read_shp is deprecated and will be removed in NetworkX 3.0.
- See https://networkx.org/documentation/latest/auto_examples/index.html#geospatial.
-
- Point geometries are
- translated into nodes, lines into edges. Coordinate tuples are used as
- keys. Attributes are preserved, line geometries are simplified into start
- and end coordinates. Accepts a single shapefile or directory of many
- shapefiles.
-
- "The Esri Shapefile or simply a shapefile is a popular geospatial vector
- data format for geographic information systems software [1]_."
-
- Parameters
- ----------
- path : file or string
- File, directory, or filename to read.
-
- simplify: bool
- If True, simplify line geometries to start and end coordinates.
- If False, and line feature geometry has multiple segments, the
- non-geometric attributes for that feature will be repeated for each
- edge comprising that feature.
-
- geom_attrs: bool
- If True, include the Wkb, Wkt and Json geometry attributes with
- each edge.
-
- NOTE: if these attributes are available, write_shp will use them
- to write the geometry. If nodes store the underlying coordinates for
- the edge geometry as well (as they do when they are read via
- this method) and they change, your geomety will be out of sync.
-
- strict: bool
- If True, raise NetworkXError when feature geometry is missing or
- GeometryType is not supported.
- If False, silently ignore missing or unsupported geometry in features.
-
- Returns
- -------
- G : NetworkX graph
-
- Raises
- ------
- ImportError
- If ogr module is not available.
-
- RuntimeError
- If file cannot be open or read.
-
- NetworkXError
- If strict=True and feature is missing geometry or GeometryType is
- not supported.
-
- Examples
- --------
- >>> G = nx.read_shp("test.shp") # doctest: +SKIP
-
- References
- ----------
- .. [1] https://en.wikipedia.org/wiki/Shapefile
- """
- msg = (
- "read_shp is deprecated and will be removed in 3.0."
- "See https://networkx.org/documentation/latest/auto_examples/index.html#geospatial."
- )
- warnings.warn(msg, DeprecationWarning, stacklevel=2)
- try:
- from osgeo import ogr
- except ImportError as err:
- raise ImportError("read_shp requires OGR: http://www.gdal.org/") from err
-
- if not isinstance(path, str):
- return
-
- net = nx.DiGraph()
- shp = ogr.Open(path)
- if shp is None:
- raise RuntimeError(f"Unable to open {path}")
- for lyr in shp:
- fields = [x.GetName() for x in lyr.schema]
- for f in lyr:
- g = f.geometry()
- if g is None:
- if strict:
- raise nx.NetworkXError("Bad data: feature missing geometry")
- else:
- continue
- flddata = [f.GetField(f.GetFieldIndex(x)) for x in fields]
- attributes = dict(zip(fields, flddata))
- attributes["ShpName"] = lyr.GetName()
- # Note: Using layer level geometry type
- if g.GetGeometryType() == ogr.wkbPoint:
- net.add_node((g.GetPoint_2D(0)), **attributes)
- elif g.GetGeometryType() in (ogr.wkbLineString, ogr.wkbMultiLineString):
- for edge in edges_from_line(g, attributes, simplify, geom_attrs):
- e1, e2, attr = edge
- net.add_edge(e1, e2)
- net[e1][e2].update(attr)
- else:
- if strict:
- raise nx.NetworkXError(
- f"GeometryType {g.GetGeometryType()} not supported"
- )
-
- return net
-
-
-def edges_from_line(geom, attrs, simplify=True, geom_attrs=True):
- """
- Generate edges for each line in geom
- Written as a helper for read_shp
-
- Parameters
- ----------
-
- geom: ogr line geometry
- To be converted into an edge or edges
-
- attrs: dict
- Attributes to be associated with all geoms
-
- simplify: bool
- If True, simplify the line as in read_shp
-
- geom_attrs: bool
- If True, add geom attributes to edge as in read_shp
-
-
- Returns
- -------
- edges: generator of edges
- each edge is a tuple of form
- (node1_coord, node2_coord, attribute_dict)
- suitable for expanding into a networkx Graph add_edge call
-
- .. deprecated:: 2.6
- """
- msg = (
- "edges_from_line is deprecated and will be removed in 3.0."
- "See https://networkx.org/documentation/latest/auto_examples/index.html#geospatial."
- )
- warnings.warn(msg, DeprecationWarning, stacklevel=2)
- try:
- from osgeo import ogr
- except ImportError as err:
- raise ImportError(
- "edges_from_line requires OGR: " "http://www.gdal.org/"
- ) from err
-
- if geom.GetGeometryType() == ogr.wkbLineString:
- if simplify:
- edge_attrs = attrs.copy()
- last = geom.GetPointCount() - 1
- if geom_attrs:
- edge_attrs["Wkb"] = geom.ExportToWkb()
- edge_attrs["Wkt"] = geom.ExportToWkt()
- edge_attrs["Json"] = geom.ExportToJson()
- yield (geom.GetPoint_2D(0), geom.GetPoint_2D(last), edge_attrs)
- else:
- for i in range(0, geom.GetPointCount() - 1):
- pt1 = geom.GetPoint_2D(i)
- pt2 = geom.GetPoint_2D(i + 1)
- edge_attrs = attrs.copy()
- if geom_attrs:
- segment = ogr.Geometry(ogr.wkbLineString)
- segment.AddPoint_2D(pt1[0], pt1[1])
- segment.AddPoint_2D(pt2[0], pt2[1])
- edge_attrs["Wkb"] = segment.ExportToWkb()
- edge_attrs["Wkt"] = segment.ExportToWkt()
- edge_attrs["Json"] = segment.ExportToJson()
- del segment
- yield (pt1, pt2, edge_attrs)
-
- elif geom.GetGeometryType() == ogr.wkbMultiLineString:
- for i in range(geom.GetGeometryCount()):
- geom_i = geom.GetGeometryRef(i)
- yield from edges_from_line(geom_i, attrs, simplify, geom_attrs)
-
-
-def write_shp(G, outdir):
- """Writes a networkx.DiGraph to two shapefiles, edges and nodes.
-
- .. deprecated:: 2.6
-
- write_shp is deprecated and will be removed in 3.0.
- See https://networkx.org/documentation/latest/auto_examples/index.html#geospatial.
-
- Nodes and edges are expected to have a Well Known Binary (Wkb) or
- Well Known Text (Wkt) key in order to generate geometries. Also
- acceptable are nodes with a numeric tuple key (x,y).
-
- "The Esri Shapefile or simply a shapefile is a popular geospatial vector
- data format for geographic information systems software [1]_."
-
- Parameters
- ----------
- G : NetworkX graph
- Directed graph
- outdir : directory path
- Output directory for the two shapefiles.
-
- Returns
- -------
- None
-
- Examples
- --------
- nx.write_shp(digraph, '/shapefiles') # doctest +SKIP
-
- References
- ----------
- .. [1] https://en.wikipedia.org/wiki/Shapefile
- """
- msg = (
- "write_shp is deprecated and will be removed in 3.0."
- "See https://networkx.org/documentation/latest/auto_examples/index.html#geospatial."
- )
- warnings.warn(msg, DeprecationWarning, stacklevel=2)
- try:
- from osgeo import ogr
- except ImportError as err:
- raise ImportError("write_shp requires OGR: http://www.gdal.org/") from err
- # easier to debug in python if ogr throws exceptions
- ogr.UseExceptions()
-
- def netgeometry(key, data):
- if "Wkb" in data:
- geom = ogr.CreateGeometryFromWkb(data["Wkb"])
- elif "Wkt" in data:
- geom = ogr.CreateGeometryFromWkt(data["Wkt"])
- elif type(key[0]).__name__ == "tuple": # edge keys are packed tuples
- geom = ogr.Geometry(ogr.wkbLineString)
- _from, _to = key[0], key[1]
- try:
- geom.SetPoint(0, *_from)
- geom.SetPoint(1, *_to)
- except TypeError:
- # assume user used tuple of int and choked ogr
- _ffrom = [float(x) for x in _from]
- _fto = [float(x) for x in _to]
- geom.SetPoint(0, *_ffrom)
- geom.SetPoint(1, *_fto)
- else:
- geom = ogr.Geometry(ogr.wkbPoint)
- try:
- geom.SetPoint(0, *key)
- except TypeError:
- # assume user used tuple of int and choked ogr
- fkey = [float(x) for x in key]
- geom.SetPoint(0, *fkey)
-
- return geom
-
- # Create_feature with new optional attributes arg (should be dict type)
- def create_feature(geometry, lyr, attributes=None):
- feature = ogr.Feature(lyr.GetLayerDefn())
- feature.SetGeometry(g)
- if attributes is not None:
- # Loop through attributes, assigning data to each field
- for field, data in attributes.items():
- feature.SetField(field, data)
- lyr.CreateFeature(feature)
- feature.Destroy()
-
- # Conversion dict between python and ogr types
- OGRTypes = {int: ogr.OFTInteger, str: ogr.OFTString, float: ogr.OFTReal}
-
- # Check/add fields from attribute data to Shapefile layers
- def add_fields_to_layer(key, value, fields, layer):
- # Field not in previous edges so add to dict
- if type(value) in OGRTypes:
- fields[key] = OGRTypes[type(value)]
- else:
- # Data type not supported, default to string (char 80)
- fields[key] = ogr.OFTString
- # Create the new field
- newfield = ogr.FieldDefn(key, fields[key])
- layer.CreateField(newfield)
-
- drv = ogr.GetDriverByName("ESRI Shapefile")
- shpdir = drv.CreateDataSource(outdir)
- # delete pre-existing output first otherwise ogr chokes
- try:
- shpdir.DeleteLayer("nodes")
- except:
- pass
- nodes = shpdir.CreateLayer("nodes", None, ogr.wkbPoint)
-
- # Storage for node field names and their data types
- node_fields = {}
-
- def create_attributes(data, fields, layer):
- attributes = {} # storage for attribute data (indexed by field names)
- for key, value in data.items():
- # Reject spatial data not required for attribute table
- if key != "Json" and key != "Wkt" and key != "Wkb" and key != "ShpName":
- # Check/add field and data type to fields dict
- if key not in fields:
- add_fields_to_layer(key, value, fields, layer)
- # Store the data from new field to dict for CreateLayer()
- attributes[key] = value
- return attributes, layer
-
- for n in G:
- data = G.nodes[n]
- g = netgeometry(n, data)
- attributes, nodes = create_attributes(data, node_fields, nodes)
- create_feature(g, nodes, attributes)
-
- try:
- shpdir.DeleteLayer("edges")
- except:
- pass
- edges = shpdir.CreateLayer("edges", None, ogr.wkbLineString)
-
- # New edge attribute write support merged into edge loop
- edge_fields = {} # storage for field names and their data types
-
- for edge in G.edges(data=True):
- data = G.get_edge_data(*edge)
- g = netgeometry(edge, data)
- attributes, edges = create_attributes(edge[2], edge_fields, edges)
- create_feature(g, edges, attributes)
-
- nodes, edges = None, None
diff --git a/networkx/readwrite/tests/test_shp.py b/networkx/readwrite/tests/test_shp.py
deleted file mode 100644
index 7ada2e86..00000000
--- a/networkx/readwrite/tests/test_shp.py
+++ /dev/null
@@ -1,288 +0,0 @@
-"""Unit tests for shp.
-"""
-
-import os
-import tempfile
-
-import pytest
-
-ogr = pytest.importorskip("osgeo.ogr")
-
-import networkx as nx
-
-
-class TestShp:
- def setup_method(self):
- def createlayer(driver, layerType=ogr.wkbLineString):
- lyr = driver.CreateLayer("edges", None, layerType)
- namedef = ogr.FieldDefn("Name", ogr.OFTString)
- namedef.SetWidth(32)
- lyr.CreateField(namedef)
- return lyr
-
- drv = ogr.GetDriverByName("ESRI Shapefile")
-
- testdir = os.path.join(tempfile.gettempdir(), "shpdir")
- shppath = os.path.join(tempfile.gettempdir(), "tmpshp.shp")
- multi_shppath = os.path.join(tempfile.gettempdir(), "tmp_mshp.shp")
-
- self.deletetmp(drv, testdir, shppath, multi_shppath)
- os.mkdir(testdir)
-
- self.names = ["a", "b", "c", "c"] # edgenames
- self.paths = (
- [(1.0, 1.0), (2.0, 2.0)],
- [(2.0, 2.0), (3.0, 3.0)],
- [(0.9, 0.9), (4.0, 0.9), (4.0, 2.0)],
- )
-
- self.simplified_names = ["a", "b", "c"] # edgenames
- self.simplified_paths = (
- [(1.0, 1.0), (2.0, 2.0)],
- [(2.0, 2.0), (3.0, 3.0)],
- [(0.9, 0.9), (4.0, 2.0)],
- )
-
- self.multi_names = ["a", "a", "a", "a"] # edgenames
-
- shp = drv.CreateDataSource(shppath)
- lyr = createlayer(shp)
-
- for path, name in zip(self.paths, self.names):
- feat = ogr.Feature(lyr.GetLayerDefn())
- g = ogr.Geometry(ogr.wkbLineString)
- for p in path:
- g.AddPoint_2D(*p)
- feat.SetGeometry(g)
- feat.SetField("Name", name)
- lyr.CreateFeature(feat)
-
- # create single record multiline shapefile for testing
- multi_shp = drv.CreateDataSource(multi_shppath)
- multi_lyr = createlayer(multi_shp, ogr.wkbMultiLineString)
-
- multi_g = ogr.Geometry(ogr.wkbMultiLineString)
- for path in self.paths:
-
- g = ogr.Geometry(ogr.wkbLineString)
- for p in path:
- g.AddPoint_2D(*p)
-
- multi_g.AddGeometry(g)
-
- multi_feat = ogr.Feature(multi_lyr.GetLayerDefn())
- multi_feat.SetGeometry(multi_g)
- multi_feat.SetField("Name", "a")
- multi_lyr.CreateFeature(multi_feat)
-
- self.shppath = shppath
- self.multi_shppath = multi_shppath
- self.testdir = testdir
- self.drv = drv
-
- def deletetmp(self, drv, *paths):
- for p in paths:
- if os.path.exists(p):
- drv.DeleteDataSource(p)
-
- def testload(self):
- def compare_graph_paths_names(g, paths, names):
- expected = nx.DiGraph()
- for p in paths:
- nx.add_path(expected, p)
- assert sorted(expected.nodes) == sorted(g.nodes)
- assert sorted(expected.edges()) == sorted(g.edges())
- g_names = [g.get_edge_data(s, e)["Name"] for s, e in g.edges()]
- assert names == sorted(g_names)
-
- # simplified
- G = nx.read_shp(self.shppath)
- compare_graph_paths_names(G, self.simplified_paths, self.simplified_names)
-
- # unsimplified
- G = nx.read_shp(self.shppath, simplify=False)
- compare_graph_paths_names(G, self.paths, self.names)
-
- # multiline unsimplified
- G = nx.read_shp(self.multi_shppath, simplify=False)
- compare_graph_paths_names(G, self.paths, self.multi_names)
-
- def checkgeom(self, lyr, expected):
- feature = lyr.GetNextFeature()
- actualwkt = []
- while feature:
- actualwkt.append(feature.GetGeometryRef().ExportToWkt())
- feature = lyr.GetNextFeature()
- assert sorted(expected) == sorted(actualwkt)
-
- def test_geometryexport(self):
- expectedpoints_simple = (
- "POINT (1 1)",
- "POINT (2 2)",
- "POINT (3 3)",
- "POINT (0.9 0.9)",
- "POINT (4 2)",
- )
- expectedlines_simple = (
- "LINESTRING (1 1,2 2)",
- "LINESTRING (2 2,3 3)",
- "LINESTRING (0.9 0.9,4.0 0.9,4 2)",
- )
- expectedpoints = (
- "POINT (1 1)",
- "POINT (2 2)",
- "POINT (3 3)",
- "POINT (0.9 0.9)",
- "POINT (4.0 0.9)",
- "POINT (4 2)",
- )
- expectedlines = (
- "LINESTRING (1 1,2 2)",
- "LINESTRING (2 2,3 3)",
- "LINESTRING (0.9 0.9,4.0 0.9)",
- "LINESTRING (4.0 0.9,4 2)",
- )
-
- tpath = os.path.join(tempfile.gettempdir(), "shpdir")
- G = nx.read_shp(self.shppath)
- nx.write_shp(G, tpath)
- shpdir = ogr.Open(tpath)
- self.checkgeom(shpdir.GetLayerByName("nodes"), expectedpoints_simple)
- self.checkgeom(shpdir.GetLayerByName("edges"), expectedlines_simple)
-
- # Test unsimplified
- # Nodes should have additional point,
- # edges should be 'flattened'
- G = nx.read_shp(self.shppath, simplify=False)
- nx.write_shp(G, tpath)
- shpdir = ogr.Open(tpath)
- self.checkgeom(shpdir.GetLayerByName("nodes"), expectedpoints)
- self.checkgeom(shpdir.GetLayerByName("edges"), expectedlines)
-
- def test_attributeexport(self):
- def testattributes(lyr, graph):
- feature = lyr.GetNextFeature()
- while feature:
- coords = []
- ref = feature.GetGeometryRef()
- last = ref.GetPointCount() - 1
- edge_nodes = (ref.GetPoint_2D(0), ref.GetPoint_2D(last))
- name = feature.GetFieldAsString("Name")
- assert graph.get_edge_data(*edge_nodes)["Name"] == name
- feature = lyr.GetNextFeature()
-
- tpath = os.path.join(tempfile.gettempdir(), "shpdir")
-
- G = nx.read_shp(self.shppath)
- nx.write_shp(G, tpath)
- shpdir = ogr.Open(tpath)
- edges = shpdir.GetLayerByName("edges")
- testattributes(edges, G)
-
- # Test export of node attributes in nx.write_shp (#2778)
- def test_nodeattributeexport(self):
- tpath = os.path.join(tempfile.gettempdir(), "shpdir")
-
- G = nx.DiGraph()
- A = (0, 0)
- B = (1, 1)
- C = (2, 2)
- G.add_edge(A, B)
- G.add_edge(A, C)
- label = "node_label"
- for n, d in G.nodes(data=True):
- d["label"] = label
- nx.write_shp(G, tpath)
-
- H = nx.read_shp(tpath)
- for n, d in H.nodes(data=True):
- assert d["label"] == label
-
- def test_wkt_export(self):
- G = nx.DiGraph()
- tpath = os.path.join(tempfile.gettempdir(), "shpdir")
- points = ("POINT (0.9 0.9)", "POINT (4 2)")
- line = ("LINESTRING (0.9 0.9,4 2)",)
- G.add_node(1, Wkt=points[0])
- G.add_node(2, Wkt=points[1])
- G.add_edge(1, 2, Wkt=line[0])
- try:
- nx.write_shp(G, tpath)
- except Exception as err:
- assert False, err
- shpdir = ogr.Open(tpath)
- self.checkgeom(shpdir.GetLayerByName("nodes"), points)
- self.checkgeom(shpdir.GetLayerByName("edges"), line)
-
- def teardown_method(self):
- self.deletetmp(self.drv, self.testdir, self.shppath)
-
-
-def test_read_shp_nofile():
- with pytest.raises(RuntimeError):
- G = nx.read_shp("hopefully_this_file_will_not_be_available")
-
-
-class TestMissingGeometry:
- def setup_method(self):
- self.setup_path()
- self.delete_shapedir()
- self.create_shapedir()
-
- def teardown_method(self):
- self.delete_shapedir()
-
- def setup_path(self):
- self.path = os.path.join(tempfile.gettempdir(), "missing_geometry")
-
- def create_shapedir(self):
- drv = ogr.GetDriverByName("ESRI Shapefile")
- shp = drv.CreateDataSource(self.path)
- lyr = shp.CreateLayer("nodes", None, ogr.wkbPoint)
- feature = ogr.Feature(lyr.GetLayerDefn())
- feature.SetGeometry(None)
- lyr.CreateFeature(feature)
- feature.Destroy()
-
- def delete_shapedir(self):
- drv = ogr.GetDriverByName("ESRI Shapefile")
- if os.path.exists(self.path):
- drv.DeleteDataSource(self.path)
-
- def test_missing_geometry(self):
- with pytest.raises(nx.NetworkXError):
- G = nx.read_shp(self.path)
-
-
-class TestMissingAttrWrite:
- def setup_method(self):
- self.setup_path()
- self.delete_shapedir()
-
- def teardown_method(self):
- self.delete_shapedir()
-
- def setup_path(self):
- self.path = os.path.join(tempfile.gettempdir(), "missing_attributes")
-
- def delete_shapedir(self):
- drv = ogr.GetDriverByName("ESRI Shapefile")
- if os.path.exists(self.path):
- drv.DeleteDataSource(self.path)
-
- def test_missing_attributes(self):
- G = nx.DiGraph()
- A = (0, 0)
- B = (1, 1)
- C = (2, 2)
- G.add_edge(A, B, foo=100)
- G.add_edge(A, C)
-
- nx.write_shp(G, self.path)
- H = nx.read_shp(self.path)
-
- for u, v, d in H.edges(data=True):
- if u == A and v == B:
- assert d["foo"] == 100
- if u == A and v == C:
- assert d["foo"] is None