topojson  a powerful library to encode geographic data as topology in Python!🌍
Project description
TopoJSON
[Work in Progress]
TopoJSON encodes geographic data structures into a shared topology. This repository describes the development of a Python implementation of this TopoJSON format. A TopoJSON topology represents one or more geometries that share sequences of positions called arcs.
Usage
The package can be used as follow:
import topojson data = [ {"type": "Polygon", "coordinates": [[[0, 0], [1, 0], [1, 1], [0, 1], [0, 0]]]}, {"type": "Polygon", "coordinates": [[[1, 0], [2, 0], [2, 1], [1, 1], [1, 0]]]} ] topojson.topology(data)
{'type': 'Topology',
'objects': {'data': {'geometries': [{'type': 'Polygon', 'arcs': [[0, 4, 1]]},
{'type': 'Polygon', 'arcs': [[2, 3]]}],
'type': 'GeometryCollection'}},
'arcs': [[[0.0, 0.0], [1.0, 0.0]],
[[1.0, 1.0], [0.0, 1.0], [0.0, 0.0]],
[[1.0, 0.0], [2.0, 0.0], [2.0, 1.0], [1.0, 1.0]],
[[1.0, 1.0], [1.0, 0.0]]]}
The result is TopoJSON.
The following geometry types are registered as correct geographical input data:
geojson.Feature
geojson.FeatureCollection
geopandas.GeoDataFrame
geopandas.GeoSeries
shapely.geometry.LineString
shapely.geometry.MultiLineString
shapely.geometry.Polygon
shapely.geometry.MultiPolygon
shapely.geometry.Point
shapely.geometry.MultiPoint
shapely.geometry.GeometryCollection
dict
of objects that provide a valid__geo_interface__
list
of objects that provide a valid__geo_interface__
Installation
The package is released on PyPi as version 1.0rc2
. Installation can be done by:
python3 m pip install topojson
The required dependencies are:
numpy
shapely
simplification
Download dependencies from https://www.lfd.uci.edu/~gohlke/pythonlibs/ for Windows where possible and use pip
for Linux and Mac.
The packages geopandas
and geojson
are solely used in the tests and recognized as types with the extractor.
Examples and tutorial notebooks
Type: list
The list should contain items that supports the __geo_interface__
import topojson list_geoms = [ {"type": "Polygon", "coordinates": [[[0, 0], [1, 0], [1, 1], [0, 1], [0, 0]]]}, {"type": "Polygon", "coordinates": [[[1, 0], [2, 0], [2, 1], [1, 1], [1, 0]]]} ]
topojson.topology(list_geoms)
{'type': 'Topology', 'objects': {'data': {'geometries': [{'type': 'Polygon', 'arcs': [[3, 0]]}, {'type': 'Polygon', 'arcs': [[1, 2]]}], 'type': 'GeometryCollection'}}, 'arcs': [[[1.0, 1.0], [0.0, 1.0], [0.0, 0.0], [1.0, 0.0]], [[1.0, 0.0], [2.0, 0.0], [2.0, 1.0], [1.0, 1.0]], [[1.0, 1.0], [1.0, 0.0]]]}
Type: dict
The dictionary should be structured like {key1
: obj1
, key2
: obj2
}.
import topojson dictionary = { "abc": { "type": "Polygon", "coordinates": [[[0, 0], [1, 0], [1, 1], [0, 1], [0, 0]]], }, "def": { "type": "Polygon", "coordinates": [[[1, 0], [2, 0], [2, 1], [1, 1], [1, 0]]], } }
topojson.topology(dictionary)
{'type': 'Topology', 'objects': {'data': {'geometries': [{'type': 'Polygon', 'arcs': [[3, 0]]}, {'type': 'Polygon', 'arcs': [[1, 2]]}], 'type': 'GeometryCollection'}}, 'arcs': [[[1.0, 1.0], [0.0, 1.0], [0.0, 0.0], [1.0, 0.0]], [[1.0, 0.0], [2.0, 0.0], [2.0, 1.0], [1.0, 1.0]], [[1.0, 1.0], [1.0, 0.0]]]}
Type: GeoDataFrame
from package geopandas
(if installed)
import geopandas import topojson from shapely import geometry %matplotlib inline gdf = geopandas.GeoDataFrame({ "name": ["abc", "def"], "geometry": [ geometry.Polygon([[0, 0], [1, 0], [1, 1], [0, 1], [0, 0]]), geometry.Polygon([[1, 0], [2, 0], [2, 1], [1, 1], [1, 0]]) ] }) gdf.plot(column="name") gdf.head()
name  geometry  

0  abc  POLYGON ((0 0, 1 0, 1 1, 0 1, 0 0)) 
1  def  POLYGON ((1 0, 2 0, 2 1, 1 1, 1 0)) 
topojson.topology(gdf)
{'type': 'Topology', 'objects': {'data': {'geometries': [{'id': '0', 'type': 'Polygon', 'properties': {'name': 'abc'}, 'bbox': (0.0, 0.0, 1.0, 1.0), 'arcs': [[3, 0]]}, {'id': '1', 'type': 'Polygon', 'properties': {'name': 'def'}, 'bbox': (1.0, 0.0, 2.0, 1.0), 'arcs': [[1, 2]]}], 'type': 'GeometryCollection'}}, 'arcs': [[[1.0, 1.0], [0.0, 1.0], [0.0, 0.0], [1.0, 0.0]], [[1.0, 0.0], [2.0, 0.0], [2.0, 1.0], [1.0, 1.0]], [[1.0, 1.0], [1.0, 0.0]]]}
Type: FeatureCollection
from package geojson
(if installed)
from geojson import Feature, Polygon, FeatureCollection feature_1 = Feature( geometry=Polygon([[[0, 0], [1, 0], [1, 1], [0, 1], [0, 0]]]), properties={"name":"abc"} ) feature_2 = Feature( geometry=Polygon([[[1, 0], [2, 0], [2, 1], [1, 1], [1, 0]]]), properties={"name":"def"} ) feature_collection = FeatureCollection([feature_1, feature_2])
topojson.topology(feature_collection)
{'type': 'Topology', 'objects': {'data': {'geometries': [{"arcs": [[3, 0]], "properties": {"name": "abc"}, "type": "Polygon"}, {"arcs": [[1, 2]], "properties": {"name": "def"}, "type": "Polygon"}], 'type': 'GeometryCollection'}}, 'arcs': [[[1.0, 1.0], [0.0, 1.0], [0.0, 0.0], [1.0, 0.0]], [[1.0, 0.0], [2.0, 0.0], [2.0, 1.0], [1.0, 1.0]], [[1.0, 1.0], [1.0, 0.0]]]}
The notebooks folder of this GitHub repository also contains a Jupyter Notebook with a tutorial. The many tests as part of this package also can be used as example material.
Changelog
Version 1.0rc2
:
 apply linemerge on nonduplicate arcs
 fix computing topology without shared boundaries (#1, #3)
 use
geopandas
andgeojson
solely for tests, but recognize them as type (#2, #4)  use
simplification
as option to simplify linestrings  include option to snap vertices to grid
 removed
rdtree
as dependency, useSRTtree
fromshapely
instead
Version 1.0rc1
:
 initial release
Development Notes
Development of this packages started by reading:
 https://bost.ocks.org/mike/topology/ and https://github.com/topojson by Mike Bostocks and
 https://github.com/calvinmetcalf/topojson.py by Calvin Metcalf.
The reason for development of this package was the willingness:
 To adopt
shapely
(GEOS) andnumpy
for the corefunctionalities in deriving the Topology.  To provide integration with other geographical packages within the Python ecosystem (eg.
geopandas
andaltair
).  Also the possibility of including the many tests available in the JavaScript implementation was hopedfor.
To create a certain synergy between the JavaScript and Python implementation the same naming conventions was adopted for the processing steps (extract
, join
, cut
, dedup
, hashmap
). Even though the actual code differs significant.
Some subtile differences are existing between the JavaScript implementation and the current Python implementation for deriving the Topology. Some of these deviations are briefly mentioned here:

The extraction class stores all the different geometrical objects as Shapely LineStrings in
linestrings
and keeps a record of these linestrings available under the keybookkeeping_geoms
. In the JavaScript implementation there is a differentiation of the geometries betweenlines
,rings
and a seperate object containing allcoordinates
. Since the current approach adoptsshapely
for much of the heavy lifting this extraction is working against us (in the cutprocess). 
In the join class only the geometries that have shared paths are considered to have junctions. This means that the intersection of two crossing lines at a single coordinate is not considered as a junction. This also means that the two ends of a LineString are not automatically considered as being a junction. So if a segment starts or finish on another segment, with that coordinate being the only coordinate in common, it is not considered as a junction.

In the computation of a shared path, a junction can be created on an existing coordinate in one of the geometries. Where in the JavaScript implementation this only can be considered when both geometries contain the coordinate.

In the process of cutting lines; the rings are rotated in the JavaScript implementation to make sure they start at a junction. This reduces the number of cuts. This rotation is done before cutting. In the current Python implementation this is done differently. First the linestrings are cut using the junction coordinates and afterwards there is tried to apply a linemerge on the nonduplicate arcs of a geometry containing at least one shared arc.
Project details
Release history Release notifications
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Filename, size  File type  Python version  Upload date  Hashes 

Filename, size topojson1.0rc3py2.py3noneany.whl (98.7 kB)  File type Wheel  Python version py2.py3  Upload date  Hashes View hashes 
Filename, size topojson1.0rc3.tar.gz (4.2 MB)  File type Source  Python version None  Upload date  Hashes View hashes 
Hashes for topojson1.0rc3py2.py3noneany.whl
Algorithm  Hash digest  

SHA256  1cf64bc4bd15b5d6d331c561798cc82ab6632188ed04831a90c93d9e86be849c 

MD5  de1db7ff19e77f95d78d4867b854d63b 

BLAKE2256  ab7f1f39e6b03108073cb27fe936662eeb79d2d974ad4dcf09da74617ae9f44b 