30DayMapChallengeに参加してみた
本記事について
- 会社の先輩に感化され、30DayMapChallengeに初めて参加してみました。
- 題目は
Data challenge: Natural Earthということで、データを可視化してVisually Stunningな地図作成を目指しました。 - WEBページの作成も不可能ではないですが、Natural Earthのような大規模なデータを扱うため、今回はPythonの
geopandas、rasterio、matplotlibを用いて作成を試みました。
モチベーション
前回の記事にも少し記載したのですが、私は普段、ユーザの位置情報とその地点の地理情報を取り扱うことが多いです。
そういった業務をしていることもあり会社の中には、mapboxなどの地図描画系ライブラリ、及びGISのエキスパートも在籍しています。
その中のお一方が30DayMapChallengeに参加、非常に美しい地図を作成されていたので、これに感化され自分も参加してみることにしました。
...、
ちなみに私は地図作成をすることはほとんどなく、先述のようなGISを取り扱うライブラリの使用機会もほとんどありません(gdalやtippecanoeの使用経験はあります)。デザインセンスにも自信はないですが、良いものを作れたらいいな...くらいの温度感で取り組みました。
ゴール
「30DayMapChallenge」の公式ホームページには、
The challenge takes place every November, with 30 different mapping themes - one for each day of the month. Participants create maps based on these themes and share them on social media using the hashtag #30DayMapChallenge.
という記載がありますので、作成した地図をソーシャルメディアで共有することを最終的なゴールとしました。
また、Day22のテーマの説明には、
Use the Natural Earth dataset as your primary source for a visually stunning small-scale world or continent map.
とありましたので、できるだけきれいな、わかりやすい地図を作ることを試みました。
使用データ・技術について
データ
Natural Earthでは様々なデータが配布されていますが、その中でも個人的に見慣れないと感じた紛争地域(Breakaway, disputed areas)のデータを活用することにしました。
地政学的な観点も考慮し、なぜその地域で紛争が起こるのかを考察する一助になるような地図をつくるため、河川・湖のデータも合わせて利用することにしました。
さらに、土地の起伏も表現したかったため、ラスターデータも活用しました。
なお、国境ラインに関してはNatural Earthの国データを活用しました。
国データに関しては以下のような免責事項が記載されていますが、今回は紛争地域データおよび国データについてはダウンロードしてから加工せずに利用しました。
Natural Earth Vector draws boundaries of countries according to defacto status. We show who actually controls the situation on the ground. Please feel free to mashup our disputed areas theme to match your particular political outlook.
技術
私が普段バックエンドを中心に業務をしているということもあり、とりあえず初参加の今回は、Pythonのgeopandasを始めとしたGISを扱うライブラリを用いて地図を作成することを試みました。
地図を作成する
※プロジェクトはGithubリポジトリでも公開しています。
描画する地点
今回はカシミール地方の地図を作成することにしました。カシミール地方はインド、パキスタン国境付近にまたがる地域のことを指します。
その中で、紛争地帯の場所、パキスタン・インド・中国の場所及びパキスタンに流れ込んでいる3本の河川の位置関係を描画しました。
データを読み込む
過去に使用経験があるshp形式のデータを利用しました。geopandasでは以下のように、1行で読み込むことが可能です。
read_fileで読み込んだshpファイルのデータは、GeoDataFrameクラスとして変数に格納されます。
# path_lakes: shpファイルのパス
import geopandas as gpd
gdf_lakes: gpd.GeoDataFrame = gpd.read_file(path_lakes)
ラスターデータはrasterioでロードします。こちらも以下のように少ない行でロードが可能です。
このプロジェクトでは特定の地域にズームする性質上、ラスターデータがガビガビにならないようにバイリニア補間を設定してデータを読み込んでいます。
with rasterio.open(path_raster) as src:
# グレースケールのラスターデータ
show(src, ax=ax, zorder=0, interpolation="bilinear", cmap="gray", alpha=0.6)
データをプロットする
GeoDataFrameクラスはplotというメソッドを持っているため、そのメソッドを実行することでmatplotlibと連携し、地図を作成することができます。
このプロジェクトでは事前にplt.subplotsでAxesを変数axとして定義しておき、その中にプロットする形式を取っています。
# 湖はシアンで描画する
gdf_lakes.plot(
ax=ax,
color="cyan",
edgecolor="cyan",
alpha=0.7,
zorder=2
)
紛争地域データに関しては、視覚的にわかりやすく表現するために引数hatchを設定して、塗り方を変更しています。
# hatchを設定して斜線で塗る
gdf_disputed.plot(
ax=ax,
facecolor="none",
edgecolor="#ff3366",
hatch="///",
linewidth=1.5,
zorder=4,
)
ちょっとした飾り付け
川や湖をよりわかりやすく表現するために、エフェクトを付けました。
エフェクトは先程のplotメソッドのpath_effectsという引数に設定を追加することで表現できます。
この設定で、河川と湖がグローエフェクトのような表現になりました。
+ rivers_effect = [
+ pe.Stroke(linewidth=4, foreground="cyan", alpha=0.4),
+ pe.Normal(),
+ ]
gdf_rivers.plot(
ax=ax,
color="#8cffff", # 河川のラインの芯の色
linewidth=0.8,
zorder=3,
+ path_effects=rivers_effect,
)
作成した地図と感想
以下のような地図を作ることができました。
感想としては、テーマの中にあったVisually Stunningには届いていなさそう...と思いつつ、geopandasを用いてshpファイルを簡単に描画できるのが嬉しかったのと、エフェクトなどを駆使してわかりやすい地図になるように工夫する過程が非常に楽しかったです。
「デザイン的な美しさ」を考慮した地図を作るのであれば、WEBでmapboxなどを用いるのが良いのかなと思いつつ、今回の方法でも他のライブラリと組み合わせることでもう少しきれいなデザインの地図にできるか調査を進めてみたいです。
30DayMapChallengeは月末まで続くので、別の日で良いテーマがあればチャレンジしてみたいと思います(次こそはWEBで)。
Discussion