不自由な地図


データの可視化といっても様々な手法がありますが、今回は地図の話をします。

Web の地図は自由に操作できて、いろんな場所をいろんな縮尺で見ることができ、それがデータ可視化にもたらす恩恵は大きいと思います。
しかし、一方でその自由度によって、見せたいデータの見せたい視点を適切に届けるための工夫がおざなりになってしまい、データ可視化の目的が適切に達成されない可能性も含んでいます。

そこで、今回は「地図に触らず地図を操作する」方法に焦点を当ててみます。
地図を操作するよりも別の要素を操作するようなアフォーダンスを設計することで、地図上で表現されるストーリーやデータを見る視点を固定させることができます。

Web 地図についてはオープンソースの地図表示用 JavaScript ライブラリである Leaflet をベースにお話したいと思います。
いわゆる、データ ビジュアライゼーションのメインテーマから少し逸れるかもしれませんが、どう可視化するかではなく、どう見せるかの知見として共有できればと思っています。

主題データ

テーマは静岡県がオープンデータとして提供している静岡のみずべ100選を使います。
静岡の美しいみずべ100箇所の写真と位置座標が含まれているデータです。
静岡県が公開しているふじのくにオープンデータ カタログで提供されているデータは CSV なので、Leaflet で扱いやすいフォーマットである GeoJSON (身内のサイトですが、ここで GeoJSON の URL が取得できます) を使います。

データの表示

早速ですが、以下のコードで地図上に静岡のみずべ100選の位置を可視化します。
なお、GeoJSON は jQuery の getJSON 関数で取得しています。

// Web 地図
var map = L.map('mapDiv'.setView([35.8, 139], 8);
// 背景地図レイヤーの追加
L.tileLayer('http://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png', {
  maxZoom: 18,
  attribution: 'Map data &copy; <a href="http://openstreetmap.org">OpenStreetMap</a> contributors, ' + '<a href="http://creativecommons.org/licenses/by-sa/2.0/">CC-BY-SA</a>',
  id: 'osm'
}).addTo(map);

// GeoJSON の取得と地図上に可視化
$.getJSON('http://data.esrij.com/datasets/884a76f217c543408df7bcc55c78acb1_0.geojson', function (data) {
  L.geoJson(data, {...}).addTo(map);
});

美しい場所の情報なので柄にもないですがハートのマーカーにしてみました。L.geoJsononEachFeature オプションの関数内で各マーカーにアイコンを割り当てています。
上記コードでは省略しているので、ソースを確認したい方は GitHub リポジトリを確認してください。

Web 地図を不自由にする

Web 地図のためのライブラリは多く存在しますが、そのほとんどはみなさんが良く知る Google Maps API のようにパンやズームによって、好きな場所に自由に移動して表示が可能です。
ただし、上でも述べたように、この自由度はデータ ビジュアライゼーションの観点でいえば、見せ方の道標や選択肢を与えず、提供側の意図しない操作によって、本来伝えたいはずのデータに対する視点を見る側が得る機会を損なうリスクがつきまといます。
伝えたいストーリーやデータが示すテーマを見る側に自然に伝えるために、一定の不自由さを与える必要があるケースというものについて考えてみたいと思います。
もちろん、ユーザーにどれだけ操作を委ねるかはデータ可視化の目的に応じた UX 設計によって判断するべきかと思いますが、今回はわかりやすく地図を使った操作をまったく行えないように設定してみます。

Leaflet の L.map クラスには地図操作に関する様々なオプションが用意されています。
Leaflet で地図の操作をできなくするには以下のようにオプションを追加するだけです。

L.map('mapDiv', {
  dragging: false, // マウスドラッグによるパン操作を不可
  touchZoom: false, // タッチによるズーム操作を不可
  scrollWheelZoom: false, // スクロールによるズーム操作を不可
  doubleClickZoom: false, // ダブルクリックによるズーム操作を不可
  boxZoom: false, // [Shift] + ドラッグによるボックスズーム操作を不可
  tap: false, // タップによるズーム操作を不可
  keyboard: false, // キーボードによる操作を不可
  zoomControl: false // ズーム コントロールの非表示
}).setView([35.8, 139], 8);

さて、この状態だと地図は完全に固定され、Web 地図である存在意義を失っています。
では Web 地図がデータを「見せる」ために、地図を移動するキーとなる要素を作成していきます。

地図が移動するキーとなる要素

ある要素を操作することによって発生するイベントを利用して地図を移動させます。
これにより、Web ページ コンテンツの主体は地図ではなくなりますが、動的な Web 地図としての強みを活かすことができます。

ある要素とは?

  • フォーム
  • チャート
  • テーブル
  • 写真
  • コンテナ

など…

イベントとは?

  • マウスクリック
  • マウスホバー
  • スクロール
  • タップ
  • スワイプ

など…

地図を移動させてみよう

では今回はキーとなる要素にコンテナ、イベントはシンプルにスクロールで実装してみましょう。
みずべ100選の美しい写真に映し出されている場所がどこに存在するのかを補足するために地図を利用します。写真が並ぶコンテナをスクロールするごとにその位置を示すように地図が自動的に移動する挙動を実装してみます。

以下のコードで、写真コンテナのスクロールに応じて、地図を移動する処理を実現しています。
写真の並び順は GeoJSON フィーチャの OBEJECTID に従った順であり、写真の順序から対応するマーカーを取得できます。また、各情報(タイトル、写真、説明文)コンテナの高さは一定のため、OBJECTID による単純なかけ算でスクロール範囲(areaTopareaBottom)を算出できます。これをもとに条件分岐を行い、スクロール範囲に入ったら、写真と対応するフィーチャへ地図を移動する処理を行っています。

// 地図移動のキーとなるスクロール範囲を算出
var areaHeight = $('.photo-container').height() + 50;
var areaTop = (feature.properties['OBJECTID']-1) * areaHeight - 50;
var areaBottom = areaTop + areaHeight - 50;
// 写真コンテナのスクロールを監視
$('div#photos').scroll(function() {
  // スクロール範囲に入ったら対応するフィーチャへ地図を移動
  if($(this).scrollTop() >= areaTop && $(this).scrollTop() < areaBottom) {
    map.setView([feature.geometry.coordinates[1], feature.geometry.coordinates[0] + 0.015], 14);
  }
});

完成品はこんな感じです。

デモで実際の動きを確認してみてください。

本稿では説明していませんが、ズーム時に対象となるマーカーをハイライトしたり、有効になっている写真以外はグレーアウトしたりと、画面上のどこにフォーカスするべきかを視覚的に伝えるための小さな仕掛けを加えています。
こういった細かい UI/UX デザインもデータ可視化の重要な周辺技術だと思います。
これらの細かい実装についてはソースコードをご覧ください。

まとめ

データ ビジュアライゼーションというと統計データを始めとした数値をどう可視化するかというテーマが一般的かと思いますが、今回は写真と位置の関連付けを取り上げ、それを見る側に伝えるために地図を不自由にするという手段を選択してみました。
次の機会があれば、もう少し数字を扱った表現にも取り組んでみたいと思います。
最後までお読みいただきありがとうございました。