Meridian.Graph (Meridian v0.1.0)

Copy Markdown View Source

A spatial graph—Yog.Graph enriched with coordinate system metadata and an optional spatial bounding box.

Implements Enumerable (iterates over {id, data} node tuples) and Inspect (compact #Meridian.Graph<...> representation).

Fields

  • graph — the underlying Yog.Graph.t()
  • crs — coordinate reference system identifier (default "EPSG:4326")
  • srid — numeric SRID when available (default 4326)
  • bounds — bounding geometry (%Geo.Polygon{} or nil)

Examples

iex> g = Meridian.Graph.new()
iex> g.crs
"EPSG:4326"
iex> g.srid
4326

iex> g = Meridian.Graph.new() |> Meridian.Graph.add_node(1, %{name: "A"})
iex> Enum.to_list(g)
[{1, %{name: "A"}}]

Summary

Functions

Adds a spatial edge to the graph.

Adds a spatial edge to the graph, raising on error.

Ensures both endpoint nodes exist, then adds an edge.

Adds a spatial node to the graph.

Adds multiple nodes from an enumerable of {id, data} tuples or a map.

Returns the number of edges in the spatial graph.

Returns all edges as a list of {from, to, weight} tuples.

Wraps an existing Yog.Graph as a spatial graph.

Checks if a node has a :geometry key in its data.

Checks if the graph contains a node with the given ID.

Returns the kind of the underlying graph (:directed or :undirected).

Merges another spatial graph into this one.

Creates a new empty spatial graph.

Returns the data associated with a node, or nil if the node does not exist.

Returns the number of nodes in the spatial graph.

Returns all nodes as a map of id => data.

Recomputes the bounding box from all node geometries.

Removes an edge from the graph.

Removes a node and all its connected edges.

Unwraps a Meridian.Graph to its underlying Yog.Graph.

Updates a node's data by merging the given map into the existing data.

Types

crs()

@type crs() :: String.t()

srid()

@type srid() :: pos_integer() | nil

t()

@type t() :: %Meridian.Graph{
  bounds: Geo.Polygon.t() | nil,
  crs: crs(),
  graph: Yog.Graph.t(),
  srid: srid()
}

Functions

add_edge(mg, from, to, weight)

@spec add_edge(t(), Yog.node_id(), Yog.node_id(), any()) ::
  {:ok, t()} | {:error, String.t()}

Adds a spatial edge to the graph.

Examples

iex> g = Meridian.Graph.new()
iex> g = g |> Meridian.Graph.add_node(:a, %{}) |> Meridian.Graph.add_node(:b, %{})
iex> {:ok, g} = Meridian.Graph.add_edge(g, :a, :b, %{distance: 10.5})
iex> g.graph.out_edges[:a][:b]
%{distance: 10.5}

add_edge!(mg, from, to, weight)

@spec add_edge!(t(), Yog.node_id(), Yog.node_id(), any()) :: t()

Adds a spatial edge to the graph, raising on error.

add_edge_ensure(mg, from, to, weight, default \\ nil)

@spec add_edge_ensure(t(), Yog.node_id(), Yog.node_id(), any(), any()) :: t()

Ensures both endpoint nodes exist, then adds an edge.

If from or to is not already in the graph, it is created with the supplied default node data. Existing nodes are left unchanged.

add_node(mg, id, data)

@spec add_node(t(), Yog.node_id(), map()) :: t()

Adds a spatial node to the graph.

data should typically contain a :geometry key with a Geo struct.

Examples

iex> g = Meridian.Graph.new()
iex> point = %Geo.Point{coordinates: {-73.9857, 40.7484}}
iex> g = Meridian.Graph.add_node(g, :nyc, %{geometry: point, name: "NYC"})
iex> Meridian.Graph.node(g, :nyc).name
"NYC"

add_nodes(mg, nodes)

@spec add_nodes(t(), Enumerable.t()) :: t()

Adds multiple nodes from an enumerable of {id, data} tuples or a map.

Examples

iex> g = Meridian.Graph.new()
iex> g = Meridian.Graph.add_nodes(g, a: %{geometry: %Geo.Point{coordinates: {0.0, 0.0}}})
iex> Meridian.Graph.node_count(g)
1

edge_count(graph)

@spec edge_count(t()) :: non_neg_integer()

Returns the number of edges in the spatial graph.

edges(graph)

@spec edges(t()) :: [{Yog.node_id(), Yog.node_id(), any()}]

Returns all edges as a list of {from, to, weight} tuples.

from_yog(graph, opts \\ [])

@spec from_yog(
  Yog.Graph.t(),
  keyword()
) :: t()

Wraps an existing Yog.Graph as a spatial graph.

Examples

iex> yog = Yog.undirected() |> Yog.add_edge_ensure(1, 2, 10)
iex> g = Meridian.Graph.from_yog(yog, crs: "EPSG:4326")
iex> g.graph == yog
true

has_geometry?(graph, id)

@spec has_geometry?(t(), Yog.node_id()) :: boolean()

Checks if a node has a :geometry key in its data.

has_node?(graph, id)

@spec has_node?(t(), Yog.node_id()) :: boolean()

Checks if the graph contains a node with the given ID.

kind(graph)

@spec kind(t()) :: :directed | :undirected

Returns the kind of the underlying graph (:directed or :undirected).

merge(a, b)

@spec merge(t(), t()) :: t()

Merges another spatial graph into this one.

Both graphs must share the same CRS. Nodes and edges from other are added; in case of node ID collisions, other's data wins.

Examples

iex> a = Meridian.Graph.new() |> Meridian.Graph.add_node(1, %{name: "A"})
iex> b = Meridian.Graph.new() |> Meridian.Graph.add_node(2, %{name: "B"}) |> Meridian.Graph.add_edge_ensure(2, 1, 5)
iex> merged = Meridian.Graph.merge(a, b)
iex> Meridian.Graph.node_count(merged)
2
iex> Meridian.Graph.edge_count(merged)
1

new(opts \\ [])

@spec new(keyword()) :: t()

Creates a new empty spatial graph.

Options

  • :kind:directed (default) or :undirected
  • :crs — CRS identifier string, defaults to "EPSG:4326"
  • :srid — numeric SRID, defaults to 4326

Examples

iex> g = Meridian.Graph.new()
iex> g.graph.kind
:directed

iex> g = Meridian.Graph.new(kind: :undirected, crs: "EPSG:3857")
iex> g.crs
"EPSG:3857"

node(graph, id)

@spec node(t(), Yog.node_id()) :: any() | nil

Returns the data associated with a node, or nil if the node does not exist.

node_count(graph)

@spec node_count(t()) :: non_neg_integer()

Returns the number of nodes in the spatial graph.

nodes(graph)

@spec nodes(t()) :: %{required(Yog.node_id()) => any()}

Returns all nodes as a map of id => data.

recompute_bounds(mg)

@spec recompute_bounds(t()) :: t()

Recomputes the bounding box from all node geometries.

remove_edge(mg, from, to)

@spec remove_edge(t(), Yog.node_id(), Yog.node_id()) :: t()

Removes an edge from the graph.

remove_node(mg, id)

@spec remove_node(t(), Yog.node_id()) :: t()

Removes a node and all its connected edges.

to_yog(graph)

@spec to_yog(t()) :: Yog.Graph.t()

Unwraps a Meridian.Graph to its underlying Yog.Graph.

Examples

iex> g = Meridian.Graph.new() |> Meridian.Graph.add_node(1, "A")
iex> %Yog.Graph{} = Meridian.Graph.to_yog(g)

update_node(mg, id, new_data)

@spec update_node(t(), Yog.node_id(), map()) :: t()

Updates a node's data by merging the given map into the existing data.

Returns the updated graph. If the node does not exist, it is created.

Examples

iex> g = Meridian.Graph.new() |> Meridian.Graph.add_node(:a, %{name: "A"})
iex> g = Meridian.Graph.update_node(g, :a, %{tags: [:highway]})
iex> Meridian.Graph.node(g, :a).tags
[:highway]