https://github.com/code-shoily/meridian
geography + graph theory + elixir
https://github.com/code-shoily/meridian
Last synced: 1 day ago
JSON representation
geography + graph theory + elixir
- Host: GitHub
- URL: https://github.com/code-shoily/meridian
- Owner: code-shoily
- License: mit
- Created: 2026-05-09T17:14:09.000Z (about 2 months ago)
- Default Branch: main
- Last Pushed: 2026-06-14T04:15:43.000Z (11 days ago)
- Last Synced: 2026-06-14T06:19:37.621Z (10 days ago)
- Language: Elixir
- Size: 125 KB
- Stars: 1
- Watchers: 0
- Forks: 0
- Open Issues: 0
-
Metadata Files:
- Readme: README.md
- Changelog: CHANGELOG.md
- License: LICENSE
- Roadmap: ROADMAP.md
Awesome Lists containing this project
README
# Meridian
[](https://hex.pm/packages/meridian)
[](https://hexdocs.pm/meridian/)
[](https://github.com/code-shoily/meridian/actions)
[](https://coveralls.io/github/code-shoily/meridian?branch=main)
[](https://opensource.org/licenses/MIT)
> Projection-aware spatial graphs for Elixir.
Meridian sits on top of [`yog_ex`](https://hex.pm/packages/yog_ex) and brings
geography into graph theory. Build graphs from maps, run spatial algorithms,
and render your networks back onto the earth.
## Installation
Add `meridian` to your list of dependencies in `mix.exs`:
```elixir
def deps do
[
{:meridian, "~> 0.1.0"}
]
end
```
### Optional dependencies
Meridian keeps its core lightweight. Heavy or native dependencies are optional:
| Feature | Dependency | Add to `mix.exs` |
|---------|-----------|------------------|
| H3 hex grids | `:h3` | `{:h3, "~> 3.0"}` |
| Geohash grids | `:geohash` | `{:geohash, "~> 1.3"}` |
| GeoJSON I/O | `:jason` | `{:jason, "~> 1.4"}` |
| HTTP map APIs | `:req` | `{:req, "~> 0.5"}` |
## Quick Start
### H3 hexagonal grid
```elixir
graph =
Meridian.Graph.new(kind: :undirected)
|> Meridian.Builder.H3.grid(center: {43.6453, -79.3806}, resolution: 9, k_ring: 2)
Meridian.Graph.node_count(graph)
#=> 19
```
### Geohash grid
```elixir
graph =
Meridian.Graph.new(kind: :undirected)
|> Meridian.Builder.Geohash.grid(
sw: {43.6, -79.4},
ne: {43.7, -79.3},
precision: 5,
topology: :rook
)
```
### GeoJSON ingest
```elixir
{:ok, graph} =
"roads.geojson"
|> File.read!()
|> Meridian.IO.GeoJSON.from_string()
```
### Spatial shortest path
```elixir
{:ok, path} =
Meridian.Pathfinding.a_star(graph, from: :a, to: :b)
path.nodes
#=> [:a, :intersection_3, :b]
path.total_weight
#=> 1240.5
```
### Render back to GeoJSON
```elixir
graph
|> Meridian.Render.GeoJSON.to_string()
|> File.write!("output.geojson")
```
## Architecture
Meridian wraps `Yog.Graph` in a `Meridian.Graph` struct that carries spatial
metadata:
```elixir
%Meridian.Graph{
graph: %Yog.Graph{},
crs: "EPSG:4326",
srid: 4326,
bounds: %Geo.Polygon{}
}
```
This means every coordinate in the graph lives in a known, declared coordinate
reference system. Merging two graphs with different CRS values raises an
`ArgumentError` — no silent coordinate confusion.
## Modules
| Module | Purpose |
|--------|---------|
| `Meridian.Graph` | Spatial graph struct, queries, and modifications |
| `Meridian.CRS` | Earth-aware distances, edge-weight computation, bounding boxes |
| `Meridian.Geometry` | CRS-agnostic geometric helpers (euclidean, centroid, contains?) |
| `Meridian.Pathfinding` | Spatially-informed A*, Dijkstra, widest path |
| `Meridian.Spatial` | Proximity queries: `within/3`, `nearest/3` |
| `Meridian.Builder.H3` | Hexagonal grid graphs via Uber H3 |
| `Meridian.Builder.Geohash` | Rectangular grid graphs via geohash |
| `Meridian.IO.GeoJSON` | GeoJSON → graph ingestion |
| `Meridian.Render.GeoJSON` | Graph → GeoJSON rendering |
## Protocols
`Meridian.Graph` implements `Enumerable` and `Inspect`:
```elixir
graph = Meridian.Graph.new() |> Meridian.Graph.add_node(1, %{name: "A"})
Enum.to_list(graph)
#=> [{1, %{name: "A"}}]
inspect(graph)
#=> "#Meridian.Graph"
```
## Relationship to `yog_ex`
`yog_ex` provides the graph engine: Dijkstra, A*, Bellman-Ford, community
detection, connectivity, and every other graph algorithm you might need.
Meridian adds the *spatial layer* on top: coordinate systems, map ingestion,
grid builders, and geographic heuristics.
You can drop down to raw `yog_ex` at any time:
```elixir
yog = Meridian.Graph.to_yog(graph)
Yog.Pathfinding.Dijkstra.shortest_path(yog, from: :a, to: :b)
```
## Roadmap
See [`ROADMAP.md`](./ROADMAP.md) for the full plan, priorities, and what's up for grabs.
Highlights:
- ✅ Spatial graph with CRS, GeoJSON I/O, H3/geohash builders
- ✅ Spatial pathfinding — A*, Dijkstra, widest path
- ✅ Livebook map rendering via MapLibre
- ✅ OpenStreetMap ingestion (bounding box, raw JSON, and NIF-accelerated `.osm.pbf` parsing) (see [#1](https://github.com/code-shoily/meridian/issues/1))
- ⏳ Network buffers, spatial indexing, real CRS reprojection
## License
MIT License — see [LICENSE](./LICENSE) for details.