Quickstart#
Start with a GeoDataFrame of a polygon data set
that has a column with attribute values referring to absolute numbers of an
occurrence, for instance the population of counties or the voter counts in
election districts.
For this example, we prepared a sample data set that you can also download from
the GitHub repository.
This data set contains polygons showing the nine federal provinces of Austria,
with population numbers attached in a column called pop20170101.
import geopandas
df = geopandas.read_file(DATA_DIRECTORY / "Austria_PopulationByNUTS2.geojson")
df
| fid | nuts2 | pop20170101 | area_km2 | geometry | |
|---|---|---|---|---|---|
| 0 | Austria_PopulationByNUTS2.0 | AT11 | 291974 | 3957.21 | MULTIPOLYGON (((609942.82 394253.82, 609947.46... |
| 1 | Austria_PopulationByNUTS2.1 | AT21 | 561098 | 9542.04 | MULTIPOLYGON (((448385.84 340577.89, 451424.65... |
| 2 | Austria_PopulationByNUTS2.2 | AT12 | 1665815 | 19190.88 | MULTIPOLYGON (((500206.72 521459.79, 502393.35... |
| 3 | Austria_PopulationByNUTS2.3 | AT31 | 1465205 | 11974.26 | MULTIPOLYGON (((429364.86 398384.06, 429318.2 ... |
| 4 | Austria_PopulationByNUTS2.4 | AT32 | 549372 | 7132.61 | MULTIPOLYGON (((443539.12 352496.95, 443549.12... |
| 5 | Austria_PopulationByNUTS2.5 | AT22 | 1237372 | 16409.74 | MULTIPOLYGON (((448385.84 340577.89, 448354.6 ... |
| 6 | Austria_PopulationByNUTS2.6 | AT33 | 746179 | 12614.21 | MULTIPOLYGON (((183502.04 410278.82, 181681.71... |
| 7 | Austria_PopulationByNUTS2.7 | AT34 | 388711 | 2580.89 | MULTIPOLYGON (((158753.18 347618.77, 153773.88... |
| 8 | Austria_PopulationByNUTS2.8 | AT13 | 1867960 | 414.03 | MULTIPOLYGON (((629216.51 473309.2, 622571.51 ... |
df.explore(column="pop20170101", cmap="Reds")
As you can clearly see, population numbers diverge greatly. Vienna (AT13), the capital, has the highest population with almost 2 million inhabitants, while it has the smallest surface area. By contrast, Carinthia (AT21) and Tyrol (AT33), in the South and Western parts of the country, have small populations spread over a large surface area.
Let’s resize the polygons so that the relative surface area is representative of
the relative population of each province, by initialising a new instance of
Cartogram, passing a column name:
import cartogram
c = cartogram.Cartogram(df, "pop20170101")
c
| fid | nuts2 | pop20170101 | area_km2 | geometry | |
|---|---|---|---|---|---|
| 0 | Austria_PopulationByNUTS2.0 | AT11 | 291974 | 3957.21 | POLYGON ((593486.809 374150.357, 593493.328 37... |
| 1 | Austria_PopulationByNUTS2.1 | AT21 | 561098 | 9542.04 | POLYGON ((441683.591 336402.448, 443996.659 33... |
| 2 | Austria_PopulationByNUTS2.2 | AT12 | 1665815 | 19190.88 | POLYGON ((487711.786 511535.541, 489677.12 513... |
| 3 | Austria_PopulationByNUTS2.3 | AT31 | 1465205 | 11974.26 | POLYGON ((420435.459 376869.504, 420391.946 37... |
| 4 | Austria_PopulationByNUTS2.4 | AT32 | 549372 | 7132.61 | POLYGON ((437602.462 341642.897, 437610.335 34... |
| 5 | Austria_PopulationByNUTS2.5 | AT22 | 1237372 | 16409.74 | POLYGON ((441683.591 336402.448, 441659.03 336... |
| 6 | Austria_PopulationByNUTS2.6 | AT33 | 746179 | 12614.21 | MULTIPOLYGON (((304767.137 356370.148, 313725.... |
| 7 | Austria_PopulationByNUTS2.7 | AT34 | 388711 | 2580.89 | POLYGON ((177610.646 345810.215, 170725.38 339... |
| 8 | Austria_PopulationByNUTS2.8 | AT13 | 1867960 | 414.03 | POLYGON ((547561.53 496623.625, 564627.071 523... |
c.explore()
cartogram.Cartogram inherits from geopandas.GeoDataFrame, so
all of the latter’s methods and attributes are available in the result
dataframe. For instance, to save the output data set to a new file, just use
to_file():
c.to_file(DATA_DIRECTORY / "cartogram.geojson")
Fine-tuning the distortions#
The algorithm implemented in python-cartogram is an approximating, iterative approach that was first presented by Dougenik et al. (1985), and is also used by the QGIS plugin cartogram3.
Because of its iterative design, the computation becomes more precise with every
repetition. This, in turn, means longer computation times. You can control the
accuracy of the output data set using two parameters, overriding their default
values: the maximum number of iterations, and the desired average areal error
remaining in the output. The two are complimentary: if the remaining average
error is lower than the specified threshold before max_iterations is reached,
the remaining iterations are skipped.
c = cartogram.Cartogram(
df,
"pop20170101",
max_iterations=99,
max_average_error=0.05,
)
Average residual area error
The remaining error is stored in an attribute of a cartogram:
cartogram.Cartogram.average_error
c.average_error
np.float64(0.031417324873839636)
References#
Dougenik, J. A., Chrisman, N. R., & Niemeyer, D. R. (1985): An algorithm to construct continuous area cartograms. The Professional Geographer, 37(1), 75–81. DOI:10.1111/j.0033-0124.1985.00075.x