Map To Poster – Create Art of your favourite city

2026-01-1710:1329670github.com

Transform your favorite cities into beautiful, minimalist designs. MapToPoster lets you create and export visually striking map posters with code. - originalankur/maptoposter

Generate beautiful, minimalist map posters for any city in the world.

Country City Theme Poster
USA San Francisco sunset
Spain Barcelona warm_beige
Italy Venice blueprint
Japan Tokyo japanese_ink
India Mumbai contrast_zones
Morocco Marrakech terracotta
Singapore Singapore neon_cyberpunk
Australia Melbourne forest
UAE Dubai midnight_blue
pip install -r requirements.txt
python create_map_poster.py --city <city> --country <country> [options]
Option Short Description Default
--city -c City name required
--country -C Country name required
--theme -t Theme name feature_based
--distance -d Map radius in meters 29000
--list-themes List all available themes
# Iconic grid patterns
python create_map_poster.py -c "New York" -C "USA" -t noir -d 12000 # Manhattan grid
python create_map_poster.py -c "Barcelona" -C "Spain" -t warm_beige -d 8000 # Eixample district # Waterfront & canals
python create_map_poster.py -c "Venice" -C "Italy" -t blueprint -d 4000 # Canal network
python create_map_poster.py -c "Amsterdam" -C "Netherlands" -t ocean -d 6000 # Concentric canals
python create_map_poster.py -c "Dubai" -C "UAE" -t midnight_blue -d 15000 # Palm & coastline # Radial patterns
python create_map_poster.py -c "Paris" -C "France" -t pastel_dream -d 10000 # Haussmann boulevards
python create_map_poster.py -c "Moscow" -C "Russia" -t noir -d 12000 # Ring roads # Organic old cities
python create_map_poster.py -c "Tokyo" -C "Japan" -t japanese_ink -d 15000 # Dense organic streets
python create_map_poster.py -c "Marrakech" -C "Morocco" -t terracotta -d 5000 # Medina maze
python create_map_poster.py -c "Rome" -C "Italy" -t warm_beige -d 8000 # Ancient layout # Coastal cities
python create_map_poster.py -c "San Francisco" -C "USA" -t sunset -d 10000 # Peninsula grid
python create_map_poster.py -c "Sydney" -C "Australia" -t ocean -d 12000 # Harbor city
python create_map_poster.py -c "Mumbai" -C "India" -t contrast_zones -d 18000 # Coastal peninsula # River cities
python create_map_poster.py -c "London" -C "UK" -t noir -d 15000 # Thames curves
python create_map_poster.py -c "Budapest" -C "Hungary" -t copper_patina -d 8000 # Danube split # List available themes
python create_map_poster.py --list-themes
Distance Best for
4000-6000m Small/dense cities (Venice, Amsterdam center)
8000-12000m Medium cities, focused downtown (Paris, Barcelona)
15000-20000m Large metros, full city view (Tokyo, Mumbai)

17 themes available in themes/ directory:

Theme Style
feature_based Classic black & white with road hierarchy
gradient_roads Smooth gradient shading
contrast_zones High contrast urban density
noir Pure black background, white roads
midnight_blue Navy background with gold roads
blueprint Architectural blueprint aesthetic
neon_cyberpunk Dark with electric pink/cyan
warm_beige Vintage sepia tones
pastel_dream Soft muted pastels
japanese_ink Minimalist ink wash style
forest Deep greens and sage
ocean Blues and teals for coastal cities
terracotta Mediterranean warmth
sunset Warm oranges and pinks
autumn Seasonal burnt oranges and reds
copper_patina Oxidized copper aesthetic
monochrome_blue Single blue color family

Posters are saved to posters/ directory with format:

{city}_{theme}_{YYYYMMDD_HHMMSS}.png

Create a JSON file in themes/ directory:

{ "name": "My Theme", "description": "Description of the theme", "bg": "#FFFFFF", "text": "#000000", "gradient_color": "#FFFFFF", "water": "#C0C0C0", "parks": "#F0F0F0", "road_motorway": "#0A0A0A", "road_primary": "#1A1A1A", "road_secondary": "#2A2A2A", "road_tertiary": "#3A3A3A", "road_residential": "#4A4A4A", "road_default": "#3A3A3A"
}
map_poster/
├── create_map_poster.py          # Main script
├── themes/               # Theme JSON files
├── fonts/                # Roboto font files
├── posters/              # Generated posters
└── README.md

Quick reference for contributors who want to extend or modify the script.

┌─────────────────┐     ┌──────────────┐     ┌─────────────────┐
│   CLI Parser    │────▶│  Geocoding   │────▶│  Data Fetching  │
│   (argparse)    │     │  (Nominatim) │     │    (OSMnx)      │
└─────────────────┘     └──────────────┘     └─────────────────┘
                                                     │
                        ┌──────────────┐             ▼
                        │    Output    │◀────┌─────────────────┐
                        │  (matplotlib)│     │   Rendering     │
                        └──────────────┘     │  (matplotlib)   │
                                             └─────────────────┘
Function Purpose Modify when...
get_coordinates() City → lat/lon via Nominatim Switching geocoding provider
create_poster() Main rendering pipeline Adding new map layers
get_edge_colors_by_type() Road color by OSM highway tag Changing road styling
get_edge_widths_by_type() Road width by importance Adjusting line weights
create_gradient_fade() Top/bottom fade effect Modifying gradient overlay
load_theme() JSON theme → dict Adding new theme properties
z=11  Text labels (city, country, coords)
z=10  Gradient fades (top & bottom)
z=3   Roads (via ox.plot_graph)
z=2   Parks (green polygons)
z=1   Water (blue polygons)
z=0   Background color
# In get_edge_colors_by_type() and get_edge_widths_by_type()
motorway, motorway_linkThickest (1.2), darkest
trunk, primaryThick (1.0)
secondaryMedium (0.8)
tertiaryThin (0.6)
residential, living_streetThinnest (0.4), lightest

New map layer (e.g., railways):

# In create_poster(), after parks fetch:
try: railways = ox.features_from_point(point, tags={'railway': 'rail'}, dist=dist)
except: railways = None # Then plot before roads:
if railways is not None and not railways.empty: railways.plot(ax=ax, color=THEME['railway'], linewidth=0.5, zorder=2.5)

New theme property:

  1. Add to theme JSON: "railway": "#FF0000"
  2. Use in code: THEME['railway']
  3. Add fallback in load_theme() default dict

All text uses transform=ax.transAxes (0-1 normalized coordinates):

y=0.14  City name (spaced letters)
y=0.125 Decorative line
y=0.10  Country name
y=0.07  Coordinates
y=0.02  Attribution (bottom-right)
# Get all buildings
buildings = ox.features_from_point(point, tags={'building': True}, dist=dist) # Get specific amenities
cafes = ox.features_from_point(point, tags={'amenity': 'cafe'}, dist=dist) # Different network types
G = ox.graph_from_point(point, dist=dist, network_type='drive') # roads only
G = ox.graph_from_point(point, dist=dist, network_type='bike') # bike paths
G = ox.graph_from_point(point, dist=dist, network_type='walk') # pedestrian
  • Large dist values (>20km) = slow downloads + memory heavy
  • Cache coordinates locally to avoid Nominatim rate limits
  • Use network_type='drive' instead of 'all' for faster renders
  • Reduce dpi from 300 to 150 for quick previews

Read the original article

Comments

  • By stanko 2026-01-1717:481 reply

    There is a related project which I used several times:

    https://github.com/anvaka/city-roads

    Edit: it outputs SVGs and you can try it online. Anvaka (author) has other really cool dataviz projects.

    • By sandos 2026-01-1916:001 reply

      Kinda sad that maptoposter uses png. SVG is so much better in this case, if you want to actually print a poster!

      • By PetahNZ 2026-01-214:07

        It does support SVG, --format=svg

  • By Helmut10001 2026-01-1714:392 reply

    San Francisco looks nice, but there seems to be a problem with the projection in some of the sample images. It looks as if it isn't UTM but a global sphere projection, which isn't suitable for local renders. It's suspicious that the word 'projection' isn't mentioned in the Readme.

    • By jasongill 2026-01-1715:091 reply

      This is an artistic project to make a fun and artsy poster, so it's not at all "suspicious" that the map projection is not critical to the artwork.

      It also appears to be open source, so perhaps you can open a pull request with your improvements based on your cartographical experience.

      • By Helmut10001 2026-01-1715:18

        You are absolutely correct. Suspicious was the wrong word and I did not mean to criticize the author or the work.

    • By jlarocco 2026-01-1716:26

      It looks like the final images have some kind of vignetting to make the corners and outter edges fade away. Probably grabbing OSM tiles and doing some image processing.

      Looks neat!

  • By mvdwoord 2026-01-187:12

    Great project! It takes a bit of fiddling to get the distance parameter right in some cases, and two possible improvements would be to allow for coordinate input rather than city name so I can point it at a specific spot as the center of the map. Another one would be to output all styles simultaneously so I can visually select from the generated images.

    Anyhow, nice work. Thanks!

HackerNews