Skip to main content

maritime-routing

Global maritime routing in Python. Computes the navigable route between any two ports in the world — or between two arbitrary points given by latitude/longitude — going around continents and islands.

Motivation

Planning a sea crossing is, at its core, a shortest-path problem on a graph: the ocean is the navigable space and the land is the set of obstacles. But that space is a spherical surface covering the whole planet, with islands, capes and straits that must be rounded — there are no predefined streets or roads.

The goal of this package is to make that computation simple and programmable:

  • based on real data (World Port Index for the ports and Natural Earth 10m Land for the coastline), not on manual approximations;
  • with a classic, transparent algorithm (A*) over a rasterized ocean/land grid, using Haversine distance as the heuristic;
  • returning ready-to-use objects (the route, the GeoJSON, the CSV and the map figure), instead of just writing files.

It is an educational and extensible foundation for maritime routing — not a real commercial routing system (which involves currents, winds, draft, EEZ, canals and economic factors), but designed to grow in that direction.

What the package does

  • Resolves ports by name (with country disambiguation) or accepts direct coordinates for origin and destination.
  • Builds a global navigable grid (1 = ocean, 0 = land) from the coastline, with per-resolution caching.
  • Runs A* with 8 neighbors, real-distance step cost and a Haversine heuristic (consistent, therefore optimal with weight 1.0).
  • Returns the sequence of route coordinates, the total distance, and exports GeoJSON/CSV and a map as in-memory objects.

Installation

With Poetry:

cd maritime-routing
poetry install
poetry run maritime-routing-fetch      # downloads the coastline and copies the ports.csv seed

Or, without Poetry, with pip:

python -m venv .venv && source .venv/bin/activate
pip install -e .
python -m maritime_routing.fetch

Dependencies and their minimum versions are declared in pyproject.toml — installation resolves everything automatically. Modern wheels already bundle GDAL/PROJ/GEOS, with no need for system libraries. Visualization uses plotly (with kaleido to export PNG), without cartopy.

Library usage (returns objects)

from maritime_routing import (
    compute_route, compute_route_by_coords,
    route_to_geojson, route_to_geojson_str, route_to_csv,
    plot_route, save_geojson, save_csv, save_figure,
    fetch_data,
)

Before computing the first route, provision the data with a single call — the coastline is downloaded and the ports.csv seed is copied into the external data/ folder:

fetch_data()                 # downloads coastline + copies the ports.csv seed
# fetch_data(include_ports=True)  # also shows the WPI notice (optional)

By port names

res = compute_route("Santos", "Shanghai",
                    grid_resolution=0.1, heuristic_weight=1.15)
res.distance_km          # float: total distance in km
res.path                 # list[(lat, lon), ...]
res.cells                # number of points
res.stats                # {'iterations', 'expanded', 'reason'}

geojson = route_to_geojson(res)     # dict (FeatureCollection)
csv_text  = route_to_csv(res)       # str
fig       = plot_route(res)         # plotly.graph_objects.Figure

# Write to disk (optional):
# save_geojson(geojson, "route.geojson")
# save_csv(csv_text, "route.csv")
# save_figure(fig, "route.png")

By origin and destination latitude/longitude

res = compute_route_by_coords(
    -23.9608, -46.3331,    # origin (lat, lon) — Santos
     31.2304, 121.4737,    # destination (lat, lon) — Shanghai
    grid_resolution=0.1, heuristic_weight=1.15,
)

Or directly through the MaritimeRouter class:

from maritime_routing import MaritimeRouter
router = MaritimeRouter(grid_resolution=0.1, heuristic_weight=1.15)
res = router.route("Santos", "Shanghai")
res2 = router.route_by_coords(-23.96, -46.33, 31.23, 121.47)

CLI usage

# By port names
maritime-routing --from "Santos" --to "Shanghai"

# Disambiguating the country
maritime-routing --from "New York" --from-country "United States" --to "Rotterdam"

# By coordinates (lat/lon of origin and destination)
maritime-routing --from-lat -23.96 --from-lon -46.33 \
                 --to-lat   31.23  --to-lon   121.47

# Coarser/faster, with a heuristic weight, writing to disk
maritime-routing --from "Santos" --to "Shanghai" \
    --resolution 0.25 --heuristic-weight 1.15 --save

Flags: --resolution, --rebuild-grid, --max-iterations, --heuristic-weight, --save (writes GeoJSON+CSV to data/routes/ and PNG to data/maps/), --no-map, --print-geojson, --print-csv, --print-points.

Also: python -m maritime_routing ... and python -m maritime_routing.fetch.

Structure

maritime-routing/
├── pyproject.toml                  # Poetry + console scripts
├── README.md
├── maritime_routing/               # the package
│   ├── __init__.py                  # public API
│   ├── __main__.py                  # python -m maritime_routing
│   ├── cli.py                       # CLI
│   ├── fetch.py                     # data download
│   ├── config.py
│   ├── distance.py                  # haversine / route_distance
│   ├── ports.py                     # PortDatabase (WPI)
│   ├── coastline.py                 # CoastlineMap (shapefile)
│   ├── raster.py                    # OceanGrid (navigable grid)
│   ├── astar.py                     # AStarRouter (A*)
│   ├── router.py                    # MaritimeRouter, RouteResult, compute_route[_by_coords]
│   ├── geojson.py                   # returns dict/str (+ save_*)
│   ├── visualize.py                 # returns Figure (+ save_figure)
│   └── data/ports.csv               # embedded seed (~70 ports, read-only)
└── data/                            # EXTERNAL to the package — user folder (generated)
    ├── ne_10m_land.*                #   coastline (downloaded)
    ├── ocean_grid_<res>.npy         #   grid caches (one per resolution)
    ├── ports.csv                    #   active (copied seed or user WPI)
    ├── routes/                      #   route GeoJSON + CSV (--save)
    └── maps/                        #   map PNG (--save)

The data/ folder is created in the current working directory (or in $MARITIME_ROUTING_DATA). Nothing is written inside the installed package — only the ports.csv seed is embedded; the active file is external.

Data

  • The active ports.csv (with Santos, Shanghai, etc.) lives in data/ports.csv (external). fetch_data() copies the seed (~70 ports) there on first run, without overwriting a CSV you may have placed yourself. For the full database (WPI), replace the file with your own CSV.
  • The coastline (ne_10m_land.shp) is downloaded into data/ (a folder external to the package; or $MARITIME_ROUTING_DATA) with a single call: fetch_data() from the API, or maritime-routing-fetch from the CLI.
  • The grid is cached as data/ocean_grid_<resolution>.npy (one file per resolution), so switching resolutions does not rebuild the grid.
  • With --save, GeoJSON/CSV go to data/routes/ and the PNG map to data/maps/. Everything lives in the same user data/ folder.

Configuration (config.py)

Parameter Default Description
GRID_RESOLUTION 0.05 Cell size in degrees
MAX_ITERATIONS 20000000 A* node expansion limit
NEIGHBOR_MODE 8 4 (rook) or 8 (with diagonals)
HEURISTIC_WEIGHT 1.0 Heuristic weight (1.0=optimal; >1=faster)
SNAP_SEARCH_RADIUS_DEG 2.0 Radius to "snap" ports/points to the coastline

The MARITIME_ROUTING_DATA environment variable overrides the writable data directory (coastline, caches, routes and maps). The default is the data/ folder in the current working directory.

Performance

  • Global grid at 0.05°: 3600 × 7200 ≈ 25.9M cells (uint8, ~26 MB); at 0.1°: 1800 × 3600; at 0.25°: 720 × 1440.
  • Rasterization via rasterio.features.rasterize (vectorized) + per-resolution caching.
  • A* with heapq (lazy deletion) and flat NumPy arrays for g_score/came_from; longitudinal wrap-around (trans-Pacific routes).
  • The Haversine heuristic is consistent (triangle inequality) → optimal A* with weight 1.0.

Practical tips (global routes)

Intercontinental routes require crossing entire ocean basins; at 0.05° A* may need millions of expansions:

# Fast (seconds): coarser resolution
maritime-routing --from "Santos" --to "Shanghai" --resolution 0.25 --rebuild-grid

# Balanced
maritime-routing --from "Santos" --to "Shanghai" --resolution 0.1 --heuristic-weight 1.15

# High resolution (several minutes): weight > 1 focuses the search
maritime-routing --from "Santos" --to "Shanghai" --resolution 0.05 --heuristic-weight 1.15

A --heuristic-weight > 1 greatly reduces expansions at the cost of a slightly suboptimal route (< 1 %). If you hit "ITERATION LIMIT reached", increase --max-iterations or the weight, or use a coarser resolution.

Limitations

  • The route is the shortest path on the grid (optimizing Haversine distance), not a real commercial route (currents, winds, draft, EEZ, stopovers…).
  • Suez/Panama canals are not modeled — A* goes around Africa and South America. (See the roadmap.)
  • Points on land are automatically "snapped" to the nearest ocean cell.
  • The lower the resolution, the faster the run and the coarser the route.

Roadmap (architecture ready for extensions)

  • Suez/Panama canals: mark the canal cells as navigable (and/or with a lower weight) in raster.py/config.py.
  • Depth restriction: integrate bathymetry (GEBCO) and make cells shallower than the draft non-navigable in OceanGrid.create_grid() (multiply masks).
  • Real commercial routes / AIS: per-cell weights (cost ≠ distance) derived from traffic density in astar._step_cost().
  • Economic weights: expose a weight array W[row,col] and multiply the step cost by it.

AI assistance

Parts of this project were developed with the assistance of an AI assistant (Claude).

The AI-assisted development process contributed to architectural improvements, code refinement, documentation updates, usability enhancements, and implementation optimizations.

All generated suggestions and modifications were carefully reviewed, tested, and verified to maintain the reliability and integrity of the project.

License

This project is licensed under the MIT License — see the LICENSE file for details.

Copyright (c) 2026 Junior Dantas

Data Sources

This project uses the following open datasets:

Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

maritime_routing-0.1.0.tar.gz (31.8 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

maritime_routing-0.1.0-py3-none-any.whl (34.9 kB view details)

Uploaded Python 3

File details

Details for the file maritime_routing-0.1.0.tar.gz.

File metadata

  • Download URL: maritime_routing-0.1.0.tar.gz
  • Upload date:
  • Size: 31.8 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/6.1.0 CPython/3.13.14

File hashes

Hashes for maritime_routing-0.1.0.tar.gz
Algorithm Hash digest
SHA256 d2cb392717c7b9ae25ef424f93224ef373cbff07a16f415d5745f93a754f9e2e
MD5 f0c5578713c040fc9a382574258f6625
BLAKE2b-256 9ece018639254e8697e9b2c741801fff36003b14199882b6f0848984ab3f2dc4

See more details on using hashes here.

File details

Details for the file maritime_routing-0.1.0-py3-none-any.whl.

File metadata

File hashes

Hashes for maritime_routing-0.1.0-py3-none-any.whl
Algorithm Hash digest
SHA256 1f9d44fbc0873440495649dca4d30b670c0a8198f4c3d0f6e4c6d0c7198fd7e7
MD5 8a9d6a647e3af09c78208363d3b8d1ed
BLAKE2b-256 1765516838a9b447f50ed012210beaa05814623f7bdee22d2c21b654660c331b

See more details on using hashes here.

Release history Release notifications | RSS feed

0.1.1

2 files

This release

0.1.0 This release

2 files

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page