Evidence

render map.py

Download source fileOpen in research workspace
from pathlib import Path
import json,html
ROOT=Path(__file__).resolve().parent.parent
def render_svg(spec):
 parts=['<svg xmlns="http://www.w3.org/2000/svg" width="1600" height="1120" viewBox="0 0 1600 1120">','<defs><marker id="arrow" markerWidth="8" markerHeight="8" refX="7" refY="4" orient="auto"><path d="M0 0 L8 4 L0 8 Z" fill="#527084"/></marker></defs>','<rect width="1600" height="1120" fill="#FAFBF8"/>']
 def rect(x,y,w,h,fill,stroke='none',rx=14):parts.append(f'<rect x="{x}" y="{y}" width="{w}" height="{h}" rx="{rx}" fill="{fill}" stroke="{stroke}"/>')
 def text(x,y,t,size=23,fill='#18384D',weight='400',anchor='start'):
  parts.append(f'<text x="{x}" y="{y}" font-family="DejaVu Sans,Arial,sans-serif" font-size="{size}" font-weight="{weight}" fill="{fill}" text-anchor="{anchor}">{html.escape(t)}</text>')
 def arrow(x1,y1,x2,y2):parts.append(f'<path d="M{x1} {y1} L{x2} {y2}" stroke="#527084" stroke-width="3" fill="none" marker-end="url(#arrow)"/>')
 def box(x,y,w,h,title,lines):
  rect(x,y,w,h,'#EAF1F4','#CFDDE4');text(x+w/2,y+34,title,25,weight='600',anchor='middle')
  for i,t in enumerate(lines):text(x+w/2,y+66+27*i,t,20,anchor='middle')
 text(60,68,spec['title'],39,weight='600')
 text(60,108,'Source structures • declared operations • retained information',23,fill='#526977')
 rect(50,145,725,885,'#FFFFFF','#DCE5E6');rect(805,145,745,885,'#FFFFFF','#DCE5E6')
 text(85,192,'SP: one local source mechanism',28,weight='600')
 text(840,192,'Companion constructions',28,weight='600')
 box(105,225,615,94,'Ordered begetting rows',['Nine source rows + primary Noah'])
 arrow(412,319,412,365);text(445,347,'accumulate',18,fill='#526977')
 box(105,377,615,94,'Regular birth field',['Complete source births, with count bindings'])
 arrow(412,471,412,532);text(445,503,'fixed Flood relation',18,fill='#526977')
 box(105,544,615,94,'Flood capacities',['Birth − Flood start + 1'])
 arrow(412,638,412,701);text(412,675,'minimum with baseline life ledger',19,fill='#526977',anchor='middle')
 box(105,713,615,108,'Capped lifespan ledger',['All nine lives reconstructed','Three source rows shortened'])
 arrow(330,821,248,874);arrow(495,821,578,874)
 text(178,855,'accumulate',17,fill='#526977');text(551,855,'round counts',17,fill='#526977')
 box(100,886,290,105,'Cumulative field',['Ordered changes','from local reductions'])
 box(435,886,290,105,'Rounded counts',['Same cap rule','resolved before rounding'])
 descriptions=[
 ('Rounded inverse','Original components → one reversal','Register and carry branch'),
 ('Calendar Keys','Measured spans → exact conversion','Units, selected parts and pivot'),
 ('Covenant / clutch','Two source paths → derived shift','Shared lifespans; additional joins'),
 ('Lists and NT','Ordered counts or slots → fields','Category, metric and source order'),
 ('Toledot','Occurrences → source sections','Multiplicity and symmetry tests')]
 for i,(title,line1,line2) in enumerate(descriptions):
  y=230+i*150
  rect(840,y,675,128,'#F0F4ED','#DAE4D6');text(865,y+36,title,27,weight='600');text(865,y+72,line1,22);text(865,y+103,line2,20,fill='#526977')
 text(60,1070,'Shared operations connect these families; they do not make one mandatory pipeline.',23,weight='600')
 text(60,1102,'A total can agree while internal boundaries, source roles or admissible grids differ.  •  C932–C1131',19,fill='#526977')
 parts.append('</svg>');return '\n'.join(parts)+'\n'
if __name__=='__main__':
 spec=json.loads((ROOT/'model/family_map_spec.json').read_text())
 (ROOT/'deliverables/490d_Chronological_Family_Map_C1131.svg').write_text(render_svg(spec))

Edition and provenance

render_map.py

SHA-256 2fe732267425f30e50164c35fc84cdf871c47dfcb907b0290a7ec88c84db48a9

C480–C1634/Research_Cycles/C0932_C1131/evidence/render_map.py