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 — 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 — 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) — 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–B means “A imports B”; <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>. <a href=\"viz-loop.html\">← measured-build loop</a> · <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}