Skip to content

Instantly share code, notes, and snippets.

@beyoung
Created July 19, 2026 08:46
Show Gist options
  • Select an option

  • Save beyoung/1bd0da1617784b60b9c94114f4205307 to your computer and use it in GitHub Desktop.

Select an option

Save beyoung/1bd0da1617784b60b9c94114f4205307 to your computer and use it in GitHub Desktop.
Python + Cartopy: Render Trans-Siberian Railway & Pan-American Highway on a dark-theme world map
Display the source blob
Display the rendered blob
Raw
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
#!/usr/bin/env python3
"""
Render the World's Longest Railway & Highway Routes
===================================================
Visualize the Trans-Siberian Railway and Pan-American Highway
using Python, Cartopy, and Matplotlib.
Requirements: pip install matplotlib cartopy numpy
"""
import json
import matplotlib
matplotlib.use('Agg')
import matplotlib.pyplot as plt
import cartopy.crs as ccrs
import cartopy.feature as cfeature
from matplotlib.lines import Line2D
# ────────────────────────────────────────────
# DATA: Waypoints along each route
# ────────────────────────────────────────────
TRANS_SIBERIAN_WAYPOINTS = [
# European Russia
[37.6176, 55.7558], # Moscow
[40.3960, 56.1365], # Vladimir
[44.0020, 56.3269], # Nizhny Novgorod
[49.6600, 58.5966], # Kirov
[56.2293, 58.0105], # Perm
[60.5975, 56.8389], # Yekaterinburg
# Siberia
[65.5344, 57.1530], # Tyumen
[73.3703, 54.9893], # Omsk
[82.9346, 55.0302], # Novosibirsk
[92.8526, 56.0090], # Krasnoyarsk
[104.2968, 52.2864], # Irkutsk
[107.6100, 51.8333], # Ulan-Ude
# Far East
[113.5007, 52.0330], # Chita
[132.9250, 48.7925], # Birobidzhan
[135.0852, 48.4802], # Khabarovsk
[131.8735, 43.1056], # Vladivostok
]
PAN_AMERICAN_WAYPOINTS = [
[-148.8782, 70.2568], # Prudhoe Bay
[-147.7230, 64.8378], # Fairbanks
[-149.8680, 61.2181], # Anchorage
[-135.0563, 60.7212], # Whitehorse
[-123.1216, 49.2827], # Vancouver
[-122.3321, 47.6062], # Seattle
[-122.6784, 45.5152], # Portland
[-122.4194, 37.7749], # San Francisco
[-118.2437, 34.0522], # Los Angeles
[-117.1611, 32.7157], # San Diego
[-117.0200, 32.5330], # Tijuana
[-110.9772, 29.0757], # Hermosillo
[-106.4100, 23.2167], # MazatlΓ‘n
[-103.3500, 20.6767], # Guadalajara
[-99.1332, 19.4326], # Mexico City
[-96.7264, 17.0732], # Oaxaca
[-93.1125, 16.7553], # Tuxtla GutiΓ©rrez
[-90.5151, 14.6244], # Guatemala City
[-89.2184, 13.6929], # San Salvador
[-86.2734, 12.1149], # Managua
[-84.0833, 9.9333], # San JosΓ©
[-79.5333, 8.9833], # Panama City
[-75.5758, 6.2170], # MedellΓ­n
[-74.0721, 4.7110], # BogotΓ‘
[-78.5000, -0.2299], # Quito
[-77.0333, -12.0500], # Lima
[-71.5375, -16.3989], # Arequipa
[-70.6483, -33.4569], # Santiago
[-67.4800, -45.8667], # Comodoro Rivadavia
[-70.9327, -53.1667], # Punta Arenas
[-68.3030, -54.8069], # Ushuaia
]
def smooth_path(coords, segments=2):
"""Add interpolated points between each waypoint for smoother curves."""
result = []
for i in range(len(coords) - 1):
result.append(coords[i])
for s in range(1, segments):
t = s / segments
result.append([
coords[i][0] + (coords[i+1][0] - coords[i][0]) * t,
coords[i][1] + (coords[i+1][1] - coords[i][1]) * t
])
result.append(coords[-1])
return result
def save_geojson(waypoints, name, filename):
"""Save waypoints as a GeoJSON LineString."""
coords = smooth_path(waypoints)
geojson = {
"type": "FeatureCollection",
"features": [{
"type": "Feature",
"properties": {"name": name},
"geometry": {
"type": "LineString",
"coordinates": coords
}
}]
}
with open(filename, 'w') as f:
json.dump(geojson, f)
print(f" GeoJSON saved: {filename} ({len(coords)} points)")
def draw_map(rail_waypoints, road_waypoints, output='railway_road_map.png'):
"""Render both routes on a dark-theme world map."""
rail_smooth = smooth_path(rail_waypoints)
road_smooth = smooth_path(road_waypoints)
rail_lons = [c[0] for c in rail_smooth]
rail_lats = [c[1] for c in rail_smooth]
road_lons = [c[0] for c in road_smooth]
road_lats = [c[1] for c in road_smooth]
fig = plt.figure(figsize=(18, 9), facecolor='#0d1117')
ax = fig.add_subplot(1, 1, 1, projection=ccrs.PlateCarree())
ax.set_facecolor('#0d1117')
ax.set_extent([-170, 180, -58, 73], crs=ccrs.PlateCarree())
# Base layers
ax.add_feature(cfeature.LAND, facecolor='#161b22', edgecolor='#1a2332', linewidth=0.3)
ax.add_feature(cfeature.OCEAN, facecolor='#0d1117')
ax.add_feature(cfeature.COASTLINE, edgecolor='#1a2332', linewidth=0.4)
ax.add_feature(cfeature.BORDERS, edgecolor='#1f2a3a', linewidth=0.2, alpha=0.5)
# Gridlines
gl = ax.gridlines(crs=ccrs.PlateCarree(), draw_labels=True,
linewidth=0.5, color='#1a2332', alpha=0.7)
gl.top_labels = False
gl.right_labels = False
gl.xlocator = plt.FixedLocator(range(-180, 181, 30))
gl.ylocator = plt.FixedLocator(range(-90, 91, 30))
# Routes
rail_line, = ax.plot(rail_lons, rail_lats, color='#f0883e', linewidth=2.2,
alpha=0.9, solid_capstyle='round', zorder=5,
transform=ccrs.PlateCarree())
road_line, = ax.plot(road_lons, road_lats, color='#58a6ff', linewidth=2.2,
alpha=0.9, solid_capstyle='round', zorder=5,
transform=ccrs.PlateCarree())
# Start/end markers
ax.plot(rail_lons[0], rail_lats[0], 'o', color='#f0883e', markersize=7, zorder=6,
transform=ccrs.PlateCarree())
ax.plot(rail_lons[-1], rail_lats[-1], 's', color='#f0883e', markersize=7, zorder=6,
transform=ccrs.PlateCarree())
ax.plot(road_lons[0], road_lats[0], 'o', color='#58a6ff', markersize=7, zorder=6,
transform=ccrs.PlateCarree())
ax.plot(road_lons[-1], road_lats[-1], 's', color='#58a6ff', markersize=7, zorder=6,
transform=ccrs.PlateCarree())
# Title
ax.text(0.5, 0.97, "World's Longest Railway & Highway Routes",
transform=ax.transAxes, color='#e6edf3', fontsize=15,
fontweight='bold', ha='center', va='top', fontfamily='monospace')
ax.text(0.5, 0.93, 'Trans-Siberian Railway Β· Pan-American Highway',
transform=ax.transAxes, color='#8b949e', fontsize=9,
ha='center', va='top', fontfamily='monospace')
# Legend
legend = ax.legend(
handles=[
Line2D([0], [0], color='#f0883e', linewidth=2.5,
label='Trans-Siberian Railway (9,289 km)'),
Line2D([0], [0], color='#58a6ff', linewidth=2.5,
label='Pan-American Highway (~30,000 km)'),
],
loc='lower left', framealpha=0.85, facecolor='#161b22',
edgecolor='#2d3a4a', labelcolor='#c9d1d9', fontsize=8
)
plt.savefig(output, dpi=180, bbox_inches='tight', facecolor=fig.get_facecolor())
plt.close()
print(f" Map saved: {output}")
if __name__ == '__main__':
print("Rendering World's Longest Routes...")
print()
print("Step 1: Saving GeoJSON files")
save_geojson(TRANS_SIBERIAN_WAYPOINTS, "Trans-Siberian Railway",
"trans_siberian_railway.geojson")
save_geojson(PAN_AMERICAN_WAYPOINTS, "Pan-American Highway",
"pan_american_highway.geojson")
print()
print("Step 2: Rendering map")
draw_map(TRANS_SIBERIAN_WAYPOINTS, PAN_AMERICAN_WAYPOINTS)
print()
print("Done! Files created:")
print(" - trans_siberian_railway.geojson")
print(" - pan_american_highway.geojson")
print(" - railway_road_map.png")
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment