はじめに
先日、ArcGISブログにて「ArcGIS で場所当てクイズ!」という記事を投稿しました。そちらの記事では ArcGIS Survey123、ArcGIS Notebooks、ArcGIS Experience Builder (Developer Edition) の 3 種類の製品を使って場所当てクイズの仕組みを作ってみたことをご紹介しました。
実はこのクイズ、先日開催されたジオ展でご紹介したデモを拡張したものになっています。いくつかプログラミングが必要になる製品を使用しているほか、ArcGIS Survey123 をクイズとして実装するための工夫もありますので、本記事ではそれらの工夫やプログラミングについて簡単にご紹介します。
ArcGIS Survey123 - 調査票の工夫とデータ構造
まずは、本題となるクイズの作成に使用した ArcGIS Survey123 について見ていきます。
ArcGIS Survey123 では選択式や自由記入など様々な形式の設問を追加することができ、今回は正解の位置の回答に [マップ] を使用しました。

マップはその名前のとおりマップを操作して位置を入力させることのできる設問ですが、ArcGIS Survey123 で [位置] にカテゴライズされる設問は「その調査票はどこを指しているのか」を意味しており、入力された結果を保存するフィーチャのジオメトリー (位置情報) として使用されます。
ここまでの説明で勘の良い方は気付いているかもしれませんが、この [位置] にカテゴライズされる設問は、調査票内に 1 つしか回答を保存することができません。これは回答した結果がフィーチャのジオメトリーとして保存されるためで、1 フィーチャにつき 1 ジオメトリーしか持つことができないことに起因します。
さて、困りました。これでは [マップ] の設問を複数配置したとしても回答は保存されないことになってしまうため、1 問しかクイズをつくることができません。
そこで、調査の [計算] 機能を利用しました。計算機能は他の設問で入力された結果を用いて回答を調整することのできる機能です。この機能を使ってマップで入力された位置情報を別の設問にコピーすることで、本来であれば保存されない情報を保存できるようになりました。コピー先の設問は非表示に設定しているため、ユーザーの操作には影響しません。

これで調査票に配置した複数のマップそれぞれで入力された位置情報を結果として保存することができるようになりました。結果は以下のように保存されています。

ユーザーによって入力された各設問の位置情報が属性情報として保存されていることが分かります。この結果をもとに次の得点計算に移っていきましょう。
ArcGIS Notebooks - 得点の計算と計算結果の保存
収集した回答を用いた得点の計算には ArcGIS Notebooks を使用しました。ArcGIS Notebooks は Jupyter Notebook を基盤とした Python スクリプト環境を ArcGIS Online 上で実行できる製品です。今回は得点の計算やその結果の保存などに利用しています。
今回実装したい機能は以下のとおりで、それぞれの項目について、かいつまんでご紹介します。
- ユーザーの回答から各回答のポイントを生成する
- 正解と回答のそれぞれのポイントの距離を計測し、得点を求める
- 計算した得点や回答のポイントをフィーチャ レイヤーに保存
ArcGIS Notebooks では ArcPy、ArcGIS API for Python をはじめとして様々な Python ライブラリーを利用できますが、今回は対象のデータがすべて ArcGIS Online 上のものであったため、ArcGIS Online と親和性の高い ArcGIS API for Python を中心にコーディングしています。
ユーザーの回答から各回答のポイントを生成する
取得できている情報は属性値として経緯度が含まれているのみで、ArcGIS で利用しやすいジオメトリーは持っていません。このため、まずは回答の情報からポイントを生成していきます。
属性値の検索には FeatureLayer モジュールの query() メソッドを使用し、取得した結果をもとに Point オブジェクトを生成します。
from arcgis.features import FeatureLayer
from arcgis.geometry import Point
# 中略 ~~~~~
# 対象のフィーチャ レイヤーの URL
calcTargetLayerUrl = "https://<サービスの URL>/FeatureServer/0"
# 計測対象のレイヤーを作成
calcTargetLayer = FeatureLayer(calcTargetLayerUrl)
# 計測対象のフィーチャを特定
# 得点計算が行われていないもの (score が NULL) のみを抽出
calcTargetSet = calcTargetLayer.query(
where = "score = NULL",
out_fields = "*"
)
# ループ回数、問題番号
ansArr = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
for feature in calcTargetSet.features:
for ansNum in ansArr:
# 問題番号毎に Point を生成
resultLat = feature.attributes["q" + str(ansNum) + "_lat"]
resultLong = feature.attributes["q" + str(ansNum) + "_long"]
resultPoint = Point({'x': float(resultLong), 'y': float(resultLat), 'spatialReference': {'wkid': 4326}}) 正解の回答のそれぞれのポイントの距離を計測し、得点を求める
回答のポイントをつくることができたので正解のポイントと照らし合わせて距離を計測します。正解のポイントは別途フィーチャ レイヤーとして用意してあるものを使用し、また距離の計測には Geometry オブジェクトの distance() メソッドを使用しています。
from arcgis.geometry import Point, distance
# 中略 ~~~~~
# 別途取得していた正解のフィーチャから Point を生成
ansFeature = ansSet.features[ansNum - 1]
ansPoint = Point({'x': ansFeature.geometry["x"], 'y': ansFeature.geometry["y"], 'spatialReference': ansFeature.geometry["spatialReference"]})
# 生成した 2 つの Point の距離を計測
scoreDistance = distance(geometry1=resultPoint, geometry2=ansPoint, geodesic=True, spatial_ref=4326)
# 計測した距離に応じて score を加算
if scoreDistance["distance"] <= 300:
score += 10
elif scoreDistance["distance"] <= 600:
score += 9
elif scoreDistance["distance"] <= 900:
score += 8
elif scoreDistance["distance"] <= 1200:
score += 7
elif scoreDistance["distance"] <= 1500:
score += 6
elif scoreDistance["distance"] <= 1800:
score += 5
elif scoreDistance["distance"] <= 2100:
score += 4
elif scoreDistance["distance"] <= 2400:
score += 3
elif scoreDistance["distance"] <= 2700:
score += 2
elif scoreDistance["distance"] < 3000:
score += 1
else:
score += 0計算した得点や回答のポイントをフィーチャ レイヤーに保存
計算した得点や回答のポイントはフィーチャ レイヤーに保存します。保存は FeatureLayer オブジェクトの edit_features() メソッドで行います。
from arcgis.features import FeatureSet
# 中略 ~~~~~
if len(calcTargetSet.features) > 0:
# 計測対象のレイヤーに score を加えて更新
calcTargetLayer.edit_features(
updates = calcTargetSet
)
print("得点追加完了")
# ユーザーの回答の Point をまとめた FeatureSet を生成
resultFeatureSet = FeatureSet(
features = resultFeaturesList,
spatial_reference = {"wkid": 3857}
)
# ユーザーの回答を保存
userAnswersLayer.edit_features(
adds = resultFeatureSet
)
print("回答フィーチャ追加完了")ここまで記述してきたコードは ArcGIS Notebooks のタスク機能を使用して定期的に実行させています。今回は 15 分に 1 回コードを実行するようにしているため、15 分ごとに得点の計算がされていないレコードに対して計算が行われます。
ArcGIS Experience Builder (Developer Edition) - 回答確認用アプリ
入力された回答の結果を確認するアプリケーションとして、ArcGIS Experience Builder (Developer Edition) を使用しました。ArcGIS Experience Builder (Developer Edition) はノーコードでアプリケーションの作成が可能な ArcGIS Experience Builder のローコード版で、ArcGIS Experience Builder の持つ機能はそのままに、一部の機能のみをプログラミングを使って作成することのできる製品です。
作成したアプリケーションは「ArcGIS で場所当てクイズ! - 回答チェック」として公開しています。今回独自に作成した機能はマップ画面左下のパネルで、主に以下の機能を実装しています。
- ニックネームを指定して、その得点を検索して表示
- 各設問の回答をマップ上にグラフィックとして配置
- 各回答のグラフィックと正解地点の距離をマップ上に表示
- 各回答の得点の内訳を表示

また、今回作成した機能では UI に Calcite Design System を使っています。Calcite Design System は ArcGIS Online のインターフェイスにも使われているデザイン キットのため、独自に作成した機能でありながら、他の標準インターフェイスと親和性の高い UI デザインを実現しています。
まとめ
今回は ArcGIS で場所当てクイズを作ってみた際の工夫やプログラミングについて簡単にご紹介しました。様々な ArcGIS 製品を組み合わせてクイズを作ってみましたが、それぞれの製品の標準機能だけでは実現が難しい部分も、プログラミングの力を借りることで思い描いていた機能を実現できました。
通常、「業務」に特化した使い方をすることが多い ArcGIS 製品ですが、少し見方を変えることで、今回のクイズのようなレクリエーションもつくることができます。今回のクイズが ArcGIS の活用の新しいアイデアになれば幸いです。
関連リンク