• Stars
    star
    143
  • Rank 257,007 (Top 6 %)
  • Language
    Python
  • Created over 13 years ago
  • Updated over 11 years ago

Reviews

There are no reviews yet. Be the first to send feedback to the community and the maintainers!

Repository Details

Map label placer with simulated annealing.

Dymo

Dymo is a placement script for map labels, isolated from the purpose-built code in GeoIQ’s Acetate. Dymo resolves positions for densely-packed point labels, and results in layouts make your maps look like they’ve been touched by a cartographer.

Dymo uses Simulated Annealing to derive an acceptable global label set, described in Steven Wouderberg’s October 2007 presentation at Utrecht University. See an animation of the process over time in these two videos of U.S. and European place names:

QUICK START

Demo area: Run make geojson to anneal labels for San Francisco and Israel sample areas from zooms 4 to 10. This will automatically build the data files, too (eg: make data). Should run in less than an hour.

World: Annealing the entire world will take several days to several weeks and will require lots of RAM and many processor cores. Modify the Makefile to remove the spatial filter as below:

# COMPOSITE FILTER (fast!)
# SPATIAL_FILTER=  --filter-bounding-box $(FILTER_SANFRANCISCO) --filter-bounding-box $(FILTER_JERUSALEM)
# NO FILTER (slow! If no filter is desired, uncomment line below, comment out line above.)
SPATIAL_FILTER=

You can change the fonts and population steps in the Makefile, too.

DETAILS

dymo-label.py is a script that converts lists of cities with included font information to GeoJSON point and label files suitable for use in geographic rendering.

Mamata Akella at the National Park Service has written a detailed tutorial on Dymo and Tile Mill, to “avoid label overlaps and improve the overall legibility of park names dramatically.” The tutorial shows how to prepare data for Dymo using ArcGIS Desktop.

###Label Usage

Place U.S. city labels at zoom 6 for two minutes:

python dymo-label.py -z 6 --minutes 2 --labels-file labels.json --places-file points.json data/US-z6.csv.gz

Place U.S. city labels at zoom 5 over a 10000-iteration 10.0 - 0.01 temperature range:

python dymo-label.py -z 5 --steps 10000 --max-temp 10 --min-temp 0.01 -l labels.json -p points.json data/US-z5.csv

Both examples will result in a pair of GeoJSON files, labels.json and points.json. The first will contain rectangular label areas, the second will contain center points of places successfully positioned by Dymo. Because labels will collide in different ways depending on map scale, labels must be placed separately for each zoom level:

U.S. Labels

For larger datasets, it’s almost always faster to run dymo-label.py with the --minutes option instead of --min-temp/--max-temp, because Dymo will automatically partition labels based on mutual overlaps and perform many small annealing processes.

Data Included

Look in data/ for a list of zoom-by-zoom city locations, organized by continent and selected by Justin O’Bierne. Data is distributed separately from code, see downloads for a link.

To prepare your own city lists or modify fonts and font sizes in input lists, Use dymo-prepare-places.py to apply population-specific font choices to an in-bound list.

###Prepare-Places Usage

python dymo-prepare-places.py --font 0 fonts/Arial.ttf 10 --font 1000000 fonts/Arial.ttf 12 --zoom 5 data/North-America-all.txt.gz data/North-America-z5.txt

Sample Output

These sample images were created during the development of Acetate, and show the results of town placement.

Central Japan:

Central Japan

Western Europe:

Western Europe

Northen Appalachians:

Northen Appalachians

Advanced Options

###Dymo Prepare Places

  • -z ZOOM, --zoom=ZOOM - Maximum zoom level. Default value is 4.
  • --zoom-field=ZOOM_FIELD - Field to use for limiting selection by zoom. Default field is zoom start.
  • -f FONTS, --font=FONTS - Additional font, in the form of three values: minimum population number (or other font field), font file path, font size. Can be specified multiple times.
  • -r RADIUS, --radius=RADIUS - Pixel buffer around each place. Default value is 0.
  • --font-field=FONT_FIELD - Field to use for font selection. Default field is population.
  • --filter-field=FILTER_FIELD - Field to use for limiting selection by theme and the value to limit by. Default is no filter.
  • --symbol-size=SYMBOL_SIZE - Size in pixels for implied townspot symbol width/height in pixels. Default size is 8.
  • --symbol-size-field=SYMBOL_SIZE_FIELD - Field to use for sizing the implied townspot symbol width/height in pixels. No default.

###Dymo Label

  • -m MINUTES, --minutes=MINUTES - Number of minutes to run annealer. Longer run times generally give better results, to a point. Default value is 2.0.
  • -z ZOOM, --zoom=ZOOM - Map zoom level. Conflicts with --scale and --projection options. Default value is 18.
  • -l LABELS_FILE, --labels-file=LABELS_FILE - Optional: name of labels file to generate.
  • -p PLACES_FILE, --places-file=PLACES_FILE - Optional: name of place points file to generate.
  • -r REGISTRATIONS_FILE, --registrations-file=REGISTRATIONS_FILE - Optional: name of registration points file to generate. This file will have an additional "justified" field with values "left", "center", or "right".
  • --min-temp=TEMP_MIN - Optional: Minimum annealing temperature, for more precise control than specifying --minutes.
  • --max-temp=TEMP_MAX - Optional: Maximum annealing temperature, for more precise control than specifying --minutes.
  • --steps=STEPS - Number of annealing steps, for more precise control than specifying --minutes.
  • --include-overlaps - Include lower-priority places when they overlap higher-priority places. Default behavior is to skip the overlapping cities.
  • --output-projected - Optional: output projected coordinates.
  • --projection=PROJECTION - Optional: PROJ.4 string to use instead of default web spherical mercator.
  • --blobs - Load input as blobs rather than points, placing labels on top of locations instead of near them.
  • --scale=SCALE - Scale to use with --projection. Equivalent to +to_meter PROJ.4 parameter, which is not used internally due to not quite working in pyproj. Conflicts with --zoom option. Default value is 1.
  • --dump-file=DUMP_FILE - Optional: filename for a sequential dump of pickled annealer states. This all has to be stored in memory, so for a large job specifying this option could use up all available RAM.
  • --dump-skip=DUMP_SKIP - Optional: number of states to skip for each state in the dump file.
  • --name-field=NAME_FIELD - Name of column for labels to name themselves. Default value is name.
  • --placement-field=PLACEMENT_FIELD - Optional: name of column for point placement. Default value is preferred placement.

###Advanced Prepare Places Usage

  • Use larger or smaller townspot symbol sizes: --symbol-size

      python dymo-prepare-places.py --symbol-size 6 --font 0 fonts/Arial.ttf 10 --font 1000000 fonts/Arial.ttf 12 --zoom 5 data/North-America-all.txt.gz data/North-America-z5.txt
    
  • Use custom townspot symbol size per feature: --symbol-size-field

      python dymo-prepare-places.py --symbol-size-field spotsize --font 0 fonts/Arial.ttf 10 --font 1000000 fonts/Arial.ttf 12 --zoom 5 data/North-America-all.txt.gz data/North-America-z5.txt
    
  • Use a custom 'population' attribute to size grade the text labels: --font-field

      python dymo-prepare-places.py --font-field rank --font 0 fonts/Arial.ttf 10 --font 1000000 fonts/Arial.ttf 12 --zoom 5 data/North-America-all.txt.gz data/North-America-z5.txt
    
  • Limit the initial visibility of a feature to a specific zoom: --zoom-field

      python dymo-prepare-places.py --zoom-field init_zoom --font 0 fonts/Arial.ttf 10 --font 1000000 fonts/Arial.ttf 12 --zoom 5 data/North-America-all.txt.gz data/North-America-z5.txt
    
  • Subselect features based on a simple filter: --filter-field

      python dymo-prepare-places.py --filter-field city_type capital_city --font 0 fonts/Arial.ttf 10 --font 1000000 fonts/Arial.ttf 12 --zoom 5 data/North-America-all.txt.gz data/North-America-z5.txt
    
  • Combo:

      python dymo-prepare-places.py -z 6 --radius 1 --font 0 "fonts/Arial.ttf" 14 --font 4 "fonts/Arial Bold.ttf" 18 --font-field "sizeclass" master_data_file.tsv --zoom-field "zoom_start" --symbol-size-field "symbol_size" --filter-field region west west-labels-z6.txt
    

###Advanced Label Usage

  • Run longer, look prettier: adjust --minutes, --min-temp, --max-temp, and --steps

  • Use a custom name field: specify a custom --name-field

      python dymo-label.py --name-field name_ascii -z 6 --minutes 2 --labels-file labels.json --places-file points.json data/North-America-z5.txt
    
  • Output multiple label, places, registration outputs: Use --labels-file, --places-file, and --registrations-file.

      python dymo-label.py --registrations-file registrations.json -z 6 --minutes 2 --labels-file labels.json --places-file points.json data/North-America-z5.txt
    
  • Provide label hints to the auto-label algorithm: Use --placement-field.

      python dymo-label.py --placement-field hint -z 6 --minutes 2 --labels-file labels.json --places-file points.json data/North-America-z5.txt
    
  • Manually troubleshoot overlaps in QGIS: Use --include-overlaps and open in QGIS and fine tune output.

      python dymo-label.py --include-overlaps -z 6 --minutes 2 --labels-file labels.json --places-file points.json data/North-America-z5.txt
    
  • Use a custom map projection: Use --output-projected, --projection, and --scale

    For an Albers map of the USA, but saved in WGS84 geographic coodinates:

      python dymo-label.py --projection "+proj=aea +lat_1=29.5 +lat_2=45.5 +lat_0=38.0 +lon_0=-98.0 +ellps=WGS84 +towgs84=0,0,0,0,0,0,0 +units=m +no_defs" --scale 2377 --steps 50000 --max-temp 230 --min-temp 0.0001 --labels-file northeast-labels.json east-labels-z3.txt --name-field "label" --placement-field "preferred_z3"
    

    For an Albers map of the USA, saved in that projection:

      python dymo-label.py --projection "+proj=aea +lat_1=29.5 +lat_2=45.5 +lat_0=38.0 +lon_0=-98.0 +ellps=WGS84 +towgs84=0,0,0,0,0,0,0 +units=m +no_defs" --output-projected --scale 2377 --steps 50000 --max-temp 230 --min-temp 0.0001 --labels-file northeast-labels.json east-labels-z3.txt --name-field "label" --placement-field "preferred_z3"
    

Dependencies

Some of the advanced options, such as custom map projections, will require the following libraries:

  • Modest Maps
  • Shapely
  • Pyproj

For projection-specific inputs, see this projections transform list.

Tips

  • Converting to Esri Shapefile format: Use GDAL/OGR's ogr2ogr tool to convert the GeoJSON Dymo output. QGIS, a free desktop GIS application, will also convert the files to SHP.

      ogr2ogr -f 'Esri Shapefile' -lco=UTF8 output.shp input.json
    

    If you have OGR 1.9+ (for the UTF8 layer creation option to preserve the unicode place names), run make shp from the Dymo directory and the SHP versions will be automatically created.

  • Reduce the file size of the GeoJSON output using Lil'JSON:

      python LilJSON.py --precision 3 input.json output.json
    

Who

Copyright 2010-2012 Michal Migurski, Nathaniel V. Kelso, and GeoIQ, offered under the BSD license. Uses Richard J. Wagner’s Python annealing library.

We’re not affiliated with Dymo Corporation.

More Repositories

1

HighRoad

The last OpenStreetMap road query you will ever need.
CartoCSS
239
star
2

Skeletron

Computes straight skeletons of simple polygons
Python
109
star
3

paperwalking

Like walking, but with paper
PHP
94
star
4

Extractotron

Placeholder for some ideas about OpenStreetMap extracts
HTML
84
star
5

Squares

…small, extensible, free and open-source library for in-browser maps, written in Typescript and using D3 under the hood.
JavaScript
70
star
6

OSM-Solar

Ultra-lightweight rendering style for OpenStreetMap
Python
66
star
7

Tile-Drawer

Quickly select and host OpenStreetMap-based map tiles in the cloud
JavaScript
59
star
8

Bloch

Rock out with your Bloch out.
Python
58
star
9

Blit

Python
57
star
10

DEM-Tools

Tools For DEMs
Python
56
star
11

census-tools

Scripts for dealing with U.S. Census data
Python
43
star
12

LilJSON

A small Python script that makes JSON smaller by removing space and reducing float precision.
Python
41
star
13

canvas-warp

Map warping with HTML canvas
JavaScript
38
star
14

modestmaps-as3

Modest Maps actionscript3 port
ActionScript
38
star
15

modestmaps-py

Modest Maps python port
Python
37
star
16

NokiaWebGL

Bits of code for pulling data out of Nokia's WebGL map tiles.
Python
33
star
17

This-Tract

One U.S. census tract at a time
JavaScript
18
star
18

Redistricting

Python
14
star
19

shlong

A web service for URLs short and long
PHP
12
star
20

modestmaps-js

Modest Maps javascript port
JavaScript
10
star
21

oauth-dance

The Dance of OAuth
Python
10
star
22

OSM.us-vector-datasource

The TileStache configuration that runs http://openstreetmap.us/~migurski/vector-datasource/
Python
9
star
23

atkinson

Atkinson dithering of PIL images in Python
8
star
24

OSMWorldData

Scripts for creating worldwide data derived from OSM.
Python
8
star
25

ColorCheat

Simple color transformations by way of a mapping file
Python
6
star
26

spatialreference

Git mirror of spatialreference.org. Also a test to see how Git deals with thousands of tiny files (spoiler: not well).
JavaScript
6
star
27

Ramseyfier

Figure out the parts of your shapefiles that make Paul Ramsey cry
Python
6
star
28

Changepipe

Makes feed for OpenStreetMap changesets based on the per-minute replication files.
Python
6
star
29

potlatch2

OpenStreetMap editor Potlatch2
5
star
30

GOSM

OpenStreetMap Genuine Advantage
Python
4
star
31

Viewfinderpanos-Index

HTTP index to Viewfinder Panoramas digital elevation models
PHP
3
star
32

whereami

The little python script that tells you where you are
Python
3
star
33

literally-any-democrat

Python
3
star
34

substream

Doofing around with the firehose
Python
3
star
35

Faumaxion

Python
3
star
36

modestmaps-php

Modest Maps php port
PHP
3
star
37

Blobdetector

Detector for blobs
C++
3
star
38

talkingpapers

Python
2
star
39

Kruddler

Post images from Tumblr to Mastadon
Python
2
star
40

PlanetIndex

Proposal for new planet.openstreetmap.org autoindex.
Python
2
star
41

GridTile

A little tiny TileCache and all it does is make grids
Python
2
star
42

chefbase

Base repo for using chef-solo. Merge me into your project! Tested on Ubuntu 14.04.
Shell
2
star
43

Numbers-Station

PHP
2
star
44

modestmaps-as2

Modest Maps actionscript2 port
ActionScript
2
star
45

census-remote-index

Remote indexes for census data from static URLs
Python
2
star
46

dwim

Do What I Mean™
Python
1
star
47

SMS2BART4ETA

SMS to BART for estimated train arrival times
PHP
1
star
48

drive.vote.map

1
star
49

RRDCore

That which can be measured will be gamed
1
star
50

GDALAMBDA

Python
1
star
51

circle-beacon

Tickles Circle CI to retry a build
Python
1
star
52

d34d

D3 For Dummies
1
star
53

OSMGridTile

Clickable maps are one of OpenStreetMap's Top Ten Tasks; this TileStache provider implements a UTFGrid-like JSON layer to support them.
Python
1
star
54

ArtisinalInts

Interface to hand-crafted integers from Brooklyn and San Francisco.
Python
1
star