Geographic projections for plotting longitude/latitude data.
Enable a projection on a figure via Bland.figure(projection: :mercator).
After that, every series treats its xs as longitude in degrees and
ys as latitude in degrees, and the renderer projects each point
through the named projection before applying the usual x/y scales.
Projections
:none(default) — identity; no projection:mercator— standard web-mercator; y clamped to ±85°:equirect— equirectangular / plate carrée (identity)
Helpers
iex> {x, y} = Bland.Geo.mercator({0.0, 0.0})
iex> {abs(Float.round(x, 6)), abs(Float.round(y, 6))}
{0.0, 0.0}
iex> {_x, y} = Bland.Geo.mercator({0.0, 45.0})
iex> Float.round(y, 6)
0.881374Coastlines
ETD ships no built-in coastline data. For simple demos a bounding box
or hand-drawn outline suffices; for real maps, parse a GeoJSON source
(e.g. Natural Earth) externally and feed the polygons in as line/4
or area/4 series with (lon, lat) coordinates.
Summary
Functions
Equirectangular projection — a no-op pass-through, included for
symmetry with mercator/1.
Generates a graticule — a list of {xs, ys} polyline tuples in lon/lat
space — suitable for adding as multiple Bland.line/4 calls.
Web-Mercator projection. Longitudes pass through as radians; latitudes
are transformed to ln(tan(π/4 + lat/2)). Latitudes are clamped to
±85.05112878° (the standard Mercator cutoff) to avoid infinities at
the poles.
Projects {lon, lat} (degrees) through projection.
Projects a list of {lon, lat} pairs.
List of supported projection atoms.
Inscribes the world coastline-less "frame" — a rectangle at the given
lon/lat range, traced as {xs, ys}. Handy as a map boundary when you
don't have real coastline data.
Functions
Equirectangular projection — a no-op pass-through, included for
symmetry with mercator/1.
Generates a graticule — a list of {xs, ys} polyline tuples in lon/lat
space — suitable for adding as multiple Bland.line/4 calls.
Options
:lon_step(default30) — spacing of meridians in degrees:lat_step(default30) — spacing of parallels in degrees:lat_range(default{-80, 80}) — extent of meridians (keeps polar clutter minimal on Mercator):lon_range(default{-180, 180}):samples(default60) — points per polyline (for curvature fidelity under projection)
Returns a list of {xs, ys} tuples. Each is one full meridian or
parallel traced from endpoint to endpoint.
graticule = Bland.Geo.graticule(lon_step: 30, lat_step: 20)
fig =
Enum.reduce(graticule, base_fig, fn {xs, ys}, acc ->
Bland.line(acc, xs, ys, stroke: :dotted)
end)
Web-Mercator projection. Longitudes pass through as radians; latitudes
are transformed to ln(tan(π/4 + lat/2)). Latitudes are clamped to
±85.05112878° (the standard Mercator cutoff) to avoid infinities at
the poles.
Projects {lon, lat} (degrees) through projection.
Unknown projections fall back to the identity transform.
Projects a list of {lon, lat} pairs.
@spec projections() :: [atom()]
List of supported projection atoms.
@spec world_rect({number(), number()}, {number(), number()}, pos_integer()) :: {[float()], [float()]}
Inscribes the world coastline-less "frame" — a rectangle at the given
lon/lat range, traced as {xs, ys}. Handy as a map boundary when you
don't have real coastline data.