274: vendor the transect page into the repo
Keeps the interactive map available offline and under version control while the song is in progress. - 274-transect.html — self-contained; carries its data in a script block, fonts from Google Fonts, no other external requests. Opens by double clicking. Same page as the published artifact. - 274-route.json, 274-districts.json — the route line and the 23 大字 bands from the 250 m reverse-geocode sweep. - 274-transect-build.py — re-reads the roster out of 274-dev.md and rewrites the page's data block in place, leaving markup and script alone. Run it after editing the table. Everything under wip/ so the auto-wiki pipeline leaves it alone. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01S6MpcBisZYhX45oDGRRJoz
This commit is contained in:
@@ -0,0 +1,186 @@
|
||||
[
|
||||
{
|
||||
"frm": 36.5,
|
||||
"to": 38.25,
|
||||
"code": "01427",
|
||||
"city": "夕張郡由仁町",
|
||||
"lv": "川端",
|
||||
"kana": "かわばた"
|
||||
},
|
||||
{
|
||||
"frm": 38.5,
|
||||
"to": 42.0,
|
||||
"code": "01429",
|
||||
"city": "夕張郡栗山町",
|
||||
"lv": "字滝下",
|
||||
"kana": "たきした"
|
||||
},
|
||||
{
|
||||
"frm": 42.25,
|
||||
"to": 43.0,
|
||||
"code": "01427",
|
||||
"city": "夕張郡由仁町",
|
||||
"lv": "川端",
|
||||
"kana": "かわばた"
|
||||
},
|
||||
{
|
||||
"frm": 43.25,
|
||||
"to": 44.0,
|
||||
"code": "01429",
|
||||
"city": "夕張郡栗山町",
|
||||
"lv": "字滝下",
|
||||
"kana": "たきした"
|
||||
},
|
||||
{
|
||||
"frm": 44.25,
|
||||
"to": 48.25,
|
||||
"code": "01209",
|
||||
"city": "夕張市",
|
||||
"lv": "滝ノ上",
|
||||
"kana": "たきのうえ"
|
||||
},
|
||||
{
|
||||
"frm": 48.5,
|
||||
"to": 55.5,
|
||||
"code": "01209",
|
||||
"city": "夕張市",
|
||||
"lv": "紅葉山",
|
||||
"kana": "もみじやま"
|
||||
},
|
||||
{
|
||||
"frm": 55.75,
|
||||
"to": 57.75,
|
||||
"code": "01209",
|
||||
"city": "夕張市",
|
||||
"lv": "楓",
|
||||
"kana": "かえで"
|
||||
},
|
||||
{
|
||||
"frm": 58.0,
|
||||
"to": 61.0,
|
||||
"code": "01209",
|
||||
"city": "夕張市",
|
||||
"lv": "登川",
|
||||
"kana": "のぼりかわ"
|
||||
},
|
||||
{
|
||||
"frm": 61.25,
|
||||
"to": 62.75,
|
||||
"code": "01586",
|
||||
"city": "勇払郡むかわ町",
|
||||
"lv": "穂別長和",
|
||||
"kana": "ほべつおさわ"
|
||||
},
|
||||
{
|
||||
"frm": 63.0,
|
||||
"to": 72.0,
|
||||
"code": "01586",
|
||||
"city": "勇払郡むかわ町",
|
||||
"lv": "穂別稲里",
|
||||
"kana": "ほべついなさと"
|
||||
},
|
||||
{
|
||||
"frm": 72.25,
|
||||
"to": 76.0,
|
||||
"code": "01586",
|
||||
"city": "勇払郡むかわ町",
|
||||
"lv": "穂別長和",
|
||||
"kana": "ほべつおさわ"
|
||||
},
|
||||
{
|
||||
"frm": 76.25,
|
||||
"to": 88.75,
|
||||
"code": "01586",
|
||||
"city": "勇払郡むかわ町",
|
||||
"lv": "穂別福山",
|
||||
"kana": "ほべつふくやま"
|
||||
},
|
||||
{
|
||||
"frm": 89.0,
|
||||
"to": 96.75,
|
||||
"code": "01463",
|
||||
"city": "勇払郡占冠村",
|
||||
"lv": "字中央",
|
||||
"kana": "ちゅうおう"
|
||||
},
|
||||
{
|
||||
"frm": 97.0,
|
||||
"to": 101.75,
|
||||
"code": "01601",
|
||||
"city": "沙流郡日高町",
|
||||
"lv": "字日高",
|
||||
"kana": "ひだか(1く)"
|
||||
},
|
||||
{
|
||||
"frm": 102.0,
|
||||
"to": 102.5,
|
||||
"code": "01601",
|
||||
"city": "沙流郡日高町",
|
||||
"lv": "新町三丁目",
|
||||
"kana": "しんまち"
|
||||
},
|
||||
{
|
||||
"frm": 102.75,
|
||||
"to": 102.75,
|
||||
"code": "01601",
|
||||
"city": "沙流郡日高町",
|
||||
"lv": "新町一丁目",
|
||||
"kana": "しんまち"
|
||||
},
|
||||
{
|
||||
"frm": 103.0,
|
||||
"to": 103.0,
|
||||
"code": "01601",
|
||||
"city": "沙流郡日高町",
|
||||
"lv": "栄町東一丁目",
|
||||
"kana": "さかえまちひがし"
|
||||
},
|
||||
{
|
||||
"frm": 103.25,
|
||||
"to": 103.5,
|
||||
"code": "01601",
|
||||
"city": "沙流郡日高町",
|
||||
"lv": "本町東一丁目",
|
||||
"kana": "ほんちょうひがし"
|
||||
},
|
||||
{
|
||||
"frm": 103.75,
|
||||
"to": 103.75,
|
||||
"code": "01601",
|
||||
"city": "沙流郡日高町",
|
||||
"lv": "本町東二丁目",
|
||||
"kana": "ほんちょうひがし"
|
||||
},
|
||||
{
|
||||
"frm": 104.0,
|
||||
"to": 104.0,
|
||||
"code": "01601",
|
||||
"city": "沙流郡日高町",
|
||||
"lv": "松風町一丁目",
|
||||
"kana": "まつかぜちょう"
|
||||
},
|
||||
{
|
||||
"frm": 104.25,
|
||||
"to": 104.25,
|
||||
"code": "01601",
|
||||
"city": "沙流郡日高町",
|
||||
"lv": "山手町一丁目",
|
||||
"kana": "やまてちょう"
|
||||
},
|
||||
{
|
||||
"frm": 104.5,
|
||||
"to": 107.0,
|
||||
"code": "01601",
|
||||
"city": "沙流郡日高町",
|
||||
"lv": "字日高",
|
||||
"kana": "ひだか(1く)"
|
||||
},
|
||||
{
|
||||
"frm": 107.25,
|
||||
"to": 107.75,
|
||||
"code": "01601",
|
||||
"city": "沙流郡日高町",
|
||||
"lv": "字千栄",
|
||||
"kana": "ちさか"
|
||||
}
|
||||
]
|
||||
File diff suppressed because one or more lines are too long
Executable
+75
@@ -0,0 +1,75 @@
|
||||
#!/usr/bin/env python3
|
||||
"""Rebuild the data payload inside 274-transect.html from 274-dev.md.
|
||||
|
||||
The HTML is self-contained: it carries its data in a <script id="data"> block so
|
||||
it opens straight from disk. This script re-reads the roster table out of
|
||||
274-dev.md, joins the route line and district bands, and writes the payload back
|
||||
into the HTML in place. The page's markup, CSS and JS are left untouched.
|
||||
|
||||
python3 274-transect-build.py
|
||||
|
||||
Inputs : 274-dev.md (roster, source of truth), 274-route.json, 274-districts.json
|
||||
Output : 274-transect.html (data block replaced)
|
||||
"""
|
||||
import io, json, os, re, sys
|
||||
|
||||
HERE = os.path.dirname(os.path.abspath(__file__))
|
||||
p = lambda n: os.path.join(HERE, n)
|
||||
CHOME = re.compile(r'[一二三四五六七八九十百]+丁目$')
|
||||
|
||||
|
||||
def roster(path):
|
||||
hdr, rows = None, []
|
||||
for line in io.open(path, encoding='utf-8'):
|
||||
if line.startswith('| km | Name |'):
|
||||
hdr = [c.strip() for c in line.strip().strip('|').split('|')]
|
||||
continue
|
||||
if hdr and line.startswith('| ') and line.count('|') >= 13:
|
||||
c = [x.strip() for x in line.strip().strip('|').split('|')]
|
||||
if re.match(r'^\d+\.\d+$', c[0]):
|
||||
rows.append(dict(zip(hdr, c)))
|
||||
if not rows:
|
||||
sys.exit('no roster rows found in %s' % path)
|
||||
return rows
|
||||
|
||||
|
||||
def oaza_of(address, cities):
|
||||
a = address or ''
|
||||
for c in cities:
|
||||
if a.startswith(c):
|
||||
a = a[len(c):]
|
||||
break
|
||||
return CHOME.sub('', a).strip() or '—'
|
||||
|
||||
|
||||
def main():
|
||||
bands = json.load(io.open(p('274-districts.json'), encoding='utf-8'))
|
||||
route = json.load(io.open(p('274-route.json'), encoding='utf-8'))
|
||||
cities = sorted({b['city'] for b in bands if b.get('city')}, key=len, reverse=True)
|
||||
|
||||
items = []
|
||||
for r in roster(p('274-dev.md')):
|
||||
items.append(dict(
|
||||
km=float(r['km']), name=r['Name'], obj=r['Object'],
|
||||
kana=r.get('Kana', ''), romaji=r.get('Romaji', ''), kind=r['Kind'],
|
||||
off=float(r['Off (m)'] or 0), lat=float(r['Lat']), lon=float(r['Lon']),
|
||||
L=r.get('Length', ''), y=r.get('Built', ''), g=r.get('Grade', ''),
|
||||
addr=r.get('Address', ''), addrk=r.get('Address kana', ''),
|
||||
oaza=oaza_of(r.get('Address', ''), cities),
|
||||
city=next((c for c in cities if (r.get('Address') or '').startswith(c)), '')))
|
||||
items.sort(key=lambda o: (o['km'], o['obj']))
|
||||
|
||||
payload = json.dumps(dict(route=route, items=items, bands=bands),
|
||||
ensure_ascii=False, separators=(',', ':'))
|
||||
html = io.open(p('274-transect.html'), encoding='utf-8').read()
|
||||
new, n = re.subn(r'(<script id="data" type="application/json">).*?(</script>)',
|
||||
lambda m: m.group(1) + payload + m.group(2), html, count=1, flags=re.S)
|
||||
if not n:
|
||||
sys.exit('data block not found in 274-transect.html')
|
||||
io.open(p('274-transect.html'), 'w', encoding='utf-8').write(new)
|
||||
print('%d entries, %d district bands, %d route points -> 274-transect.html'
|
||||
% (len(items), len(bands), len(route)))
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
main()
|
||||
File diff suppressed because one or more lines are too long
Reference in New Issue
Block a user