Evidence

draw family map.py

Download source fileOpen in research workspace
from pathlib import Path
from html import escape
from xml.etree import ElementTree as ET
P=Path('/workspace/scratch/1b40da62dcbd/c832_c931/prep')
W,H=1500,1120
svg=[f'<svg xmlns="http://www.w3.org/2000/svg" width="{W}" height="{H}" viewBox="0 0 {W} {H}" role="img" aria-labelledby="title desc">',
'<title id="title">How the chronological families fit together</title>',
'<desc id="desc">A precise schematic of the shared measurement and construction grammar through research step C910. Three stages retain source objects, apply declared measurements and operations, and compare whole fields. Six examples show genealogy, lists, New Testament display, one-pass decimal inverse, calendar Keys, and Covenant carriers. Shared topology does not imply equal weights; equal totals do not imply equal interiors; generated maps are not a universal date conversion.</desc>',
'<defs><marker id="arrow" markerWidth="8" markerHeight="8" refX="6" refY="3" orient="auto" markerUnits="strokeWidth"><path d="M0,0 L6,3 L0,6 Z" fill="#397E91"/></marker></defs>',
'<rect width="1500" height="1120" fill="#FFFFFF"/>']
def rect(x,y,w,h,fill='#F5F8FA',stroke='#D8E1E8',rx=10):svg.append(f'<rect x="{x}" y="{y}" width="{w}" height="{h}" rx="{rx}" fill="{fill}" stroke="{stroke}"/>')
def text(x,y,s,size=22,color='#17324D',weight='400',anchor='start'):
 svg.append(f'<text x="{x}" y="{y}" font-family="DejaVu Sans, sans-serif" font-size="{size}" fill="{color}" font-weight="{weight}" text-anchor="{anchor}">{escape(s)}</text>')
def line(x1,y1,x2,y2,stroke='#D8E1E8',width=1,arrow=False):svg.append(f'<line x1="{x1}" y1="{y1}" x2="{x2}" y2="{y2}" stroke="{stroke}" stroke-width="{width}"'+(' marker-end="url(#arrow)"' if arrow else '')+'/>')
text(56,63,'How the chronological families fit together',38,weight='700')
text(56,104,'Shared operations on source-labelled structures',25,color='#506577')
cardx=[56,538,1020];cardw=424
cards=[('1  RETAIN THE SOURCE OBJECT',['Order · labels · weights · categories','Digits · phases · endpoint roles']),('2  DECLARE THE CONSTRUCTION',['Measure · accumulate · round · scale','Specify anchor, grid and operation']),('3  COMPARE WHOLE FIELDS',['Check every boundary and subdivision','Identify what survives and what changes'])]
for x,(head,lines) in zip(cardx,cards):
 rect(x,141,cardw,124,fill='#EFF6F8',stroke='#BFD5DE')
 text(x+20,174,head,20,weight='700')
 for i,s in enumerate(lines):text(x+20,211+28*i,s,18.3,color='#304F64')
for x in [480,962]:line(x+9,203,x+42,203,'#397E91',2.5,True)
text(56,312,'SOURCE FAMILY',17,color='#506577',weight='700')
text(363,312,'MEASUREMENT / OPERATION',17,color='#506577',weight='700')
text(874,312,'WHOLE-FAMILY RESULT',17,color='#506577',weight='700')
rows=[
 {'family':['Regular / cumulative','/ Rounded'],'ref':'C831 foundation; C863–865',
  'op':['Select begetting ages or lifespans.','Accumulate selected rows and residuals.'],
  'result':['One ordered path generates distinct fields.','Shared births can retain different lifespans.']},
 {'family':['Lists and','festival paths'],'ref':'C832–849; C904',
  'op':['Apply categories, declared order and scale.','Compare margins and every running sum.'],
  'result':['Equal totals preserve only part of the data.','Reordering changes intermediate boundaries.']},
 {'family':['NT display / MT graph'],'ref':'C859–871; C905',
  'op':['Align names; retain each edge’s measure.','Realize the declared 70-year display.'],
  'result':['Restored names align; durations still differ.','NT: 70 | 70    •    Restored MT: 35 | 130']},
 {'family':['One-pass decimal','inverse'],'ref':'File52c; C850–858',
  'op':['Reverse digits of each original duration.','Retain zero places and the selected anchor.'],
  'result':['Paired gains follow digit and borrow rules.','990 / 1980 are branches, not free shifts.']},
 {'family':['Calendar Keys'],'ref':'C872–889',
  'op':['Apply an exact Key on a declared grid.','Retain anchors and intermediate domains.'],
  'result':['J → P: 6877 → 6900 → 7000','P → J: 6877 → 20930/3 → 7000 ¹']},
 {'family':['Covenant carriers'],'ref':'C890–906',
  'op':['M = R + 12(C − R)','C = source head; R = declared target.'],
  'result':['Six macro heads follow one anchored rule.','A retained 147 differs from uniform scaling.']}
]
for i,r in enumerate(rows):
 y=335+i*105
 rect(56,y,1388,96,fill=('#FAFCFD' if i%2==0 else '#F2F6F8'),stroke='#DCE5EB',rx=7)
 if len(r['family'])==2:
  text(73,y+27,r['family'][0],21,weight='700');text(73,y+51,r['family'][1],21,weight='700');text(73,y+77,r['ref'],15.5,color='#64778A')
 else:
  text(73,y+35,r['family'][0],21,weight='700');text(73,y+67,r['ref'],15.5,color='#64778A')
 line(340,y+15,340,y+80)
 for j,s in enumerate(r['op']):text(363,y+35+29*j,s,20,color='#304F64')
 line(824,y+48,852,y+48,'#397E91',2,True)
 for j,s in enumerate(r['result']):text(874,y+35+29*j,s,20,color='#17324D')
text(57,984,'¹ J = 300/299; P = 70/69. Exact diagnostic; scalar composition alone does not authorize a chronology route.',17,color='#64778A')
# Three compact statements about the information retained by the map.
for x,w,title,sub in [
 (56,424,'Shared topology ≠ same weights','Name alignment retains source-specific measures.'),
 (538,424,'Same total ≠ same interior','Ordered boundaries and subdivisions still matter.'),
 (1020,424,'No universal date conversion','Generated maps keep declared source domains.')]:
 rect(x,1005,w,76,fill='#17324D',stroke='#17324D',rx=8)
 text(x+17,1035,title,20.5,color='#FFFFFF',weight='700')
 text(x+17,1060,sub,15.3,color='#DDEAF0')
text(56,1104,'DRAFT • C831 foundation + C832–C910 • Exact mathematical relations; historical interpretation remains a separate claim.',16.3,color='#64778A')
svg.append('</svg>')
p=P/'FAMILY_MAP_DRAFT.svg';p.write_text('\n'.join(svg)+'\n')
ET.parse(p)
print(str(p))

Linked sources and evidence

Edition and provenance

draw_family_map.py

SHA-256 0da86f80b9a45217ec1d984d217d23ce651fda1e9b5f9fc58611c58947e3576b

C480–C1634/Research_Cycles/C0832_C0931/prep/draw_family_map.py