Elixir Livebook で国土交通省の都市計画データを視覚化する（工業地域や商業地域、道路などを地図上に表す）

## はじめに

『国交省GISデータ「全公開」の衝撃、企業はどう活用すればいいのか？』という記事を見ました

https://www.sbbit.jp/article/cont1/145362

とりあえず、 Livebook で視覚化してみましょう

https://livebook.dev/

以前、行政区域データを扱ったときと基本的には同じ手順になります

https://qiita.com/RyoWakabayashi/items/1a12439d2971444ba33b

実装したノートブックはこちら

https://github.com/RyoWakabayashi/elixir-learning/blob/main/livebooks/gis/gis_city.livemd

## 出典

「国土数値情報（都市計画データ）」（国土交通省）（<https://nlftp.mlit.go.jp/ksj/gml/datalist/KsjTmplt-A55-2022.html>）を加工して作成

## 都市計画とは

好き勝手に無秩序に都市を作ってしまうと、道路が上手く繋がっていないせいで渋滞が起きたり、商業施設があちこちに分散して不便になったり、住宅地のすぐ近くに工場ができたり、様々な問題が起こってしまいます

そこで、合理的に土地を使って都市を作るために都市計画を立てます

都市計画法という法律に都市計画のルールが決められています

https://laws.e-gov.go.jp/law/343AC0000000100

第一章　第二条　（都市計画の基本理念）

> 都市計画は、農林漁業との健全な調和を図りつつ、健康で文化的な都市生活及び機能的な都市活動を確保すべきこと並びにこのためには適正な制限のもとに土地の合理的な利用が図られるべきことを基本理念として定めるものとする。

法律を読むより、実際に作られた都市計画を読んだ方が分かりやすいです

https://www.city.oita.oita.jp/o169/machizukuri/toshi/1278403844374.html

都市計画では、「どの土地をどういう目的で使うか？」といったことが計画されます

国土交通省で全国自治体の都市計画データが統一フォーマットで公開されたため、様々なことに活用しやすくなりました

## 都市計画データのダウンロード

以下の国土交通省の Web サイトから都市計画データがダウンロードできます

https://nlftp.mlit.go.jp/ksj/gml/datalist/KsjTmplt-A55-2022.html

年度とデータ形式を選択します

本記事では [GEOJSON](https://geojson.org/) 形式を使用します

![スクリーンショット 2024-08-18 20.19.54.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1485835/428d3563-5782-9590-51f2-814afd6dd147.png)

続いて県と市を指定すると、ダウンロードボタンが表示されます

本記事では大分県大分市を使用します

![スクリーンショット 2024-08-18 20.22.10.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1485835/f3333a4b-fd0d-65ee-3835-38537738f867.png)

データは "A55-22_44201_GEOJSON.zip" といったような ZIP ファイルでダウンロードされます

展開すると、以下のようなファイルが含まれています

- 44201_bouka.geojson
- 44201_chikukei.geojson
- 44201_douro.geojson
- 44201_koudori.geojson
- 44201_kouen.geojson
- 44201_ritteki.geojson
- 44201_senbiki.geojson
- 44201_tkbt.geojson
- 44201_tochiku.geojson
- 44201_tokei.geojson
- 44201_youto.geojson
- A55_R4_AttributeCodelist.xlsx
- KS-META-A55-23_44.xml

本記事ではこれらのファイルを "/tmp/geo/" 配下に配置したものとして進めます

## Livebook のはじめ方

Livebook のはじめ方は以下の記事を参照してください

https://qiita.com/RyoWakabayashi/items/dc82ad3ed866d58a8acf

## 都市計画視覚化の実装

### セットアップ

Livebook を起動し、右上 "+ New notebook" ボタンで新しいノートブックを作成します

![スクリーンショット 2024-08-18 20.28.55.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1485835/2f37b62c-5a95-2a63-7173-e3175d370308.png)

セットアップセル（"Notebook dependencies and setup" と書いてある枠内）をクリックします

![スクリーンショット 2024-08-18 20.29.53.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1485835/e7c2f657-4152-c066-d883-4e3f8bfa2690.png)

すると、黒い枠に変わり、 Elixir のコードが入力できるようになります

![スクリーンショット 2024-08-18 20.32.20.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1485835/4a7bafed-5906-3872-5029-0ea39b983041.png)

以下のコードを入力し、左上の "Reconnect and setup" をクリックします

```elixir
Mix.install([
  {:geo, "~> 3.6"},
  {:jason, "~> 1.4"},
  {:kino, "~> 0.13"},
  {:kino_maplibre, "~> 0.1"}
])
```

これにより、必要なモジュールがインストールされます

### ファイル一覧の取得

ディレクトリーは以下にある ".geojson" ファイルの一覧を取得します

```elixir
geo_dir = "/tmp/geo"

geojson_file =
  geo_dir
  # ファイル一覧取得
  |> File.ls!()
  # `.geojson` で終わるものを取得
  |> Enum.filter(&String.ends_with?(&1, ".geojson"))
  # 並べ替え
  |> Enum.sort()
```

実行結果

```elixir
["44201_bouka.geojson", "44201_chikukei.geojson", "44201_douro.geojson", "44201_koudori.geojson",
 "44201_kouen.geojson", "44201_ritteki.geojson", "44201_senbiki.geojson", "44201_tkbt.geojson",
 "44201_tochiku.geojson", "44201_tokei.geojson", "44201_youto.geojson"]
```

### GEOJSON の読込

各ファイルを読み込みます

```elixir
geo_data =
  geojson_file
  |> Enum.into(%{}, fn filename ->
    key =
      filename
      |> String.split(".")
      |> hd()
      |> String.split("_")
      |> Enum.reverse()
      |> hd()
      |> String.to_atom()

    data =
      [geo_dir, filename]
      |> Path.join()
      |> File.read!()
      |> Jason.decode!()
      |> Geo.JSON.decode!()

    {key, data}
  end)
```

例えば `geo_data.tokei` の中には都市計画区域のデータが入っています

### 関数の定義

後で使う関数を定義しておきます

```elixir
# 地理情報を抽出する
filter_geometries = fn geometries, key, value ->
  geometries
  |> Enum.filter(fn geometry ->
    Map.get(geometry.properties, key) == value
  end)
  |> then(fn filtered ->
    %{
      __struct__: Geo.GeometryCollection,
      srid: nil,
      geometries: filtered,
      properties: %{}
    }
  end)
end
```

```elixir
# 地図上にレイヤーを追加する
add_layer = fn map, data, key, color, opacity ->
  map
  |> MapLibre.add_geo_source(key, data)
  |> MapLibre.add_layer(
    id: key,
    source: key,
    type: :fill,
    paint: [fill_color: color, fill_opacity: opacity]
  )
end
```

### 都市計画区域

以下のコードを実行すると、大分市の都市計画区域が地図上に青く表示されます

```elixir
MapLibre.new(style: :terrain, center: {131.68, 33.21}, zoom: 9.5)
|> add_layer.(geo_data.tokei, "都市計画区域", "#0000FF", 0.5)
```

![スクリーンショット 2024-08-18 20.52.02.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1485835/49406f17-b998-9f71-5a6c-fa0a0f0050d3.png)

青くなっていないところは都市計画区域外です

このように、 MapLibre を使うことで地図情報を簡単に視覚化できます

### 区域区分

区域区分は以下の二つに分類されます

- 市街化区域: すでに市街化されているか、今後10年以内に優先的かつ計画的に市街化する地域
- 市街化調整区域: 市街化を抑制する地域

市街化区域を紫、市街化調整区域を緑で色分けしてみましょう

```elixir
senbiki_color_map =
  %{
    "市街化区域" => "#FF00FF",
    "市街化調整区域" => "#00FF00"
  }
```

```elixir
senbiki_map = MapLibre.new(style: :terrain, center: {131.68, 33.21}, zoom: 9.5)

senbiki_color_map
|> Enum.reduce(senbiki_map, fn {senbiki, color}, map ->
  target_data = filter_geometries.(geo_data.senbiki.geometries, "区域区分", senbiki)
  add_layer.(map, target_data, senbiki, color, 0.7)
end)
```

![スクリーンショット 2024-08-18 21.23.53.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1485835/fc4f33cb-90a2-22ed-5e30-3ece509fc07e.png)

概ね、平野が紫に、山地が緑になっています

### 用途地域

用途地域とは、商業地域や工業地域など、目的に応じた用途を定めている地域です

用途地域データを一つ見てみましょう

```elixir
hd(geo_data.youto.geometries)
```

実行結果

```elixir
%Geo.Polygon{
  coordinates: [
    [
      {131.65889593, 33.137780418},
      {131.658823506, 33.137769104},
      {131.658637339, 33.138286862},
      {131.658549054, 33.13849049},
      {131.65847681, 33.138666893},
      {131.658259591, 33.139260104},
      {131.658187178, 33.139464643},
      {131.658143537, 33.139574701},
      ...
    ]
  ],
  srid: nil,
  properties: %{
    "Citycode" => "44201",
    "Cityname" => "大分市",
    "Pref" => "大分県",
    "YoutoID" => 12,
    "告示番号" => nil,
    "容積率" => 200.0,
    "建ぺい率" => 60.0,
    "決定区分" => nil,
    "決定日" => nil,
    "決定者" => nil,
    "用途地域" => "工業地域"
  }
}
```

地域は多角形（ポリゴン）として表され、その頂点を `coordinates` 内に緯度経度で保持しています

`properties` には各地域の属性情報が入っており、 `YoutoID` や `用途地域` を見れば、どの用途に使う地域なのかがわかるようになっています

:::note info
`YoutoID` などのコードマスターは[こちら](https://nlftp.mlit.go.jp/ksj/gml/codelist/A55_R4_AttributeCodelist.xlsx)
:::

用途地域毎に色分けしてみましょう

```elixir
youto_color_map =
  %{
    "第１種低層住居専用地域" => "#549F52",
    "第２種低層住居専用地域" => "#B0D397",
    "第１種中高層住居専用地域" => "#64B36D",
    "第２種中高層住居専用地域" => "#9FC662",
    "第１種住居地域" => "#F4EB4E",
    "第２種住居地域" => "#F5C345",
    "準住居地域" => "#ED9D3E",
    "田園住居地域" => "#BE6C38",
    "近隣商業地域" => "#EACFE2",
    "商業地域" => "#BC7CAE",
    "準工業地域" => "#9595C5",
    "工業地域" => "#D9EBF1",
    "工業専用地域" => "#77C4F2"
  }
```

各関数を利用し、用途地域毎のレイヤーを地図上に表示します

```elixir
youto_map = MapLibre.new(style: :terrain, center: {131.68, 33.21}, zoom: 10.5)

youto_color_map
|> Enum.reduce(youto_map, fn {youto, color}, map ->
  target_data = filter_geometries.(geo_data.youto.geometries, "用途地域", youto)
  add_layer.(map, target_data, youto, color, 0.7)
end)
```

実行結果

![スクリーンショット 2024-08-18 21.09.51.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1485835/e77e2998-5f26-7ea4-c773-4a375f554fca.png)

また、以下のコードを実行すると、用途地域毎に別タブで表示することができます

```elixir
youto_color_map
|> Enum.map(fn {youto, color} ->
  target_data = filter_geometries.(geo_data.youto.geometries, "用途地域", youto)

  map =
    MapLibre.new(style: :terrain, center: {131.68, 33.21}, zoom: 10.5)
    |> add_layer.(target_data, youto, color, 0.7)

  {youto, map}
end)
|> Kino.Layout.tabs()
```

実行結果

![map_tab.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1485835/cba0d01d-8836-7476-33ee-5d30e74c6644.gif)

大分駅周辺が商業地域、新日鐵の辺りが工業専用地域になっていることなどが分かります

### 高度利用地区

高度利用地区とは、有効活用するために空けておく地区です

```elixir
MapLibre.new(style: :terrain, center: {131.606, 33.234}, zoom: 16)
|> add_layer.(geo_data.koudori, "高度利用地区", "#0000FF", 0.7)
```

実行結果

![スクリーンショット 2024-08-18 21.34.05.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1485835/a1fe6215-c490-c370-3399-41e32c5e1b88.png)

大分駅北西側が対象になっています

近年、大規模な整理が行われたことは記憶に新しいですね

### 防火地域・準防火地域

防火地域・準防火地域は、市街地における火災の被害抑制のため、設備などに制限を設ける地域です

防火地域を明るい赤、準防火地域を暗い赤で視覚化してみます

```elixir
bouka_color_map =
  %{
    "防火地域" => "#FF0000",
    "準防火地域" => "#880000"
  }

bouka_map = MapLibre.new(style: :terrain, center: {131.64, 33.24}, zoom: 12)

bouka_color_map
|> Enum.reduce(bouka_map, fn {bouka, color}, map ->
  target_data = filter_geometries.(geo_data.bouka.geometries, "防火準防火", bouka)
  add_layer.(map, target_data, bouka, color, 0.8)
end)
```

実行結果

![スクリーンショット 2024-08-18 21.43.05.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1485835/74b888e0-9989-976e-1524-3de9ab205128.png)

準防火地域は大分市街地と鶴崎が対象になっています

防火地域は大分駅から竹町、中央町の商店街辺りが対象です

### 地区計画

開発や再開発を促進しようとしている地区です

```elixir
MapLibre.new(style: :terrain, center: {131.68, 33.21}, zoom: 10.5)
|> add_layer.(geo_data.chikukei, "地区計画", "#0000FF", 0.8)
```

実行結果

![スクリーンショット 2024-08-18 21.48.05.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1485835/547bae7f-3756-e3c4-33ba-40e3969c6905.png)

大分駅周辺や荷揚町などが対象になっています

荷揚リンクスクエアが最近オープンしましたね

https://log-oita.com/link-square-20240401/

### 特別用途地区

住環境を保全するなどの目的のため、大型集客施設などの建築を抑制する地区です

```elixir
MapLibre.new(style: :terrain, center: {131.68, 33.21}, zoom: 10.5)
|> add_layer.(geo_data.tkbt, "特別用途地区", "#0000FF", 0.8)
```

実行結果

![スクリーンショット 2024-08-18 21.57.59.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1485835/c6e73ddf-f9f6-a3ec-d6f9-814606b0a5b1.png)

### 土地区画整理事業

土地区画整理事業の対象となっている地域です

https://www.mlit.go.jp/toshi/city/sigaiti/toshi_urbanmainte_tk_000020.html

> 土地区画整理事業は、道路、公園、河川等の公共施設を整備・改善し、土地の区画を整え宅地の利用の増進を図る事業

```elixir
MapLibre.new(style: :terrain, center: {131.68, 33.21}, zoom: 10.5)
|> add_layer.(geo_data.tochiku, "土地区画整理事業", "#FF00FF", 0.8)
```

実行結果

![スクリーンショット 2024-08-18 22.03.43.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1485835/6ffc7fb0-66dc-5094-eb0b-5c2c938c5ea3.png)

大分市街地から鶴崎、大在、坂ノ市など、人口の多い地域をカバーしています

### 立地適正化計画

住居や福祉施設、商業施設がまとまっているようにするための計画です

https://www.mlit.go.jp/en/toshi/city_plan/compactcity_network.html

> 我が国の都市における今後のまちづくりは、人口の急激な減少と高齢化を背景として、高齢者や子育て世代にとって、安心できる健康で快適な生活環境を実現すること、財政面及び経済面において持続可能な都市経営を可能とすることが大きな課題です。こうした中、医療・福祉施設、商業施設や住居等がまとまって立地し、高齢者をはじめとする住民が公共交通によりこれらの生活利便施設等にアクセスできるなど、福祉や交通なども含めて都市全体の構造を見直し、『コンパクト・プラス・ネットワーク』の考えで進めていくことが重要です。

居住誘導区域外に住居を建てる場合、特別な届出が必要になります

また、都市機能誘導区域外に大規模商業施設や福祉施設を建てる場合、逆に都市機能誘導区域内の大規模商業施設や福祉施設を休廃止する場合にも特別な届出が必要です

`居住誘導区域` を赤、 `都市機能誘導区域` を青にしました

```elixir
ritteki_color_map =
  %{
    "居住誘導区域" => "#FF0000",
    "都市機能誘導区域" => "#0000FF"
  }

ritteki_map = MapLibre.new(style: :terrain, center: {131.68, 33.21}, zoom: 10.5)

ritteki_color_map
|> Enum.reduce(ritteki_map, fn {ritteki, color}, map ->
  target_data = filter_geometries.(geo_data.ritteki.geometries, "区域区分", ritteki)
  add_layer.(map, target_data, ritteki, color, 0.5)
end)
```

実行計画

![スクリーンショット 2024-08-18 22.13.15.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1485835/71803f26-9ed3-99c2-183d-e7e25ebed065.png)

いわゆる市街地に集中するように計画されています

### 都市施設

公園や緑地、墓場、道路など、都市機能に必要な施設を視覚化します

- 公園: 黄
- 緑地: 緑
- 墓場: 青
- 道路、広場: 黒線

```elixir
kouen_color_map =
  %{
    "公園" => "#FFFF00",
    "緑地" => "#00FF00",
    "墓園" => "#0000FF"
  }

road_data = filter_geometries.(geo_data.douro.geometries, "区分", "道路")
plaza_data = filter_geometries.(geo_data.douro.geometries, "区分", "広場")

kouen_map = MapLibre.new(style: :terrain, center: {131.68, 33.21}, zoom: 10.5)

kouen_color_map
|> Enum.reduce(kouen_map, fn {kouen, color}, map ->
  target_data = filter_geometries.(geo_data.kouen.geometries, "種類", kouen)
  add_layer.(map, target_data, kouen, color, 0.8)
end)
|> MapLibre.add_geo_source("道路", road_data)
|> MapLibre.add_layer(id: "道路", source: "道路", type: :line)
|> MapLibre.add_geo_source("広場", plaza_data)
|> MapLibre.add_layer(id: "広場", source: "道路", type: :line)
```

実行結果

![スクリーンショット 2024-08-18 22.30.10.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1485835/333555ca-6b7a-3e84-b557-bda2e2a91fc5.png)

川沿いに緑地が作られていることがわかります

一番大きい黄色は大分スポーツ公園ですね

https://www.oita-sportspark.jp/

## まとめ

都市計画データを視覚化することで、今後10年、どこの土地がどのように使われようとしているのかが分かります

本記事のように 2024 年現在から 2022 年の都市計画を見ると、「だからあの辺りにあの施設ができたのか」というように納得できるデータです

皆さんも、地元の都市計画を見てみましょう