code wiki / _hdl_build / nx_viz_sankey_page.nx

nx_viz_sankey_page.nx source

↩ module page · 156 lines · 8466 B

1// nx_viz_sankey_page.nx -- COMPOSED live SANKEY: parse a node/link flow TSV, lay out with nx_viz_sankey 2// (vsk_layout: throughput + per-column stacking), draw nodes as rects + links as thickness-proportional ribbons 3// (cubic-Bezier centerlines, stacked at per-node offsets) coloured per source (nx_viz_color). Self-contained HTML 4// for the wiki. usage: nx_viz_sankey_page [in.tsv] [out.html]. license_tier: ORIGINAL 5import "nx_viz_sankey.nx" 6import "nx_viz_shape.nx" 7import "nx_viz_color.nx" 8import "nx_syscalls.nx" 9const K_MAGIC_2048: i64 = 2048 10const K_MAGIC_262144: i64 = 262144 11 12func cw(fd: i64, s: *u8) -> i64 { var n: i64 = 0; while s[n] != (0 as u8) { n = n + 1 } sys_write(fd, s, n); return 0 } 13func emit_hex6(out: *u8, off: i64, color: i64) -> i64 { 14 var o: i64 = off; out[o] = 35 as u8; o = o + 1 15 var sh: i64 = 20 16 while sh >= 0 { let nib: i64 = (color >> sh) & 15; var ch: i64 = 48 + nib; if nib >= 10 { ch = 87 + nib } out[o] = ch as u8; o = o + 1; sh = sh - 4 } 17 return o 18} 19func atoi_rng(buf: *u8, s: i64, e: i64) -> i64 { 20 var v: i64 = 0; var k: i64 = s 21 while k < e { let d: i64 = buf[k] as i64; if d >= 48 { if d <= 57 { v = v * 10 + (d - 48) } } k = k + 1 } 22 return v 23} 24 25func main(argc: i64, argv: *i64) -> i64 { 26 var inp: *u8 = "knowledge/registry/viz_genesis_flow.tsv" as *u8 27 var outp: *u8 = "/mnt/c/Users/elder/nishi-core/nxc2/web_assets/viz_sankey.html" as *u8 28 if argc >= 2 { inp = argv[1] as *u8 } 29 if argc >= 3 { outp = argv[2] as *u8 } 30 31 let lenp: *i64 = sys_mmap(16) as *i64 32 let buf: *u8 = sys_read_file(inp, lenp) 33 if (buf as i64) == 0 { cw(2, "nx_viz_sankey_page: cannot read flow\n" as *u8); return 2 } 34 let n: i64 = lenp[0] 35 36 let column: *i64 = sys_mmap(K_MAGIC_2048) as *i64 37 let lab_off: *i64 = sys_mmap(K_MAGIC_2048) as *i64 38 let lab_len: *i64 = sys_mmap(K_MAGIC_2048) as *i64 39 let src: *i64 = sys_mmap(K_MAGIC_2048) as *i64 40 let dst: *i64 = sys_mmap(K_MAGIC_2048) as *i64 41 let val: *i64 = sys_mmap(K_MAGIC_2048) as *i64 42 var nc: i64 = 0; var m: i64 = 0 43 44 var i: i64 = 0 45 while i < n { 46 let ls: i64 = i 47 var le: i64 = ls 48 while le < n { if buf[le] == (10 as u8) { break } le = le + 1 } 49 if le > ls { 50 if buf[ls] != (35 as u8) { 51 var t1: i64 = ls 52 while t1 < le { if buf[t1] == (9 as u8) { break } t1 = t1 + 1 } 53 var t2: i64 = t1 + 1 54 while t2 < le { if buf[t2] == (9 as u8) { break } t2 = t2 + 1 } 55 var t3: i64 = t2 + 1 56 while t3 < le { if buf[t3] == (9 as u8) { break } t3 = t3 + 1 } 57 if buf[ls] == (78 as u8) { 58 column[nc] = atoi_rng(buf, t1 + 1, t2) 59 lab_off[nc] = t2 + 1 60 var ll: i64 = le - (t2 + 1); if ll < 0 { ll = 0 } 61 lab_len[nc] = ll 62 nc = nc + 1 63 } 64 if buf[ls] == (76 as u8) { 65 src[m] = atoi_rng(buf, t1 + 1, t2) 66 dst[m] = atoi_rng(buf, t2 + 1, t3) 67 val[m] = atoi_rng(buf, t3 + 1, le) 68 m = m + 1 69 } 70 } 71 } 72 i = le + 1 73 } 74 if nc == 0 { cw(2, "nx_viz_sankey_page: no nodes\n" as *u8); return 3 } 75 76 let node_h: *i64 = sys_mmap(K_MAGIC_2048) as *i64 77 let node_y: *i64 = sys_mmap(K_MAGIC_2048) as *i64 78 let cols: i64 = vsk_layout(nc, column, m, src, dst, val, 2, node_h, node_y) 79 80 let SCALE: i64 = 14 81 let NODEW: i64 = 18 82 let COLSP: i64 = 150 83 let MX: i64 = 56 84 let MY: i64 = 36 85 let W: i64 = MX * 2 + (cols - 1) * COLSP + NODEW 86 var maxbot: i64 = 0 87 var q: i64 = 0 88 while q < nc { let b: i64 = (node_y[q] + node_h[q]) * SCALE; if b > maxbot { maxbot = b } q = q + 1 } 89 let H: i64 = MY * 2 + maxbot 90 91 // per-node pixel geometry + running offsets for stacked link endpoints 92 let npx: *i64 = sys_mmap(K_MAGIC_2048) as *i64 93 let npy: *i64 = sys_mmap(K_MAGIC_2048) as *i64 94 let nph: *i64 = sys_mmap(K_MAGIC_2048) as *i64 95 let uout: *i64 = sys_mmap(K_MAGIC_2048) as *i64 96 let uin: *i64 = sys_mmap(K_MAGIC_2048) as *i64 97 q = 0 98 while q < nc { 99 npx[q] = MX + column[q] * COLSP 100 npy[q] = MY + node_y[q] * SCALE 101 nph[q] = node_h[q] * SCALE 102 uout[q] = 0; uin[q] = 0 103 q = q + 1 104 } 105 106 let ob: *u8 = sys_mmap(K_MAGIC_262144) 107 var o: i64 = 0 108 o = vsh_lit(ob, o, "<!DOCTYPE html><html><head><meta charset=\"utf-8\"><meta name=\"viewport\" content=\"width=device-width,initial-scale=1\"><title>Nishi Viz &mdash; Sankey</title>" as *u8) 109 o = vsh_lit(ob, o, "<style>body{margin:0;background:#0d1117;color:#e6edf3;font-family:system-ui,-apple-system,sans-serif;padding:28px}h1{font-size:20px;margin:0 0 6px}p{color:#9aa4b2;max-width:820px;line-height:1.55}code{color:#79c0ff}a{color:#58a6ff;text-decoration:none}.card{margin-top:18px;background:#161b22;border:1px solid #30363d;border-radius:10px;padding:12px;display:inline-block}</style></head><body>" as *u8) 110 o = vsh_lit(ob, o, "<h1>Nishi Visualization Suite &mdash; sankey (genesis tech-tree flow)</h1>" as *u8) 111 o = vsh_lit(ob, o, "<p>The genesis lineage as a flow, laid out by <code>nx_viz_sankey</code> (node height = throughput, stacked per column) &mdash; ribbons are thickness-proportional cubic curves, stacked at per-node offsets, drawn by <code>nx_viz_shape</code>, coloured by source (<code>nx_viz_color</code>). No d3.js, no CDN.</p>" as *u8) 112 o = vsh_lit(ob, o, "<div class=\"card\"><svg xmlns=\"http://www.w3.org/2000/svg\" width=\"" as *u8) 113 o = vsh_n(ob, o, W); o = vsh_lit(ob, o, "\" height=\"" as *u8); o = vsh_n(ob, o, H); o = vsh_lit(ob, o, "\" font-family=\"system-ui,sans-serif\">" as *u8) 114 115 // links (ribbons) under the nodes 116 var e: i64 = 0 117 while e < m { 118 let a: i64 = src[e]; let b: i64 = dst[e] 119 let th: i64 = val[e] * SCALE 120 let sx: i64 = npx[a] + NODEW 121 let dx: i64 = npx[b] 122 let sy: i64 = npy[a] + uout[a] + th / 2 123 let dy: i64 = npy[b] + uin[b] + th / 2 124 uout[a] = uout[a] + th; uin[b] = uin[b] + th 125 let midx: i64 = (sx + dx) / 2 126 o = vsh_lit(ob, o, "<path d=\"M " as *u8); o = vsh_n(ob, o, sx); o = vsh_lit(ob, o, " " as *u8); o = vsh_n(ob, o, sy) 127 o = vsh_lit(ob, o, " C " as *u8); o = vsh_n(ob, o, midx); o = vsh_lit(ob, o, " " as *u8); o = vsh_n(ob, o, sy) 128 o = vsh_lit(ob, o, " " as *u8); o = vsh_n(ob, o, midx); o = vsh_lit(ob, o, " " as *u8); o = vsh_n(ob, o, dy) 129 o = vsh_lit(ob, o, " " as *u8); o = vsh_n(ob, o, dx); o = vsh_lit(ob, o, " " as *u8); o = vsh_n(ob, o, dy) 130 o = vsh_lit(ob, o, "\" stroke=\"" as *u8); o = emit_hex6(ob, o, vc_categorical(a, nc)) 131 o = vsh_lit(ob, o, "\" stroke-width=\"" as *u8); o = vsh_n(ob, o, th); o = vsh_lit(ob, o, "\" fill=\"none\" stroke-opacity=\"0.4\"/>" as *u8) 132 e = e + 1 133 } 134 // nodes (rects + labels) 135 q = 0 136 while q < nc { 137 o = vsh_lit(ob, o, "<rect x=\"" as *u8); o = vsh_n(ob, o, npx[q]); o = vsh_lit(ob, o, "\" y=\"" as *u8); o = vsh_n(ob, o, npy[q]) 138 o = vsh_lit(ob, o, "\" width=\"" as *u8); o = vsh_n(ob, o, NODEW); o = vsh_lit(ob, o, "\" height=\"" as *u8); o = vsh_n(ob, o, nph[q]) 139 o = vsh_lit(ob, o, "\" rx=\"2\" fill=\"" as *u8); o = emit_hex6(ob, o, vc_categorical(q, nc)); o = vsh_lit(ob, o, "\"/>" as *u8) 140 o = vsh_lit(ob, o, "<text x=\"" as *u8); o = vsh_n(ob, o, npx[q] + NODEW + 5); o = vsh_lit(ob, o, "\" y=\"" as *u8); o = vsh_n(ob, o, npy[q] + nph[q] / 2 + 4) 141 o = vsh_lit(ob, o, "\" font-size=\"13\" fill=\"#e6edf3\">" as *u8) 142 var lk: i64 = lab_off[q]; let lend: i64 = lab_off[q] + lab_len[q] 143 while lk < lend { ob[o] = buf[lk]; o = o + 1; lk = lk + 1 } 144 o = vsh_lit(ob, o, "</text>" as *u8) 145 q = q + 1 146 } 147 o = vsh_lit(ob, o, "</svg></div>" as *u8) 148 o = vsh_lit(ob, o, "<p style=\"margin-top:16px;font-size:13px\">Generated by <code>nx_viz_sankey_page</code> from <code>viz_genesis_flow.tsv</code>. &nbsp;<a href=\"viz-chord.html\">&larr; chord</a> &middot; <a href=\"viz-zoom.html\">wasm zoom</a></p></body></html>" as *u8) 149 150 let fd: i64 = sys_openat_wr(outp, 0x1a4) 151 if fd < 0 { cw(2, "nx_viz_sankey_page: cannot open output\n" as *u8); return 4 } 152 sys_write(fd, ob, o) 153 sys_close(fd) 154 cw(1, "[nx_viz_sankey_page] wrote " as *u8); cw(1, outp); cw(1, "\n" as *u8) 155 return 0 156}