code wiki / _hdl_build / nx_viz_graph.nx

nx_viz_graph.nx source

↩ module page · 177 lines · 8905 B

1// nx_viz_graph.nx -- COMPOSED live FORCE-GRAPH: parse a node/edge TSV, seed node positions on a circle 2// (nx_viz_trig vs_cos/vs_sin), lay it out with nx_viz_force (Fruchterman-Reingold), draw edges+nodes+labels as 3// SVG (nx_viz_shape serializer) into a self-contained HTML page for the wiki. Demonstrates the force layer on 4// real data (here the library's own import graph). usage: nx_viz_graph [in.tsv] [out.html]. license_tier: ORIGINAL 5import "nx_viz_force.nx" 6import "nx_viz_shape.nx" 7import "nx_viz_color.nx" 8import "nx_syscalls.nx" 9const K_MAGIC_4096: i64 = 4096 10const K_MAGIC_10000: i64 = 10000 11const K_MAGIC_262144: i64 = 262144 12 13func 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 } 14// emit "#RRGGBB" for a packed 0xRRGGBB color at out[off]; returns new off. 15func emit_hex6(out: *u8, off: i64, color: i64) -> i64 { 16 var o: i64 = off 17 out[o] = 35 as u8; o = o + 1 18 var sh: i64 = 20 19 while sh >= 0 { 20 let nib: i64 = (color >> sh) & 15 21 var ch: i64 = 48 + nib 22 if nib >= 10 { ch = 87 + nib } 23 out[o] = ch as u8; o = o + 1 24 sh = sh - 4 25 } 26 return o 27} 28func pn(fd: i64, v: i64) -> i64 { 29 var x: i64 = v; let t: *u8 = sys_mmap(28); var tk: i64 = 0 30 if x == 0 { t[0] = 48 as u8; tk = 1 } 31 while x > 0 { t[tk] = (48 + (x % 10)) as u8; x = x / 10; tk = tk + 1 } 32 let r: *u8 = sys_mmap(28); var z: i64 = 0 33 while z < tk { r[z] = t[tk - 1 - z]; z = z + 1 } 34 sys_write(fd, r, tk); return 0 35} 36func atoi_rng(buf: *u8, s: i64, e: i64) -> i64 { 37 var v: i64 = 0; var k: i64 = s 38 while k < e { let d: i64 = buf[k] as i64; if d >= 48 { if d <= 57 { v = v * 10 + (d - 48) } } k = k + 1 } 39 return v 40} 41 42func main(argc: i64, argv: *i64) -> i64 { 43 var inp: *u8 = "knowledge/registry/viz_module_graph.tsv" as *u8 44 var outp: *u8 = "/mnt/c/Users/elder/nishi-core/nxc2/web_assets/viz_graph.html" as *u8 45 if argc >= 2 { inp = argv[1] as *u8 } 46 if argc >= 3 { outp = argv[2] as *u8 } 47 48 let lenp: *i64 = sys_mmap(16) as *i64 49 let buf: *u8 = sys_read_file(inp, lenp) 50 if (buf as i64) == 0 { cw(2, "nx_viz_graph: cannot read graph\n" as *u8); return 2 } 51 let n: i64 = lenp[0] 52 53 let lab_off: *i64 = sys_mmap(K_MAGIC_4096) as *i64 54 let lab_len: *i64 = sys_mmap(K_MAGIC_4096) as *i64 55 let tip_off: *i64 = sys_mmap(K_MAGIC_4096) as *i64 56 let tip_len: *i64 = sys_mmap(K_MAGIC_4096) as *i64 57 let xs: *i64 = sys_mmap(K_MAGIC_4096) as *i64 58 let ys: *i64 = sys_mmap(K_MAGIC_4096) as *i64 59 let ea: *i64 = sys_mmap(K_MAGIC_4096) as *i64 60 let eb: *i64 = sys_mmap(K_MAGIC_4096) as *i64 61 var nc: i64 = 0 62 var m: i64 = 0 63 64 var i: i64 = 0 65 while i < n { 66 let ls: i64 = i 67 var le: i64 = ls 68 while le < n { if buf[le] == (10 as u8) { break } le = le + 1 } 69 if le > ls { 70 if buf[ls] != (35 as u8) { 71 var t1: i64 = ls 72 while t1 < le { if buf[t1] == (9 as u8) { break } t1 = t1 + 1 } 73 if t1 < le { 74 var t2: i64 = t1 + 1 75 while t2 < le { if buf[t2] == (9 as u8) { break } t2 = t2 + 1 } 76 if buf[ls] == (78 as u8) { 77 lab_off[nc] = t1 + 1 78 lab_len[nc] = t2 - (t1 + 1) 79 tip_off[nc] = t2 + 1 80 var tl: i64 = le - (t2 + 1); if tl < 0 { tl = 0 } 81 tip_len[nc] = tl 82 nc = nc + 1 83 } 84 if buf[ls] == (69 as u8) { 85 ea[m] = atoi_rng(buf, t1 + 1, t2) 86 eb[m] = atoi_rng(buf, t2 + 1, le) 87 m = m + 1 88 } 89 } 90 } 91 } 92 i = le + 1 93 } 94 if nc == 0 { cw(2, "nx_viz_graph: no nodes\n" as *u8); return 3 } 95 96 let W: i64 = 1000 97 let H: i64 = 760 98 let cx: i64 = W / 2 99 let cy: i64 = H / 2 100 let R: i64 = 320 101 var p: i64 = 0 102 while p < nc { 103 let ang: i64 = (p * 360) / nc 104 xs[p] = cx + (R * vs_cos(ang)) / K_MAGIC_10000 105 ys[p] = cy + (R * vs_sin(ang)) / K_MAGIC_10000 106 p = p + 1 107 } 108 vf_layout(nc, xs, ys, m, ea, eb, W, H, 300, 130) 109 110 // fit the laid-out graph to the frame [PAD, W-PAD] x [PAD, H-PAD], UNIFORM scale (preserve graph shape) 111 var minx: i64 = xs[0]; var maxx: i64 = xs[0]; var miny: i64 = ys[0]; var maxy: i64 = ys[0] 112 var fi: i64 = 1 113 while fi < nc { 114 if xs[fi] < minx { minx = xs[fi] } 115 if xs[fi] > maxx { maxx = xs[fi] } 116 if ys[fi] < miny { miny = ys[fi] } 117 if ys[fi] > maxy { maxy = ys[fi] } 118 fi = fi + 1 119 } 120 var bw: i64 = maxx - minx; if bw < 1 { bw = 1 } 121 var bh: i64 = maxy - miny; if bh < 1 { bh = 1 } 122 let PAD: i64 = 70 123 let tw: i64 = W - 2 * PAD 124 let th: i64 = H - 2 * PAD 125 var s: i64 = (tw * 1000) / bw 126 let sy: i64 = (th * 1000) / bh 127 if sy < s { s = sy } 128 let offx: i64 = PAD + (tw - (bw * s) / 1000) / 2 129 let offy: i64 = PAD + (th - (bh * s) / 1000) / 2 130 var fj: i64 = 0 131 while fj < nc { 132 xs[fj] = offx + ((xs[fj] - minx) * s) / 1000 133 ys[fj] = offy + ((ys[fj] - miny) * s) / 1000 134 fj = fj + 1 135 } 136 137 let ob: *u8 = sys_mmap(K_MAGIC_262144) 138 var o: i64 = 0 139 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; Force Graph</title>" as *u8) 140 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) 141 o = vsh_lit(ob, o, "<h1>Nishi Visualization Suite &mdash; force-directed module graph</h1>" as *u8) 142 o = vsh_lit(ob, o, "<p>The library's OWN import graph, laid out by <code>nx_viz_force</code> (Fruchterman-Reingold, pure integer) &mdash; nodes seeded on a circle by <code>nx_viz_trig</code>, edges + nodes drawn by <code>nx_viz_shape</code>. No d3.js, no CDN. An edge A&ndash;B means &ldquo;A imports B&rdquo;; <code>trig</code> is the hub (shape + force depend on it), the three standalone modules float free.</p>" as *u8) 143 o = vsh_lit(ob, o, "<div class=\"card\"><svg xmlns=\"http://www.w3.org/2000/svg\" width=\"" as *u8) 144 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) 145 var e: i64 = 0 146 while e < m { 147 let a: i64 = ea[e]; let b: i64 = eb[e] 148 o = vsh_lit(ob, o, "<line x1=\"" as *u8); o = vsh_n(ob, o, xs[a]); o = vsh_lit(ob, o, "\" y1=\"" as *u8); o = vsh_n(ob, o, ys[a]) 149 o = vsh_lit(ob, o, "\" x2=\"" as *u8); o = vsh_n(ob, o, xs[b]); o = vsh_lit(ob, o, "\" y2=\"" as *u8); o = vsh_n(ob, o, ys[b]) 150 o = vsh_lit(ob, o, "\" stroke=\"#3a6ea5\" stroke-width=\"2\"/>" as *u8) 151 e = e + 1 152 } 153 var q: i64 = 0 154 while q < nc { 155 o = vsh_lit(ob, o, "<g><title>" as *u8) 156 var tk: i64 = tip_off[q]; let te: i64 = tip_off[q] + tip_len[q] 157 while tk < te { ob[o] = buf[tk]; o = o + 1; tk = tk + 1 } 158 o = vsh_lit(ob, o, "</title><circle cx=\"" as *u8); o = vsh_n(ob, o, xs[q]); o = vsh_lit(ob, o, "\" cy=\"" as *u8); o = vsh_n(ob, o, ys[q]) 159 o = vsh_lit(ob, o, "\" r=\"23\" fill=\"" as *u8); o = emit_hex6(ob, o, vc_categorical(q, nc)); o = vsh_lit(ob, o, "\" stroke=\"#fff\" stroke-width=\"1.5\"/>" as *u8) 160 o = vsh_lit(ob, o, "<text x=\"" as *u8); o = vsh_n(ob, o, xs[q]); o = vsh_lit(ob, o, "\" y=\"" as *u8); o = vsh_n(ob, o, ys[q] + 4) 161 o = vsh_lit(ob, o, "\" text-anchor=\"middle\" font-size=\"10\" fill=\"#ffffff\">" as *u8) 162 var lk: i64 = lab_off[q]; let lend: i64 = lab_off[q] + lab_len[q] 163 while lk < lend { ob[o] = buf[lk]; o = o + 1; lk = lk + 1 } 164 o = vsh_lit(ob, o, "</text></g>" as *u8) 165 q = q + 1 166 } 167 o = vsh_lit(ob, o, "</svg></div>" as *u8) 168 o = vsh_lit(ob, o, "<p style=\"margin-top:16px;font-size:13px\">Generated by <code>nx_viz_graph</code> from <code>viz_module_graph.tsv</code>. &nbsp;<a href=\"viz-loop.html\">&larr; measured-build loop</a> &middot; <a href=\"atlas.html\">viz atlas</a></p>" as *u8) 169 o = vsh_lit(ob, o, "</body></html>" as *u8) 170 171 let fd: i64 = sys_openat_wr(outp, 0x1a4) 172 if fd < 0 { cw(2, "nx_viz_graph: cannot open output\n" as *u8); return 4 } 173 sys_write(fd, ob, o) 174 sys_close(fd) 175 cw(1, "[nx_viz_graph] wrote " as *u8); cw(1, outp); cw(1, " (" as *u8); pn(1, nc); cw(1, " nodes, " as *u8); pn(1, m); cw(1, " edges)\n" as *u8) 176 return 0 177}