City to Map
Mix.install([
{:kino, "~> 0.14.2"},
{:kino_maplibre, "~> 0.1.12"},
{:httpoison, "~> 2.2"},
{:jason, "~> 1.4"}
])
Introduction
The notebook allows the user to enter any location and have it plotted on a world map. The locations of all matches on nominatim.openstreetmap.org are then fetched and the user picks one based on the openstreetmap display name.
This is accomplished throw the use of:
- Kino A package for adding interactive components to notebooks.
- HTTPoison A package for performing REST calls.
- Jason A package for JSON marchalling and unmarshalling.
- MapLibra A package for displaying maps in Livebook.
Convenience
alias MapLibre, as: Ml
Input
kinos = [
Kino.Input.text("Enter city name:", default: "Berkeley")
]
layout = Kino.Layout.grid(kinos)
Fetch latitude and longitude of all matches:
matches =
kinos
|> Enum.at(0)
|> Kino.Input.read()
|> (fn city ->
%HTTPoison.Response{status_code: 200, body: body} =
HTTPoison.get!("https://nominatim.openstreetmap.org/search?q=#{city}&format=json")
{:ok, matches} = Jason.decode(body)
matches
|> Enum.map(fn match ->
%{"lat" => lat, "lon" => long, "display_name" => dname} = match
{String.to_float(lat), String.to_float(long), dname}
end)
end).()
Allow the user to pick any match:
options = matches |> Enum.with_index(fn {_, _, name}, i -> {i, name} end)
kinos = [
Kino.Input.select("Pick match:", options)
]
layout = Kino.Layout.grid(kinos)
{lat, long, dname} =
kinos
|> Enum.at(0)
|> Kino.Input.read()
|> (fn index ->matches |> Enum.at(index) end).()
Display
locations = %{
"lat" => [lat],
"long" => [long],
"place" => [dname]
}
Ml.new()
|> Ml.add_table_source(
"locations",
locations,
{:lat_lng, ["lat", "long"]},
properties: ["place"]
)
|> Ml.add_layer(
id: "locations",
source: "locations",
type: :circle,
paint: [circle_color: "brown", circle_opacity: 0.8, circle_radius: 8]
)
|> Kino.MapLibre.info_on_click("locations", "place")