今日はオープンデータの日、世界中でオープンデータに関するイベントが開催されています。
「You are invited — Open Data Day」

コロナ禍の今年は富山、石川、福井、北陸三県合同でオンライン開催!情報提供タイムの後は、ブレイクアウトルームに分かれてオープンデータかるたを使ったアイデアソン!

オープンデータが書かれたカルタを並べて、データをちょい足し、アイデアをまとめて発表しました!

インターナショナルオープンデータデイ@北陸オンラインでの学び、オープンデータとSDGsを組み合わせたカードゲームがおもしろそう!

力強いメッセージ「誰だってオープンデータは作れる!」 by Code for Toyama City の寺田さん
早速、データづくりから始めます。

「code4sabae/SDGs_ja: SDGS(持続可能な開発目標)、17の目標(ゴール)と169のターゲットのCSVデータ(English/Japanese)」
GitHubで検索して発見した「datapopalliance/SDGs: Excel and CSV versions of the goals, targets, and indicators from the Sustainable Development Goals (SDGs).」をフォークして、日本語とタイトルと色と画像を足しました。
作成したCSVは、csvbeautyを通しているのでExcelからプログラムまで幅広く活用いただけます。webアプリやサーバーでのDenoで使う場合、下記のようなコードで簡単に使えます!
<script type="module">
import { CSV } from "https://code4sabae.github.io/js/CSV.js";
window.onload = async () => {
const baseurl = "https://code4sabae.github.io/SDGs_ja/";
const goals = CSV.toJSON(await CSV.fetch(baseurl + "SDG-goals.csv"));
console.log(goals);
const targets = CSV.toJSON(await CSV.fetch(baseurl + "SDG-targets.csv"));
console.log(targets);
};
</script>
オープンデータかるたとSDGsを組み合わせる準備ができました!
データの準備だけではちょっとさみしいので、簡単なゲームを作ってみました。

「SDGs GOALQUIZ」
169のターゲットをランダムにシャッフルし、クイズゲーム風に表示されるターゲットから、対応するゴール(目標)を選び、正答率を競うゲームです。
日本語、英語、両対応。途中での切り替えもできます(アイコンを切り替えるにはリロードが必要)。なかなかに難しいです。
SDGsアイコンはオープンデータではありません。非営利で資金調達目的でなければ申請なしに使用できます。詳しくは、国連のサイトをご確認ください。
「SDGsのポスター・ロゴ・アイコンおよびガイドライン | 国連広報センター」
クイズゲームのメインプログラム、JavaScriptでなかなか分かりやすく書けたと思います。
window.onload = async () => {
const baseurl = "https://code4sabae.github.io/SDGs_ja/";
const goals = CSV.toJSON(await CSV.fetch(baseurl + "SDG-goals.csv"));
const targets = CSV.toJSON(await CSV.fetch(baseurl + "SDG-targets.csv"));
const body = document.body;
add(body, "h1", "SDGs " + lang("ゴールクイズ", "GOALQUIZ"));
const result = add(body, "div");
result.className = "result";
const quiz = add(body, "div");
quiz.className = "quiz";
const logos = add(body, "div");
logos.className = "logos";
const sels = [];
for (const goal of goals) {
const img = new Image();
img.src = baseurl + goal[lang("logo_ja", "logo")];
logos.appendChild(img);
sels.push(img);
}
const credit = add(body, "div");
credit.className = "credit";
add(credit, "span", "App: CC BY @taisukef", "https://fukuno.jig.jp/3146");
add(credit, "span", " ");
add(credit, "span", "(src on GitHub)", "https://github.com/code4sabae/goalquiz");
add(credit, "br");
add(credit, "div", "Data: SDGs_ja on GitHub", "https://github.com/code4sabae/SDGs_ja");
add(credit, "span", "Japanese", "#ja");
add(credit, "span", " / ");
add(credit, "span", "English", "#en");
add(body, "qr-code");
shuffle(targets);
let point = 0;
for (let i = 0; i < targets.length; i++) {
quiz.innerHTML = " ";
quiz.style.backgroundColor = "white";
quiz.style.color = "black";
const target = targets[i];
const goal = goals[target.goal - 1];
const desc = lang("description_ja", "description");
const title = lang("title_ja", "title");
const tid = startShowText(quiz, target[desc], lang(50, 25));
const ans = await waitClick(sels) + 1;
clearInterval(tid);
quiz.textContent = target[desc];
quiz.innerHTML += "<br>" + lang("あなたの回答", "Your Choice") + ":" + ans + " 「" + goals[ans - 1][title] + "」";
await sleep(300);
quiz.style.backgroundColor = goal.color;
quiz.style.color = "white";
if (ans == target.goal) {
quiz.innerHTML += "<br>" + lang("正解!", "Correct!");
point++;
} else {
quiz.innerHTML += "<br>" + lang("まちがい! 正解は ", "Wrong.. Correct answer is ") + target.goal + " 「" + goal[title] + "」";
}
result.textContent = lang(
(i + 1) + "問中" + point + "問正解 正解率" + (point / (i + 1) * 100).toFixed(1) + "%",
"Q cnt " + (i + 1) + ", Corrects " + point + ", Rate " + (point / (i + 1) * 100).toFixed(1) + "%"
);
await sleep(1000);
}
alert(lang("おめでとうございます!全169ターゲットのクイズを終えました!", "Congratulations!! You've finished quiz of 169 targets."))
};
(src on GitHub)