maptoposter README

The project's README from github.com/originalankur/maptoposter. As one markdown file: README.md.

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
USA Seattle emerald

Installation

Make sure uv is installed. Running the script by prepending uv run automatically creates and manages a virtual environment.

# First run will automatically install dependencies
uv run ./create_map_poster.py --city "Paris" --country "France"

# Or sync dependencies explicitly first (using locked versions)
uv sync --locked
uv run ./create_map_poster.py --city "Paris" --country "France"

With pip + venv

python -m venv .venv
source .venv/bin/activate  # On Windows: .venv\Scripts\activate
pip install -r requirements.txt

Usage

Generate Poster

If you're using uv:

uv run ./create_map_poster.py --city <city> --country <country> [options]

Otherwise (pip + venv):

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

Required Options

Option Short Description
--city -c City name (used for geocoding)
--country -C Country name (used for geocoding)

Optional Flags

Option Short Description Default
OPTIONAL: --latitude -lat Override latitude center point (use with --longitude)
OPTIONAL: --longitude -long Override longitude center point (use with --latitude)
OPTIONAL: --country-label Override country text displayed on poster
OPTIONAL: --theme -t Theme name terracotta
OPTIONAL: --distance -d Map radius in meters 18000
OPTIONAL: --list-themes List all available themes
OPTIONAL: --all-themes Generate posters for all available themes
OPTIONAL: --width -W Image width in inches 12 (max: 20)
OPTIONAL: --height -H Image height in inches 16 (max: 20)

Multilingual Support - i18n

Display city and country names in your language with custom fonts from google fonts:

Option Short Description
--display-city -dc Custom display name for city (e.g., "東京")
--display-country -dC Custom display name for country (e.g., "日本")
--font-family Google Fonts family name (e.g., "Noto Sans JP")

Examples:

# Japanese
python create_map_poster.py -c "Tokyo" -C "Japan" -dc "東京" -dC "日本" --font-family "Noto Sans JP"

# Korean
python create_map_poster.py -c "Seoul" -C "South Korea" -dc "서울" -dC "대한민국" --font-family "Noto Sans KR"

# Arabic
python create_map_poster.py -c "Dubai" -C "UAE" -dc "دبي" -dC "الإمارات" --font-family "Cairo"

Note: Fonts are automatically downloaded from Google Fonts and cached locally in fonts/cache/.

Resolution Guide (300 DPI)

Use these values for -W and -H to target specific resolutions:

Target Resolution (px) Inches (-W / -H)
Instagram Post 1080 x 1080 3.6 x 3.6
Mobile Wallpaper 1080 x 1920 3.6 x 6.4
HD Wallpaper 1920 x 1080 6.4 x 3.6
4K Wallpaper 3840 x 2160 12.8 x 7.2
A4 Print 2480 x 3508 8.3 x 11.7

Usage Examples

Basic Examples

# Simple usage with default theme
python create_map_poster.py -c "Paris" -C "France"

# With custom theme and distance
python create_map_poster.py -c "New York" -C "USA" -t noir -d 12000

Multilingual Examples (Non-Latin Scripts)

Display city names in their native scripts:

# Japanese
python create_map_poster.py -c "Tokyo" -C "Japan" -dc "東京" -dC "日本" --font-family "Noto Sans JP" -t japanese_ink

# Korean
python create_map_poster.py -c "Seoul" -C "South Korea" -dc "서울" -dC "대한민국" --font-family "Noto Sans KR" -t midnight_blue

# Thai
python create_map_poster.py -c "Bangkok" -C "Thailand" -dc "กรุงเทพมหานคร" -dC "ประเทศไทย" --font-family "Noto Sans Thai" -t sunset

# Arabic
python create_map_poster.py -c "Dubai" -C "UAE" -dc "دبي" -dC "الإمارات" --font-family "Cairo" -t terracotta

# Chinese (Simplified)
python create_map_poster.py -c "Beijing" -C "China" -dc "北京" -dC "中国" --font-family "Noto Sans SC"

# Khmer
python create_map_poster.py -c "Phnom Penh" -C "Cambodia" -dc "ភ្នំពេញ" -dC "កម្ពុជា" --font-family "Noto Sans Khmer"

Advanced 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

# Override center coordinates
python create_map_poster.py --city "New York" --country "USA" -lat 40.776676 -long -73.971321 -t noir

# List available themes
python create_map_poster.py --list-themes

# Generate posters for every theme
python create_map_poster.py -c "Tokyo" -C "Japan" --all-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
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
emerald Lush dark green aesthetic
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
├── font_management.py      # Font loading and Google Fonts integration
├── themes/                 # Theme JSON files
├── fonts/                  # Font files
│   ├── Roboto-*.ttf        # Default Roboto fonts
│   └── cache/              # Downloaded Google Fonts (auto-generated)
├── posters/                # Generated posters
└── README.md

Hacker's Guide

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

Contributors Guide

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
is_latin_script() Detects script for typography Supporting new scripts
load_fonts() Load custom/default fonts Changing font loading logic

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_link     → Thickest (1.2), darkest
trunk, primary              → Thick (1.0)
secondary                   → Medium (0.8)
tertiary                    → Thin (0.6)
residential, living_street  → Thinnest (0.4), lightest

Typography & Script Detection

The script automatically detects text scripts to apply appropriate typography:

Script detection uses Unicode ranges (U+0000-U+024F for Latin). If >80% of alphabetic characters are Latin, spacing is applied.

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 = railways.to_crs(g_proj.graph["crs"])
    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 for Latin scripts)
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

maptoposter (originalankur/maptoposter)

Searching Database…

What is this?MapToPoster is a Python script that generates beautiful, minimalist map posters of any city in the world, rendering street networks with OpenStreetMap data into themed, print-ready artwork.
Is this a GUI app or a command-line script?It is a command-line Python script; there is no graphical interface, and the maintainers explicitly don't want a web/desktop UI added.
How do I generate my first poster?Install uv (recommended) and run the script with uv run, passing --city and --country; alternatively use pip + venv to set up the environment manually.
Do I need anything besides Python to run it?You need Python plus packages like OSMnx and matplotlib (managed automatically via uv or a pip venv); fonts for non-Latin scripts are auto-downloaded from Google Fonts and cached locally.
Any gotchas with distance or rendering speed?Large --distance values (over 20km) cause slow downloads and heavy memory use; using networktype='drive' instead of 'all' renders faster, and lowering DPI from 300 to 150 speeds up previews.
Does it run on any OS?It's a cross-platform Python CLI script, so it runs on Windows, macOS, and Linux wherever Python and uv/pip are available.
Does it need internet access?Yes — city coordinates are fetched via Nominatim geocoding and street data via OSMnx/OpenStreetMap, so it needs an internet connection to download map data.
How many themes are available out of the box?17 built-in themes ship in the themes/ directory, ranging from 'noir' and 'blueprint' to 'sunset' and 'japaneseink', each defined by a JSON file.
Can I create my own theme?Yes, you add a new JSON file in the themes/ directory defining colors and properties, following the existing theme format.
Does it support languages with non-Latin scripts like Japanese or Arabic?Yes, you can override the displayed city/country name and pick a Google Fonts family, and the script auto-detects script type to apply correct letter spacing for Latin vs non-Latin text.
What size posters can I export?Width and height are configurable up to 20 inches each at 300 DPI, with a resolution guide covering Instagram, wallpapers, 4K, and A4 print sizes.
Size
312.5 MB
Stars
14.2K
Updated
CommitMar 01
Age
9mo
Commits · 90 Days