Generate print-ready posters of electrical grid infrastructure from OpenStreetMap data. Browse the rendered posters in the online gallery. Transmission lines for a country or continent are downloaded and rendered with GeoPandas, OSMnx, and Matplotlib. Grid2Poster is heavily inspired by maptoposter and reuses some of its styling.
Grid2Poster supports countries, states, provinces and continents, as well as predefined regions. Browse more stunnding poster in the grid2poster gallery.
Grid2Poster uses OpenStreetMap features tagged as:
power=linepower=minor_linewhen enabledpower=cablewhen enabledpower=plantwhen enabled
Feature completeness depends on OpenStreetMap coverage in the selected country or region.
Coverage and quality in your country can be improved by mapping transmission infrastructure directly in OpenStreetMap. MapYourGrid is a community initiative that coordinates this work. It provides tutorials, country-level completeness/quality statistics and mapping tools for tracing power lines, generators and substations from imagery. With Open Infrastructure Map you can browse all the electrical grid data in OpenStreetMap.
Preprinted posters in various styles and A3 are available for most regions of the world in our grid2poster gallery:
The project lives in two branches: the main branch and the gh-pages branch. To create your own posters, clone the main branch with the --single-branch flag, as the gh-pages branch contains all the gallery plots and is therefore massive.
git clone --single-branch https://github.com/open-energy-transition/grid2poster
python -m venv .venv
source .venv/bin/activate
pip install -r requirements.txtTo create a poster for a country, state or province, use the --country option to resolve the boundaries via Nominatim. Setting a large '--tile-size-km' in kilometres and '--tile-delay' in seconds reduces the timeout of the Overpass server. By default, every run creates both a PNG and an SVG file.
By default posters print at A3 portrait (297 × 420 mm) at 300 DPI. Use --paper-size for another named preset, --width/--height for custom millimeter dimensions, and --landscape to flip orientation.
python create_grid_poster.py --country Brazil --tile-delay 30 --tile-size-km 500Depending on the size of the country and whether distribution grids are excluded, loading the data via a single query (--single-query) is much faster. For large countries with lots of distribution grids, the data should be loaded in multiple tiles:
python create_grid_poster.py --country Pakistan --single-queryInclude distribution grids if available. Grid coverage varies significantly across the globe and is mainly only available in Europe and North America.
python create_grid_poster.py --country Germany --include-minor-linesList available themes. Create a new theme JSON file in the 'themes' directory to find your own style.
python create_grid_poster.py --list-themesOnce a region's data has been loaded, re-rendering it with another theme is much faster: the boundaries and OSM power features are served from the cache instead of being downloaded again. This makes it cheap to experiment with different styles for the same country.
python create_grid_poster.py --country Brazil --theme neon_cyberpunk
python create_grid_poster.py --country Brazil --theme paper_grid # reuses the cached dataA theme JSON defines colors per voltage tier (line_unknown, line_low, line_mid, line_high, line_extra). It may optionally also set the line thickness (in points) per tier with lw_unknown, lw_low, lw_mid, lw_high, lw_extra, and lw_minor. Any width key you omit falls back to the built-in default for that tier.
Cables (--include-cables, underground/submarine) inherit their voltage-tier color and a dampened width by default. A theme may override this with cable_color (a hex color used for all cables instead of the tier color) and cable_lw_scale (the multiplier applied to the tier line width; defaults to 0.5). Omit them to keep the current behavior.
Power plants (--show-plants) are drawn as markers sized by installed capacity (plant:output:electricity, square-root area scaling) and colored by generation source (plant:source), bucketed into solar, wind, hydro, nuclear, coal, gas, oil, biomass and other. Marker colors are derived automatically from each theme's palette so they fit the poster style; a theme may pin any bucket explicitly with plant_solar, plant_wind, plant_hydro, plant_nuclear, plant_coal, plant_gas, plant_oil, plant_biomass, plant_other, and override the marker outline with plant_edge. A second metadata row lists the installed GW per source. Use --min-plant-capacity to hide small plants and --plant-marker-scale to tune marker sizes.
python create_grid_poster.py --country Austria --show-plants --min-plant-capacity 10Use a local GeoJSON file as the boundary instead of geocoding (handy for custom regions or sub-national areas). All polygonal features in the file are dissolved into a single boundary. The --country value is still used for the poster title and output filename. --landscape will render in landscape (horizontal) orientation.
python create_grid_poster.py --country "Middle East and North Africa" --boundary-geojson ./regions/mena.geojson --landscape --theme neon_cyberpunk Render an entire continent. Continent boundaries come from the Natural Earth admin-0 dataset (downloaded and cached on first use) because Nominatim does not resolve continent names. Accepted values are Africa, Antarctica, Asia, Europe, North America, Oceania, and South America. The aggregate name Global combines every inhabited continent.
python create_grid_poster.py --country Africa --tile-size-km 500Continent-scale runs hit the Overpass API hundreds of times and can take several hours. A larger --tile-size-km cuts the number of queries; pick a value that still stays under the Overpass per-query size limit.
--country Global renders the whole inhabited world as the union of the continents, clipped to a tight bounding box so it fills the page. It is the longest job in the tool (many hundreds of Overpass queries, several hours), so use a large --tile-size-km, a generous --tile-delay, and high --voltage-tiers so HV/EHV lines stand out at world scale. The themes/ directory ships three palettes tuned for this scale: global_grid_atlas (dark atlas), global_grid_atlas_neon (neon), and global_paper_grid_atlas (warm paper).
python create_grid_poster.py --country Global \
--display-country "The Global Electrical Transmission Grid" --subtitle "Electrify Everything" \
--theme global_grid_atlas_neon --landscape --paper-size a0 \
--tile-size-km 1000 --tile-delay 30 --voltage-tiers 110,220,400,765 --padding -0.1If the default Overpass endpoint (overpass-api.de) is rate-limiting or refusing connections, switch to a mirror with --overpass-endpoint:
python create_grid_poster.py --country Germany --overpass-endpoint https://overpass.kumi.systems/api/interpreterOther public mirrors include https://overpass.private.coffee/api/interpreter.
Most options can be combined in a single run. The command below renders the continental European grid in the monochrome_density theme, pulling in distribution (--include-minor-lines) and underground/submarine (--include-cables) infrastructure, and tuning the framing and download behaviour:
python3 create_grid_poster.py --country "Europe" --boundary-geojson ./regions/europe.geojson \
--tile-size-km 800 --include-cables --include-minor-lines --theme monochrome_density \
--tile-delay 30 --landscape --shift-y 0.18 --padding -0.35 --no-cache --cable-sea-buffer-km 500What each flag contributes:
--boundary-geojson ./regions/europe.geojson- use the predefined 37-unit Europe boundary instead of geocoding.--tile-size-km 800with--tile-delay 30- fewer, larger Overpass tiles spaced 30 s apart to stay under per-query limits without tripping rate limits.--include-minor-lines/--include-cables- addpower=minor_lineandpower=cablefeatures on top of the transmission lines.--cable-sea-buffer-km 500- inflate the boundary 500 km over water so long submarine cables survive coastline clipping.--theme monochrome_density/--landscape- black-on-cream density styling in horizontal orientation.--shift-y 0.18and--padding -0.35- push the grid up by 18 % and crop tightly into the bounds for a full-bleed composition.--no-cache- ignore any cached data on this run and fetch fresh (results are still written back to the cache).
| Option | Default | Description |
|---|---|---|
--country |
- | Country or region name resolvable by Nominatim, a continent name (Africa, Antarctica, Asia, Europe, North America, Oceania, South America), or the aggregate Global |
--boundary-geojson |
- | Path to a local GeoJSON file with polygonal boundary features. Overrides the Nominatim/Natural Earth lookup. Useful for custom regions, sub-national areas, or offline workflows. |
--display-country |
value of --country |
Text to print on the poster. Useful when the geocoder name differs from the desired title. |
--subtitle |
ELECTRICAL TRANSMISSION GRID (or ELECTRICAL GRID with --include-minor-lines) |
Override the subtitle printed under the country/region name. |
--padding |
0.10 |
Fractional padding around the boundary bounds. Lower values zoom in (0 = tight fit, -0.05 = crop slightly into the bounds); higher values pull the view out. |
--shift-x |
0.0 |
Shift the grid data horizontally on the poster, as a fraction of the data extent. Positive values shift right, negative shift left (e.g. 0.1 = shift 10% right). |
--shift-y |
0.0 |
Shift the grid data vertically on the poster, as a fraction of the data extent. Positive values shift up, negative shift down (e.g. 0.1 = shift 10% up). |
--theme |
paper_grid |
Theme ID from the themes/ directory. |
--list-themes |
- | List available themes and exit. |
--voltage-tiers |
60,150,300,500 |
Lower kV bounds for the four voltage tiers (low, mid, high, extra), comma-separated. Controls how lines are colored/weighted and the legend labels - tune to the grid being mapped (e.g. 60,220,400,765). |
--include-minor-lines |
off | Also fetch power=minor_line features. |
--include-cables / --no-include-cables |
off | Fetch power=cable features (underground/submarine). Off by default; pass --include-cables to enable. |
--cable-sea-buffer-km |
200.0 |
When --include-cables is on, inflate the boundary by this many kilometers over water so submarine cables between islands and to neighboring countries are queried from Overpass and survive coastline clipping. Set to 0 to disable. |
--show-plants |
off | Fetch power=plant features and overlay them as markers sized by capacity (plant:output:electricity) and colored by source (plant:source). |
--min-plant-capacity |
0.0 |
Only draw plants with at least this electrical output in MW. Plants with unknown capacity are dropped when set. |
--plant-marker-scale |
1.0 |
Multiplier for plant marker sizes. Increase for sparse grids, decrease to reduce clutter. |
--include-outlying |
off | Keep overseas territories and other polygons far from the main landmass. By default the geocoded boundary is filtered to the mainland (and nearby islands), so posters for countries like the Netherlands or France do not include Aruba, Curaçao, French Guiana, etc. |
--paper-size |
- | Named preset, portrait orientation. Overrides --width/--height. Choices: a5, a4, a3, a2, a1, a0, letter, legal, tabloid. Combine with --landscape to flip. |
--width |
297.0 |
Poster width in millimeters (default: A3 short side). |
--height |
420.0 |
Poster height in millimeters (default: A3 long side). |
--landscape |
off | Render in landscape (horizontal) orientation. Swaps width and height if width < height. |
--dpi |
300 |
Raster output DPI (applies to PNG output). |
--title-size |
auto | Title font size in points. Auto-scaled from poster size by default; set to override. |
--tile-size-km |
400 |
Overpass query tile size in kilometers. Use smaller values for very large countries or busy servers. |
--overpass-endpoint |
OSMnx default (overpass-api.de) |
Override the Overpass API URL. Use a mirror (e.g. https://overpass.kumi.systems/api/interpreter) when the default is rate-limiting or unreachable. |
--format |
png svg |
Output format(s): any combination of png, svg, pdf. Multiple values are written in one run. |
--output |
auto-generated in posters/ |
Output file path. When set, only a single file is written and its format is inferred from the extension. |
--crs |
EPSG:3857 |
Projection used for rendering. EPSG:3857 (Pseudo-Mercator) works well for country posters. |
--hide-metadata |
off | Do not print segment counts on the poster. |
--hide-borders |
off | Do not draw the region boundary outline. |
--logo |
- | Path to an SVG or PNG logo to place in the lower-left corner. SVGs are rasterized with cairosvg (install it for SVG support); PNGs are used as-is. |
--logo-size |
20.0 |
Logo width in millimeters. Its height scales to preserve the aspect ratio. |
--logo-margin |
12.0 |
Margin in millimeters between the logo and the lower-left poster edges. |
--logo-alpha |
1.0 |
Logo opacity, from 0 (transparent) to 1 (fully opaque). |
--single-query |
off | Fetch all power features in a single Overpass query instead of tiling. Faster for small/medium regions but may time out on large countries or continents. |
--tile-delay |
30 |
Seconds to wait between Overpass tile API requests. Useful to avoid rate-limiting on busy public endpoints. |
--export-geojson |
off | Also save all transmission lines as a single GeoJSON in WGS84 (EPSG:4326). Pass a path to override the default location in posters/. |
--no-cache |
off | Ignore cached boundaries and OSM power features on this run. Fresh results are still written to the cache for future runs. |
--verbose-osmnx |
off | Print OSMnx request logs. |
Generated posters are written to the posters/ directory by default. Intermediate OSM responses and processed geometries are cached in cache/ to avoid repeated downloads. Because of this cache, the first render of a region is the slow one - every subsequent run for that region (for example with a different theme) skips the downloads and is much faster.
The regions/ directory ships with multi-country boundaries that map to common power-system groupings. Pass any of them via --boundary-geojson and set --country to the title you want printed on the poster:
python create_grid_poster.py --country "Europe" --boundary-geojson ./regions/europe.geojson --tile-size-km 300| File | Coverage |
|---|---|
regions/australia_mainland_tasmania.geojson |
Australia: mainland and Tasmania; outlying territories excluded. |
regions/britain_and_ireland.geojson |
Great Britain (excl. Shetland) and the island of Ireland. |
regions/canada_southern_provinces.geojson |
Canada south of 60°N; excludes Yukon, NWT, Nunavut. |
regions/central_asia.geojson |
Kazakhstan, Kyrgyzstan, Tajikistan, Turkmenistan, Uzbekistan. |
regions/chile_to_quellon.geojson |
Chile from the northern border south to Quellón on Chiloé Island; excludes Patagonia south of Chiloé and the remote Pacific islands (Easter Island, Juan Fernández). |
regions/continental_europe.geojson |
Continental Europe Synchronous Area (ENTSO-E Regional Group) approximation - ~26 countries from Albania to Ukraine. Approximate country-boundary geometry, not a TSO/control-area dataset. |
regions/east_africa.geojson |
11 East African countries from Eritrea/Djibouti south to Tanzania. |
regions/eastern_interconnection.geojson |
Eastern Interconnection (approximate mask): central Canada to the Atlantic coast excluding Quebec, south to Florida, west to the Rockies. Hand-generalized, not an exact grid boundary. |
regions/europe.geojson |
37 European units including UK, Ireland, Nordics, Turkey, Ukraine, Belarus, and the Crimea peninsula; excludes Russia. Crimea geometry comes from the Natural Earth Russia feature but is included here per Ukraine. |
regions/great_lakes.geojson |
Great Lakes region straddling the US Midwest and Ontario. |
regions/iberia.geojson |
Spain and Portugal. |
regions/ireland_island.geojson |
Island of Ireland (Republic of Ireland + Northern Ireland). |
regions/japan_main_islands.geojson |
Japan's four main islands plus adjacent small islands; excludes Okinawa, Ogasawara, Senkaku. |
regions/java_bali.geojson |
Indonesian islands of Java and Bali. |
regions/latin_america.geojson |
48 entries from Mexico through Argentina, including the Caribbean and overseas territories. |
regions/malay_peninsula.geojson |
Malay Peninsula: Peninsular Malaysia, Singapore, and southern Thailand. |
regions/mediterranean.geojson |
22 countries bordering the Mediterranean. |
regions/mena.geojson |
Middle East and North Africa - 18 countries. |
regions/middle_america.geojson |
Middle America - 35 entries: Mexico, Central America, and the Caribbean islands and territories. |
regions/quebec_south.geojson |
Southern Quebec, Canada. |
regions/salish_sea.geojson |
Salish Sea region: southwestern British Columbia and northwestern Washington. |
regions/scandinavia.geojson |
Denmark, Finland, Norway, Sweden. |
regions/south_africa_no_prince_edward.geojson |
South Africa mainland; excludes Prince Edward Islands. |
regions/south_asia.geojson |
India, Pakistan, Bangladesh, Nepal, Bhutan, Sri Lanka. |
regions/southeast_asia.geojson |
11 Southeast Asian countries (Brunei through Vietnam). |
regions/southern_african_power_pool.geojson |
Southern African Power Pool - 12 member countries (Angola, Botswana, DRC, Eswatini, Lesotho, Malawi, Mozambique, Namibia, South Africa, Tanzania, Zambia, Zimbabwe). |
regions/uk_no_shetland.geojson |
United Kingdom without the Shetland Islands. |
regions/us_canada_mainland.geojson |
Continental US and Canadian mainland south of 60°N; excludes Alaska, Hawaii, Arctic islands. |
regions/us_mainland.geojson |
Contiguous United States (CONUS); excludes Alaska and Hawaii. |
regions/wapp.geojson |
West African Power Pool - 14 member countries. |
regions/wecc.geojson |
Western Electricity Coordinating Council / Western Interconnection footprint across western North America. |
For ad-hoc areas (a single state, a metro region, a custom polygon), supply your own GeoJSON via --boundary-geojson. All polygonal features in the file are dissolved into one boundary.
The online gallery is served from the orphan gh-pages branch, which has no shared history with main. The install instructions above use --single-branch main and therefore do not fetch it.Fetch it explicitly the first time you contribute:
git fetch origin gh-pagesTo add a poster:
- Render it from
mainwithcreate_grid_poster.py.python create_grid_poster.py --country Spain --theme paper_grid
- Move the PNG (and SVG, if you want to offer the vector download) out of
posters/so it survives the branch switch, then switch togh-pages:mv posters/spain_grid_paper_grid_*.png /tmp/ git checkout gh-pages mv /tmp/spain_grid_paper_grid_*.png posters/
- Rebuild the manifest and commit:
python build_manifest.py git add posters/ git commit -m "Add Spain (paper_grid)" - Open a pull request targeting
gh-pages(notmain).
Map data © OpenStreetMap contributors.
















