実際のデータでCarto Tile地図を作成する

# はじめに
[こちらのページ](https://www.un.org/geospatial/mapsgeo/webservices)で公開されているCarto tileを作成します。今までは、[こちらの記事](https://qiita.com/k96mz/items/ccf2d2628d89cfa824a6)でベクトルタイルの作成を、[こちらの記事](https://qiita.com/k96mz/items/49f9976ad6ed9fdd701a)で主にスタイリングのコードの解説を、[こちらの記事](https://qiita.com/k96mz/items/b55a44c63bb917cd1c06)で実際に地図を作成する方法を記載しました。現在、公開されている地図は[こちら](https://un-geospatial.github.io/cartotile-plain-design/index.html)から見られます。また、以前に実験的に作成された地図は[こちら](https://un-geospatial.github.io/cartotile-plain-design/index_1_1.html)から見られます。現在公開されているCarto tileのGitHubページは[こちら](https://github.com/UN-Geospatial/cartotile-plain-design)です。
今回は実際のデータを使用して、地図を作成するところまでを記事にしたいと思います。

使用したレポジトリは[こちら](https://github.com/k96mz/20241004CartoTileStylizedfromArcdata)です。

# shpデータを取得する
まずは元データを取得します。私の環境では、ArcCatalogを利用して保存されているデータをshpファイルとしてエクスポートします。
ArcToolbox > Conversion Tools > To Geodatabase > Feature Class to Feature Classのツールを使用して、以下のスクリーンショットの設定にして実行します。以下はラインデータであるbndlについて実行していますが、ポリゴンデータであるbnda、wbyaについても同様です。

![FeatureClass2FeatureClass-bndl.PNG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3684675/a45e9ade-8a11-d601-3496-74a331cf2fec.png)

次にCRSを「WGS 1984(つまりEPSG:4326)」に変換します。
Data Management Tools > Projections and Transformations > Projectツールを使用して、以下のスクリーンショットの設定にして実行します。以下はラインデータであるbndlについて実行していますが、ポリゴンデータであるbnda、wbyaについても同様です。

![BNDLto4326.PNG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3684675/7f032c96-11bd-2c3f-408c-8c3fb753d8ec.png)

# 中央子午線(central meridian)の位置をずらす
このままの状態で進めていくと、下図のようにロシアの一部が切れて表示されてしまいます。そのため、この時点で中央子午線をずらしておく必要があります。

![スクリーンショット 2024-10-09 13.50.27.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3684675/6f429a18-495e-2024-b92e-5365a34edfbb.png)

### Multipart to Singlepartツールを使用する
この後、地物を移動させますが、1つの地物が複数の部分（例えば、島のような複数のポリゴンを含む場合）を持つとき、それをそれぞれの部分ごとに独立した地物として扱いたいので本ツールを使用します。本ツールを使用することで地物が分割されます。これをしておかないと、地物を移動させたときに、移動しなくても良い地物まで移動させてしまうことがあります。


Data Managment Tool > Features > Multipart to Singlepartツールを使用します。

![tosingle.PNG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3684675/d0ec81f1-8874-2693-670f-e748eafddeb9.png)

変換前と変換後のbndlの地物数を比較すると743から911に増加していました。bndaについては、246から497に増加していました。wbyaについては、カスピ海の一つのポリゴンしかないため、実施していません。

### 全ての地物を経度方向に-11度ずらす

まずは、右下の方に表示されている単位が、Decimal Degreesであることを確認してください。対象shpファイルを右クリックし、Selection > Select Allとしてすべての地物を選択します。ここで、レイヤclipboxは経度-180~180, 緯度-90~90をカバーするポリゴンで、自身で作成したものです。

![selection2.PNG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3684675/7fe28607-9436-6d27-81d2-a0f74f45afd3.png)

次にEditor > Start Editingとして、編集対象のshpファイルを選択します。
再度、Editor > Moveとして、Xに-11と入力し地物全体を経度方向に-11度移動させます。

![move2.PNG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3684675/00ddac77-cfa5-7579-0803-2ecaac559317.png)


移動させたあとは、下図を見ても分かる通り、-180より左側に移動した地物があり、これらを正常な範囲に再移動させる必要があります。つまり、対象地物の経度座標に360を足す必要があります。

![aftermove2.PNG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3684675/100050b3-b46e-f770-0b92-50eb049d1f8d.png)

移動させたいレイヤのみを選択できる状態にして、対象地物を地道に移動させていきます。まずは以下の通り選択します。Shiftを押しながら選択すると、複数の範囲を一気に選択できます。

![selectfeature.PNG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3684675/07b2a561-469f-f7a5-2f38-42d113029af4.png)

つぎに経度方向に360度移動させます。無事に下図の通り移動しました。

![afterselectfeature360.PNG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3684675/b7984a33-6a8a-2ddf-b804-17b6c2168193.png)

作業が完了したら、Editor > Save Edits、さらにEditor > Stop Editingを忘れないようにします。
この作業をbndl、bnda、wbyaの3つのレイヤで行います。bndaの作業前と作業後（薄緑）を比べるときちんと移動されていることがわかります。

![afterselectfeature360bnda.PNG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3684675/1c8ab43c-ba26-60f1-0908-4e0963670307.png)

### GeoJsonファイルへの変換

以前に記事に記載した通りに、ogr2ogrのコマンドを用いてshpファイルからGeoJsonファイルへの変換を行います。

# 投影法の変換
このままベクトルタイルを作成するとウェブメルカトル（EPSG:3857)で作成されてしまい、高緯度の領域が大きく縦に伸びる地図となってしまいます。そこで、[Dirty Reprojectors](https://developmentseed.org/dirty-reprojectors-app/)というツールを利用します。このツールを利用した変換を行うと、各座標値が地理的な意味を持たなくなることに注意してください。

サイトにおいて、作成したGeoJsonファイルをアップロードして、その後「robinson」をProjectionに選びます。ロビンソン図法は、世界全体を把握するという目的から見て優れた表現とされている図法です。次に、ダウンロードボタンをクリックすると投影法が変換されたGeoJsonファイルを得ることができます。

![スクリーンショット 2024-10-09 13.31.27.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3684675/1e8398ba-49f9-cd2d-1412-3e87ebe50383.png)

変換したGeoJsonファイル（茶色）を変換前のもの（ピンク色）と比べると大きく位置が異なっていることが分かります。

![スクリーンショット 2024-10-09 13.36.38.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3684675/f0f18820-f0fd-153c-099b-d2d5fe0b1fdf.png)

変換のイメージとしては、そのままベクトルタイルに変換すると高緯度付近が大きく縦に伸びるので、一度Dirty Reprojectorsで縮めてから、tippecanoeで実行する際にウェブメルカトルにすることで再度元の位置に戻しているというものかと思います。

※うまく変換されない場合の対処法
Dirty Reprojectorsのサイトでは、chromeだとラインデータの変換がうまくいかないこともあると聞いていましたが、私の場合は問題ありませんでした。もし問題がある場合は、Edgeで試してみると良いと思います。

:::note info
カスピ海のデータのみが含まれているwbyaのファイルは、なぜかうまく変換出来ませんでした。しかし、[こちらのページ](https://github.com/developmentseed/dirty-reprojectors)にある方法のコマンドを実行するとうまくいきます。プログラム実行時に以下のような警告も出ますが問題ないようです。

![スクリーンショット 2024-10-23 14.04.56.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3684675/573929cd-82d3-f1ee-e46f-3cc6ccd9f192.png)
:::


# 穴開きポリゴンのエラー処理
経度補正をしてさらにdirty補正をすることにより、穴開きポリゴンにエラーが発生するようです。具体的には、南アフリカ共和国の中にレソトが存在しますが、穴開きポリゴンがうまく作られていないようで、レソトのポップアップがうまく表示されません。

![スクリーンショット 2024-10-12 15.44.30.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3684675/9c808642-9f92-aa86-044a-702967d9c3ae.png)

QGISの機能で、 Vector > Geometry Tools > Check Validityとして調べても、以下のとおりエラーポリゴンと表示されます。

![スクリーンショット 2024-10-12 15.52.33.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3684675/528f1e58-af30-53d6-af03-d9ab332400c0.png)

そこで、Fix Geometriesツールを使用することで、このエラーを修正します。

![スクリーンショット 2024-10-12 15.55.38.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3684675/b4567018-c5d2-0a7c-eb2c-b6e2f5985cbb.png)

実行後は、作成されたレイヤーをGeoJsonファイルとしてエクスポートします。

# ベクトルタイルを作成する

以下のようなコマンドを実行してベクトルタイルを作成します。ズームレベルは0~2まで、レイヤ名はそれぞれ「bndl（ライン）」、「bnda（ポリゴン）」、「wbya（カスピ海ポリゴン」としています。
```
tippecanoe -e VTstylizedsingle-11dirty-fixed2 --no-tile-compression --no-feature-limit --no-tile-size-limit --drop-rate=1 -Z0 -z2 -L bndl:data/geojsonwgs84single-11dirty/bndl4326single-11dirty.geojson -L bnda:data/geojsonwgs84single-11dirty/bnda4326single-11dirty_fixed.geojson -L wbya:data/geojsonwgs84-11dirty/wbya4326-11dirty.geojson
```


5パターンのベクトルタイルとそのベクトルタイルを見られる地図サイトは以下のとおりです。

◯経度補正なし、dirty補正なし
https\://k96mz.github.io/20241004CartoTileStylizedfromArcdata/VTstylized/{z}/{x}/{y}.pbf

地図
https://k96mz.github.io/20241004CartoTileStylizedfromArcdata/index_1_2.html

◯経度補正なし、dirty補正あり
https\://k96mz.github.io/20241004CartoTileStylizedfromArcdata/VTstylizeddirty/{z}/{x}/{y}.pbf

地図
https://k96mz.github.io/20241004CartoTileStylizedfromArcdata/index_1_2dirty.html

◯経度補正あり、dirty補正あり
https\://k96mz.github.io/20241004CartoTileStylizedfromArcdata/VTstylizedsingle-11dirty/{z}/{x}/{y}.pbf

地図
https://k96mz.github.io/20241004CartoTileStylizedfromArcdata/index_1_2single-11dirty.html

◯経度補正あり、dirty補正あり、穴開きポリゴンのエラー処理あり
https\://k96mz.github.io/20241004CartoTileStylizedfromArcdata/VTstylizedsingle-11dirty-fixed/{z}/{x}/{y}.pbf

地図
https://k96mz.github.io/20241004CartoTileStylizedfromArcdata/index_1_2single-11dirty-fixed.html

◯経度補正あり、dirty補正あり、穴開きポリゴンのエラー処理あり、カスピ海ポリゴン追加
https\://k96mz.github.io/20241004CartoTileStylizedfromArcdata/VTstylizedsingle-11dirty-fixed2/{z}/{x}/{y}.pbf

地図
https://k96mz.github.io/20241004CartoTileStylizedfromArcdata/index_1_2single-11dirty-fixed2.html

◯経度補正あり、dirty補正あり、穴開きポリゴンのエラー処理あり、カスピ海ポリゴン追加、カスピ海ポリゴン周囲線追加
https\://k96mz.github.io/20241004CartoTileStylizedfromArcdata/VTstylizedsingle-11dirty-fixed3/{z}/{x}/{y}.pbf

地図
https://k96mz.github.io/20241004CartoTileStylizedfromArcdata/index_1_2single-11dirty-fixed3.html

# スタイルファイルを作成する
次にスタイル設定を含むHTMLファイルを作成していきます。以下のURLのindex_1_1.htmlの記述から必要な部分だけ修正していくことにします。

https://github.com/UN-Geospatial/cartotile-plain-design/blob/master/index_1_1.html

```html:index_1_2.html
<!DOCTYPE html>
<html>
  <head>
    <meta charset="utf-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1" />
    <title></title>
    <link
      rel="stylesheet"
      type="text/css"
      href="https://UN-Geospatial.github.io/cartotile-plain-design/mapbox-gl.css"
    />
    <style>
      body {
        margin: 0;
        top: 0;
        bottom: 0;
        width: 100%;
      }
      p.stscod1 {
        font-style: normal;
        font-size: 9pt;
        font-family: "arial", "Roboto";
      }
      p.stscod2 {
        font-style: italic;
        font-size: 8.5pt;
        font-family: "arial", "Roboto";
      }
      p.stscod3 {
        font-style: normal;
        font-size: 9pt;
        font-family: "arial", "Roboto";
      }
      p.stscod4 {
        font-style: normal;
        font-size: 8.5pt;
        font-family: "arial", "Roboto";
      }
      p.stscod5 {
        font-style: normal;
        font-size: 8.5pt;
        font-family: "arial", "Roboto";
      }
      p.stscod6 {
        font-style: italic;
        font-size: 8pt;
        font-family: "arial", "Roboto";
      }
      p.stscod99 {
        font-style: normal;
        font-size: 6.5pt;
        font-family: "arial", "Roboto";
      }
      #map {
        position: absolute;
        top: 0;
        bottom: 0;
        width: 100%;
      }
    </style>
    <script src="https://UN-Geospatial.github.io/cartotile-plain-design/mapbox-gl.js"></script>
  </head>
  <body>
    <style>
      .mapboxgl-popup {
        max-width: 400px;
      }
    </style>
    <div id="map"></div>
    <script>
      map = new mapboxgl.Map({
        container: "map",
        attributionControl: true,
        hash: true,
        renderWorldCopies: false,
        maxZoom: 2,
        zoom: 0.8,
        style: {
          version: 8,
          sources: {
            v: {
              type: "vector",
              tiles: [
                "https://k96mz.github.io/20241004CartoTileStylizedfromArcdata/VTstylized/{z}/{x}/{y}.pbf",
              ],
              attribution:
                '<table><tr><td style="font-size: 7pt; line-height: 100%">The boundaries and names shown and the designations used on this map do not imply official endorsement or acceptance by the United Nations.​ Final boundary between the Republic of Sudan and the Republic of South Sudan has not yet been determined.​<br>* Non-Self Governing Territories<br>** Dotted line represents approximately the Line of Control in Jammu and Kashmir agreed upon by India and Pakistan. The final status of Jammu and Kashmir has not yet been agreed upon by the parties.​<br>*** A dispute exists between the Governments of Argentina and the United Kingdom of Great Britain and Northern Ireland concerning sovereignty over the Falkland Islands (Malvinas).</td><td  style="font-size: 5pt; color: #009EDB" valign="bottom">Powered by<br><img src="https://unopengis.github.io/watermark/watermark.png" alt="UN OpenGIS logo" width="50" height="50"></td></tr></table>',
              maxzoom: 2,
              minzoom: 0,
            },
          },
          glyphs:
            "https://UN-Geospatial.github.io/cartotile-plain-design/font/{fontstack}/{range}.pbf",
          transition: {
            duration: 0,
            delay: 0,
          },
          layers: [
            {
              id: "background",
              type: "background",
              layout: { visibility: "visible" },
              paint: {
                "background-color": ["rgb", 255, 255, 255],
              },
            },
            {
              id: "bnda",
              type: "fill",
              source: "v",
              "source-layer": "bnda",
              maxzoom: 4,
              minzoom: 0,
              filter: ["none", ["==", "ISO3CD", "ATA"]],
              paint: {
                "fill-color": ["rgb", 237, 237, 237],
              },
            },
            {
              id: "bndl_solid",
              type: "line",
              source: "v",
              "source-layer": "bndl",
              maxzoom: 4,
              minzoom: 0,
              filter: [
                "any",
                ["==", "BDYTYP", 1],
                ["==", "BDYTYP", 0],
                ["==", "BDYTYP", 2],
              ],
              paint: {
                "line-color": ["rgb", 77, 77, 77],
                "line-width": 0.8,
              },
            },
            {
              id: "bndl_dashed",
              type: "line",
              source: "v",
              "source-layer": "bndl",
              maxzoom: 4,
              minzoom: 0,
              filter: ["all", ["==", "BDYTYP", 3]],
              paint: {
                "line-color": ["rgb", 77, 77, 77],
                "line-dasharray": [3, 2],
                "line-width": 0.8,
              },
            },
            {
              id: "bndl_dotted",
              type: "line",
              source: "v",
              "source-layer": "bndl",
              maxzoom: 4,
              minzoom: 0,
              filter: ["all", ["==", "BDYTYP", 4]],
              paint: {
                "line-color": ["rgb", 77, 77, 77],
                "line-dasharray": [1, 2],
                "line-width": 0.8,
              },
            },
          ],
        },
      });
      map.on("load", () => {
        map.addControl(new mapboxgl.NavigationControl());
      });

      var popup = new mapboxgl.Popup({
        closeButton: false,
        closeOnClick: false,
      });

      map.on("mousemove", "bnda", function (e) {
        map.getCanvas().style.cursor = "pointer";

        if (e.features[0].properties.STSCOD == 1) {
          var html =
            "<p class='stscod1'>" +
            e.features[0].properties.LBL_EN.toUpperCase() +
            "</p>";

          popup.setLngLat(e.lngLat).setHTML(html).addTo(map);
        } else if (e.features[0].properties.STSCOD == 2) {
          var html =
            "<p class='stscod2'>" +
            e.features[0].properties.LBL_EN.toUpperCase() +
            "</p>";

          popup.setLngLat(e.lngLat).setHTML(html).addTo(map);
        } else if (e.features[0].properties.STSCOD == 3) {
          if (
            e.features[0].properties.LBL_EN == "Falkland Islands (Malvinas) ***"
          ) {
            var html =
              "<p class='stscod3'>" + e.features[0].properties.LBL_EN + "</p>";
          } else {
            var html =
              "<p class='stscod3'>" + e.features[0].properties.LBL_EN + "</p>";
          }

          popup.setLngLat(e.lngLat).setHTML(html).addTo(map);
        } else if (e.features[0].properties.STSCOD == 4) {
          var html =
            "<p class='stscod4'>" + e.features[0].properties.LBL_EN + "</p>";

          popup.setLngLat(e.lngLat).setHTML(html).addTo(map);
        } else if (e.features[0].properties.STSCOD == 5) {
          var html =
            "<p class='stscod5'>" + e.features[0].properties.LBL_EN + "</p>";

          popup.setLngLat(e.lngLat).setHTML(html).addTo(map);
        } else if (e.features[0].properties.STSCOD == 6) {
          var html =
            "<p class='stscod6'>" + e.features[0].properties.LBL_EN + "</p>";

          popup.setLngLat(e.lngLat).setHTML(html).addTo(map);
        } else if (e.features[0].properties.STSCOD == 99) {
          if (e.features[0].properties.LBL_EN == "Jammu and Kashmir") {
            var html =
              "<p class='stscod6'>" + e.features[0].properties.LBL_EN + "​</p>";

            popup.setLngLat(e.lngLat).setHTML(html).addTo(map);
          } else {
            popup.remove();
          }
        }
      });

      map.on("mouseleave", "bnda", function () {
        map.getCanvas().style.cursor = "";
        popup.remove();
      });
    </script>
  </body>
</html>
```

変更点は以下です。
・参照するベクトルタイルを変更
・bndlの実線に関して、南極を削除する記載['!=', 'ISO3CD', 'ATA']などを追加。
・bndlのfilterで使用されている「bdytyp」を大文字の「BDYTYP」に変更
・bndaのポップアップ表示で使用されている「stscod」を大文字の「STSCOD」に変更、同様に「lbl_en」を大文字の「LBL_EN」に変更

## 属性の確認
bndl（ライン）とbnda（ポリゴン）について、htmlでスタイリングに使用されている属性の内容を解説します。

### bndlの「BDYTYP」
0: 海岸線
1: 内陸の国境線
2: データなし
3: 合意されていない国境線（ガザ地区など）
4: カシミール地方のデータ１つのみ

0~2は実線、3は実線が3ピクセルでその後2ピクセルの空白の繰り返し、4は実線が1ピクセルでその後2ピクセルの空白の繰り返し

### bndaの「STSCOD」
0: 南極のみ
1: 国境問題等がなさそうな国
2: ヨルダン川西岸とガザ地区の2箇所のみ
3: 西サハラやグアムなどの非自治地域(LBN_ENに「Western Sahara*」などと*マークあり。「Falkland Islands (Malvinas) *」も含む）
4: グリーンランドなどの自治領
5: 台湾のみ
6: データなし
99:カシミール地方やエジプトとスーダンの国境付近の地域などの国境が定まっていない地域

### bndaの「LBL_EN」
国名を示します。「NAM_EN」だとJapanと記載されているところが、「LBL_EN」だと大文字となりJAPANとなります。また西サハラなどの非自治地域は*マークがついて、「Western Sahara*」と表示されます。

### その他確認のポイント
南極の表示非表示
注釈の表示
Jammu and Kashimirの**
Falkland islands(Malvinas)の***
WG4_UNVT_project(private)>07_technical_lecture>2020-09-23_UNGIS
にDirty Reprojectorsの記載あり。

# まとめ
Carto tileを作成しました。修正等あれば、随時対応していきます。

# Reference

https://qiita.com/k96mz/items/ccf2d2628d89cfa824a6

https://qiita.com/k96mz/items/49f9976ad6ed9fdd701a

https://qiita.com/k96mz/items/b55a44c63bb917cd1c06

https://github.com/k96mz/20241004CartoTileStylizedfromArcdata/tree/main