Skip to main content
Pre-release

This release is a pre-release and may not be stable for production use.

TopoJSON

PyPI version License

[Ready for Beta Users!]

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 in multiple different ways, with the purpose to create a TopoJSON topology:

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]]]}
]

tj = topojson.Topology(data, prequantize=False, topology=True)
tj.to_json()
{"type": "Topology", "linestrings": [[[1.0, 0.0], [0.0, 0.0], [0.0, 1.0], [1.0, 1.0]], [[1.0, 0.0], [1.0, 1.0]], [[1.0, 1.0], [2.0, 1.0], [2.0, 0.0], [1.0, 0.0]]], "objects": {"data": {"geometries": [{"type": "Polygon", "arcs": [[-2, 0]]}, {"type": "Polygon", "arcs": [[1, 2]]}], "type": "GeometryCollection"}}, "bbox": [0.0, 0.0, 2.0, 1.0], "arcs": [[[1.0, 0.0], [0.0, 0.0], [0.0, 1.0], [1.0, 1.0]], [[1.0, 0.0], [1.0, 1.0]], [[1.0, 1.0], [2.0, 1.0], [2.0, 0.0], [1.0, 0.0]]]}

This 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.0rc3. Installation can be done by:

python3 -m pip install topojson

The required dependencies are:

  • numpy
  • shapely
  • simplification
  • geojson

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.

For better experience make sure you have altair installed as well. For the interactive experience also install ipywidgets.

Examples and tutorial notebooks

Input 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]]]}
]

apply Topology and present the output as dict

tj = topojson.Topology(data, prequantize=False, topology=True)
tj.to_dict()
{'type': 'Topology',
 'linestrings': [[[1.0, 0.0], [0.0, 0.0], [0.0, 1.0], [1.0, 1.0]],
  [[1.0, 0.0], [1.0, 1.0]],
  [[1.0, 1.0], [2.0, 1.0], [2.0, 0.0], [1.0, 0.0]]],
 'objects': {'data': {'geometries': [{'type': 'Polygon', 'arcs': [[-2, 0]]},
    {'type': 'Polygon', 'arcs': [[1, 2]]}],
   'type': 'GeometryCollection'}},
 'options': TopoOptions(
   {'prequantize': False,
  'presimplify': False,
  'simplify_with': 'shapely',
  'topology': True,
  'topoquantize': False,
  'toposimplify': 0.0001,
  'winding_order': 'CW_CCW'}
 ),
 'bbox': (0.0, 0.0, 2.0, 1.0),
 'arcs': [[[1.0, 0.0], [0.0, 0.0], [0.0, 1.0], [1.0, 1.0]],
  [[1.0, 0.0], [1.0, 1.0]],
  [[1.0, 1.0], [2.0, 1.0], [2.0, 0.0], [1.0, 0.0]]]}

Input Type: dict

The dictionary should be structured like {key1: obj1, key2: obj2}.

import topojson

dictionary = {
    0: {
        "type": "Polygon",
        "coordinates": [[[0, 0], [1, 0], [1, 1], [0, 1], [0, 0]]],
    },
    1: {
        "type": "Polygon",
        "coordinates": [[[1, 0], [2, 0], [2, 1], [1, 1], [1, 0]]],
    }
}

apply Topology and present the output as scalable vector graphic

tj = topojson.Topology(dictionary, prequantize=False, topology=True)
tj.to_svg()
svg

Input 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))
geodataframe

apply Topology and present output as altair chart (if installed)

tj = topojson.Topology(gdf, prequantize=False, topology=True)
tj.to_alt(color='properties.name:N')
altair

Input 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])

apply Topology and present output as geodataframe (if geopandas is installed)

tj = topojson.Topology(feature_collection, prequantize=False, topology=True)
tj.to_gdf()
geometry id name
0 POLYGON ((1 1, 1 0, 0 0, 0 1, 1 1)) None abc
1 POLYGON ((1 0, 1 1, 2 1, 2 0, 1 0)) None def

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.0rc3:

  • TODO

Version 1.0rc2:

  • apply linemerge on non-duplicate arcs
  • fix computing topology without shared boundaries (#1, #3)
  • use geopandas and geojson 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, use SRTtree from shapely instead

Version 1.0rc1:

  • initial release

Development Notes

Development of this packages started by reading:

The reason for development of this package was the willingness:

  • To adopt shapely (GEOS) and numpy for the core-functionalities in deriving the Topology.
  • To provide integration with other geographical packages within the Python ecosystem (eg. geopandas and altair).
  • Also the possibility of including the many tests available in the JavaScript implementation was hoped-for.

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:

  1. The extraction class stores all the different geometrical objects as Shapely LineStrings in linestrings and keeps a record of these linestrings available under the key bookkeeping_geoms. In the JavaScript implementation there is a differentiation of the geometries between lines, rings and a seperate object containing all coordinates. Since the current approach adopts shapely for much of the heavy lifting this extraction is working against us (in the cut-process).

  2. 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.

  3. 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.

  4. 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 non-duplicate arcs of a geometry containing at least one shared arc.

Metadata

Release files for topojson 1.0rc4

For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.

Source distribution (sdist)

Source distribution for topojson 1.0rc4
File Size Uploaded
topojson-1.0rc4.tar.gz 4.3 MB Details

Built distribution (wheel)

Table of built distributions (wheels) for topojson 1.0rc4
File Interpreter ABI Platform
topojson-1.0rc4-py2.py3-none-any.whl Python 3, Python 2 none any Details

Total release size: 4.4 MB

Release files / topojson-1.0rc4.tar.gz

Download URL topojson-1.0rc4.tar.gz
Size 4.3 MB
Tags Source
SHA-256 checksum
How to use checksums
c65a733140c5d01bbc7784f67a668acb5fd4b255b56efbf1a114df0d166343e4
BLAKE2b-256 checksum
How to use checksums
961d60e1ab41b9acf6aff1f6cbc7992490ce027cffa1abd4fcd7afe4d6c497a8
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via python-requests/2.19.1

Release files / topojson-1.0rc4-py2.py3-none-any.whl

Download URL topojson-1.0rc4-py2.py3-none-any.whl
Size 101.4 kB
Tags Python 2 Python 3
SHA-256 checksum
How to use checksums
2c07da901515db4176aafbd82b5ece783eb9de482f7b6b3e3cdbe2fa2c86ff3b
BLAKE2b-256 checksum
How to use checksums
ea2f36575294e5957e5dac06f14fd968450c3fb0b63320ca9f89c90fdbba47cc
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via python-requests/2.19.1
Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page