はじめに
国土地理院は、従来よりベクトルタイル提供実験を行っていますが、9月初めに最適化ベクトルタイル試験公開を公開しています。このレポジトリでは、最適化ベクトルタイルの仕様のほか、表示用の「サンプルスタイル(標準地図風)」も提供されています。
ベクトルタイルの利点として、1つのベクトルタイルから、目的に合わせて地図をデザインすることができます。最適化ベクトルタイルの公開当初は最初はスルーしていたのですが、せっかくですから、この最適化ベクトルタイルについても、様々なデザインで表示したいという欲が湧いてきました。
そこで、今回は、最適化ベクトルタイルのスタイル作成時に考えたことや気づきを記事に残したいと思います。なお、私は「地図のデザイン設定」のことをスタイルと呼んでいます。(Mapbox GL JS の style に倣ってのことです。)
また、地理院が従来提供しているベクトルタイルと最適化ベクトルタイルの何が異なるかについては、主な違いを以下の記事にまとめています。
戦略
戦略の内容
以下のように、作業戦略を決めました。
具体的には、以下のような作業を行います。
- 「サンプルスタイル(標準地図風)」で使われている色を把握する。
- 使われている色を目的別に分類する。
- 目的ごとのキー名で色を置き換えたひな型となるスタイルを作成する。(画像中①に相当)
- ひな型から様々なバリエーションのスタイルへ変換する。(画像中②に相当)
理由
まず、スタイルを作成するにあたり、どこまで自由にデザインをしたいかを考えつつ、既存のリソースを活用できないか調査を行いました。
実は、以前も国土地理院のベクトルタイルのデザインについては、個人的に色々と試行錯誤をしていたことがあります(たとえば、シンプルなデザインを作るという試み)。このときの経験から考えると、やはり印象を大きく変えるのは色であり、色を変えながらさまざまなバリエーションのスタイルを作りたいという思いが大きかったです。ほかにも変更したい部分はありましたが、たくさんのバリエーションを作りたいという類のものではありませんでした。
特に、提供されている「サンプルスタイル(標準地図風)」を確認すると、スタイルのレイヤ数は123と従来のスタイルに比べて非常に少ないながらも、かなりダイナミックな filter 条件や、色や線幅等の条件分岐を設定しているようです。属性値等を含めて、仕様書も公開されていますので、こちらを参考に位置からスタイルを作成することもできるかもしれませんが、すでに提供されているサンプルスタイルのような芸当は難しいと判断しました。
そこで、今回は、これらの条件を踏まえ、「サンプルスタイル(標準地図風)」をベースに、色を変更しやすくするための「ひな型」となるスタイルを作成し、そこから様々なカラーバリエーションのスタイルを作成することにしました。
また、コードの説明はしませんが、スタイルの変換(Node.js)と消費(ブラウザ)と、作業は基本的に JavaScript でカバーできます。
以下、作業の各ステップを詳しく見ていきます。
作業内容
使われている色を把握する
まず、公開されている「サンプルスタイル(標準地図風)」でどのような色が使われているか把握します。機械的に抽出すればよいかと思いますが、今後の作業も考えると、注意点は以下の通りです。
- 幸いにも、色は
rgba(r, g, b, a)
またはrgb(r, g, b)
の形式で統一されている。 - ただし、各レイヤの
*-color
に、単純な色のデータが記述されているわけではなく、条件分岐で複雑な記述となっているので、ネストを探って色を取得する必要がある。 - 透過度は、各レイヤの
*-opacity
でも設定できるが、複雑な条件設定では、透過度をrgba(r, g, b, a)
の記述を用いて制御している場合があるので、rgba の記述では、不透明度も取得して、引き継ぐ必要がある。 -
rgb(255, 255, 255)
やrgb(100, 100, 100)
など様々な場所で使われている色を、その色情報だけで役割を分類するのは大変なので、source-layer
(場合によっては、layer のid
やline-color
等の属性値名等)も含めて吟味する必要がある。
以上から、*-color
に設定されているすべての色(不透明度情報も含む)について、レイヤの id
、source-layer
も含めて把握する必要があります。たとえば、以下のようなレイヤであれば、rgb(0,176,236)
、rgba(100,100,100,1)
、rgba(20,90,255,1)
を抽出し、それぞれの色に id
:海岸線
、source-layer
:Cstline
、属性値名:line-color
を紐づけておきます。
{
"id": "海岸線",
"type": "line",
"source": "v",
"source-layer": "Cstline",
"filter": [
"in",
[ "get", "vt_code" ],
[ "literal", [ 5101, 5103 ] ]
],
"paint": {
"line-color": [
"step",
[ "zoom" ], "rgb(0,176,236)", 8,
[ "match",
[ "get", "vt_code" ],
[ 5103 ], "rgba(100,100,100,1)",
"rgba(20,90,255,1)"
]
],
…
}
}
使われている色を目的別に分類する
上記で抽出した使われている色を、役割毎に分類します。細かく分けることもできますが、後々、色を設定する際に複雑になりすぎないように、思い切ってまとめていきます。このあたりは、腕の見せどころなのかもしれません。なお、対応表から漏れた色は、そのまま元の色を表示させることにします。
元の色 | 役割毎のキー名 |
source-layer 条件 |
属性値名条件 | 役割 | 備考 |
---|---|---|---|---|---|
rgb(255,255,255) |
-text-white-halo- |
text-halo-* |
文字の縁取りの色 | 元が白の文字色 | |
rgb(0,0,255) |
-water-main-vivid- |
text-* |
水面系統(濃) | 水域関係の文字色 | |
rgb(60,50,181) |
-water-main-vivid- |
text-* |
水域関係の文字色 | ||
rgb(20,90,255) |
-water-main-vivid- |
text-* |
水面系統(薄) | 水域関係の文字色 | |
rgb(190,210,255) |
-water-main-main- |
text-* |
水域関係の文字色(水面と同じ色 | ||
rgb(200,160,60) |
-landform-main-main- |
text-* |
等高線・地形 | 等高線関係の文字色 | |
rgb(19,97,69) |
-text-green-main- |
text-* |
文字色(元緑) | 元が緑の文字色(駅名、路線名等 | |
rgb(160,160,160) |
-text-gray-main- |
text-* |
文字色(元灰) | 元が灰色の文字色 | |
rgb(80,80,80) |
-text-gray-main- |
text-* |
文字色(元濃灰) | 元が濃い灰色の文字色 | |
rgb(0,0,0) |
-text-black-main- |
text-* |
文字色(元黒) | 元が黒色の文字色 | |
rgb(255,255,255) |
-text-white-main- |
text-* |
文字色(元白) | 元が白の文字色 | |
rgb(255,255,255) |
-background-base-main- |
背景 | 背景 | ||
rgb(255,230,190) |
-building-normal-main- |
普通建物 | 普通建物 | ||
rgb(255,187,153) |
-building-middle-main- |
堅ろう建物 | 堅ろう建物 | ||
rgb(255,119,51) |
-building-high-main- |
高層建物 | 高層建物 | ||
rgb(255,135,75) |
-building-normal-outline- |
建物外周線 | 建物外周線 | ||
rgb(100,195,115) |
-road-expressway-main- |
高速道路 | 高速道路 | ||
rgb(235,130,120) |
-road-highway-main- |
国道 | 国道 | ||
rgb(255,255,0) |
-road-prefectural-main- |
県道 | 県道 | ||
rgb(255,255,255) |
-road-normal-main- |
RdCL | その他の道路 | その他の道路 | |
rgb(200,200,200) |
-road-edge- |
RdCL | 道路の枠線 | 道路の枠線 | |
rgb(173,173,173) |
-road-edge- |
RdCL | 道路の枠線 | ||
rgb(100,100,100) |
-road-edge- |
RdCL | 道路の枠線 | ||
rgb(0,0,0) |
-road-edge- |
RdCL | 道路の枠線 | ||
rgb(0,155,191) |
-railway-subway-main- |
地下鉄 | 地下鉄 | ||
rgb(100,0,0) |
-railway-normal-main- |
鉄道 | 鉄道 | ||
rgb(255,255,255) |
-railway-station-main- |
RailCL | 鉄道(駅の白い部分) | ||
rgb(173,173,173) |
-railway-normal-main- |
RailCL | 鉄道 | ||
rgb(100,100,100) |
-railway-normal-main- |
RailCL | 鉄道 | ||
rgb(0,0,0) |
-railway-normal-main- |
RailCL | 鉄道 | ||
rgb(255,255,255) |
-railway-normal-blank- |
RailCL | 鉄道(白い部分) | JRの白黒表現の白の部分 | |
rgb(190,210,255) |
-water-main-main- |
水域面 | 水域 | ||
rgb(20,90,255) |
-water-main-vivid- |
水涯線 | 水涯線 | ||
rgb(0,176,236) |
-water-main-vivid- |
水涯線(小ZL海岸線) | |||
rgb(200,160,60) |
-landform-main-main- |
等高線・地形 | 砂礫地 | ||
rgb(235,242,235) |
-landform-main-main- |
砂礫地 | |||
rgb(200,250,230) |
-wetland-main-main- |
湿地 | 湿地 | ||
rgb(217,217,217) |
-water-main-vivid- |
水域面 | 万年雪 | ||
rgb(68,0,128) |
-border-muni-main- |
国境・行政界 | 市区町村界(紫)等 | ||
rgb(34,24,21) |
-border-muni-main- |
行政区画界線国の所属界 | |||
rgb(231,39,65) |
-line-gray- |
その他 | 航路 | ||
rgb(150,150,150) |
-line-gray- |
特定地区界等 | |||
rgb(100,100,100) |
-line-gray- |
送電線等 | |||
rgb(200,200,200) |
-line-gray- |
ダム(面)等 |
ひな型となるスタイルを作成する
上記で整理したサンプルスタイルで使われている色と役割(キー名)を元に、サンプルスタイル中の色のデータをキー名に置き換えます。これにより、次の工程で、キー名をもとに色を挿入することができるようになります。ただし、すでに記載しましたが、 rgba(r, g, b, a)
表記の際は、不透明度を保存する必要がありますので、これをキー名ののちに # で区切って残すことにしました。つまり、以下のように変換されます。
rgba(255,255,0,0.5)
→ -road-prefectural-main-#0.5
ひな型スタイルの一部を例示します。なお、ひな型は、直接 Mapbox GL JS 等では読み込めません。
{
"id": "海岸線",
"type": "line",
"source": "v",
"source-layer": "Cstline",
"filter": [
"in",
[ "get", "vt_code" ],
[ "literal", [ 5101, 5103 ] ]
],
"paint": {
"line-color": [
"step",
[ "zoom" ], "-water-main-vivid-#1", 8,
[ "match",
[ "get", "vt_code" ],
[ 5103 ], "-line-gray-#1",
"-water-main-vivid-#1"
]
],
…
}
}
なお、この段階で、色以外についての調整(後述)ができるような準備も合わせて行っています。
ひな型から様々なバリエーションのスタイルへ変換する
ひな型スタイルができたら、今度はキー名と使いたい色の対応表を作成することで、好きな色を適用したスタイルを作成することができるようになります。たとえば、以下のようなデザインにする場合の対応表を例示します。
キー名 | rgb |
---|---|
default |
rgb( 30, 30, 30 ) |
-background-base-main- |
rgb( 30, 30, 30 ) |
-railway-subway-main- |
rgb( 79, 226, 255 ) |
-railway-normal-blank- |
rgb( 50, 50, 50 ) |
-railway-normal-main- |
rgb( 79, 226, 255 ) |
-railway-station-main- |
rgb( 79, 226, 255 ) |
-road-normal-main- |
rgb( 40, 40, 40 ) |
-road-highway-main- |
rgb( 80, 90, 100 ) |
-road-prefectural-main- |
rgb( 60, 60, 60 ) |
-road-expressway-main- |
rgb( 100, 110, 120 ) |
-road-edge- |
rgb( 35, 35, 35 ) |
-building-normal-main- |
rgb( 20, 25, 30 ) |
-building-middle-main- |
rgb( 40, 45, 50 ) |
-building-high-main- |
rgb( 50, 55, 80 ) |
-building-normal-outline- |
rgb( 20, 20, 30 ) |
-wetland-main-main- |
rgb( 100, 100, 100 ) |
-landform-main-main- |
rgb( 50, 50, 50 ) |
-water-main-main- |
rgb( 0, 0, 0 ) |
-water-main-vivid- |
rgb( 80, 80, 80 ) |
-border-muni-main- |
rgb( 180, 180, 180 ) |
-text-gray-main- |
rgb( 150, 150, 150 ) |
-text-black-main- |
rgb( 200, 200, 200 ) |
-text-green-main- |
rgb( 200, 230, 255 ) |
-text-blue-main- |
rgb( 200, 200, 255 ) |
-text-white-main- |
rgb( 255, 255, 255 ) |
-text-white-halo- |
rgb( 50, 50, 50 ) |
-line-gray- |
rgb( 80, 90, 100 ) |
Tips
- JR の縞々模様については、元が白の部分は、背景色に似た色にすると自然かと思いますが、そっくりそのまま背景色と同じにするのではなく、少しだけ違う色にすると、背景と同化せずにわかりやすくなるような気がします。
この対応表をもとに、ひな型スタイルに埋め込んであるキー名と # で付与した不透明度から、色を rgba の形で復元していけばよいわけです。なお、対照表にないキー名は、default
へ変換します。以下、変換を例示します。
-road-prefectural-main-#0.5
→ rgba( 60, 60, 60, 0.5 )
補足:色以外の調整
さて、最初に主に色のみの変更ということでしたが、「サンプルスタイル(標準地図風)」で気になった以下の点については、調整を施しています。
まずは、レイヤの追加や順番変更はせずに、極力省力で対応してみます。省力ですので、自分の好みを完全に反映できているわけではありません。
- 鉄道の表現の単純化
- 線の太さの設定をシンプルにしています。
- 使わないレイヤについては、
layout
のvisibility
をnone
としています。 - 個人的に、地下部分は点線の方が分かりやすいのですが、
line-dasharray
が、Mapbox GL JS の v1 系ではデータドリブン設定に対応しておらず、透過度を上げる表現としています。(なお、後述のレイヤ追加により解消します。)
本記事投稿時は、以下の理由で JR の白黒の縞々模様は省略していましたが、試行錯誤しているうちに、サンプルスタイルを生かして、白黒パターンを残してよいのではという考えになりました。このあたりは、好みや見慣れるかどうか、という部分かと思います。
- ZL11~14では、データが比較的細切れで、JR の白黒を表現すると、あまりきれいではない。
- スタイル設定において、駅・JR・JR以外、単線・複線以上が複雑な分岐条件で記載されているほか、上記の理由で ZL14 で表現が切り替わるため、制御が非常に難しい。
-
鉄道のラインデータを細く
- 上記の鉄道表現単純化に合わせて、線幅を小さくし、すっきりとシャープな見た目にしました。
-
鉄道の終端部を
round
に変更- 必要に応じて、
line-cap
をround
に設定しています。 - 鉄道の場合は、単に駅の形状が丸い方が好みだからです。
- 必要に応じて、
-
道路の終端部を
round
に変更 -
小縮尺の都道府県境界の点線間隔を修正
-
id
名が「行政区画界線地方界」のレイヤで、点線の間隔が広すぎて、どこが境界かわかりにくいと感じたので、間隔を狭めています。
-
以下は、レイヤ順序の入れ替えや追加等による、より大掛かりな調整です。
- 駅のレイヤを追加
- これにより、スタイルの表現の衝突を回避できるため、地下鉄やトンネルの部分を点線で表現することが可能となります。
- 建物の 3D 化
作ったもの
スタイルの例
以下のようなスタイルを作成してみました。
- 色をふんだんに使ったタイプ
- 暗い色基調のダークモードタイプ
- 彩度を抑えたモノクロタイプ
- 単色タイプ(以下のスタイルは青写真をイメージ)
それぞれ、fill-extrusion
による 3D ライクなスタイルも作成しています。
色をふんだんに使ったタイプ
色をふんだんに使ったタイプ(3D)
ダークモードタイプ1
ダークモードタイプ2(青ベース)
ダークモードタイプ1(3D)
ダークモードタイプ2(青ベース、3D)
モノクロタイプ1
モノクロタイプ2(青ベース)
モノクロタイプ1(3D)
モノクロタイプ2(青ベース、3D)
単色タイプ(青写真)
単色タイプ(電子回路)
単色タイプ(青写真)(3D)
単色タイプ(電子回路)(3D)
ソースコード
以下のレポジトリにひな型となるスタイルを作成するプログラム、ひな型から、様々なバリエーションのスタイルへ変換するプログラムを入れてあります。だいぶ「秘伝のたれ」感が出てきておりますが……。
感想
調査からひな型スタイルの作成まで、1営業日くらいかかってしまいました(実はこの記事執筆にもそのくらいかかってしまっているのですが……)。
「サンプルスタイル(標準地図風)」を見ると、スタイル数が少なくなっている代わりに非常に複雑な条件分岐が駆使されていることがわかりました。これを1から構築して管理するのは、なかなか大変な気がしますので、サンプルスタイルの提供は、そのベクトルタイルを利用するにあたって重要な条件だと感じています。スタイルの調整の大変さは、以下の記事が参考になります。
今回のような条件分岐を駆使したスタイルの最適化は、少ないレイヤ数で豊かな表現ができる一方で、カスタマイズが難しくなっていくのではないかと感じています。たとえば、国道の色を変えたいときに、「国道」レイヤの line-color
設定に rgba を入れるだけなら楽ですが、今回のように条件分岐が複雑な場合、設定と設定値が1対1で対応せず、該当する部分を探して変更する必要があります。これを汎用のツールを使って編集するのは大変そうです。スタイルをどうやって編集してもらえば良いのか、開発者向けとエンドユーザー向けで分けて考えてみます。
開発者向け
ベクトルタイルの提供者は、提供するタイルを自由なスタイルで使って欲しいのであれば、
- 汎用性のあるサンプルスタイルを提供する(最適化できず、パフォーマンス劣化の可能性)
- 最適化したサンプルスタイルとともに、専用の編集ツールも提供(編集ツールの開発コスト)
- ユーザーの選択肢は、出来合いのスタイルからの選択肢のみと割り切る(ユーザーは希望があれば、JSON を直接編集する)
という選択肢を考える必要が出てくるのかもしれません。
ただし、最初の「汎用性」については、汎用性の定義を明確に決めるのは簡単ではないかもしれません。Mapbox GL JS の style 仕様は、QGIS でも(完全ではないが?)対応するなど、普及を感じられますが、どこまでなら「汎用的」と言えるかは、まだグラデーションがあると感じています。
専用の編集ツールと複数のスタイルについては、たとえば、主要なベクトルタイルの提供者としては、国土地理院のほか、Mapbox 社、Esri 社、MapTiler 社が思い浮かびます。こちらの提供者は、複数の構築済みのスタイルのほか、スタイル編集ツールも提供しており、やはりベクトルタイルの提供とスタイルの提供は、ワンセットではないかと感じる次第です。
以下、簡単に各者の様子を見てみますが、しっかり触ったわけではありませんので、誤解も含まれるかもしれません。ご承知おきいただくとともに、何かあればご指摘いただけると幸いです。
-
- Mapbox 社提供の編集ツール。
- 要ログイン
- Component という複数レイヤのまとまり毎に編集することが可能。紹介ページに以下のような記述があるとおり、全体のスタイルを崩すことなく、色や線幅といった変更を全体・個別に適用することができるようである。
道路の幅が全体の道路網のサイズと比例するよう、簡単に調整できます
建物を3Dモデル化することで、建物を示す領域に奥行きを追加
- レイヤごとにも編集可能だが、今のところ、条件分岐については対応していない様子。
-
ArcGIS Vector Tile Style Editor
- Esri 社提供の編集ツール。
- 要ログイン
- 自分は使うことができないが、紹介ブログを見る限り、Quick Edit、Edit by Color、Edit Layer Styles、Layer Editor と複数のレベルで編集が可能そうな紹介がなされている。
-
- 国土地理院提供の閲覧・編集ツール。
- ログイン不要。提供実験中。
- グループまとめて編集可能だが、すべて同じスタイルが適用されてしまうようである。
- レイヤごとも編集可能だが、条件分岐の設定等はできないようである。
-
- OSS だが、地図データは MapTiler 社のものを利用しているようである。
- ログイン不要
- グループごとの編集はできなさそうである。
- レイヤ毎の編集が可能なほか、JSON を直接編集できる機能があり、これを用いて複雑な条件設定が可能なようである。
- MapTiler 社のブログを見る限り、MapTiler 社提供のエディタも、maputnik をベースにしていそうな UI である(あくまで憶測。)
結局、究極の汎用性は JSON エディタに行きつくのかもしれませんね。たとえば、Geolonia という会社が国連ベクトルタイルツールキット(UNVT)に寄贈したという地図デザイン編集ソフトウェア「Charites(カリテス)」は、まだ自分は触ったことはありませんが、この「JSON を低コストで編集しよう」という発想のもとで非常に役立つのではないかと考えています。なお、Geolonia 社もベクトルタイルを提供しており、スタイル提供状況としては、複数の出来合いスタイル+ maputnik という案内をされています。
エンドユーザー向け
こちらは、自分が地図を見ていて感じることをまとめてみました。実際に他の人に話を聞いたわけではありませんので、本当に n=1 の感想となります。
さて、実際に地図を使うエンドユーザーにとって、オンザフライでスタイルを編集できる必要はあるのか、というと別の問題な気がします。
ベクトルタイルを使えば、たとえば、目的の地物を強調表示するといった使い方も考えられます。一方、エンドユーザーにとって、関心の対象は、「都道府県境界」「国道」「JR」といったカテゴリ単位ではなくて、「ほげ県の領域」「ぴよ号線」「ふが線」といった、もっとローカルなものだと思います。もっと言えば、POI、ルート検索など、背景地図ではなくて、上乗せデータとして提供すべきデータなのではないかと感じました。実は、背景地図に対して、編集機能はあまり求めないのではと予想しています。
また、ベクトルタイルは、属性との表示ができますから、見た目を複雑に調整するよりも、その属性を表示(地図上に symbol レイヤとして加える or ポップアップで表示する、等)できれば事足りる可能性もあるかと思います。
最適化したスタイルを使う場合、背景地図を用いた機能としては、「必要ない地物をレイヤ単位で表示・非表示ができる+その地物の情報を表示する」くらいが、投資コストと見合う妥当な線ではないかと感じています。
終わりに
思い付きの作業でしたが、記事作成も含めてだいぶ時間がかかってしまいました。スタイル作成はとても楽しいのですが、時間が溶けるため、需要等を考えたうえで投資しないといけないなと感じた次第です。
また、気づいた点や追加情報あれば、追記していきたいと思います。