2026-10-01 19:56:29 +02:00
|
|
|
#!/usr/bin/env python3
|
|
|
|
|
"""Builds the app's map of Japan's prefectures from Natural Earth.
|
|
|
|
|
|
|
|
|
|
Natural Earth's vector data is in the public domain. This script downloads
|
|
|
|
|
its Admin 1 (states, provinces) layer at 1:10m, release v5.1.2, checks the
|
|
|
|
|
download against the hash recorded below, keeps Japan's 47 prefectures, and
|
feat(map): every country on earth, picked continent first
Map questions can now be on the world's countries besides Japan's
prefectures: a new question chooses its map above it.
The world is Natural Earth's 1:50m countries (public domain), as they are
on the ground, one region per ISO 3166-1 code (239; Gibraltar and the US
Outlying Islands from the 1:10m layer, which has them), named in every
language a studyset can be in from the Unicode CLDR (Unicode License v3,
its notice in the licence list). tool/maps/world_countries.py builds it;
the outline code it shares with the Japan script moved to outlines.py,
which still writes Japan's file byte for byte. The 1.8 MB file is parsed
off the screen's isolate.
Picking goes in layers on both maps: on the whole map one taps a group
(a continent, or Kantō, Kansai …; chips name them too) and the map flies
there, then one taps the region; Back returns. A group of one (Hokkaidō,
Okinawa) and what is in none (Antarctica) are picked at once. A country
in two groups (Russia, Türkiye, Cyprus) opens the one nearer the tap.
Oceania's frame runs past 180° so the Pacific stays in one piece.
What is still too small to hit gets a ring, 48 dp of reach as Material's
touch target: on the ring it is picked; near it, where the tap could mean
it or its neighbours, the map zooms in rather than guess. Pinching and a
mouse's wheel zoom as before.
Names show in the app's language, beside them the map's own (Japanese for
Japan) or the studyset's (キプロス beside Cyprus in a Japanese studyset).
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01MMm7usAo6q9ZZRoPkWjoxi
Signed-off-by: Tizian 「ティツィアーン」 <raisondetredev@pm.me>
2026-10-12 07:18:20 +02:00
|
|
|
reduces them to a compact outline for display (outlines.py): Douglas-Peucker
|
|
|
|
|
simplification (0.006 degrees), islands too small to see dropped (each
|
|
|
|
|
prefecture keeps its largest), coordinates rounded to 4 decimals. The result
|
|
|
|
|
is an approximation, not survey-accurate data.
|
2026-10-01 19:56:29 +02:00
|
|
|
|
|
|
|
|
Each region is named by its ISO 3166-2 code (JP-01 ... JP-47), with Natural
|
|
|
|
|
Earth's English and Japanese names.
|
|
|
|
|
|
|
|
|
|
Run from the repository root with Python 3 and no other packages:
|
|
|
|
|
|
|
|
|
|
python3 tool/maps/japan_prefectures.py
|
|
|
|
|
|
|
|
|
|
It rewrites halkyon_learn_flutter/assets/maps/japan_prefectures.geojson.
|
|
|
|
|
"""
|
|
|
|
|
|
|
|
|
|
import json
|
|
|
|
|
import sys
|
|
|
|
|
from pathlib import Path
|
|
|
|
|
|
feat(map): every country on earth, picked continent first
Map questions can now be on the world's countries besides Japan's
prefectures: a new question chooses its map above it.
The world is Natural Earth's 1:50m countries (public domain), as they are
on the ground, one region per ISO 3166-1 code (239; Gibraltar and the US
Outlying Islands from the 1:10m layer, which has them), named in every
language a studyset can be in from the Unicode CLDR (Unicode License v3,
its notice in the licence list). tool/maps/world_countries.py builds it;
the outline code it shares with the Japan script moved to outlines.py,
which still writes Japan's file byte for byte. The 1.8 MB file is parsed
off the screen's isolate.
Picking goes in layers on both maps: on the whole map one taps a group
(a continent, or Kantō, Kansai …; chips name them too) and the map flies
there, then one taps the region; Back returns. A group of one (Hokkaidō,
Okinawa) and what is in none (Antarctica) are picked at once. A country
in two groups (Russia, Türkiye, Cyprus) opens the one nearer the tap.
Oceania's frame runs past 180° so the Pacific stays in one piece.
What is still too small to hit gets a ring, 48 dp of reach as Material's
touch target: on the ring it is picked; near it, where the tap could mean
it or its neighbours, the map zooms in rather than guess. Pinching and a
mouse's wheel zoom as before.
Names show in the app's language, beside them the map's own (Japanese for
Japan) or the studyset's (キプロス beside Cyprus in a Japanese studyset).
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01MMm7usAo6q9ZZRoPkWjoxi
Signed-off-by: Tizian 「ティツィアーン」 <raisondetredev@pm.me>
2026-10-12 07:18:20 +02:00
|
|
|
sys.path.insert(0, str(Path(__file__).parent))
|
|
|
|
|
from outlines import download, polygons_of, reduce # noqa: E402
|
|
|
|
|
|
2026-10-01 19:56:29 +02:00
|
|
|
SOURCE = (
|
|
|
|
|
"https://raw.githubusercontent.com/nvkelso/natural-earth-vector/"
|
|
|
|
|
"v5.1.2/geojson/ne_10m_admin_1_states_provinces.geojson"
|
|
|
|
|
)
|
|
|
|
|
SOURCE_SHA256 = "22d0e3ad85eb3e27f17cabf8ba2d50e554fbc27a87796ff891d958185da62fb5"
|
|
|
|
|
TARGET = Path("halkyon_learn_flutter/assets/maps/japan_prefectures.geojson")
|
|
|
|
|
|
|
|
|
|
TOLERANCE = 0.006 # degrees
|
|
|
|
|
MIN_AREA = 0.0005 # square degrees; smaller islands are dropped
|
|
|
|
|
DECIMALS = 4
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
def main():
|
feat(map): every country on earth, picked continent first
Map questions can now be on the world's countries besides Japan's
prefectures: a new question chooses its map above it.
The world is Natural Earth's 1:50m countries (public domain), as they are
on the ground, one region per ISO 3166-1 code (239; Gibraltar and the US
Outlying Islands from the 1:10m layer, which has them), named in every
language a studyset can be in from the Unicode CLDR (Unicode License v3,
its notice in the licence list). tool/maps/world_countries.py builds it;
the outline code it shares with the Japan script moved to outlines.py,
which still writes Japan's file byte for byte. The 1.8 MB file is parsed
off the screen's isolate.
Picking goes in layers on both maps: on the whole map one taps a group
(a continent, or Kantō, Kansai …; chips name them too) and the map flies
there, then one taps the region; Back returns. A group of one (Hokkaidō,
Okinawa) and what is in none (Antarctica) are picked at once. A country
in two groups (Russia, Türkiye, Cyprus) opens the one nearer the tap.
Oceania's frame runs past 180° so the Pacific stays in one piece.
What is still too small to hit gets a ring, 48 dp of reach as Material's
touch target: on the ring it is picked; near it, where the tap could mean
it or its neighbours, the map zooms in rather than guess. Pinching and a
mouse's wheel zoom as before.
Names show in the app's language, beside them the map's own (Japanese for
Japan) or the studyset's (キプロス beside Cyprus in a Japanese studyset).
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01MMm7usAo6q9ZZRoPkWjoxi
Signed-off-by: Tizian 「ティツィアーン」 <raisondetredev@pm.me>
2026-10-12 07:18:20 +02:00
|
|
|
source = json.loads(download(SOURCE, SOURCE_SHA256))
|
2026-10-01 19:56:29 +02:00
|
|
|
features = []
|
|
|
|
|
for feature in source["features"]:
|
|
|
|
|
properties = feature["properties"]
|
|
|
|
|
if properties.get("adm0_a3") != "JPN":
|
|
|
|
|
continue
|
|
|
|
|
features.append({
|
|
|
|
|
"type": "Feature",
|
|
|
|
|
"properties": {
|
|
|
|
|
"code": properties["iso_3166_2"],
|
|
|
|
|
"name": properties["name"],
|
|
|
|
|
"name_ja": properties["name_ja"],
|
|
|
|
|
},
|
feat(map): every country on earth, picked continent first
Map questions can now be on the world's countries besides Japan's
prefectures: a new question chooses its map above it.
The world is Natural Earth's 1:50m countries (public domain), as they are
on the ground, one region per ISO 3166-1 code (239; Gibraltar and the US
Outlying Islands from the 1:10m layer, which has them), named in every
language a studyset can be in from the Unicode CLDR (Unicode License v3,
its notice in the licence list). tool/maps/world_countries.py builds it;
the outline code it shares with the Japan script moved to outlines.py,
which still writes Japan's file byte for byte. The 1.8 MB file is parsed
off the screen's isolate.
Picking goes in layers on both maps: on the whole map one taps a group
(a continent, or Kantō, Kansai …; chips name them too) and the map flies
there, then one taps the region; Back returns. A group of one (Hokkaidō,
Okinawa) and what is in none (Antarctica) are picked at once. A country
in two groups (Russia, Türkiye, Cyprus) opens the one nearer the tap.
Oceania's frame runs past 180° so the Pacific stays in one piece.
What is still too small to hit gets a ring, 48 dp of reach as Material's
touch target: on the ring it is picked; near it, where the tap could mean
it or its neighbours, the map zooms in rather than guess. Pinching and a
mouse's wheel zoom as before.
Names show in the app's language, beside them the map's own (Japanese for
Japan) or the studyset's (キプロス beside Cyprus in a Japanese studyset).
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01MMm7usAo6q9ZZRoPkWjoxi
Signed-off-by: Tizian 「ティツィアーン」 <raisondetredev@pm.me>
2026-10-12 07:18:20 +02:00
|
|
|
"geometry": reduce(polygons_of(feature["geometry"]), TOLERANCE,
|
|
|
|
|
MIN_AREA, DECIMALS),
|
2026-10-01 19:56:29 +02:00
|
|
|
})
|
|
|
|
|
features.sort(key=lambda feature: feature["properties"]["code"])
|
|
|
|
|
codes = [feature["properties"]["code"] for feature in features]
|
|
|
|
|
if codes != [f"JP-{n:02d}" for n in range(1, 48)]:
|
|
|
|
|
sys.exit(f"Expected the 47 prefectures JP-01 ... JP-47, got {codes}")
|
|
|
|
|
TARGET.write_text(json.dumps(
|
|
|
|
|
{"type": "FeatureCollection", "features": features},
|
|
|
|
|
ensure_ascii=False, separators=(",", ":")) + "\n", encoding="utf-8")
|
|
|
|
|
print(f"Wrote {TARGET} ({TARGET.stat().st_size} bytes)", file=sys.stderr)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
if __name__ == "__main__":
|
|
|
|
|
main()
|