Powered by AppSignal & Oban Pro
Would you like to see your link here? Contact us

City to Map

city2map.livemd

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")