Skip to content

cthonney/maptoposter-docker

 
 

Repository files navigation

Credits

Based on the original work by Ankur.
Original Repository: maptoposter
Vibe coding with Google Antigravity and Gemini.⛱️

Docker Usage

Using Docker Compose (Recommended)

Create a docker-compose.yml file:

version: '3.8' services: maptoposter: image: ghcr.io/cthonney/maptoposter-docker:latest container_name: maptoposter ports: - "5025:5025" volumes: # Local directory to retrieve generated PNGs - ./posters:/app/posters restart: unless-stopped

To start the web application:

docker-compose up -d

Access the application at http://localhost:5025.

Using Docker CLI

Build the image:

docker build -t maptoposter .

Run the container:

docker run -p 5025:5025 -v $(pwd)/posters:/app/posters maptoposter

Accessing the Application

Once the container is running (via Docker Compose or Docker CLI), access the web interface at:

http://localhost:5025

City Map Poster Generator

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

Examples

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

Installation (Python CLI)

pip install -r requirements.txt

Usage (Python CLI)

python create_map_poster.py --city <city> --country <country> [options]

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

Examples

# 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 Guide

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)

Themes

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

Output

Posters are saved to posters/ directory with format:

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

Adding Custom Themes

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

Project Structure

map_poster/ ├── create_map_poster.py # Main script ├── themes/ # Theme JSON files ├── fonts/ # Roboto font files ├── posters/ # Generated posters └── README.md 

Hacker's Guide

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

Architecture Overview

┌─────────────────┐ ┌──────────────┐ ┌─────────────────┐ │ CLI Parser │────▶│ Geocoding │────▶│ Data Fetching │ │ (argparse) │ │ (Nominatim) │ │ (OSMnx) │ └─────────────────┘ └──────────────┘ └─────────────────┘ │ ┌──────────────┐ ▼ │ Output │◀────┌─────────────────┐ │ (matplotlib)│ │ Rendering │ └──────────────┘ │ (matplotlib) │ └─────────────────┘ 

Key Functions

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

Rendering Layers (z-order)

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 

OSM Highway Types → Road Hierarchy

# 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

Adding New Features

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

Typography Positioning

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) 

Useful OSMnx Patterns

# 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

Performance Tips

  • 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

About

Docker version: Transform your favorite cities into beautiful, minimalist designs. MapToPoster lets you create and export visually striking map posters with code.

Resources

License

Stars

Watchers

Forks

Releases

No releases published

Packages

 
 
 

Contributors

Languages

  • Python 75.4%
  • JavaScript 6.7%
  • CSS 6.7%
  • HTML 6.7%
  • Dockerfile 4.5%