allotaxonometer-ui 0.1.2 → 0.1.4
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/index.js +1517 -535
- package/dist/ssr/index.js +582 -282
- package/dist/style.css +35 -24
- package/package.json +18 -7
package/dist/index.js
CHANGED
|
@@ -1,82 +1,74 @@
|
|
|
1
1
|
import 'svelte/internal/disclose-version';
|
|
2
2
|
import * as $ from 'svelte/internal/client';
|
|
3
|
-
import { scaleLinear } from 'd3-scale';
|
|
4
|
-
import { range, extent } from 'd3-array';
|
|
5
3
|
import * as d3 from 'd3';
|
|
6
|
-
import {
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
// Pure D3 calculations - no DOM manipulation
|
|
26
|
-
let xScale = scaleLinear().domain(extent(testData, (d) => d.x)).range([20, 380]);
|
|
27
|
-
let yScale = scaleLinear().domain(extent(testData, (d) => d.y)).range([180, 20]);
|
|
28
|
-
|
|
29
|
-
// Calculate positions
|
|
30
|
-
let points = testData.map((d) => ({
|
|
31
|
-
cx: xScale(d.x),
|
|
32
|
-
cy: yScale(d.y),
|
|
33
|
-
r: 4 + d.value * 6,
|
|
34
|
-
fill: `hsl(${d.value * 360}, 70%, 50%)`
|
|
35
|
-
}));
|
|
36
|
-
|
|
37
|
-
var svg = root$9();
|
|
38
|
-
var text = $.sibling($.child(svg));
|
|
39
|
-
var text_1 = $.child(text, true);
|
|
40
|
-
|
|
41
|
-
$.reset(text);
|
|
42
|
-
|
|
43
|
-
var g = $.sibling(text);
|
|
44
|
-
|
|
45
|
-
$.each(g, 21, () => points, $.index, ($$anchor, point) => {
|
|
46
|
-
var circle = root_1$8();
|
|
47
|
-
|
|
48
|
-
$.template_effect(() => {
|
|
49
|
-
$.set_attribute(circle, 'cx', $.get(point).cx);
|
|
50
|
-
$.set_attribute(circle, 'cy', $.get(point).cy);
|
|
51
|
-
$.set_attribute(circle, 'r', $.get(point).r);
|
|
52
|
-
$.set_attribute(circle, 'fill', $.get(point).fill);
|
|
53
|
-
});
|
|
54
|
-
|
|
55
|
-
$.append($$anchor, circle);
|
|
56
|
-
});
|
|
57
|
-
|
|
58
|
-
$.reset(g);
|
|
59
|
-
$.next(4);
|
|
60
|
-
$.reset(svg);
|
|
61
|
-
$.template_effect(() => $.set_text(text_1, message()));
|
|
62
|
-
$.append($$anchor, svg);
|
|
63
|
-
$.pop();
|
|
4
|
+
import { map, extent, InternSet, range, rollup, scaleLinear, scaleBand, rgb, interpolateInferno, scaleOrdinal } from 'd3';
|
|
5
|
+
import { descending, sum, group, extent as extent$1 } from 'd3-array';
|
|
6
|
+
|
|
7
|
+
const colors = {
|
|
8
|
+
darkgrey: "rgb(140, 140, 140)",
|
|
9
|
+
darkergrey: "rgb(89, 89, 89)"};
|
|
10
|
+
|
|
11
|
+
const fonts = {
|
|
12
|
+
family: '"EB Garamond", "Garamond", "Century Schoolbook L", "URW Bookman L", "Bookman Old Style", "Times", serif',
|
|
13
|
+
sizes: {
|
|
14
|
+
sm: "12px",
|
|
15
|
+
lg: "16px"}
|
|
16
|
+
};
|
|
17
|
+
|
|
18
|
+
// Style builder function
|
|
19
|
+
function style(props) {
|
|
20
|
+
return Object.entries(props)
|
|
21
|
+
.map(([key, value]) => `${key.replace(/([A-Z])/g, '-$1').toLowerCase()}: ${value}`)
|
|
22
|
+
.join('; ');
|
|
64
23
|
}
|
|
65
24
|
|
|
66
|
-
|
|
67
|
-
|
|
25
|
+
// Axis styles
|
|
26
|
+
const axisStyles = {
|
|
27
|
+
label: () => style({
|
|
28
|
+
fontFamily: fonts.family,
|
|
29
|
+
fontSize: fonts.sizes.lg,
|
|
30
|
+
fill: colors.darkergrey,
|
|
31
|
+
textAnchor: "middle"
|
|
32
|
+
}),
|
|
33
|
+
|
|
34
|
+
tickLabel: () => style({
|
|
35
|
+
fontFamily: fonts.family,
|
|
36
|
+
fontSize: fonts.sizes.sm,
|
|
37
|
+
fill: colors.darkergrey,
|
|
38
|
+
}),
|
|
39
|
+
|
|
40
|
+
helperText: () => style({
|
|
41
|
+
fontFamily: fonts.family,
|
|
42
|
+
fontSize: fonts.sizes.sm,
|
|
43
|
+
fill: colors.darkgrey,
|
|
44
|
+
textAnchor: "middle",
|
|
45
|
+
opacity: "0.8"
|
|
46
|
+
}),
|
|
47
|
+
|
|
48
|
+
tickLine: () => style({
|
|
49
|
+
stroke: colors.darkgrey,
|
|
50
|
+
strokeWidth: "0.5"
|
|
51
|
+
})
|
|
52
|
+
};
|
|
53
|
+
|
|
54
|
+
var root_1$7 = $.from_svg(`<g><line x1="0" x2="0" y1="0" y2="6"></line></g><g><text dx="5" dy="13" text-anchor="start"> </text></g>`, 1);
|
|
55
|
+
var root$8 = $.from_svg(`<g class="axis x"><!><g class="xlab"><text dy="45">Rank r</text><text dy="63">for</text><text dy="80"> </text><text dy="60">more →</text><text dy="75">frequent</text><text dy="60">← less</text><text dy="75">frequent</text></g></g>`);
|
|
68
56
|
|
|
69
57
|
function AxisX($$anchor, $$props) {
|
|
70
58
|
$.push($$props, true);
|
|
71
59
|
|
|
72
|
-
let logFormat10 = $$props.scale.tickFormat();
|
|
73
|
-
let xTicks = $$props.scale.ticks();
|
|
60
|
+
let logFormat10 = $.derived(() => $$props.scale.tickFormat());
|
|
61
|
+
let xTicks = $.derived(() => $$props.scale.ticks().filter((t) => t >= 1 && Number.isInteger(Math.log10(t))));
|
|
74
62
|
var g = root$8();
|
|
75
63
|
var node = $.child(g);
|
|
76
64
|
|
|
77
|
-
$.each(node, 17, () => xTicks, $.index, ($$anchor, tick) => {
|
|
65
|
+
$.each(node, 17, () => $.get(xTicks), $.index, ($$anchor, tick) => {
|
|
78
66
|
var fragment = root_1$7();
|
|
79
67
|
var g_1 = $.first_child(fragment);
|
|
68
|
+
var line = $.child(g_1);
|
|
69
|
+
|
|
70
|
+
$.reset(g_1);
|
|
71
|
+
|
|
80
72
|
var g_2 = $.sibling(g_1);
|
|
81
73
|
var text = $.child(g_2);
|
|
82
74
|
var text_1 = $.child(text, true);
|
|
@@ -85,15 +77,19 @@ function AxisX($$anchor, $$props) {
|
|
|
85
77
|
$.reset(g_2);
|
|
86
78
|
|
|
87
79
|
$.template_effect(
|
|
88
|
-
($0, $1, $2) => {
|
|
80
|
+
($0, $1, $2, $3, $4) => {
|
|
89
81
|
$.set_attribute(g_1, 'transform', `translate(${$0 ?? ''}, 0)`);
|
|
90
|
-
$.
|
|
91
|
-
$.
|
|
82
|
+
$.set_style(line, $1);
|
|
83
|
+
$.set_attribute(g_2, 'transform', `translate(${$2 ?? ''}, 0) scale(-1,1) rotate(45)`);
|
|
84
|
+
$.set_style(text, $3);
|
|
85
|
+
$.set_text(text_1, $4);
|
|
92
86
|
},
|
|
93
87
|
[
|
|
94
88
|
() => $$props.scale($.get(tick)),
|
|
89
|
+
() => axisStyles.tickLine(),
|
|
95
90
|
() => $$props.scale($.get(tick)),
|
|
96
|
-
() =>
|
|
91
|
+
() => axisStyles.tickLabel(),
|
|
92
|
+
() => $.get(logFormat10)($.get(tick))
|
|
97
93
|
]
|
|
98
94
|
);
|
|
99
95
|
|
|
@@ -120,35 +116,63 @@ function AxisX($$anchor, $$props) {
|
|
|
120
116
|
$.reset(g_3);
|
|
121
117
|
$.reset(g);
|
|
122
118
|
|
|
123
|
-
$.template_effect(
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
119
|
+
$.template_effect(
|
|
120
|
+
($0, $1, $2, $3, $4, $5, $6) => {
|
|
121
|
+
$.set_attribute(g, 'transform', `translate(0, ${$$props.innerHeight ?? ''})`);
|
|
122
|
+
$.set_attribute(text_2, 'x', $$props.innerHeight / 2);
|
|
123
|
+
$.set_attribute(text_2, 'transform', `scale(-1,1) translate(-${$$props.innerHeight ?? ''}, 0)`);
|
|
124
|
+
$.set_style(text_2, $0);
|
|
125
|
+
$.set_attribute(text_3, 'x', $$props.innerHeight / 2);
|
|
126
|
+
$.set_attribute(text_3, 'transform', `scale(-1,1) translate(-${$$props.innerHeight ?? ''}, 0)`);
|
|
127
|
+
$.set_style(text_3, $1);
|
|
128
|
+
$.set_attribute(text_4, 'x', $$props.innerHeight / 2);
|
|
129
|
+
$.set_attribute(text_4, 'transform', `scale(-1,1) translate(-${$$props.innerHeight ?? ''}, 0)`);
|
|
130
|
+
$.set_style(text_4, $2);
|
|
131
|
+
$.set_text(text_5, $$props.title[1]);
|
|
132
|
+
$.set_attribute(text_6, 'x', $$props.innerHeight - 40);
|
|
133
|
+
$.set_attribute(text_6, 'transform', `scale(-1,1) translate(-${$$props.innerHeight ?? ''}, 0)`);
|
|
134
|
+
$.set_style(text_6, $3);
|
|
135
|
+
$.set_attribute(text_7, 'x', $$props.innerHeight - 40);
|
|
136
|
+
$.set_attribute(text_7, 'transform', `scale(-1,1) translate(-${$$props.innerHeight ?? ''}, 0)`);
|
|
137
|
+
$.set_style(text_7, $4);
|
|
138
|
+
$.set_attribute(text_8, 'transform', `scale(-1,1) translate(-${$$props.innerHeight ?? ''}, 0)`);
|
|
139
|
+
$.set_style(text_8, $5);
|
|
140
|
+
$.set_attribute(text_9, 'transform', `scale(-1,1) translate(-${$$props.innerHeight ?? ''}, 0)`);
|
|
141
|
+
$.set_style(text_9, $6);
|
|
142
|
+
},
|
|
143
|
+
[
|
|
144
|
+
() => axisStyles.label(),
|
|
145
|
+
() => axisStyles.label(),
|
|
146
|
+
() => axisStyles.label(),
|
|
147
|
+
() => axisStyles.helperText(),
|
|
148
|
+
() => axisStyles.helperText(),
|
|
149
|
+
() => axisStyles.helperText(),
|
|
150
|
+
() => axisStyles.helperText()
|
|
151
|
+
]
|
|
152
|
+
);
|
|
133
153
|
|
|
134
154
|
$.append($$anchor, g);
|
|
135
155
|
$.pop();
|
|
136
156
|
}
|
|
137
157
|
|
|
138
|
-
var root_1$6 = $.from_svg(`<g
|
|
139
|
-
var root$7 = $.from_svg(`<g class="axis y"><!><g class="ylab
|
|
158
|
+
var root_1$6 = $.from_svg(`<g><line x1="0" x2="-6" y1="0" y2="0"></line></g><g><text dx="-5" dy="13" text-anchor="end"> </text></g>`, 1);
|
|
159
|
+
var root$7 = $.from_svg(`<g class="axis y"><!><g class="ylab" transform="rotate(90)"><text dy="45">Rank r</text><text dy="63">for</text><text dy="80"> </text><text dy="60">less →</text><text dy="75">frequent</text><text dy="60">← more</text><text dy="75">frequent</text></g></g>`);
|
|
140
160
|
|
|
141
161
|
function AxisY($$anchor, $$props) {
|
|
142
162
|
$.push($$props, true);
|
|
143
163
|
|
|
144
|
-
let logFormat10 = $$props.scale.tickFormat();
|
|
145
|
-
let yTicks = $.derived(() => $$props.scale.ticks());
|
|
164
|
+
let logFormat10 = $.derived(() => $$props.scale.tickFormat());
|
|
165
|
+
let yTicks = $.derived(() => $$props.scale.ticks().filter((t) => t >= 1 && Number.isInteger(Math.log10(t))));
|
|
146
166
|
var g = root$7();
|
|
147
167
|
var node = $.child(g);
|
|
148
168
|
|
|
149
169
|
$.each(node, 17, () => $.get(yTicks), $.index, ($$anchor, tick) => {
|
|
150
170
|
var fragment = root_1$6();
|
|
151
171
|
var g_1 = $.first_child(fragment);
|
|
172
|
+
var line = $.child(g_1);
|
|
173
|
+
|
|
174
|
+
$.reset(g_1);
|
|
175
|
+
|
|
152
176
|
var g_2 = $.sibling(g_1);
|
|
153
177
|
var text = $.child(g_2);
|
|
154
178
|
var text_1 = $.child(text, true);
|
|
@@ -157,15 +181,19 @@ function AxisY($$anchor, $$props) {
|
|
|
157
181
|
$.reset(g_2);
|
|
158
182
|
|
|
159
183
|
$.template_effect(
|
|
160
|
-
($0, $1, $2) => {
|
|
184
|
+
($0, $1, $2, $3, $4) => {
|
|
161
185
|
$.set_attribute(g_1, 'transform', `translate(0, ${$0 ?? ''})`);
|
|
162
|
-
$.
|
|
163
|
-
$.
|
|
186
|
+
$.set_style(line, $1);
|
|
187
|
+
$.set_attribute(g_2, 'transform', `translate(0, ${$2 ?? ''}) rotate(45)`);
|
|
188
|
+
$.set_style(text, $3);
|
|
189
|
+
$.set_text(text_1, $4);
|
|
164
190
|
},
|
|
165
191
|
[
|
|
166
192
|
() => $$props.scale($.get(tick)),
|
|
193
|
+
() => axisStyles.tickLine(),
|
|
167
194
|
() => $$props.scale($.get(tick)),
|
|
168
|
-
() =>
|
|
195
|
+
() => axisStyles.tickLabel(),
|
|
196
|
+
() => $.get(logFormat10)($.get(tick))
|
|
169
197
|
]
|
|
170
198
|
);
|
|
171
199
|
|
|
@@ -192,15 +220,33 @@ function AxisY($$anchor, $$props) {
|
|
|
192
220
|
$.reset(g_3);
|
|
193
221
|
$.reset(g);
|
|
194
222
|
|
|
195
|
-
$.template_effect(
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
223
|
+
$.template_effect(
|
|
224
|
+
($0, $1, $2, $3, $4, $5, $6) => {
|
|
225
|
+
$.set_attribute(g, 'transform', `translate(${$$props.innerHeight ?? ''}, 0) scale(-1, 1)`);
|
|
226
|
+
$.set_attribute(text_2, 'x', $$props.innerHeight / 2);
|
|
227
|
+
$.set_style(text_2, $0);
|
|
228
|
+
$.set_attribute(text_3, 'x', $$props.innerHeight / 2);
|
|
229
|
+
$.set_style(text_3, $1);
|
|
230
|
+
$.set_attribute(text_4, 'x', $$props.innerHeight / 2);
|
|
231
|
+
$.set_style(text_4, $2);
|
|
232
|
+
$.set_text(text_5, $$props.title[0]);
|
|
233
|
+
$.set_attribute(text_6, 'x', $$props.innerHeight - 40);
|
|
234
|
+
$.set_style(text_6, $3);
|
|
235
|
+
$.set_attribute(text_7, 'x', $$props.innerHeight - 40);
|
|
236
|
+
$.set_style(text_7, $4);
|
|
237
|
+
$.set_style(text_8, $5);
|
|
238
|
+
$.set_style(text_9, $6);
|
|
239
|
+
},
|
|
240
|
+
[
|
|
241
|
+
() => axisStyles.label(),
|
|
242
|
+
() => axisStyles.label(),
|
|
243
|
+
() => axisStyles.label(),
|
|
244
|
+
() => axisStyles.helperText(),
|
|
245
|
+
() => axisStyles.helperText(),
|
|
246
|
+
() => axisStyles.helperText(),
|
|
247
|
+
() => axisStyles.helperText()
|
|
248
|
+
]
|
|
249
|
+
);
|
|
204
250
|
|
|
205
251
|
$.append($$anchor, g);
|
|
206
252
|
$.pop();
|
|
@@ -269,14 +315,14 @@ function Contours($$anchor, $$props) {
|
|
|
269
315
|
}
|
|
270
316
|
}
|
|
271
317
|
|
|
272
|
-
function make_grid(Ninset, tmpr1, tmpr2, alpha,
|
|
318
|
+
function make_grid(Ninset, tmpr1, tmpr2, alpha, divnorm) {
|
|
273
319
|
const deltamatrix = Array.from({ length: Ninset }, () => Array(Ninset).fill(0));
|
|
274
320
|
|
|
275
321
|
for (let i = 0; i < Ninset; i++) {
|
|
276
322
|
for (let j = 0; j < Ninset; j++) {
|
|
277
323
|
const divElem = alpha_norm_type2(1 / tmpr1[i], 1 / tmpr2[j], alpha);
|
|
278
324
|
|
|
279
|
-
deltamatrix[i][j] = divElem /
|
|
325
|
+
deltamatrix[i][j] = divElem / divnorm;
|
|
280
326
|
}
|
|
281
327
|
|
|
282
328
|
deltamatrix[i][i] = -1;
|
|
@@ -319,14 +365,14 @@ function Contours($$anchor, $$props) {
|
|
|
319
365
|
return out;
|
|
320
366
|
}
|
|
321
367
|
|
|
322
|
-
function get_contours(alpha, maxlog10,
|
|
368
|
+
function get_contours(alpha, maxlog10, divnorm) {
|
|
323
369
|
const Ninset = 10 ** 3;
|
|
324
370
|
const tmpr1 = d3.range(0, 1000).map((d) => Math.pow(10, d / 999 * 5));
|
|
325
371
|
const tmpr2 = d3.range(0, 1000).map((d) => Math.pow(10, d / 999 * 5));
|
|
326
372
|
const Ncontours = 10;
|
|
327
373
|
const scale = d3.scaleLinear().domain([0, Ncontours + 1]).range([1, tmpr1.length]);
|
|
328
374
|
const contour_indices = d3.range(Ncontours + 2).map((i) => Math.round(scale(i)));
|
|
329
|
-
const grid = make_grid(Ninset, tmpr1, tmpr2, alpha,
|
|
375
|
+
const grid = make_grid(Ninset, tmpr1, tmpr2, alpha, divnorm);
|
|
330
376
|
const indices = contour_indices.slice(1, -1);
|
|
331
377
|
const lastRow = grid[grid.length - 1];
|
|
332
378
|
const heights = indices.map((index) => lastRow[index]);
|
|
@@ -339,7 +385,7 @@ function Contours($$anchor, $$props) {
|
|
|
339
385
|
}
|
|
340
386
|
|
|
341
387
|
// Only calculate contours in browser
|
|
342
|
-
let mycontours = $.derived(() => get_contours($$props.alpha, $$props.maxlog10, $$props.
|
|
388
|
+
let mycontours = $.derived(() => get_contours($$props.alpha, $$props.maxlog10, $$props.divnorm));
|
|
343
389
|
const x = $.derived(() => d3.scaleLinear([0, $$props.maxlog10], [0, $$props.DiamondInnerHeight]));
|
|
344
390
|
const y = $.derived(() => d3.scaleLinear([$$props.maxlog10, 0], [$$props.DiamondInnerHeight, 0]));
|
|
345
391
|
const pathData = d3.line().x((d, i) => $.get(x)(d[0])).y((d, i) => $.get(y)(d[1]));
|
|
@@ -357,32 +403,91 @@ function Contours($$anchor, $$props) {
|
|
|
357
403
|
$.pop();
|
|
358
404
|
}
|
|
359
405
|
|
|
360
|
-
|
|
361
|
-
|
|
362
|
-
|
|
406
|
+
// Helper: convert [0–1, 0–1, 0–1] → "rgb(R, G, B)"
|
|
407
|
+
function rgbArrayToCss(rgbArray) {
|
|
408
|
+
const [r, g, b] = rgbArray.map(v => Math.round(v * 255));
|
|
409
|
+
return `rgb(${r}, ${g}, ${b})`;
|
|
410
|
+
}
|
|
411
|
+
|
|
412
|
+
// // imported from matlab version. Normalized RGB color definitions
|
|
413
|
+
const rawColors = {
|
|
414
|
+
blue: [43, 103, 198].map(v => v / 255),
|
|
415
|
+
red: [198, 43, 103].map(v => v / 255),
|
|
416
|
+
|
|
417
|
+
paleblue: [195, 230, 243].map(v => v / 255),
|
|
418
|
+
palered: [255, 204, 204].map(v => v / 255),
|
|
419
|
+
|
|
420
|
+
lightergrey: [1, 1, 1].map(v => v * 0.96),
|
|
421
|
+
lightishgrey: [1, 1, 1].map(v => v * 0.93),
|
|
422
|
+
lightgrey: [1, 1, 1].map(v => v * 0.90),
|
|
423
|
+
|
|
424
|
+
lightgreyer: [1, 1, 1].map(v => v * 0.85),
|
|
425
|
+
lightgreyish: [1, 1, 1].map(v => v * 0.80),
|
|
426
|
+
|
|
427
|
+
grey: [1, 1, 1].map(v => v * 0.75),
|
|
428
|
+
darkgrey: [1, 1, 1].map(v => v * 0.55),
|
|
429
|
+
darkergrey: [1, 1, 1].map(v => v * 0.35),
|
|
430
|
+
verydarkgrey: [1, 1, 1].map(v => v * 0.15),
|
|
431
|
+
superdarkgrey: [1, 1, 1].map(v => v * 0.10),
|
|
432
|
+
reallyverdarkgrey: [1, 1, 1].map(v => v * 0.05),
|
|
433
|
+
|
|
434
|
+
orange: [255, 116, 0].map(v => v / 255)
|
|
435
|
+
};
|
|
436
|
+
|
|
437
|
+
// Create CSS strings for each
|
|
438
|
+
const cssColors = {};
|
|
439
|
+
for (const [key, rgb] of Object.entries(rawColors)) {
|
|
440
|
+
cssColors[key] = rgbArrayToCss(rgb);
|
|
441
|
+
}
|
|
442
|
+
|
|
443
|
+
// Export both raw RGB arrays and CSS strings
|
|
444
|
+
const alloColors = {
|
|
445
|
+
css: cssColors // e.g., colors.css.blue → "rgb(43, 103, 198)"
|
|
446
|
+
};
|
|
447
|
+
|
|
448
|
+
// System font stack in order of preference
|
|
449
|
+
const alloFonts = `"EB Garamond", "Garamond", "Century Schoolbook L", "URW Bookman L", "Bookman Old Style", "Times", serif`;
|
|
450
|
+
|
|
451
|
+
function updateTooltipPosition(event, tooltipVisible, tooltipX, tooltipY) {
|
|
452
|
+
if ($.get(tooltipVisible)) {
|
|
453
|
+
$.set(tooltipX, event.clientX + 15);
|
|
454
|
+
$.set(tooltipY, event.clientY - 10);
|
|
455
|
+
}
|
|
456
|
+
}
|
|
457
|
+
|
|
458
|
+
var root_1$3 = $.from_svg(`<rect class="diamond-cell"></rect>`);
|
|
459
|
+
var root_2$3 = $.from_svg(`<rect></rect>`);
|
|
460
|
+
var root_3$1 = $.from_svg(`<text dy="5"> </text>`);
|
|
461
|
+
var root_4$1 = $.from_html(`<div><!></div>`);
|
|
462
|
+
var root$4 = $.from_html(`<div style="position: relative;"><svg xmlns="http://www.w3.org/2000/svg" style="overflow: visible; display: block;"><polygon class="diamond-background grey-triangle" fill-opacity="0.8" stroke="black" stroke-width="0.5"></polygon><polygon class="diamond-background blue-triangle" fill-opacity="0.8" stroke="black" stroke-width="0.5"></polygon><!><!><!><!><!><!><line x1="0" y1="0"></line><!></svg> <!></div>`);
|
|
363
463
|
|
|
364
464
|
function Diamond($$anchor, $$props) {
|
|
365
465
|
$.push($$props, true);
|
|
366
466
|
|
|
467
|
+
let DiamondHeight = $.prop($$props, 'DiamondHeight', 3, 600),
|
|
468
|
+
marginInner = $.prop($$props, 'marginInner', 3, 160),
|
|
469
|
+
marginDiamond = $.prop($$props, 'marginDiamond', 3, 40);
|
|
470
|
+
|
|
471
|
+
// Extract data from dat object
|
|
472
|
+
let diamond_dat = $.derived(() => $$props.dat.counts);
|
|
473
|
+
$.derived(() => $$props.dat.deltas);
|
|
474
|
+
// Calculate derived dimensions (matching D3 version exactly)
|
|
475
|
+
let innerHeight = $.derived(() => DiamondHeight() - marginInner());
|
|
476
|
+
let diamondHeight = $.derived(() => $.get(innerHeight) - marginDiamond());
|
|
477
|
+
|
|
367
478
|
function get_relevant_types(diamond_dat) {
|
|
368
|
-
const ncells =
|
|
369
|
-
const
|
|
370
|
-
const cummulative_bin = d3.range(0, ncells, bin_size);
|
|
479
|
+
const ncells = d3.max(diamond_dat, (d) => d.x1);
|
|
480
|
+
const cumbin = d3.range(0, ncells, 1.5);
|
|
371
481
|
const relevant_types = [];
|
|
372
482
|
|
|
373
483
|
for (let sys of ["right", "left"]) {
|
|
374
|
-
for (let i = 1; i <
|
|
375
|
-
const filtered_dat = diamond_dat.filter((d) => d.value > 0 && d.which_sys == sys).filter((d) => d.coord_on_diag >=
|
|
484
|
+
for (let i = 1; i < cumbin.length; i++) {
|
|
485
|
+
const filtered_dat = diamond_dat.filter((d) => d.value > 0 && d.which_sys == sys).filter((d) => d.coord_on_diag >= cumbin[i - 1] && d.coord_on_diag < cumbin[i]);
|
|
376
486
|
|
|
377
487
|
if (filtered_dat.length > 0) {
|
|
378
488
|
const cos_dists = filtered_dat.map((d) => d.cos_dist);
|
|
379
|
-
|
|
380
|
-
const max_dist = cos_dists.reduce((a, b) => {
|
|
381
|
-
return Math.max(a, b);
|
|
382
|
-
});
|
|
383
|
-
|
|
489
|
+
const max_dist = cos_dists.reduce((a, b) => Math.max(a, b));
|
|
384
490
|
const max_dist_idx = cos_dists.indexOf(max_dist);
|
|
385
|
-
// Use a simple random selection instead of d3.shuffle during SSR
|
|
386
491
|
const types = filtered_dat[max_dist_idx]['types'].split(",");
|
|
387
492
|
const name = types[Math.floor(Math.random() * types.length)];
|
|
388
493
|
|
|
@@ -395,57 +500,79 @@ function Diamond($$anchor, $$props) {
|
|
|
395
500
|
}
|
|
396
501
|
|
|
397
502
|
function rin(arr1, arr2) {
|
|
398
|
-
return Array.from(arr1, (x) =>
|
|
399
|
-
return arr2.indexOf(x) == -1 ? false : true;
|
|
400
|
-
});
|
|
503
|
+
return Array.from(arr1, (x) => arr2.indexOf(x) !== -1);
|
|
401
504
|
}
|
|
402
505
|
|
|
403
506
|
// Wrangling data
|
|
404
|
-
let relevant_types = $.derived(() => get_relevant_types(
|
|
405
|
-
|
|
406
|
-
let
|
|
407
|
-
let
|
|
408
|
-
let rounded_max_rank = $.derived(() => 10 ** Math.ceil(Math.max(Math.log10($.get(max_rank)))));
|
|
409
|
-
let ncells = $.derived(() => d3.max($.get(max_rank_raw)));
|
|
507
|
+
let relevant_types = $.derived(() => get_relevant_types($.get(diamond_dat)));
|
|
508
|
+
let ncells = $.derived(() => d3.max($.get(diamond_dat), (d) => d.x1));
|
|
509
|
+
let max_rank = $.derived(() => d3.max($.get(diamond_dat), (d) => d.rank_L[1]));
|
|
510
|
+
let rounded_max_rank = $.derived(() => 10 ** Math.ceil(Math.log10($.get(max_rank))));
|
|
410
511
|
let xyDomain = $.derived(() => [1, $.get(rounded_max_rank)]);
|
|
411
|
-
//
|
|
412
|
-
let
|
|
413
|
-
let
|
|
414
|
-
let
|
|
415
|
-
let
|
|
512
|
+
// Scales (matching D3 version dimensions)
|
|
513
|
+
let xy = $.derived(() => d3.scaleBand().domain($.get(diamond_dat).map((d) => d.y1)).range([0, $.get(diamondHeight)]));
|
|
514
|
+
let logScale = $.derived(() => d3.scaleLog().domain($.get(xyDomain)).range([0, $.get(innerHeight)]).nice());
|
|
515
|
+
let linScale = $.derived(() => d3.scaleLinear().domain([0, $.get(ncells) - 1]).range([0, $.get(innerHeight)]));
|
|
516
|
+
let wxy = $.derived(() => d3.scaleBand().domain(d3.range($.get(ncells))).range([0, $.get(innerHeight)]));
|
|
416
517
|
let color_scale = d3.scaleSequentialLog().domain([$.get(rounded_max_rank), 1]).interpolator(d3.interpolateInferno);
|
|
417
518
|
|
|
418
|
-
// Background
|
|
419
|
-
let blue_triangle = [
|
|
519
|
+
// Background triangles
|
|
520
|
+
let blue_triangle = $.derived(() => [
|
|
420
521
|
[
|
|
421
|
-
|
|
422
|
-
|
|
522
|
+
$.get(innerHeight),
|
|
523
|
+
$.get(innerHeight)
|
|
423
524
|
],
|
|
424
525
|
[0, 0],
|
|
425
|
-
[0,
|
|
426
|
-
].join(" ");
|
|
526
|
+
[0, $.get(innerHeight)]
|
|
527
|
+
].join(" "));
|
|
427
528
|
|
|
428
|
-
let grey_triangle = [
|
|
529
|
+
let grey_triangle = $.derived(() => [
|
|
429
530
|
[
|
|
430
|
-
|
|
431
|
-
|
|
531
|
+
$.get(innerHeight),
|
|
532
|
+
$.get(innerHeight)
|
|
432
533
|
],
|
|
433
534
|
[0, 0],
|
|
434
|
-
[
|
|
435
|
-
].join(" ");
|
|
535
|
+
[$.get(innerHeight), 0]
|
|
536
|
+
].join(" "));
|
|
436
537
|
|
|
437
538
|
function filter_labs(d, relevant_types) {
|
|
438
539
|
return rin(relevant_types, d.types.split(",")).some((x) => x === true);
|
|
439
540
|
}
|
|
440
541
|
|
|
441
|
-
|
|
442
|
-
|
|
542
|
+
// TOOLTIP
|
|
543
|
+
let tooltipVisible = $.state(false);
|
|
544
|
+
let tooltipContent = $.state('');
|
|
545
|
+
let tooltipX = $.state(0);
|
|
546
|
+
let tooltipY = $.state(0);
|
|
547
|
+
|
|
548
|
+
function showTooltip(event, d) {
|
|
549
|
+
if (d.value === 0) return;
|
|
550
|
+
|
|
551
|
+
const tokens = d.types.split(",");
|
|
552
|
+
const displayTokens = tokens.length < 50 ? tokens.slice(0, 8).join(", ") : tokens.slice(0, 8).join(", ") + " ...";
|
|
553
|
+
|
|
554
|
+
$.set(tooltipContent, `
|
|
555
|
+
<div style="color: rgb(89, 89, 89); font-size: 11px;">Types: ${displayTokens}</div>
|
|
556
|
+
`);
|
|
557
|
+
|
|
558
|
+
$.set(tooltipX, event.clientX + 15);
|
|
559
|
+
$.set(tooltipY, event.clientY - 10);
|
|
560
|
+
$.set(tooltipVisible, true);
|
|
561
|
+
}
|
|
562
|
+
|
|
563
|
+
function hideTooltip() {
|
|
564
|
+
$.set(tooltipVisible, false);
|
|
565
|
+
}
|
|
566
|
+
|
|
567
|
+
var div = root$4();
|
|
568
|
+
var svg = $.child(div);
|
|
569
|
+
var polygon = $.child(svg);
|
|
443
570
|
var polygon_1 = $.sibling(polygon);
|
|
444
571
|
var node = $.sibling(polygon_1);
|
|
445
572
|
|
|
446
573
|
AxisX(node, {
|
|
447
|
-
get
|
|
448
|
-
return
|
|
574
|
+
get innerHeight() {
|
|
575
|
+
return $.get(innerHeight);
|
|
449
576
|
},
|
|
450
577
|
get scale() {
|
|
451
578
|
return $.get(logScale);
|
|
@@ -458,8 +585,8 @@ function Diamond($$anchor, $$props) {
|
|
|
458
585
|
var node_1 = $.sibling(node);
|
|
459
586
|
|
|
460
587
|
AxisY(node_1, {
|
|
461
|
-
get
|
|
462
|
-
return
|
|
588
|
+
get innerHeight() {
|
|
589
|
+
return $.get(innerHeight);
|
|
463
590
|
},
|
|
464
591
|
get scale() {
|
|
465
592
|
return $.get(logScale);
|
|
@@ -473,7 +600,7 @@ function Diamond($$anchor, $$props) {
|
|
|
473
600
|
|
|
474
601
|
Grid(node_2, {
|
|
475
602
|
get height() {
|
|
476
|
-
return
|
|
603
|
+
return $.get(innerHeight);
|
|
477
604
|
},
|
|
478
605
|
get wxy() {
|
|
479
606
|
return $.get(wxy);
|
|
@@ -488,7 +615,7 @@ function Diamond($$anchor, $$props) {
|
|
|
488
615
|
|
|
489
616
|
var node_3 = $.sibling(node_2);
|
|
490
617
|
|
|
491
|
-
$.each(node_3, 17, () =>
|
|
618
|
+
$.each(node_3, 17, () => $.get(diamond_dat), $.index, ($$anchor, d) => {
|
|
492
619
|
var rect = root_1$3();
|
|
493
620
|
|
|
494
621
|
$.template_effect(
|
|
@@ -498,14 +625,13 @@ function Diamond($$anchor, $$props) {
|
|
|
498
625
|
$.set_attribute(rect, 'width', $2);
|
|
499
626
|
$.set_attribute(rect, 'height', $3);
|
|
500
627
|
$.set_attribute(rect, 'fill', $4);
|
|
501
|
-
$.set_attribute(rect, 'opacity', $.get(d).value === null ? 0 : 1.);
|
|
502
628
|
},
|
|
503
629
|
[
|
|
504
630
|
() => $.get(xy)($.get(d).x1),
|
|
505
631
|
() => $.get(xy)($.get(d).y1),
|
|
506
632
|
() => $.get(xy).bandwidth(),
|
|
507
633
|
() => $.get(xy).bandwidth(),
|
|
508
|
-
() => color_scale($.get(d).value)
|
|
634
|
+
() => $.get(d).value === 0 ? "none" : color_scale($.get(d).value)
|
|
509
635
|
]
|
|
510
636
|
);
|
|
511
637
|
|
|
@@ -514,353 +640,543 @@ function Diamond($$anchor, $$props) {
|
|
|
514
640
|
|
|
515
641
|
var node_4 = $.sibling(node_3);
|
|
516
642
|
|
|
517
|
-
$.each(node_4, 17, () =>
|
|
518
|
-
var
|
|
519
|
-
|
|
643
|
+
$.each(node_4, 17, () => $.get(diamond_dat), $.index, ($$anchor, d) => {
|
|
644
|
+
var rect_1 = root_2$3();
|
|
645
|
+
|
|
646
|
+
rect_1.__mousemove = [
|
|
647
|
+
updateTooltipPosition,
|
|
648
|
+
tooltipVisible,
|
|
649
|
+
tooltipX,
|
|
650
|
+
tooltipY
|
|
651
|
+
];
|
|
652
|
+
|
|
653
|
+
$.template_effect(
|
|
654
|
+
($0, $1, $2, $3) => {
|
|
655
|
+
$.set_attribute(rect_1, 'x', $0);
|
|
656
|
+
$.set_attribute(rect_1, 'y', $1);
|
|
657
|
+
$.set_attribute(rect_1, 'width', $2);
|
|
658
|
+
$.set_attribute(rect_1, 'height', $3);
|
|
659
|
+
$.set_attribute(rect_1, 'fill', $.get(d).value > 0 ? 'rgba(255,255,255,0.001)' : 'none');
|
|
660
|
+
$.set_attribute(rect_1, 'stroke', $.get(d).value > 0 ? alloColors.css.darkergrey : 'none');
|
|
661
|
+
$.set_attribute(rect_1, 'stroke-width', $.get(d).value > 0 ? '1.18' : '0');
|
|
662
|
+
$.set_attribute(rect_1, 'stroke-opacity', $.get(d).value > 0 ? '0.4' : '0');
|
|
663
|
+
$.set_style(rect_1, `cursor: ${$.get(d).value > 0 ? 'pointer' : 'default'};`);
|
|
664
|
+
},
|
|
665
|
+
[
|
|
666
|
+
() => $.get(xy)($.get(d).x1),
|
|
667
|
+
() => $.get(xy)($.get(d).y1),
|
|
668
|
+
() => $.get(xy).bandwidth(),
|
|
669
|
+
() => $.get(xy).bandwidth()
|
|
670
|
+
]
|
|
671
|
+
);
|
|
672
|
+
|
|
673
|
+
$.event('mouseenter', rect_1, (e) => showTooltip(e, $.get(d)));
|
|
674
|
+
$.event('mouseleave', rect_1, hideTooltip);
|
|
675
|
+
$.append($$anchor, rect_1);
|
|
676
|
+
});
|
|
677
|
+
|
|
678
|
+
var node_5 = $.sibling(node_4);
|
|
679
|
+
|
|
680
|
+
$.each(node_5, 17, () => $.get(diamond_dat).filter((d) => filter_labs(d, $.get(relevant_types))), $.index, ($$anchor, d) => {
|
|
681
|
+
var text = root_3$1();
|
|
520
682
|
var text_1 = $.child(text, true);
|
|
521
683
|
|
|
522
684
|
$.reset(text);
|
|
523
|
-
$.reset(g_1);
|
|
524
685
|
|
|
525
686
|
$.template_effect(
|
|
526
687
|
($0, $1, $2, $3, $4, $5) => {
|
|
527
|
-
$.set_attribute(
|
|
528
|
-
|
|
529
|
-
|
|
530
|
-
rotate(-45, ${$0 ?? ''}, ${$1 ?? ''})
|
|
531
|
-
translate(${$2 ?? ''}, 0)
|
|
532
|
-
`);
|
|
533
|
-
|
|
534
|
-
$.set_attribute(text, 'x', $3);
|
|
535
|
-
$.set_attribute(text, 'y', $4);
|
|
688
|
+
$.set_attribute(text, 'x', $0);
|
|
689
|
+
$.set_attribute(text, 'y', $1);
|
|
690
|
+
$.set_attribute(text, 'dx', $.get(d).x1 - $.get(d).y1 <= 0 ? 5 : -5);
|
|
536
691
|
$.set_attribute(text, 'text-anchor', $.get(d).x1 - $.get(d).y1 <= 0 ? "start" : "end");
|
|
692
|
+
$.set_attribute(text, 'transform', `scale(1,-1) rotate(-90) rotate(-45, ${$2 ?? ''}, ${$3 ?? ''}) translate(${$4 ?? ''}, 0)`);
|
|
693
|
+
$.set_style(text, `font-family: ${alloFonts}; font-size: 12px; fill: ${alloColors.css.darkergrey ?? ''};`);
|
|
537
694
|
$.set_text(text_1, $5);
|
|
538
695
|
},
|
|
539
696
|
[
|
|
697
|
+
() => $.get(xy)($.get(d).x1),
|
|
698
|
+
() => Number.isInteger($.get(d).coord_on_diag) ? $.get(xy)($.get(d).y1) : $.get(xy)($.get(d).y1) - 1,
|
|
540
699
|
() => $.get(xy)($.get(d).x1),
|
|
541
700
|
() => $.get(xy)($.get(d).y1),
|
|
542
701
|
() => $.get(d).which_sys === "right" ? $.get(xy)(Math.sqrt($.get(d).cos_dist)) * 1.5 : -$.get(xy)(Math.sqrt($.get(d).cos_dist)) * 1.5,
|
|
543
|
-
() => $.get(xy)($.get(d).x1),
|
|
544
|
-
() => Number.isInteger($.get(d).coord_on_diag) ? $.get(xy)($.get(d).y1) : $.get(xy)($.get(d).y1) - 1,
|
|
545
702
|
() => $.get(d).types.split(",")[0]
|
|
546
703
|
]
|
|
547
704
|
);
|
|
548
705
|
|
|
549
|
-
$.append($$anchor,
|
|
706
|
+
$.append($$anchor, text);
|
|
550
707
|
});
|
|
551
708
|
|
|
552
|
-
var
|
|
709
|
+
var line = $.sibling(node_5);
|
|
710
|
+
var node_6 = $.sibling(line);
|
|
553
711
|
|
|
554
|
-
Contours(
|
|
712
|
+
Contours(node_6, {
|
|
555
713
|
get alpha() {
|
|
556
714
|
return $$props.alpha;
|
|
557
715
|
},
|
|
558
716
|
get maxlog10() {
|
|
559
717
|
return $$props.maxlog10;
|
|
560
718
|
},
|
|
561
|
-
get
|
|
562
|
-
return $$props.
|
|
719
|
+
get divnorm() {
|
|
720
|
+
return $$props.divnorm;
|
|
563
721
|
},
|
|
564
722
|
get DiamondInnerHeight() {
|
|
565
|
-
return
|
|
723
|
+
return $.get(innerHeight);
|
|
566
724
|
}
|
|
567
725
|
});
|
|
568
726
|
|
|
569
|
-
$.reset(
|
|
727
|
+
$.reset(svg);
|
|
728
|
+
|
|
729
|
+
var node_7 = $.sibling(svg, 2);
|
|
730
|
+
|
|
731
|
+
{
|
|
732
|
+
var consequent = ($$anchor) => {
|
|
733
|
+
var div_1 = root_4$1();
|
|
734
|
+
var node_8 = $.child(div_1);
|
|
735
|
+
|
|
736
|
+
$.html(node_8, () => $.get(tooltipContent));
|
|
737
|
+
$.reset(div_1);
|
|
738
|
+
|
|
739
|
+
$.template_effect(() => $.set_style(div_1, `
|
|
740
|
+
position: fixed;
|
|
741
|
+
left: ${$.get(tooltipX) ?? ''}px;
|
|
742
|
+
top: ${$.get(tooltipY) ?? ''}px;
|
|
743
|
+
background: white;
|
|
744
|
+
border: 1px solid rgb(200, 200, 200);
|
|
745
|
+
border-radius: 6px;
|
|
746
|
+
padding: 10px 12px;
|
|
747
|
+
font-family: 'EB Garamond', serif;
|
|
748
|
+
font-size: 12px;
|
|
749
|
+
line-height: 1.5;
|
|
750
|
+
box-shadow: 0 4px 12px rgba(0, 0, 0, 0.15);
|
|
751
|
+
pointer-events: none;
|
|
752
|
+
z-index: 1000;
|
|
753
|
+
max-width: 280px;
|
|
754
|
+
`));
|
|
755
|
+
|
|
756
|
+
$.append($$anchor, div_1);
|
|
757
|
+
};
|
|
758
|
+
|
|
759
|
+
$.if(node_7, ($$render) => {
|
|
760
|
+
if ($.get(tooltipVisible)) $$render(consequent);
|
|
761
|
+
});
|
|
762
|
+
}
|
|
763
|
+
|
|
764
|
+
$.reset(div);
|
|
570
765
|
|
|
571
766
|
$.template_effect(() => {
|
|
572
|
-
$.set_attribute(
|
|
573
|
-
$.set_attribute(
|
|
574
|
-
$.set_attribute(
|
|
767
|
+
$.set_attribute(svg, 'width', DiamondHeight());
|
|
768
|
+
$.set_attribute(svg, 'height', DiamondHeight());
|
|
769
|
+
$.set_attribute(svg, 'viewBox', `0 0 ${DiamondHeight() ?? ''} ${DiamondHeight() ?? ''}`);
|
|
770
|
+
$.set_attribute(svg, 'transform', `scale(-1,1) rotate(45) translate(${$.get(innerHeight) / 4}, ${$.get(innerHeight) / 4})`);
|
|
771
|
+
$.set_attribute(polygon, 'points', $.get(grey_triangle));
|
|
772
|
+
$.set_attribute(polygon, 'fill', alloColors.css.lightgrey);
|
|
773
|
+
$.set_attribute(polygon_1, 'points', $.get(blue_triangle));
|
|
774
|
+
$.set_attribute(polygon_1, 'fill', alloColors.css.paleblue);
|
|
775
|
+
$.set_attribute(line, 'x2', $.get(innerHeight) - 7);
|
|
776
|
+
$.set_attribute(line, 'y2', $.get(innerHeight) - 7);
|
|
777
|
+
$.set_style(line, `stroke: ${alloColors.css.verydarkgrey ?? ''}; stroke-width: 0.5;`);
|
|
575
778
|
});
|
|
576
779
|
|
|
577
|
-
$.append($$anchor,
|
|
780
|
+
$.append($$anchor, div);
|
|
578
781
|
$.pop();
|
|
579
782
|
}
|
|
580
783
|
|
|
581
|
-
|
|
582
|
-
|
|
583
|
-
var
|
|
784
|
+
$.delegate(['mousemove']);
|
|
785
|
+
|
|
786
|
+
var root_1$2 = $.from_svg(`<line y1="0" y2="6" style="stroke: currentColor; stroke-width: 1;"></line><line class="wordshift-grid-line" y1="0"></line><text y="-12" text-anchor="middle"> </text>`, 1);
|
|
787
|
+
var root_2$2 = $.from_svg(`<rect class="wordshift-bar" style="mix-blend-mode: multiply;"></rect>`);
|
|
788
|
+
var root_4 = $.from_svg(`<text dy="0.32em"> </text>`);
|
|
789
|
+
var root_3 = $.from_svg(`<g class="wordshift-label-group"><text dy="0.32em"> </text><!></g>`);
|
|
790
|
+
var root$3 = $.from_svg(`<svg style="overflow: visible; display: block;"><g class="wordshift-container"><g class="wordshift-axis x"><!><text y="-35" text-anchor="middle"> </text></g><!><g class="wordshift-y-axis"></g></g></svg>`);
|
|
584
791
|
|
|
585
792
|
function Wordshift($$anchor, $$props) {
|
|
586
793
|
$.push($$props, true);
|
|
587
794
|
|
|
588
|
-
let
|
|
589
|
-
|
|
590
|
-
|
|
591
|
-
|
|
592
|
-
|
|
593
|
-
|
|
795
|
+
let x = $.prop($$props, 'x', 3, (d) => d.metric),
|
|
796
|
+
y = $.prop($$props, 'y', 3, (d) => d.type),
|
|
797
|
+
marginTop = $.prop($$props, 'marginTop', 3, 50),
|
|
798
|
+
marginRight = $.prop($$props, 'marginRight', 3, 60),
|
|
799
|
+
marginBottom = $.prop($$props, 'marginBottom', 3, 40),
|
|
800
|
+
marginLeft = $.prop($$props, 'marginLeft', 3, 70),
|
|
801
|
+
width = $.prop($$props, 'width', 3, 360),
|
|
802
|
+
xFormat = $.prop($$props, 'xFormat', 3, '%'),
|
|
803
|
+
xLabel = $.prop($$props, 'xLabel', 3, '← System 1 · Divergence contribution · System 2 →'),
|
|
804
|
+
yPadding = $.prop($$props, 'yPadding', 3, 0),
|
|
805
|
+
colors = $.prop($$props, 'colors', 19, () => [
|
|
806
|
+
alloColors.css.lightgrey,
|
|
807
|
+
alloColors.css.paleblue
|
|
808
|
+
]),
|
|
809
|
+
barHeightFactor = $.prop($$props, 'barHeightFactor', 3, 0.7);
|
|
810
|
+
|
|
811
|
+
// Compute values (matching D3 version exactly)
|
|
812
|
+
let X = $.derived(() => d3.map($$props.barData, x()));
|
|
813
|
+
let Y = $.derived(() => d3.map($$props.barData, y()));
|
|
814
|
+
// Compute domains
|
|
815
|
+
let computedXDomain = $.derived(() => $$props.xDomain || d3.extent($.get(X)));
|
|
594
816
|
let yDomain = $.derived(() => new d3.InternSet($.get(Y)));
|
|
595
|
-
|
|
596
|
-
|
|
597
|
-
|
|
598
|
-
|
|
599
|
-
|
|
817
|
+
// Match D3 dimensions exactly
|
|
818
|
+
const xAxisYOffset = 10; // Space below x-axis (from original)
|
|
819
|
+
const bandHeight = 18; // Fixed band height (from original)
|
|
820
|
+
const shiftSvgBy = 12; // shift svg up to align with system titles
|
|
821
|
+
const barYOffset = 10; // Additional offset just for bars
|
|
822
|
+
let compactHeight = $.derived(() => $.get(yDomain).size * bandHeight);
|
|
823
|
+
let innerWidth = $.derived(() => width() - marginLeft() - marginRight());
|
|
824
|
+
let innerHeight = $.derived(() => $.get(compactHeight) + xAxisYOffset);
|
|
825
|
+
let computedHeight = $.derived(() => $.get(innerHeight) + marginTop() + marginBottom());
|
|
826
|
+
// Compute ranges exactly like D3
|
|
827
|
+
let xRange = $.derived(() => [0, $.get(innerWidth)]);
|
|
600
828
|
|
|
601
829
|
let yRange = $.derived(() => [
|
|
602
|
-
|
|
603
|
-
|
|
830
|
+
xAxisYOffset + barYOffset,
|
|
831
|
+
xAxisYOffset + barYOffset + $.get(compactHeight)
|
|
604
832
|
]);
|
|
605
833
|
|
|
606
|
-
|
|
607
|
-
let
|
|
608
|
-
let
|
|
609
|
-
|
|
610
|
-
|
|
834
|
+
// Filter indices and create lookup
|
|
835
|
+
let I = $.derived(() => d3.range($.get(X).length).filter((i) => $.get(yDomain).has($.get(Y)[i])));
|
|
836
|
+
let YX = $.derived(() => d3.rollup($.get(I), ([i]) => $.get(X)[i], (i) => $.get(Y)[i]));
|
|
837
|
+
// Scales
|
|
838
|
+
let xScale = $.derived(() => d3.scaleLinear($.get(computedXDomain), $.get(xRange)));
|
|
839
|
+
let yScale = $.derived(() => d3.scaleBand().domain($.get(yDomain)).range($.get(yRange)).padding(yPadding()));
|
|
840
|
+
let format = $.derived(() => $.get(xScale).tickFormat(100, xFormat()));
|
|
841
|
+
let xTicks = $.derived(() => $.get(xScale).ticks(width() / 80));
|
|
842
|
+
|
|
843
|
+
// Helper function matching D3 logic exactly
|
|
844
|
+
function parseLabelData(label) {
|
|
845
|
+
const splitIndex = label.indexOf(' ');
|
|
846
|
+
let name_y, numbers_y;
|
|
847
|
+
|
|
848
|
+
if (splitIndex === -1) {
|
|
849
|
+
name_y = label;
|
|
850
|
+
numbers_y = "";
|
|
851
|
+
} else {
|
|
852
|
+
name_y = label.slice(0, splitIndex);
|
|
853
|
+
numbers_y = label.slice(splitIndex + 1).trim();
|
|
854
|
+
|
|
855
|
+
// Strip first and last characters from numbers_y if possible
|
|
856
|
+
if (numbers_y.length > 2) {
|
|
857
|
+
numbers_y = numbers_y.slice(1, numbers_y.length - 1);
|
|
858
|
+
}
|
|
859
|
+
}
|
|
860
|
+
|
|
861
|
+
return { name_y, numbers_y };
|
|
862
|
+
}
|
|
863
|
+
|
|
864
|
+
let finalHeight = $.derived(() => $$props.height || $.get(computedHeight));
|
|
865
|
+
var svg = root$3();
|
|
866
|
+
var g = $.child(svg);
|
|
611
867
|
var g_1 = $.child(g);
|
|
612
868
|
|
|
613
|
-
$.
|
|
614
|
-
var g_2 = root_1$2();
|
|
615
|
-
var line = $.child(g_2);
|
|
616
|
-
var text = $.child(line, true);
|
|
869
|
+
$.set_attribute(g_1, 'transform', 'translate(0, 10)');
|
|
617
870
|
|
|
618
|
-
|
|
871
|
+
var node = $.child(g_1);
|
|
619
872
|
|
|
620
|
-
|
|
621
|
-
var
|
|
873
|
+
$.each(node, 17, () => $.get(xTicks), $.index, ($$anchor, tick) => {
|
|
874
|
+
var fragment = root_1$2();
|
|
875
|
+
var line = $.first_child(fragment);
|
|
876
|
+
var line_1 = $.sibling(line);
|
|
877
|
+
var text = $.sibling(line_1);
|
|
878
|
+
var text_1 = $.child(text, true);
|
|
622
879
|
|
|
623
|
-
$.reset(
|
|
624
|
-
$.reset(g_2);
|
|
880
|
+
$.reset(text);
|
|
625
881
|
|
|
626
882
|
$.template_effect(
|
|
627
|
-
($0, $1, $2) => {
|
|
883
|
+
($0, $1, $2, $3, $4, $5) => {
|
|
628
884
|
$.set_attribute(line, 'x1', $0);
|
|
629
885
|
$.set_attribute(line, 'x2', $1);
|
|
630
|
-
$.set_attribute(
|
|
631
|
-
$.
|
|
632
|
-
$.set_attribute(
|
|
633
|
-
$.
|
|
886
|
+
$.set_attribute(line_1, 'x1', $2);
|
|
887
|
+
$.set_attribute(line_1, 'x2', $3);
|
|
888
|
+
$.set_attribute(line_1, 'y2', $.get(innerHeight) - xAxisYOffset + barYOffset);
|
|
889
|
+
$.set_style(line_1, $.get(tick) === 0 ? `stroke: ${alloColors.css.verydarkgrey}; stroke-width: 1; stroke-opacity: 0.8;` : `stroke: currentColor; stroke-opacity: 0.1;`);
|
|
890
|
+
$.set_attribute(text, 'x', $4);
|
|
891
|
+
$.set_style(text, `font-family: ${alloFonts}; font-size: 14px; fill: ${alloColors.css.verydarkgrey ?? ''};`);
|
|
892
|
+
$.set_text(text_1, $5);
|
|
634
893
|
},
|
|
635
894
|
[
|
|
636
895
|
() => $.get(xScale)($.get(tick)),
|
|
637
896
|
() => $.get(xScale)($.get(tick)),
|
|
638
|
-
() => $.get(xScale)($.get(tick))
|
|
897
|
+
() => $.get(xScale)($.get(tick)),
|
|
898
|
+
() => $.get(xScale)($.get(tick)),
|
|
899
|
+
() => $.get(xScale)($.get(tick)),
|
|
900
|
+
() => $.get(format)($.get(tick))
|
|
639
901
|
]
|
|
640
902
|
);
|
|
641
903
|
|
|
642
|
-
$.append($$anchor,
|
|
904
|
+
$.append($$anchor, fragment);
|
|
643
905
|
});
|
|
644
906
|
|
|
645
|
-
$.
|
|
907
|
+
var text_2 = $.sibling(node);
|
|
908
|
+
var text_3 = $.child(text_2, true);
|
|
646
909
|
|
|
647
|
-
|
|
910
|
+
$.reset(text_2);
|
|
911
|
+
$.reset(g_1);
|
|
648
912
|
|
|
649
|
-
|
|
650
|
-
var fragment = root_2$2();
|
|
651
|
-
var rect = $.first_child(fragment);
|
|
652
|
-
var text_3 = $.sibling(rect);
|
|
653
|
-
var text_4 = $.child(text_3, true);
|
|
913
|
+
var node_1 = $.sibling(g_1);
|
|
654
914
|
|
|
655
|
-
|
|
915
|
+
$.each(node_1, 17, () => $.get(I), $.index, ($$anchor, i) => {
|
|
916
|
+
var rect = root_2$2();
|
|
656
917
|
|
|
657
918
|
$.template_effect(
|
|
658
|
-
($0, $1, $2, $3
|
|
919
|
+
($0, $1, $2, $3) => {
|
|
659
920
|
$.set_attribute(rect, 'x', $0);
|
|
660
921
|
$.set_attribute(rect, 'y', $1);
|
|
661
|
-
$.set_attribute(rect, 'fill', colors[$.get(
|
|
922
|
+
$.set_attribute(rect, 'fill', colors()[$.get(X)[$.get(i)] > 0 ? colors().length - 1 : 0]);
|
|
662
923
|
$.set_attribute(rect, 'width', $2);
|
|
663
924
|
$.set_attribute(rect, 'height', $3);
|
|
664
|
-
$.set_attribute(text_3, 'x', $4);
|
|
665
|
-
$.set_attribute(text_3, 'y', $5);
|
|
666
|
-
$.set_text(text_4, $.get(d).type);
|
|
667
925
|
},
|
|
668
926
|
[
|
|
669
|
-
() => Math.min($.get(xScale)(0), $.get(xScale)($.get(
|
|
670
|
-
() => $.get(yScale)($.get(
|
|
671
|
-
() => Math.abs($.get(xScale)($.get(
|
|
672
|
-
() => $.get(yScale).bandwidth()
|
|
673
|
-
() => Math.min($.get(xScale)(0), $.get(xScale)($.get(d).metric)),
|
|
674
|
-
() => $.get(yScale)($.get(d).type)
|
|
927
|
+
() => Math.min($.get(xScale)(0), $.get(xScale)($.get(X)[$.get(i)])),
|
|
928
|
+
() => $.get(yScale)($.get(Y)[$.get(i)]) + ($.get(yScale).bandwidth() - $.get(yScale).bandwidth() * barHeightFactor()) / 2,
|
|
929
|
+
() => Math.abs($.get(xScale)($.get(X)[$.get(i)]) - $.get(xScale)(0)),
|
|
930
|
+
() => $.get(yScale).bandwidth() * barHeightFactor()
|
|
675
931
|
]
|
|
676
932
|
);
|
|
677
933
|
|
|
678
|
-
$.append($$anchor,
|
|
934
|
+
$.append($$anchor, rect);
|
|
679
935
|
});
|
|
680
936
|
|
|
937
|
+
var g_2 = $.sibling(node_1);
|
|
938
|
+
|
|
939
|
+
$.each(g_2, 21, () => $.get(yScale).domain(), $.index, ($$anchor, label) => {
|
|
940
|
+
var g_3 = root_3();
|
|
941
|
+
const labelData = $.derived(() => parseLabelData($.get(label)));
|
|
942
|
+
const xValue = $.derived(() => $.get(YX).get($.get(label)));
|
|
943
|
+
var text_4 = $.child(g_3);
|
|
944
|
+
var text_5 = $.child(text_4, true);
|
|
945
|
+
|
|
946
|
+
$.reset(text_4);
|
|
947
|
+
|
|
948
|
+
var node_2 = $.sibling(text_4);
|
|
949
|
+
|
|
950
|
+
{
|
|
951
|
+
var consequent = ($$anchor) => {
|
|
952
|
+
var text_6 = root_4();
|
|
953
|
+
var text_7 = $.child(text_6, true);
|
|
954
|
+
|
|
955
|
+
$.reset(text_6);
|
|
956
|
+
|
|
957
|
+
$.template_effect(() => {
|
|
958
|
+
$.set_attribute(text_6, 'x', $.get(xValue) > 0 ? -6 : 6);
|
|
959
|
+
$.set_attribute(text_6, 'text-anchor', $.get(xValue) > 0 ? "end" : "start");
|
|
960
|
+
$.set_style(text_6, `font-family: ${alloFonts}; font-size: 14px; fill: ${alloColors.css.darkergrey ?? ''}; opacity: 0.5;`);
|
|
961
|
+
$.set_text(text_7, $.get(labelData).numbers_y);
|
|
962
|
+
});
|
|
963
|
+
|
|
964
|
+
$.append($$anchor, text_6);
|
|
965
|
+
};
|
|
966
|
+
|
|
967
|
+
$.if(node_2, ($$render) => {
|
|
968
|
+
if ($.get(labelData).numbers_y) $$render(consequent);
|
|
969
|
+
});
|
|
970
|
+
}
|
|
971
|
+
|
|
972
|
+
$.reset(g_3);
|
|
973
|
+
|
|
974
|
+
$.template_effect(
|
|
975
|
+
($0) => {
|
|
976
|
+
$.set_attribute(g_3, 'transform', `translate(0, ${$0 ?? ''})`);
|
|
977
|
+
$.set_attribute(text_4, 'x', $.get(xValue) > 0 ? 6 : -6);
|
|
978
|
+
$.set_attribute(text_4, 'text-anchor', $.get(xValue) > 0 ? "start" : "end");
|
|
979
|
+
$.set_style(text_4, `font-family: ${alloFonts}; font-size: 14px; fill: ${alloColors.css.verydarkgrey ?? ''};`);
|
|
980
|
+
$.set_text(text_5, $.get(labelData).name_y);
|
|
981
|
+
},
|
|
982
|
+
[
|
|
983
|
+
() => $.get(yScale)($.get(label)) + $.get(yScale).bandwidth() / 2
|
|
984
|
+
]
|
|
985
|
+
);
|
|
986
|
+
|
|
987
|
+
$.append($$anchor, g_3);
|
|
988
|
+
});
|
|
989
|
+
|
|
990
|
+
$.reset(g_2);
|
|
681
991
|
$.reset(g);
|
|
682
|
-
$.
|
|
683
|
-
|
|
992
|
+
$.reset(svg);
|
|
993
|
+
|
|
994
|
+
$.template_effect(
|
|
995
|
+
($0, $1) => {
|
|
996
|
+
$.set_attribute(svg, 'width', width());
|
|
997
|
+
$.set_attribute(svg, 'height', $.get(finalHeight));
|
|
998
|
+
$.set_attribute(svg, 'viewBox', `0 0 ${width() ?? ''} ${$.get(finalHeight) ?? ''}`);
|
|
999
|
+
$.set_attribute(g, 'transform', `translate(${marginLeft() ?? ''}, ${marginTop() - shiftSvgBy})`);
|
|
1000
|
+
$.set_attribute(text_2, 'x', $0);
|
|
1001
|
+
$.set_style(text_2, `font-family: ${alloFonts}; font-size: 16px; fill: ${alloColors.css.verydarkgrey ?? ''};`);
|
|
1002
|
+
$.set_text(text_3, xLabel());
|
|
1003
|
+
$.set_attribute(g_2, 'transform', `translate(${$1 ?? ''}, 0)`);
|
|
1004
|
+
},
|
|
1005
|
+
[
|
|
1006
|
+
() => $.get(xScale)(0),
|
|
1007
|
+
() => $.get(xScale)(0)
|
|
1008
|
+
]
|
|
1009
|
+
);
|
|
1010
|
+
|
|
1011
|
+
$.append($$anchor, svg);
|
|
684
1012
|
$.pop();
|
|
685
1013
|
}
|
|
686
1014
|
|
|
687
|
-
var root_1$1 = $.from_svg(`<rect></rect><text
|
|
688
|
-
var root_2$1 = $.from_svg(`<
|
|
689
|
-
var root$2 = $.from_svg(`<g class="balance-chart"
|
|
1015
|
+
var root_1$1 = $.from_svg(`<rect></rect><text dy="0.35em"> </text>`, 1);
|
|
1016
|
+
var root_2$1 = $.from_svg(`<text x="0" dy="0.35em" text-anchor="middle"> </text>`);
|
|
1017
|
+
var root$2 = $.from_svg(`<svg style="overflow: visible; display: block;"><g class="balance-chart"><!><g class="y-axis"></g></g></svg>`);
|
|
690
1018
|
|
|
691
1019
|
function DivergingBarChart($$anchor, $$props) {
|
|
692
1020
|
$.push($$props, true);
|
|
693
1021
|
|
|
694
|
-
|
|
695
|
-
|
|
696
|
-
|
|
697
|
-
|
|
698
|
-
|
|
699
|
-
|
|
1022
|
+
let x = $.prop($$props, 'x', 3, (d) => d.frequency),
|
|
1023
|
+
y = $.prop($$props, 'y', 3, (d) => d.y_coord),
|
|
1024
|
+
marginTop = $.prop($$props, 'marginTop', 3, 0),
|
|
1025
|
+
marginRight = $.prop($$props, 'marginRight', 3, 40),
|
|
1026
|
+
marginBottom = $.prop($$props, 'marginBottom', 3, 10),
|
|
1027
|
+
marginLeft = $.prop($$props, 'marginLeft', 3, 40),
|
|
1028
|
+
width = $.prop($$props, 'width', 3, 200),
|
|
1029
|
+
yPadding = $.prop($$props, 'yPadding', 3, 0.5),
|
|
1030
|
+
colors = $.prop($$props, 'colors', 19, () => [
|
|
1031
|
+
alloColors.css.lightgrey,
|
|
1032
|
+
alloColors.css.paleblue
|
|
1033
|
+
]);
|
|
700
1034
|
|
|
701
|
-
|
|
702
|
-
|
|
703
|
-
|
|
1035
|
+
// Compute values (matching D3 version exactly)
|
|
1036
|
+
let X = $.derived(() => map($$props.data, x()));
|
|
1037
|
+
let Y = $.derived(() => map($$props.data, y()));
|
|
1038
|
+
// Compute domains
|
|
1039
|
+
let xDomain = $.derived(() => extent($.get(X)));
|
|
1040
|
+
let yDomain = $.derived(() => new InternSet($.get(Y)));
|
|
704
1041
|
|
|
705
|
-
|
|
706
|
-
|
|
1042
|
+
// Compute dimensions
|
|
1043
|
+
let xRange = $.derived(() => [
|
|
1044
|
+
marginLeft(),
|
|
1045
|
+
width() - marginRight()
|
|
1046
|
+
]);
|
|
707
1047
|
|
|
708
|
-
let
|
|
709
|
-
let types_2 = $.derived(() => $$props.test_elem_2.map((d) => d.types));
|
|
710
|
-
let union_types = $.derived(() => union($.get(types_1), $.get(types_2)));
|
|
711
|
-
let tot_types = $.derived(() => $.get(types_1).length + $.get(types_2).length);
|
|
712
|
-
let width = 200;
|
|
713
|
-
let margin = { right: 40, top: 30, left: 40, bottom: 10 };
|
|
714
|
-
let yPadding = 0.5;
|
|
715
|
-
let colors = ["lightgrey", "lightblue"];
|
|
1048
|
+
let height = $.derived(() => Math.ceil(($.get(yDomain).size + yPadding()) * 25) + marginTop() + marginBottom());
|
|
716
1049
|
|
|
717
|
-
let
|
|
718
|
-
|
|
719
|
-
|
|
720
|
-
frequency: +($.get(types_2).length / $.get(tot_types)).toFixed(3)
|
|
721
|
-
},
|
|
722
|
-
{
|
|
723
|
-
y_coord: "total count",
|
|
724
|
-
frequency: -($.get(types_1).length / $.get(tot_types)).toFixed(3)
|
|
725
|
-
},
|
|
726
|
-
{
|
|
727
|
-
y_coord: "all names",
|
|
728
|
-
frequency: +($.get(types_2).length / $.get(union_types).size).toFixed(3)
|
|
729
|
-
},
|
|
730
|
-
{
|
|
731
|
-
y_coord: "all names",
|
|
732
|
-
frequency: -($.get(types_1).length / $.get(union_types).size).toFixed(3)
|
|
733
|
-
},
|
|
734
|
-
{
|
|
735
|
-
y_coord: "exclusive names",
|
|
736
|
-
frequency: +(setdiff($.get(types_2), $.get(types_1)).size / $.get(types_2).length).toFixed(3)
|
|
737
|
-
},
|
|
738
|
-
{
|
|
739
|
-
y_coord: "exclusive names",
|
|
740
|
-
frequency: -(setdiff($.get(types_1), $.get(types_2)).size / $.get(types_1).length).toFixed(3)
|
|
741
|
-
}
|
|
1050
|
+
let yRange = $.derived(() => [
|
|
1051
|
+
marginTop(),
|
|
1052
|
+
$.get(height) - marginBottom()
|
|
742
1053
|
]);
|
|
743
1054
|
|
|
744
|
-
|
|
745
|
-
let
|
|
746
|
-
let
|
|
747
|
-
|
|
748
|
-
let
|
|
749
|
-
let
|
|
750
|
-
let I = $.derived(() => range$1($.get(X).length).filter((i) => $.get(yDomain).has($.get(Y)[i])));
|
|
751
|
-
$.derived(() => rollup($.get(I), ([i]) => $.get(X)[i], (i) => $.get(Y)[i]));
|
|
752
|
-
let xScale = $.derived(() => scaleLinear$1($.get(xDomain), $.get(xRange)));
|
|
753
|
-
let yScale = $.derived(() => scaleBand().domain($.get(yDomain)).range([margin.top, $.get(height) - margin.bottom]).padding(yPadding));
|
|
1055
|
+
// Filter indices and create lookup
|
|
1056
|
+
let I = $.derived(() => range($.get(X).length).filter((i) => $.get(yDomain).has($.get(Y)[i])));
|
|
1057
|
+
let YX = $.derived(() => rollup($.get(I), ([i]) => $.get(X)[i], (i) => $.get(Y)[i]));
|
|
1058
|
+
// Scales
|
|
1059
|
+
let xScale = $.derived(() => scaleLinear($.get(xDomain), $.get(xRange)));
|
|
1060
|
+
let yScale = $.derived(() => scaleBand().domain($.get(yDomain)).range($.get(yRange)).padding(yPadding()));
|
|
754
1061
|
let format = $.derived(() => $.get(xScale).tickFormat(100, "%"));
|
|
755
|
-
var
|
|
1062
|
+
var svg = root$2();
|
|
1063
|
+
var g = $.child(svg);
|
|
756
1064
|
var node = $.child(g);
|
|
757
1065
|
|
|
758
|
-
$.each(node, 17, () =>
|
|
1066
|
+
$.each(node, 17, () => $.get(I), $.index, ($$anchor, i) => {
|
|
759
1067
|
var fragment = root_1$1();
|
|
760
1068
|
var rect = $.first_child(fragment);
|
|
761
|
-
var
|
|
762
|
-
var
|
|
1069
|
+
var text = $.sibling(rect);
|
|
1070
|
+
var text_1 = $.child(text, true);
|
|
763
1071
|
|
|
764
|
-
$.reset(
|
|
1072
|
+
$.reset(text);
|
|
765
1073
|
|
|
766
1074
|
$.template_effect(
|
|
767
1075
|
($0, $1, $2, $3, $4, $5, $6) => {
|
|
768
1076
|
$.set_attribute(rect, 'x', $0);
|
|
769
1077
|
$.set_attribute(rect, 'y', $1);
|
|
770
|
-
$.set_attribute(rect, 'fill', colors[$.get(X)[i] > 0 ? colors.length - 1 : 0]);
|
|
1078
|
+
$.set_attribute(rect, 'fill', colors()[$.get(X)[$.get(i)] > 0 ? colors().length - 1 : 0]);
|
|
771
1079
|
$.set_attribute(rect, 'width', $2);
|
|
772
1080
|
$.set_attribute(rect, 'height', $3);
|
|
773
|
-
$.set_attribute(
|
|
774
|
-
$.set_attribute(
|
|
775
|
-
$.set_attribute(
|
|
776
|
-
$.
|
|
1081
|
+
$.set_attribute(text, 'x', $4);
|
|
1082
|
+
$.set_attribute(text, 'y', $5);
|
|
1083
|
+
$.set_attribute(text, 'text-anchor', $.get(X)[$.get(i)] < 0 ? "end" : "start");
|
|
1084
|
+
$.set_style(text, `font-family: ${alloFonts}; font-size: 10px; fill: ${alloColors.css.darkergrey ?? ''}; opacity: 0.5;`);
|
|
1085
|
+
$.set_text(text_1, $6);
|
|
777
1086
|
},
|
|
778
1087
|
[
|
|
779
|
-
() => Math.min($.get(xScale)(0), $.get(xScale)($.get(
|
|
780
|
-
() => $.get(yScale)($.get(
|
|
781
|
-
() => Math.abs($.get(xScale)($.get(
|
|
1088
|
+
() => Math.min($.get(xScale)(0), $.get(xScale)($.get(X)[$.get(i)])),
|
|
1089
|
+
() => $.get(yScale)($.get(Y)[$.get(i)]),
|
|
1090
|
+
() => Math.abs($.get(xScale)($.get(X)[$.get(i)]) - $.get(xScale)(0)),
|
|
782
1091
|
() => $.get(yScale).bandwidth(),
|
|
783
|
-
() => $.get(xScale)($.get(X)[i]) + Math.sign($.get(X)[i] - 0) * 4,
|
|
784
|
-
() => $.get(yScale)($.get(Y)[i]) + $.get(yScale).bandwidth() / 2,
|
|
785
|
-
() => $.get(format)(Math.abs($.get(
|
|
1092
|
+
() => $.get(xScale)($.get(X)[$.get(i)]) + Math.sign($.get(X)[$.get(i)] - 0) * 4,
|
|
1093
|
+
() => $.get(yScale)($.get(Y)[$.get(i)]) + $.get(yScale).bandwidth() / 2,
|
|
1094
|
+
() => $.get(format)(Math.abs($.get(X)[$.get(i)]))
|
|
786
1095
|
]
|
|
787
1096
|
);
|
|
788
1097
|
|
|
789
1098
|
$.append($$anchor, fragment);
|
|
790
1099
|
});
|
|
791
1100
|
|
|
792
|
-
var
|
|
1101
|
+
var g_1 = $.sibling(node);
|
|
793
1102
|
|
|
794
|
-
$.each(
|
|
795
|
-
var
|
|
796
|
-
var text_3 = $.child(
|
|
797
|
-
var text_4 = $.child(text_3, true);
|
|
1103
|
+
$.each(g_1, 21, () => $.get(yScale).domain(), $.index, ($$anchor, label) => {
|
|
1104
|
+
var text_2 = root_2$1();
|
|
1105
|
+
var text_3 = $.child(text_2, true);
|
|
798
1106
|
|
|
799
|
-
$.reset(
|
|
800
|
-
$.reset(g_1);
|
|
1107
|
+
$.reset(text_2);
|
|
801
1108
|
|
|
802
1109
|
$.template_effect(
|
|
803
1110
|
($0, $1) => {
|
|
804
|
-
$.set_attribute(
|
|
805
|
-
$.set_attribute(
|
|
806
|
-
$.
|
|
1111
|
+
$.set_attribute(text_2, 'y', $0);
|
|
1112
|
+
$.set_attribute(text_2, 'opacity', $1);
|
|
1113
|
+
$.set_style(text_2, `font-family: ${alloFonts}; font-size: 14px; fill: ${alloColors.css.darkergrey ?? ''};`);
|
|
1114
|
+
$.set_text(text_3, $.get(label));
|
|
807
1115
|
},
|
|
808
1116
|
[
|
|
809
|
-
() => $.get(
|
|
810
|
-
() => $.get(
|
|
1117
|
+
() => $.get(yScale)($.get(label)) + $.get(yScale).bandwidth() / 2,
|
|
1118
|
+
() => $.get(YX).get($.get(label)) ? "0.5" : "1"
|
|
811
1119
|
]
|
|
812
1120
|
);
|
|
813
1121
|
|
|
814
|
-
$.append($$anchor,
|
|
1122
|
+
$.append($$anchor, text_2);
|
|
815
1123
|
});
|
|
816
1124
|
|
|
1125
|
+
$.reset(g_1);
|
|
817
1126
|
$.reset(g);
|
|
818
|
-
$.
|
|
819
|
-
|
|
1127
|
+
$.reset(svg);
|
|
1128
|
+
|
|
1129
|
+
$.template_effect(
|
|
1130
|
+
($0) => {
|
|
1131
|
+
$.set_attribute(svg, 'width', width());
|
|
1132
|
+
$.set_attribute(svg, 'height', $.get(height));
|
|
1133
|
+
$.set_attribute(svg, 'viewBox', `0 0 ${width() ?? ''} ${$.get(height) ?? ''}`);
|
|
1134
|
+
$.set_attribute(g_1, 'transform', `translate(${$0 ?? ''}, -12)`);
|
|
1135
|
+
},
|
|
1136
|
+
[() => $.get(xScale)(0)]
|
|
1137
|
+
);
|
|
1138
|
+
|
|
1139
|
+
$.append($$anchor, svg);
|
|
820
1140
|
$.pop();
|
|
821
1141
|
}
|
|
822
1142
|
|
|
823
|
-
var root_1 = $.from_svg(`<rect
|
|
824
|
-
var
|
|
825
|
-
var
|
|
826
|
-
var root$1 = $.from_svg(`<g class="legend-container"></g><!>`, 1);
|
|
1143
|
+
var root_1 = $.from_svg(`<rect transform="rotate(-90) translate(-70,0)" style="stroke: black; stroke-width: 0.65; shape-rendering: crispEdges;"></rect>`);
|
|
1144
|
+
var root_2 = $.from_svg(`<g class="tick"><text dx="30" dy="-30" transform="rotate(90)"> </text></g>`);
|
|
1145
|
+
var root$1 = $.from_svg(`<svg style="overflow: visible; display: block;"><!><g transform="rotate(-90) translate(-60,5)"><!><text class="title" dx="30" dy="-5" transform="rotate(90)">Counts per cell</text></g></svg>`);
|
|
827
1146
|
|
|
828
1147
|
function Legend($$anchor, $$props) {
|
|
829
1148
|
$.push($$props, true);
|
|
830
1149
|
|
|
831
|
-
|
|
832
|
-
|
|
833
|
-
|
|
834
|
-
|
|
835
|
-
|
|
836
|
-
|
|
837
|
-
|
|
838
|
-
|
|
839
|
-
|
|
840
|
-
|
|
841
|
-
|
|
842
|
-
|
|
843
|
-
|
|
844
|
-
|
|
845
|
-
let logFormat10 = $.derived(() => $.get(logY).tickFormat());
|
|
846
|
-
let yTicks = $.derived(() => $.get(logY).ticks());
|
|
847
|
-
var fragment = root$1();
|
|
848
|
-
var g = $.first_child(fragment);
|
|
849
|
-
|
|
850
|
-
$.each(g, 21, () => color.domain(), $.index, ($$anchor, d) => {
|
|
851
|
-
var rect = root_1();
|
|
1150
|
+
let tickSize = $.prop($$props, 'tickSize', 3, 0),
|
|
1151
|
+
height = $.prop($$props, 'height', 19, () => 44 + tickSize()),
|
|
1152
|
+
width = $.prop($$props, 'width', 3, 300),
|
|
1153
|
+
marginTop = $.prop($$props, 'marginTop', 3, 13),
|
|
1154
|
+
marginBottom = $.prop($$props, 'marginBottom', 19, () => 16 + tickSize()),
|
|
1155
|
+
marginLeft = $.prop($$props, 'marginLeft', 3, 0),
|
|
1156
|
+
N_CATEGO = $.prop($$props, 'N_CATEGO', 3, 20);
|
|
1157
|
+
|
|
1158
|
+
const myramp = range(N_CATEGO()).map((i) => rgb(interpolateInferno(i / (N_CATEGO() - 1))).hex());
|
|
1159
|
+
const color = scaleOrdinal(range(N_CATEGO()), myramp);
|
|
1160
|
+
let x = $.derived(() => scaleBand().domain(color.domain()).rangeRound([marginLeft(), width() - 100]));
|
|
1161
|
+
let x2 = $.derived(() => scaleBand().domain(range($$props.max_count_log).map((i) => 10 ** i).sort((a, b) => b - a)).rangeRound([marginLeft() - 40, width() - 90]));
|
|
1162
|
+
var svg = root$1();
|
|
1163
|
+
var node = $.child(svg);
|
|
852
1164
|
|
|
853
|
-
|
|
854
|
-
|
|
855
|
-
$.set_attribute(rect, 'height', 13);
|
|
1165
|
+
$.each(node, 17, () => color.domain(), $.index, ($$anchor, d) => {
|
|
1166
|
+
var rect = root_1();
|
|
856
1167
|
|
|
857
1168
|
$.template_effect(
|
|
858
|
-
($0, $1) => {
|
|
859
|
-
$.set_attribute(rect, '
|
|
860
|
-
$.set_attribute(rect, '
|
|
1169
|
+
($0, $1, $2, $3) => {
|
|
1170
|
+
$.set_attribute(rect, 'x', $0);
|
|
1171
|
+
$.set_attribute(rect, 'y', marginTop());
|
|
1172
|
+
$.set_attribute(rect, 'width', $1);
|
|
1173
|
+
$.set_attribute(rect, 'height', $2);
|
|
1174
|
+
$.set_attribute(rect, 'fill', $3);
|
|
861
1175
|
},
|
|
862
1176
|
[
|
|
863
|
-
() => $.get(
|
|
1177
|
+
() => $.get(x)($.get(d)),
|
|
1178
|
+
() => Math.max(0, $.get(x).bandwidth()),
|
|
1179
|
+
() => $.get(x).bandwidth(),
|
|
864
1180
|
() => color($.get(d))
|
|
865
1181
|
]
|
|
866
1182
|
);
|
|
@@ -868,106 +1184,98 @@ function Legend($$anchor, $$props) {
|
|
|
868
1184
|
$.append($$anchor, rect);
|
|
869
1185
|
});
|
|
870
1186
|
|
|
871
|
-
$.
|
|
872
|
-
|
|
873
|
-
var node = $.sibling(g);
|
|
1187
|
+
var g = $.sibling(node);
|
|
1188
|
+
var node_1 = $.child(g);
|
|
874
1189
|
|
|
875
|
-
$.each(
|
|
876
|
-
var
|
|
877
|
-
var g_1 = $.first_child(fragment_1);
|
|
1190
|
+
$.each(node_1, 17, () => $.get(x2).domain(), $.index, ($$anchor, tick) => {
|
|
1191
|
+
var g_1 = root_2();
|
|
878
1192
|
var text = $.child(g_1);
|
|
879
1193
|
var text_1 = $.child(text, true);
|
|
880
1194
|
|
|
881
1195
|
$.reset(text);
|
|
882
1196
|
$.reset(g_1);
|
|
883
1197
|
|
|
884
|
-
var node_1 = $.sibling(g_1);
|
|
885
|
-
|
|
886
|
-
{
|
|
887
|
-
var consequent = ($$anchor) => {
|
|
888
|
-
var g_2 = root_3();
|
|
889
|
-
var text_2 = $.child(g_2);
|
|
890
|
-
|
|
891
|
-
$.set_attribute(text_2, 'dy', "9");
|
|
892
|
-
$.reset(g_2);
|
|
893
|
-
|
|
894
|
-
$.template_effect(($0) => $.set_attribute(g_2, 'transform', `translate(${margin.left}, ${$0 ?? ''})`), [
|
|
895
|
-
() => $$props.DiamondHeight + $.get(logY)($.get(tick)) - margin.top
|
|
896
|
-
]);
|
|
897
|
-
|
|
898
|
-
$.append($$anchor, g_2);
|
|
899
|
-
};
|
|
900
|
-
|
|
901
|
-
$.if(node_1, ($$render) => {
|
|
902
|
-
if (i === $.get(yTicks).length - 1) $$render(consequent);
|
|
903
|
-
});
|
|
904
|
-
}
|
|
905
|
-
|
|
906
1198
|
$.template_effect(
|
|
907
|
-
($0
|
|
908
|
-
$.set_attribute(g_1, 'transform', `translate(${
|
|
909
|
-
$.
|
|
910
|
-
$.set_text(text_1,
|
|
1199
|
+
($0) => {
|
|
1200
|
+
$.set_attribute(g_1, 'transform', `translate(${$0 ?? ''}, 0)`);
|
|
1201
|
+
$.set_style(text, `font-family: ${alloFonts}; font-size: 14px; fill: ${alloColors.css.verydarkgrey ?? ''}; text-anchor: start;`);
|
|
1202
|
+
$.set_text(text_1, $.get(tick));
|
|
911
1203
|
},
|
|
912
|
-
[
|
|
913
|
-
() => $$props.DiamondHeight + $.get(logY)($.get(tick)) - margin.top,
|
|
914
|
-
() => $.get(logFormat10)($.get(tick))
|
|
915
|
-
]
|
|
1204
|
+
[() => $.get(x2)($.get(tick))]
|
|
916
1205
|
);
|
|
917
1206
|
|
|
918
|
-
$.append($$anchor,
|
|
1207
|
+
$.append($$anchor, g_1);
|
|
919
1208
|
});
|
|
920
1209
|
|
|
921
|
-
|
|
922
|
-
|
|
1210
|
+
var text_2 = $.sibling(node_1);
|
|
1211
|
+
|
|
1212
|
+
$.reset(g);
|
|
1213
|
+
$.reset(svg);
|
|
1214
|
+
|
|
1215
|
+
$.template_effect(() => {
|
|
1216
|
+
$.set_attribute(svg, 'width', width());
|
|
1217
|
+
$.set_attribute(svg, 'height', height());
|
|
1218
|
+
$.set_attribute(svg, 'viewBox', `0 0 ${width() ?? ''} ${height() ?? ''}`);
|
|
1219
|
+
$.set_attribute(text_2, 'x', marginLeft() - 25);
|
|
1220
|
+
$.set_attribute(text_2, 'y', marginTop() + marginBottom());
|
|
1221
|
+
$.set_style(text_2, `font-family: ${alloFonts}; font-size: 14px; fill: ${alloColors.css.verydarkgrey ?? ''}; text-anchor: start;`);
|
|
1222
|
+
});
|
|
1223
|
+
|
|
1224
|
+
$.append($$anchor, svg);
|
|
923
1225
|
$.pop();
|
|
924
1226
|
}
|
|
925
1227
|
|
|
926
|
-
var root = $.from_html(`<div><
|
|
1228
|
+
var root = $.from_html(`<div class="allotaxonometer-dashboard" style="position: relative; margin: 0; padding: 0;"><div style="display:flex; flex-wrap: wrap; align-items:center; justify-content: center; row-gap: 50px;"><div style="margin-top:20px"><div style="display:flex; gap: 10em; justify-content: center; margin-bottom: -70px; margin-right: 70px; position: relative;"><div style="position: relative;"><div> </div> <div> </div> <div> </div></div> <div> </div></div> <div id="diamondplot"><!></div> <div style="display: flex; gap: 13em; justify-content: center;"><div id="legend" style="margin-left: -50px;"><!></div> <div id="balance"><!></div></div></div> <div style="margin-top:60px; overflow: visible;"><div id="wordshift" style="overflow: visible;"><!></div></div></div></div>`);
|
|
927
1229
|
|
|
928
1230
|
function Dashboard($$anchor, $$props) {
|
|
929
|
-
|
|
930
|
-
|
|
1231
|
+
$.push($$props, true);
|
|
1232
|
+
|
|
1233
|
+
let dat = $.prop($$props, 'dat', 3, null),
|
|
1234
|
+
alpha = $.prop($$props, 'alpha', 3, 0.58),
|
|
1235
|
+
divnorm = $.prop($$props, 'divnorm', 3, 1),
|
|
931
1236
|
barData = $.prop($$props, 'barData', 19, () => []),
|
|
932
|
-
|
|
933
|
-
|
|
934
|
-
|
|
935
|
-
|
|
1237
|
+
balanceData = $.prop($$props, 'balanceData', 19, () => []),
|
|
1238
|
+
xDomain = $.prop($$props, 'xDomain', 3, undefined),
|
|
1239
|
+
instrumentText = $.prop($$props, 'instrumentText', 3, 'Instrument: Rank-Turbulence Divergence'),
|
|
1240
|
+
title = $.prop($$props, 'title', 19, () => ['System 1', 'System 2']),
|
|
1241
|
+
maxlog10 = $.prop($$props, 'maxlog10', 3, 0);
|
|
1242
|
+
$.prop($$props, 'height', 3, 815);
|
|
1243
|
+
$.prop($$props, 'width', 3, 1200);
|
|
1244
|
+
let DashboardHeight = $.prop($$props, 'DashboardHeight', 3, 815),
|
|
1245
|
+
DashboardWidth = $.prop($$props, 'DashboardWidth', 3, 1200),
|
|
936
1246
|
DiamondHeight = $.prop($$props, 'DiamondHeight', 3, 600),
|
|
937
1247
|
DiamondWidth = $.prop($$props, 'DiamondWidth', 3, 600),
|
|
938
|
-
|
|
939
|
-
|
|
940
|
-
|
|
941
|
-
|
|
942
|
-
|
|
943
|
-
|
|
944
|
-
|
|
945
|
-
|
|
946
|
-
|
|
947
|
-
|
|
948
|
-
showWordshift = $.prop($$props, 'showWordshift', 3, true),
|
|
949
|
-
showDivergingBar = $.prop($$props, 'showDivergingBar', 3, true),
|
|
950
|
-
showLegend = $.prop($$props, 'showLegend', 3, true),
|
|
951
|
-
restProps = $.rest_props($$props, [
|
|
1248
|
+
marginInner = $.prop($$props, 'marginInner', 3, 160),
|
|
1249
|
+
marginDiamond = $.prop($$props, 'marginDiamond', 3, 40),
|
|
1250
|
+
max_count_log = $.prop($$props, 'max_count_log', 3, undefined);
|
|
1251
|
+
$.prop($$props, 'class', 3, '');
|
|
1252
|
+
$.prop($$props, 'style', 3, '');
|
|
1253
|
+
$.prop($$props, 'showDiamond', 3, true);
|
|
1254
|
+
$.prop($$props, 'showWordshift', 3, true);
|
|
1255
|
+
$.prop($$props, 'showDivergingBar', 3, true);
|
|
1256
|
+
$.prop($$props, 'showLegend', 3, true);
|
|
1257
|
+
$.rest_props($$props, [
|
|
952
1258
|
'$$slots',
|
|
953
1259
|
'$$events',
|
|
954
1260
|
'$$legacy',
|
|
955
|
-
'
|
|
956
|
-
'
|
|
1261
|
+
'dat',
|
|
1262
|
+
'alpha',
|
|
1263
|
+
'divnorm',
|
|
957
1264
|
'barData',
|
|
958
|
-
'
|
|
959
|
-
'
|
|
1265
|
+
'balanceData',
|
|
1266
|
+
'xDomain',
|
|
1267
|
+
'instrumentText',
|
|
1268
|
+
'title',
|
|
1269
|
+
'maxlog10',
|
|
960
1270
|
'height',
|
|
961
1271
|
'width',
|
|
1272
|
+
'DashboardHeight',
|
|
1273
|
+
'DashboardWidth',
|
|
962
1274
|
'DiamondHeight',
|
|
963
1275
|
'DiamondWidth',
|
|
964
|
-
'
|
|
965
|
-
'
|
|
966
|
-
'
|
|
967
|
-
'alpha',
|
|
968
|
-
'maxlog10',
|
|
969
|
-
'rtd',
|
|
970
|
-
'title',
|
|
1276
|
+
'marginInner',
|
|
1277
|
+
'marginDiamond',
|
|
1278
|
+
'max_count_log',
|
|
971
1279
|
'class',
|
|
972
1280
|
'style',
|
|
973
1281
|
'showDiamond',
|
|
@@ -976,135 +1284,809 @@ function Dashboard($$anchor, $$props) {
|
|
|
976
1284
|
'showLegend'
|
|
977
1285
|
]);
|
|
978
1286
|
|
|
1287
|
+
let max_shift = $.derived(() => barData().length > 0 ? Math.max(...barData().map((d) => Math.abs(d.metric))) : 1);
|
|
1288
|
+
|
|
1289
|
+
let wordshiftXDomain = $.derived(() => xDomain() || [
|
|
1290
|
+
-$.get(max_shift) * 1.5,
|
|
1291
|
+
$.get(max_shift) * 1.5
|
|
1292
|
+
]);
|
|
1293
|
+
|
|
979
1294
|
var div = root();
|
|
1295
|
+
var div_1 = $.child(div);
|
|
1296
|
+
var div_2 = $.child(div_1);
|
|
1297
|
+
var div_3 = $.child(div_2);
|
|
1298
|
+
var div_4 = $.child(div_3);
|
|
1299
|
+
var div_5 = $.child(div_4);
|
|
1300
|
+
var text = $.child(div_5, true);
|
|
980
1301
|
|
|
981
|
-
$.
|
|
982
|
-
div,
|
|
983
|
-
() => ({
|
|
984
|
-
class: `allotaxonometer-dashboard ${className() ?? ''}`,
|
|
985
|
-
style: style(),
|
|
986
|
-
...restProps
|
|
987
|
-
}),
|
|
988
|
-
undefined,
|
|
989
|
-
'svelte-n6o6ey'
|
|
990
|
-
);
|
|
1302
|
+
$.reset(div_5);
|
|
991
1303
|
|
|
992
|
-
var
|
|
993
|
-
var
|
|
1304
|
+
var div_6 = $.sibling(div_5, 2);
|
|
1305
|
+
var text_1 = $.child(div_6, true);
|
|
994
1306
|
|
|
995
|
-
|
|
996
|
-
var consequent = ($$anchor) => {
|
|
997
|
-
Diamond($$anchor, {
|
|
998
|
-
get diamond_count() {
|
|
999
|
-
return diamond_count();
|
|
1000
|
-
},
|
|
1001
|
-
get diamond_dat() {
|
|
1002
|
-
return diamond_dat();
|
|
1003
|
-
},
|
|
1004
|
-
get DiamondInnerHeight() {
|
|
1005
|
-
return DiamondInnerHeight();
|
|
1006
|
-
},
|
|
1007
|
-
get margin() {
|
|
1008
|
-
return margin();
|
|
1009
|
-
},
|
|
1010
|
-
get trueDiamondHeight() {
|
|
1011
|
-
return trueDiamondHeight();
|
|
1012
|
-
},
|
|
1013
|
-
get alpha() {
|
|
1014
|
-
return alpha();
|
|
1015
|
-
},
|
|
1016
|
-
get maxlog10() {
|
|
1017
|
-
return maxlog10();
|
|
1018
|
-
},
|
|
1019
|
-
get rtd() {
|
|
1020
|
-
return rtd();
|
|
1021
|
-
},
|
|
1022
|
-
get title() {
|
|
1023
|
-
return title();
|
|
1024
|
-
}
|
|
1025
|
-
});
|
|
1026
|
-
};
|
|
1307
|
+
$.reset(div_6);
|
|
1027
1308
|
|
|
1028
|
-
|
|
1029
|
-
|
|
1030
|
-
});
|
|
1031
|
-
}
|
|
1309
|
+
var div_7 = $.sibling(div_6, 2);
|
|
1310
|
+
var text_2 = $.child(div_7);
|
|
1032
1311
|
|
|
1033
|
-
|
|
1312
|
+
$.reset(div_7);
|
|
1313
|
+
$.reset(div_4);
|
|
1034
1314
|
|
|
1035
|
-
|
|
1036
|
-
|
|
1037
|
-
Wordshift($$anchor, {
|
|
1038
|
-
get barData() {
|
|
1039
|
-
return barData();
|
|
1040
|
-
},
|
|
1041
|
-
get DashboardHeight() {
|
|
1042
|
-
return height();
|
|
1043
|
-
},
|
|
1044
|
-
get DashboardWidth() {
|
|
1045
|
-
return width();
|
|
1046
|
-
}
|
|
1047
|
-
});
|
|
1048
|
-
};
|
|
1315
|
+
var div_8 = $.sibling(div_4, 2);
|
|
1316
|
+
var text_3 = $.child(div_8, true);
|
|
1049
1317
|
|
|
1050
|
-
|
|
1051
|
-
|
|
1052
|
-
});
|
|
1053
|
-
}
|
|
1318
|
+
$.reset(div_8);
|
|
1319
|
+
$.reset(div_3);
|
|
1054
1320
|
|
|
1055
|
-
var
|
|
1321
|
+
var div_9 = $.sibling(div_3, 2);
|
|
1322
|
+
var node = $.child(div_9);
|
|
1056
1323
|
|
|
1057
|
-
{
|
|
1058
|
-
|
|
1059
|
-
|
|
1060
|
-
|
|
1061
|
-
|
|
1062
|
-
|
|
1063
|
-
|
|
1064
|
-
|
|
1065
|
-
|
|
1066
|
-
|
|
1067
|
-
|
|
1068
|
-
|
|
1069
|
-
|
|
1070
|
-
|
|
1071
|
-
|
|
1072
|
-
|
|
1073
|
-
|
|
1324
|
+
Diamond(node, {
|
|
1325
|
+
get dat() {
|
|
1326
|
+
return dat();
|
|
1327
|
+
},
|
|
1328
|
+
get alpha() {
|
|
1329
|
+
return alpha();
|
|
1330
|
+
},
|
|
1331
|
+
get divnorm() {
|
|
1332
|
+
return divnorm();
|
|
1333
|
+
},
|
|
1334
|
+
get title() {
|
|
1335
|
+
return title();
|
|
1336
|
+
},
|
|
1337
|
+
get maxlog10() {
|
|
1338
|
+
return maxlog10();
|
|
1339
|
+
},
|
|
1340
|
+
get DiamondHeight() {
|
|
1341
|
+
return DiamondHeight();
|
|
1342
|
+
},
|
|
1343
|
+
get marginInner() {
|
|
1344
|
+
return marginInner();
|
|
1345
|
+
},
|
|
1346
|
+
get marginDiamond() {
|
|
1347
|
+
return marginDiamond();
|
|
1348
|
+
}
|
|
1349
|
+
});
|
|
1074
1350
|
|
|
1075
|
-
|
|
1076
|
-
if (showDivergingBar()) $$render(consequent_2);
|
|
1077
|
-
});
|
|
1078
|
-
}
|
|
1351
|
+
$.reset(div_9);
|
|
1079
1352
|
|
|
1080
|
-
var
|
|
1353
|
+
var div_10 = $.sibling(div_9, 2);
|
|
1354
|
+
var div_11 = $.child(div_10);
|
|
1355
|
+
var node_1 = $.child(div_11);
|
|
1356
|
+
const expression = $.derived(() => max_count_log() || 5);
|
|
1081
1357
|
|
|
1082
|
-
{
|
|
1083
|
-
|
|
1084
|
-
|
|
1085
|
-
|
|
1086
|
-
|
|
1087
|
-
|
|
1088
|
-
|
|
1089
|
-
|
|
1090
|
-
|
|
1091
|
-
|
|
1092
|
-
|
|
1358
|
+
Legend(node_1, {
|
|
1359
|
+
get diamond_dat() {
|
|
1360
|
+
return dat().counts;
|
|
1361
|
+
},
|
|
1362
|
+
get DiamondHeight() {
|
|
1363
|
+
return DiamondHeight();
|
|
1364
|
+
},
|
|
1365
|
+
get max_count_log() {
|
|
1366
|
+
return $.get(expression);
|
|
1367
|
+
}
|
|
1368
|
+
});
|
|
1093
1369
|
|
|
1094
|
-
|
|
1095
|
-
if (showLegend()) $$render(consequent_3);
|
|
1096
|
-
});
|
|
1097
|
-
}
|
|
1370
|
+
$.reset(div_11);
|
|
1098
1371
|
|
|
1099
|
-
$.
|
|
1372
|
+
var div_12 = $.sibling(div_11, 2);
|
|
1373
|
+
var node_2 = $.child(div_12);
|
|
1374
|
+
|
|
1375
|
+
DivergingBarChart(node_2, {
|
|
1376
|
+
get data() {
|
|
1377
|
+
return balanceData();
|
|
1378
|
+
},
|
|
1379
|
+
get DiamondHeight() {
|
|
1380
|
+
return DiamondHeight();
|
|
1381
|
+
},
|
|
1382
|
+
get DiamondWidth() {
|
|
1383
|
+
return DiamondWidth();
|
|
1384
|
+
}
|
|
1385
|
+
});
|
|
1386
|
+
|
|
1387
|
+
$.reset(div_12);
|
|
1388
|
+
$.reset(div_10);
|
|
1389
|
+
$.reset(div_2);
|
|
1390
|
+
|
|
1391
|
+
var div_13 = $.sibling(div_2, 2);
|
|
1392
|
+
var div_14 = $.child(div_13);
|
|
1393
|
+
var node_3 = $.child(div_14);
|
|
1394
|
+
|
|
1395
|
+
Wordshift(node_3, {
|
|
1396
|
+
get barData() {
|
|
1397
|
+
return barData();
|
|
1398
|
+
},
|
|
1399
|
+
get DashboardHeight() {
|
|
1400
|
+
return DashboardHeight();
|
|
1401
|
+
},
|
|
1402
|
+
get DashboardWidth() {
|
|
1403
|
+
return DashboardWidth();
|
|
1404
|
+
},
|
|
1405
|
+
get xDomain() {
|
|
1406
|
+
return $.get(wordshiftXDomain);
|
|
1407
|
+
},
|
|
1408
|
+
width: 640,
|
|
1409
|
+
marginLeft: 140
|
|
1410
|
+
});
|
|
1411
|
+
|
|
1412
|
+
$.reset(div_14);
|
|
1413
|
+
$.reset(div_13);
|
|
1414
|
+
$.reset(div_1);
|
|
1100
1415
|
$.reset(div);
|
|
1101
1416
|
|
|
1102
1417
|
$.template_effect(() => {
|
|
1103
|
-
$.
|
|
1104
|
-
$.
|
|
1418
|
+
$.set_style(div_5, `font-family: ${alloFonts}; font-size: 16px; color: ${alloColors.css.superdarkgrey ?? ''};`);
|
|
1419
|
+
$.set_text(text, title()[0]);
|
|
1420
|
+
$.set_style(div_6, `position: absolute; top: 100%; left: -12em; margin-top: 2.5em; font-family: ${alloFonts}; font-size: 14px; color: ${alloColors.css.darkgrey ?? ''};`);
|
|
1421
|
+
$.set_text(text_1, instrumentText());
|
|
1422
|
+
$.set_style(div_7, `position: absolute; top: 100%; left: -12em; margin-top: 3.5em; font-family: ${alloFonts}; font-size: 14px; color: ${alloColors.css.darkgrey ?? ''};`);
|
|
1423
|
+
$.set_text(text_2, `α = ${alpha() ?? ''}`);
|
|
1424
|
+
$.set_style(div_8, `font-family: ${alloFonts}; font-size: 16px; color: ${alloColors.css.superdarkgrey ?? ''};`);
|
|
1425
|
+
$.set_text(text_3, title()[1]);
|
|
1105
1426
|
});
|
|
1106
1427
|
|
|
1107
1428
|
$.append($$anchor, div);
|
|
1429
|
+
$.pop();
|
|
1430
|
+
}
|
|
1431
|
+
|
|
1432
|
+
// Takes arrays, returns a Set object containing the union of both arrays
|
|
1433
|
+
function getUnions(x,y) {
|
|
1434
|
+
let a = new Set(x); // convert array x to a Set object
|
|
1435
|
+
let b = new Set(y); // convert array y to a Set object
|
|
1436
|
+
return new Set([...a, ...b]); // return a new Set object containing the union of a and b
|
|
1437
|
+
}
|
|
1438
|
+
|
|
1439
|
+
// Takes arrays, returns a Set object
|
|
1440
|
+
function setdiff(x,y) {
|
|
1441
|
+
let a = new Set(x); // convert array x to a Set object
|
|
1442
|
+
let b = new Set(y); // convert array y to a Set object
|
|
1443
|
+
// return a new Set object containing elements in a that are not present in b
|
|
1444
|
+
return new Set(
|
|
1445
|
+
[...a].filter(x => !b.has(x)));
|
|
1446
|
+
}
|
|
1447
|
+
|
|
1448
|
+
function which(x) {
|
|
1449
|
+
// Which indices are TRUE?
|
|
1450
|
+
// Description:
|
|
1451
|
+
// Give the ‘TRUE’ indices of a logical object, allowing for array indices.
|
|
1452
|
+
// Arguments:
|
|
1453
|
+
// x: a ‘logical’ vector or array.
|
|
1454
|
+
return x.reduce(
|
|
1455
|
+
(out, bool, index) => bool ? out.concat(index) : out,
|
|
1456
|
+
[]
|
|
1457
|
+
)
|
|
1458
|
+
}
|
|
1459
|
+
|
|
1460
|
+
|
|
1461
|
+
function matlab_sort(A, rev) {
|
|
1462
|
+
// Inspired by matlab, this functions keep track of the original indices of an array after sorting.
|
|
1463
|
+
// Returns both the sorted vector `v` and the original indices.
|
|
1464
|
+
//
|
|
1465
|
+
// examples
|
|
1466
|
+
// A = [5, 4, 1, 2, 3]
|
|
1467
|
+
// ([1, 2, 3, 3, 4, 5], [3, 4, 5, 6, 2, 1])
|
|
1468
|
+
|
|
1469
|
+
let sorted = rev ? A.slice().sort((a, b) => b - a) : A.slice().sort((a, b) => a - b);
|
|
1470
|
+
|
|
1471
|
+
const A_cp = A.slice();
|
|
1472
|
+
const orig_idx = [];
|
|
1473
|
+
for (let i = 0; i < A.length; ++i) {
|
|
1474
|
+
orig_idx.push(A_cp.indexOf(sorted[i]));
|
|
1475
|
+
delete A_cp[A_cp.indexOf(sorted[i])];
|
|
1476
|
+
}
|
|
1477
|
+
|
|
1478
|
+
return {'value': sorted, 'orig_idx': orig_idx}
|
|
1479
|
+
}
|
|
1480
|
+
|
|
1481
|
+
function tiedrank(arr) {
|
|
1482
|
+
// tiedrank(X) computes the ranks of the values in the vector X. If any X values are tied, tiedrank computes their average rank. Same as in matlab.
|
|
1483
|
+
function getIndex(arr, val) {
|
|
1484
|
+
var indexes = [], i;
|
|
1485
|
+
for(i = 0; i < arr.length; i++)
|
|
1486
|
+
if (arr[i] === val)
|
|
1487
|
+
indexes.push(i+1);
|
|
1488
|
+
return indexes.reduce((a, b) => a + b) / indexes.length;
|
|
1489
|
+
}
|
|
1490
|
+
|
|
1491
|
+
const sorted = arr.slice().sort((a, b) => b - a);
|
|
1492
|
+
return arr.map(e => getIndex(sorted, e))
|
|
1493
|
+
}
|
|
1494
|
+
|
|
1495
|
+
function rank_maxlog10(mixedelements) {
|
|
1496
|
+
// Get maximum of log10 ranks from both systems, then round up
|
|
1497
|
+
let logged_max = [
|
|
1498
|
+
Math.max(...mixedelements[[0]].ranks), Math.max(...mixedelements[[1]].ranks)
|
|
1499
|
+
].map(Math.log10);
|
|
1500
|
+
return Math.ceil(Math.max(...[logged_max[0], logged_max[1]]))
|
|
1501
|
+
}
|
|
1502
|
+
|
|
1503
|
+
function rin(arr1, arr2) {
|
|
1504
|
+
// Find element arr1 presents in arr2, i.e. arr1 %in% arr2
|
|
1505
|
+
//
|
|
1506
|
+
// examples
|
|
1507
|
+
// A = ["bob", "george", "jesus"]
|
|
1508
|
+
// B = ["bob", "jesus", "terrence"]
|
|
1509
|
+
// rin(A, B)
|
|
1510
|
+
// [true, false, true]
|
|
1511
|
+
return Array.from(arr1, (x) => {
|
|
1512
|
+
return arr2.indexOf(x) == -1 ? false : true
|
|
1513
|
+
})
|
|
1514
|
+
}
|
|
1515
|
+
|
|
1516
|
+
function zeros(length){
|
|
1517
|
+
// Create array of all zeros. Similar to matlab.
|
|
1518
|
+
function createArray(length) {
|
|
1519
|
+
var arr = new Array(length || 0),
|
|
1520
|
+
i = length;
|
|
1521
|
+
if (arguments.length > 1) {
|
|
1522
|
+
var args = Array.prototype.slice.call(arguments, 1);
|
|
1523
|
+
while(i--) arr[length-1 - i] = createArray.apply(this, args);
|
|
1524
|
+
}
|
|
1525
|
+
return arr;
|
|
1526
|
+
}
|
|
1527
|
+
let empty_mat = createArray(length,length);
|
|
1528
|
+
return Array.from(empty_mat, arr => arr.fill(0))
|
|
1529
|
+
}
|
|
1530
|
+
|
|
1531
|
+
// Builds a mixed element array containing the union of types in elem1 and elem2
|
|
1532
|
+
function buildMixedElems(elem1, elem2) {
|
|
1533
|
+
const mixedelem = [[], []];
|
|
1534
|
+
const x = elem1.map(d=>d.types); // extract types from elem1
|
|
1535
|
+
const y = elem2.map(d=>d.types); // extract types from elem
|
|
1536
|
+
const union = Array.from(getUnions(x,y)); // get the union of x and y
|
|
1537
|
+
mixedelem[0]['types'] = union; // store union in mixedelem array for elem1
|
|
1538
|
+
mixedelem[1]['types'] = union; // store union in mixedelem array for elem2
|
|
1539
|
+
return mixedelem // return mixedelem array
|
|
1540
|
+
}
|
|
1541
|
+
|
|
1542
|
+
// Combine elements and return a combined array containing counts, ranks, probs, and totalunique
|
|
1543
|
+
function combElems(elem1, elem2) {
|
|
1544
|
+
const mixedelem = buildMixedElems(elem1, elem2); // build mixed elements array
|
|
1545
|
+
const enum_list = [elem1, elem2]; // list containing elem1 and elem2
|
|
1546
|
+
|
|
1547
|
+
for (let j=0; j < enum_list.length; j++) {
|
|
1548
|
+
const enumlist_types = enum_list[j].map(d => d.types); // extract types from enum_list[j]
|
|
1549
|
+
const counts = new Array(mixedelem[j]['types'].length); // initialize counts array
|
|
1550
|
+
const probs = new Array(mixedelem[j]['types'].length); // initialize probs array
|
|
1551
|
+
|
|
1552
|
+
|
|
1553
|
+
// for each index in mixed elem[j], which is the union of both systems
|
|
1554
|
+
for (let i=0; i < mixedelem[j]['types'].length; i++) { // find the index of type mixedelem[j]['types'][i] in system 1 or 2
|
|
1555
|
+
// find the index of type mixedelem[j]['types'][i] in system 1 or 2
|
|
1556
|
+
let idx_type_enumlist_in_elem = enumlist_types.indexOf(mixedelem[j]['types'][i]);
|
|
1557
|
+
// if it exists, grabs counts and probs information else put a 0.
|
|
1558
|
+
counts[i] = idx_type_enumlist_in_elem === -1 ? 0 : enum_list[j][idx_type_enumlist_in_elem]["counts"];
|
|
1559
|
+
probs[i] = idx_type_enumlist_in_elem === -1 ? 0 : enum_list[j][idx_type_enumlist_in_elem]["probs"];
|
|
1560
|
+
}
|
|
1561
|
+
|
|
1562
|
+
|
|
1563
|
+
// store counts, ranks, probs, and totalunique in mixedelem array for elem1 or elem2
|
|
1564
|
+
mixedelem[j]['counts'] = counts;
|
|
1565
|
+
mixedelem[j]['ranks'] = tiedrank(mixedelem[j]['counts']);
|
|
1566
|
+
mixedelem[j]['probs'] = probs;
|
|
1567
|
+
mixedelem[j]['totalunique'] = getUnions().length;
|
|
1568
|
+
|
|
1569
|
+
}
|
|
1570
|
+
|
|
1571
|
+
return mixedelem // return mixedelem array
|
|
1572
|
+
}
|
|
1573
|
+
|
|
1574
|
+
// helpers to wrangle data for the balance plot
|
|
1575
|
+
function balanceDat(elem1, elem2) {
|
|
1576
|
+
const types_1 = elem1.map(d => d.types);
|
|
1577
|
+
const types_2 = elem2.map(d => d.types);
|
|
1578
|
+
|
|
1579
|
+
const union_types = getUnions(types_1, types_2);
|
|
1580
|
+
const tot_types = types_1.length+types_2.length;
|
|
1581
|
+
|
|
1582
|
+
return [
|
|
1583
|
+
{ y_coord: "total count", frequency: +(types_2.length / tot_types).toFixed(3) },
|
|
1584
|
+
{ y_coord: "total count", frequency: -(types_1.length / tot_types).toFixed(3) },
|
|
1585
|
+
{ y_coord: "all names", frequency: +(types_2.length / union_types.size).toFixed(3) },
|
|
1586
|
+
{ y_coord: "all names", frequency: -(types_1.length / union_types.size).toFixed(3) },
|
|
1587
|
+
{ y_coord: "exclusive names", frequency: +(setdiff(types_2, types_1).size / types_2.length).toFixed(3) },
|
|
1588
|
+
{ y_coord: "exclusive names", frequency: -(setdiff(types_1, types_2).size / types_1.length).toFixed(3) }
|
|
1589
|
+
]
|
|
1590
|
+
}
|
|
1591
|
+
|
|
1592
|
+
// helper to wrangle the data for the wordshift plot
|
|
1593
|
+
function wordShift_dat(me, dat) {
|
|
1594
|
+
const out = [];
|
|
1595
|
+
for (let i=0; i < me[0]['types'].length; i++) {
|
|
1596
|
+
const rank_diff = me[0]['ranks'][i]-me[1]['ranks'][i];
|
|
1597
|
+
out.push({
|
|
1598
|
+
'type': `${me[0]['types'][i]} (${me[0]['ranks'][i]} ⇋ ${me[1]['ranks'][i]})` ,
|
|
1599
|
+
'rank_diff': rank_diff,
|
|
1600
|
+
'metric': rank_diff < 0 ? -dat.deltas[i] : dat.deltas[i],
|
|
1601
|
+
});
|
|
1602
|
+
}
|
|
1603
|
+
|
|
1604
|
+
return out.slice().sort((a, b) => descending(Math.abs(a.metric), Math.abs(b.metric)))
|
|
1605
|
+
}
|
|
1606
|
+
|
|
1607
|
+
// This function calculates the divergence between two arrays of inverse ranks
|
|
1608
|
+
// based on the specified alpha value. If alpha is equal to infinity, it returns
|
|
1609
|
+
// an array with the maximum of each element in inv_r1 and inv_r2. If alpha is
|
|
1610
|
+
// equal to 0, it returns an array with the log of the ratio of the maximum and
|
|
1611
|
+
// minimum of 1/inv_r1 and 1/inv_r2 for each element. Otherwise, it returns an
|
|
1612
|
+
// array with the absolute value of (alpha + 1)/alpha * (inv_r1^alpha - inv_r2^alpha)^(1/(alpha + 1))
|
|
1613
|
+
// for each element.
|
|
1614
|
+
|
|
1615
|
+
function divElems(inv_r1, inv_r2, alpha) {
|
|
1616
|
+
if (alpha === Infinity) {
|
|
1617
|
+
return inv_r1.map((d,i) => inv_r1[i] == inv_r2[i] ? 0 : Math.max(inv_r1[i], inv_r2[i]))
|
|
1618
|
+
} else if (alpha == 0) {
|
|
1619
|
+
const x_max = inv_r1.map((d,i) => Math.max(1 / inv_r1[i], 1 / inv_r2[i]));
|
|
1620
|
+
const x_min = inv_r1.map((d,i) => Math.min(1 / inv_r1[i], 1 / inv_r2[i]));
|
|
1621
|
+
return inv_r1.map((d,i) => Math.log10(x_max[i] / x_min[i]))
|
|
1622
|
+
} else {
|
|
1623
|
+
return inv_r1.map((d,i) => (alpha+1) / alpha * Math.abs(inv_r1[i]**alpha - inv_r2[i]**alpha)**(1. / (alpha+1)))
|
|
1624
|
+
}
|
|
1625
|
+
}
|
|
1626
|
+
|
|
1627
|
+
// This function calculates the normalization factor for the divergence between
|
|
1628
|
+
// two arrays of inverse ranks. It first extracts the counts from the mixedelements
|
|
1629
|
+
// parameter and finds the indices where the counts are greater than 0. It then
|
|
1630
|
+
// calculates the disjoint set for each array based on the number of non-zero
|
|
1631
|
+
// counts. If alpha is equal to infinity, it returns the sum of the elements in
|
|
1632
|
+
// inv_r1 and inv_r2 for the indices with non-zero counts. If alpha is equal to
|
|
1633
|
+
// 0, it returns the sum of the absolute value of the log of the ratio of each
|
|
1634
|
+
// element in inv_r1 and the disjoint set for inv_r2, and the absolute value of
|
|
1635
|
+
// the log of the ratio of each element in inv_r2 and the disjoint set for inv_r1.
|
|
1636
|
+
// Otherwise, it returns the sum of (alpha + 1)/alpha * (inv_r1^alpha - disjoint set^alpha)^(1/(alpha + 1))
|
|
1637
|
+
// for each element in inv_r1, and the same for inv_r2.
|
|
1638
|
+
|
|
1639
|
+
function norm_divElems(mixedelements, inv_r1, inv_r2, alpha) {
|
|
1640
|
+
const c1 = mixedelements[0]['counts'];
|
|
1641
|
+
const c2 = mixedelements[1]['counts'];
|
|
1642
|
+
|
|
1643
|
+
const indices1 = which(c1.map(d => d > 0));
|
|
1644
|
+
const indices2 = which(c2.map(d => d > 0));
|
|
1645
|
+
|
|
1646
|
+
const N1 = indices1.length;
|
|
1647
|
+
const N2 = indices2.length;
|
|
1648
|
+
|
|
1649
|
+
// This function calculates the disjoint set for a given array of inverse ranks
|
|
1650
|
+
// based on the number of non-zero counts in the array and the number of non-zero
|
|
1651
|
+
// counts in the other array. It returns 1/(number of non-zero counts in other array +
|
|
1652
|
+
// number of non-zero counts in this array/2)
|
|
1653
|
+
|
|
1654
|
+
function calc_disjoint(N1, N2) {
|
|
1655
|
+
return( 1 / (N2 + N1/2) )
|
|
1656
|
+
}
|
|
1657
|
+
|
|
1658
|
+
const inv_r1_disjoint = calc_disjoint(N1, N2);
|
|
1659
|
+
const inv_r2_disjoint = calc_disjoint(N2, N1);
|
|
1660
|
+
|
|
1661
|
+
if (alpha === Infinity) {
|
|
1662
|
+
|
|
1663
|
+
return sum(indices1.map((i) => inv_r1[i])) + sum(indices2.map((i) => inv_r2[i]))
|
|
1664
|
+
|
|
1665
|
+
} else if (alpha === 0) {
|
|
1666
|
+
const term1 = sum(
|
|
1667
|
+
indices1.map((i) => Math.abs(Math.log(inv_r1[i] / inv_r2_disjoint)))
|
|
1668
|
+
);
|
|
1669
|
+
const term2 = sum(
|
|
1670
|
+
indices2.map((i) => Math.abs(Math.log(inv_r2[i] / inv_r1_disjoint)))
|
|
1671
|
+
);
|
|
1672
|
+
return term1 + term2
|
|
1673
|
+
} else {
|
|
1674
|
+
const term1 = (alpha+1)/alpha * sum(
|
|
1675
|
+
indices1.map((i) => inv_r1[i]).map( d => (Math.abs(d**alpha) - inv_r2_disjoint**alpha)**(1./(alpha+1) ))
|
|
1676
|
+
);
|
|
1677
|
+
const term2 = (alpha+1)/alpha * sum(
|
|
1678
|
+
indices2.map((i) => inv_r2[i]).map(d => Math.abs(inv_r1_disjoint**alpha - d**alpha)**(1. / (alpha+1)))
|
|
1679
|
+
);
|
|
1680
|
+
return term1 + term2
|
|
1681
|
+
}
|
|
1682
|
+
}
|
|
1683
|
+
|
|
1684
|
+
// This function calculates the rank turbulence divergence for two arrays of mixed
|
|
1685
|
+
// elements, using the specified alpha value. It first calculates the arrays of
|
|
1686
|
+
// inverse ranks for each mixed element array and then calculates the divergence
|
|
1687
|
+
// and normalization factors using the divElems and norm_divElems functions. It
|
|
1688
|
+
// returns the divergence divided by the normalization.
|
|
1689
|
+
|
|
1690
|
+
function rank_turbulence_divergence(mixedelements, alpha) {
|
|
1691
|
+
|
|
1692
|
+
const inv_r1 = mixedelements[0]['ranks'].map(d => Math.pow(d, -1));
|
|
1693
|
+
const inv_r2 = mixedelements[1]['ranks'].map(d => Math.pow(d, -1));
|
|
1694
|
+
|
|
1695
|
+
const divergence_elements = divElems(inv_r1, inv_r2, alpha);
|
|
1696
|
+
const normalization = norm_divElems(mixedelements, inv_r1, inv_r2, alpha);
|
|
1697
|
+
|
|
1698
|
+
return { // the divergence used to wordshift dat to sort name in wordshift plot
|
|
1699
|
+
// is equal to the formula in the upperleft of the diamond plot. However
|
|
1700
|
+
// the formula is a proportionality and miss the normalization constant
|
|
1701
|
+
// shown here.
|
|
1702
|
+
// Example: for alpha = infinity, for the rank 1 names on both systems, the formula as written is equal to max(1/1, 1/former_rank) = 1/1 =1
|
|
1703
|
+
// this value of 1 is then divided by the normalization constant.
|
|
1704
|
+
// this constant of proportionality is the reason for the difference between the 1/1 that the written formula gives you
|
|
1705
|
+
// and the decimal value that wordshift_dat states and which is actuallly used to sort the types.
|
|
1706
|
+
'divergence_elements': divergence_elements.map(d => d / normalization),
|
|
1707
|
+
'normalization': normalization
|
|
1708
|
+
}
|
|
1709
|
+
}
|
|
1710
|
+
|
|
1711
|
+
const VOID = -1;
|
|
1712
|
+
const PRIMITIVE = 0;
|
|
1713
|
+
const ARRAY = 1;
|
|
1714
|
+
const OBJECT = 2;
|
|
1715
|
+
const DATE = 3;
|
|
1716
|
+
const REGEXP = 4;
|
|
1717
|
+
const MAP = 5;
|
|
1718
|
+
const SET = 6;
|
|
1719
|
+
const ERROR = 7;
|
|
1720
|
+
const BIGINT = 8;
|
|
1721
|
+
// export const SYMBOL = 9;
|
|
1722
|
+
|
|
1723
|
+
const env = typeof self === 'object' ? self : globalThis;
|
|
1724
|
+
|
|
1725
|
+
const deserializer = ($, _) => {
|
|
1726
|
+
const as = (out, index) => {
|
|
1727
|
+
$.set(index, out);
|
|
1728
|
+
return out;
|
|
1729
|
+
};
|
|
1730
|
+
|
|
1731
|
+
const unpair = index => {
|
|
1732
|
+
if ($.has(index))
|
|
1733
|
+
return $.get(index);
|
|
1734
|
+
|
|
1735
|
+
const [type, value] = _[index];
|
|
1736
|
+
switch (type) {
|
|
1737
|
+
case PRIMITIVE:
|
|
1738
|
+
case VOID:
|
|
1739
|
+
return as(value, index);
|
|
1740
|
+
case ARRAY: {
|
|
1741
|
+
const arr = as([], index);
|
|
1742
|
+
for (const index of value)
|
|
1743
|
+
arr.push(unpair(index));
|
|
1744
|
+
return arr;
|
|
1745
|
+
}
|
|
1746
|
+
case OBJECT: {
|
|
1747
|
+
const object = as({}, index);
|
|
1748
|
+
for (const [key, index] of value)
|
|
1749
|
+
object[unpair(key)] = unpair(index);
|
|
1750
|
+
return object;
|
|
1751
|
+
}
|
|
1752
|
+
case DATE:
|
|
1753
|
+
return as(new Date(value), index);
|
|
1754
|
+
case REGEXP: {
|
|
1755
|
+
const {source, flags} = value;
|
|
1756
|
+
return as(new RegExp(source, flags), index);
|
|
1757
|
+
}
|
|
1758
|
+
case MAP: {
|
|
1759
|
+
const map = as(new Map, index);
|
|
1760
|
+
for (const [key, index] of value)
|
|
1761
|
+
map.set(unpair(key), unpair(index));
|
|
1762
|
+
return map;
|
|
1763
|
+
}
|
|
1764
|
+
case SET: {
|
|
1765
|
+
const set = as(new Set, index);
|
|
1766
|
+
for (const index of value)
|
|
1767
|
+
set.add(unpair(index));
|
|
1768
|
+
return set;
|
|
1769
|
+
}
|
|
1770
|
+
case ERROR: {
|
|
1771
|
+
const {name, message} = value;
|
|
1772
|
+
return as(new env[name](message), index);
|
|
1773
|
+
}
|
|
1774
|
+
case BIGINT:
|
|
1775
|
+
return as(BigInt(value), index);
|
|
1776
|
+
case 'BigInt':
|
|
1777
|
+
return as(Object(BigInt(value)), index);
|
|
1778
|
+
case 'ArrayBuffer':
|
|
1779
|
+
return as(new Uint8Array(value).buffer, value);
|
|
1780
|
+
case 'DataView': {
|
|
1781
|
+
const { buffer } = new Uint8Array(value);
|
|
1782
|
+
return as(new DataView(buffer), value);
|
|
1783
|
+
}
|
|
1784
|
+
}
|
|
1785
|
+
return as(new env[type](value), index);
|
|
1786
|
+
};
|
|
1787
|
+
|
|
1788
|
+
return unpair;
|
|
1789
|
+
};
|
|
1790
|
+
|
|
1791
|
+
/**
|
|
1792
|
+
* @typedef {Array<string,any>} Record a type representation
|
|
1793
|
+
*/
|
|
1794
|
+
|
|
1795
|
+
/**
|
|
1796
|
+
* Returns a deserialized value from a serialized array of Records.
|
|
1797
|
+
* @param {Record[]} serialized a previously serialized value.
|
|
1798
|
+
* @returns {any}
|
|
1799
|
+
*/
|
|
1800
|
+
const deserialize = serialized => deserializer(new Map, serialized)(0);
|
|
1801
|
+
|
|
1802
|
+
const EMPTY = '';
|
|
1803
|
+
|
|
1804
|
+
const {toString} = {};
|
|
1805
|
+
const {keys} = Object;
|
|
1806
|
+
|
|
1807
|
+
const typeOf = value => {
|
|
1808
|
+
const type = typeof value;
|
|
1809
|
+
if (type !== 'object' || !value)
|
|
1810
|
+
return [PRIMITIVE, type];
|
|
1811
|
+
|
|
1812
|
+
const asString = toString.call(value).slice(8, -1);
|
|
1813
|
+
switch (asString) {
|
|
1814
|
+
case 'Array':
|
|
1815
|
+
return [ARRAY, EMPTY];
|
|
1816
|
+
case 'Object':
|
|
1817
|
+
return [OBJECT, EMPTY];
|
|
1818
|
+
case 'Date':
|
|
1819
|
+
return [DATE, EMPTY];
|
|
1820
|
+
case 'RegExp':
|
|
1821
|
+
return [REGEXP, EMPTY];
|
|
1822
|
+
case 'Map':
|
|
1823
|
+
return [MAP, EMPTY];
|
|
1824
|
+
case 'Set':
|
|
1825
|
+
return [SET, EMPTY];
|
|
1826
|
+
case 'DataView':
|
|
1827
|
+
return [ARRAY, asString];
|
|
1828
|
+
}
|
|
1829
|
+
|
|
1830
|
+
if (asString.includes('Array'))
|
|
1831
|
+
return [ARRAY, asString];
|
|
1832
|
+
|
|
1833
|
+
if (asString.includes('Error'))
|
|
1834
|
+
return [ERROR, asString];
|
|
1835
|
+
|
|
1836
|
+
return [OBJECT, asString];
|
|
1837
|
+
};
|
|
1838
|
+
|
|
1839
|
+
const shouldSkip = ([TYPE, type]) => (
|
|
1840
|
+
TYPE === PRIMITIVE &&
|
|
1841
|
+
(type === 'function' || type === 'symbol')
|
|
1842
|
+
);
|
|
1843
|
+
|
|
1844
|
+
const serializer = (strict, json, $, _) => {
|
|
1845
|
+
|
|
1846
|
+
const as = (out, value) => {
|
|
1847
|
+
const index = _.push(out) - 1;
|
|
1848
|
+
$.set(value, index);
|
|
1849
|
+
return index;
|
|
1850
|
+
};
|
|
1851
|
+
|
|
1852
|
+
const pair = value => {
|
|
1853
|
+
if ($.has(value))
|
|
1854
|
+
return $.get(value);
|
|
1855
|
+
|
|
1856
|
+
let [TYPE, type] = typeOf(value);
|
|
1857
|
+
switch (TYPE) {
|
|
1858
|
+
case PRIMITIVE: {
|
|
1859
|
+
let entry = value;
|
|
1860
|
+
switch (type) {
|
|
1861
|
+
case 'bigint':
|
|
1862
|
+
TYPE = BIGINT;
|
|
1863
|
+
entry = value.toString();
|
|
1864
|
+
break;
|
|
1865
|
+
case 'function':
|
|
1866
|
+
case 'symbol':
|
|
1867
|
+
if (strict)
|
|
1868
|
+
throw new TypeError('unable to serialize ' + type);
|
|
1869
|
+
entry = null;
|
|
1870
|
+
break;
|
|
1871
|
+
case 'undefined':
|
|
1872
|
+
return as([VOID], value);
|
|
1873
|
+
}
|
|
1874
|
+
return as([TYPE, entry], value);
|
|
1875
|
+
}
|
|
1876
|
+
case ARRAY: {
|
|
1877
|
+
if (type) {
|
|
1878
|
+
let spread = value;
|
|
1879
|
+
if (type === 'DataView') {
|
|
1880
|
+
spread = new Uint8Array(value.buffer);
|
|
1881
|
+
}
|
|
1882
|
+
else if (type === 'ArrayBuffer') {
|
|
1883
|
+
spread = new Uint8Array(value);
|
|
1884
|
+
}
|
|
1885
|
+
return as([type, [...spread]], value);
|
|
1886
|
+
}
|
|
1887
|
+
|
|
1888
|
+
const arr = [];
|
|
1889
|
+
const index = as([TYPE, arr], value);
|
|
1890
|
+
for (const entry of value)
|
|
1891
|
+
arr.push(pair(entry));
|
|
1892
|
+
return index;
|
|
1893
|
+
}
|
|
1894
|
+
case OBJECT: {
|
|
1895
|
+
if (type) {
|
|
1896
|
+
switch (type) {
|
|
1897
|
+
case 'BigInt':
|
|
1898
|
+
return as([type, value.toString()], value);
|
|
1899
|
+
case 'Boolean':
|
|
1900
|
+
case 'Number':
|
|
1901
|
+
case 'String':
|
|
1902
|
+
return as([type, value.valueOf()], value);
|
|
1903
|
+
}
|
|
1904
|
+
}
|
|
1905
|
+
|
|
1906
|
+
if (json && ('toJSON' in value))
|
|
1907
|
+
return pair(value.toJSON());
|
|
1908
|
+
|
|
1909
|
+
const entries = [];
|
|
1910
|
+
const index = as([TYPE, entries], value);
|
|
1911
|
+
for (const key of keys(value)) {
|
|
1912
|
+
if (strict || !shouldSkip(typeOf(value[key])))
|
|
1913
|
+
entries.push([pair(key), pair(value[key])]);
|
|
1914
|
+
}
|
|
1915
|
+
return index;
|
|
1916
|
+
}
|
|
1917
|
+
case DATE:
|
|
1918
|
+
return as([TYPE, value.toISOString()], value);
|
|
1919
|
+
case REGEXP: {
|
|
1920
|
+
const {source, flags} = value;
|
|
1921
|
+
return as([TYPE, {source, flags}], value);
|
|
1922
|
+
}
|
|
1923
|
+
case MAP: {
|
|
1924
|
+
const entries = [];
|
|
1925
|
+
const index = as([TYPE, entries], value);
|
|
1926
|
+
for (const [key, entry] of value) {
|
|
1927
|
+
if (strict || !(shouldSkip(typeOf(key)) || shouldSkip(typeOf(entry))))
|
|
1928
|
+
entries.push([pair(key), pair(entry)]);
|
|
1929
|
+
}
|
|
1930
|
+
return index;
|
|
1931
|
+
}
|
|
1932
|
+
case SET: {
|
|
1933
|
+
const entries = [];
|
|
1934
|
+
const index = as([TYPE, entries], value);
|
|
1935
|
+
for (const entry of value) {
|
|
1936
|
+
if (strict || !shouldSkip(typeOf(entry)))
|
|
1937
|
+
entries.push(pair(entry));
|
|
1938
|
+
}
|
|
1939
|
+
return index;
|
|
1940
|
+
}
|
|
1941
|
+
}
|
|
1942
|
+
|
|
1943
|
+
const {message} = value;
|
|
1944
|
+
return as([TYPE, {name: type, message}], value);
|
|
1945
|
+
};
|
|
1946
|
+
|
|
1947
|
+
return pair;
|
|
1948
|
+
};
|
|
1949
|
+
|
|
1950
|
+
/**
|
|
1951
|
+
* @typedef {Array<string,any>} Record a type representation
|
|
1952
|
+
*/
|
|
1953
|
+
|
|
1954
|
+
/**
|
|
1955
|
+
* Returns an array of serialized Records.
|
|
1956
|
+
* @param {any} value a serializable value.
|
|
1957
|
+
* @param {{json?: boolean, lossy?: boolean}?} options an object with a `lossy` or `json` property that,
|
|
1958
|
+
* if `true`, will not throw errors on incompatible types, and behave more
|
|
1959
|
+
* like JSON stringify would behave. Symbol and Function will be discarded.
|
|
1960
|
+
* @returns {Record[]}
|
|
1961
|
+
*/
|
|
1962
|
+
const serialize = (value, {json, lossy} = {}) => {
|
|
1963
|
+
const _ = [];
|
|
1964
|
+
return serializer(!(json || lossy), !!json, new Map, _)(value), _;
|
|
1965
|
+
};
|
|
1966
|
+
|
|
1967
|
+
/**
|
|
1968
|
+
* @typedef {Array<string,any>} Record a type representation
|
|
1969
|
+
*/
|
|
1970
|
+
|
|
1971
|
+
/**
|
|
1972
|
+
* Returns an array of serialized Records.
|
|
1973
|
+
* @param {any} any a serializable value.
|
|
1974
|
+
* @param {{transfer?: any[], json?: boolean, lossy?: boolean}?} options an object with
|
|
1975
|
+
* a transfer option (ignored when polyfilled) and/or non standard fields that
|
|
1976
|
+
* fallback to the polyfill if present.
|
|
1977
|
+
* @returns {Record[]}
|
|
1978
|
+
*/
|
|
1979
|
+
const structuredClone$1 = typeof structuredClone === "function" ?
|
|
1980
|
+
/* c8 ignore start */
|
|
1981
|
+
(any, options) => (
|
|
1982
|
+
options && ('json' in options || 'lossy' in options) ?
|
|
1983
|
+
deserialize(serialize(any, options)) : structuredClone(any)
|
|
1984
|
+
) :
|
|
1985
|
+
(any, options) => deserialize(serialize(any, options));
|
|
1986
|
+
|
|
1987
|
+
function rank2coord(rank) { return Math.floor(Math.log10(rank) / (1/15)) }
|
|
1988
|
+
|
|
1989
|
+
// Augment information already in `me` class with coordinates.
|
|
1990
|
+
function diamond_counts(mixedelements) {
|
|
1991
|
+
|
|
1992
|
+
let maxlog10 = rank_maxlog10(mixedelements); // max of values of me[system]['rank'] in logspace
|
|
1993
|
+
|
|
1994
|
+
if (maxlog10 < 1) {
|
|
1995
|
+
maxlog10 = 1;
|
|
1996
|
+
}
|
|
1997
|
+
|
|
1998
|
+
const CELL_LENGTH = 1/15;
|
|
1999
|
+
const Ncells = Math.floor(maxlog10/CELL_LENGTH) + 1;
|
|
2000
|
+
|
|
2001
|
+
// me = mixed elements which is of the form:
|
|
2002
|
+
// [array_from_system_L, array_from_system_R]
|
|
2003
|
+
// where each array is of the form [types:{types}, counts:{counts}, ranks:{ranks}, probs:{probs}, totalunique]
|
|
2004
|
+
// where types is in the order [rank1TypeFromL, rank1TypeFromR, ... rankMaxTypeFromL, rankMaxTypeFromR] and if there is a tie it goes ... ranknTypeFromL, ranknTypeFromR_1, ranknTypeFromR_2, ranknplus1TypeFromL ... Example 1880-2015 charlie and clarence tie from left
|
|
2005
|
+
// counts, ranks, and probs are correct corresponding to the types
|
|
2006
|
+
const x1s = mixedelements[0]['ranks'].map(r => rank2coord(r)); // Math.floor(Math.log10(rank) / (1/15))
|
|
2007
|
+
const y1s = mixedelements[1]['ranks'].map(r => rank2coord(r));
|
|
2008
|
+
|
|
2009
|
+
// all the combination of coords that exists. There are many duplicated coords.
|
|
2010
|
+
const existing_coords = Array.from(mixedelements[0]['ranks'], (d,i) => { return `(${x1s[i]}, ${y1s[i]})` }); // for i in range(len(me[0]['ranks'])), existing_coords.append('x1s[i], y1s[i]'). or alternatively existing_coords = [str(pair) for pair in zip(x1s, y1s)]
|
|
2011
|
+
// note we make this a tring so that indexOf works later. In python we would use a 2-tuple
|
|
2012
|
+
|
|
2013
|
+
// return existing_coords
|
|
2014
|
+
|
|
2015
|
+
const out = [];
|
|
2016
|
+
// iterate through each cell
|
|
2017
|
+
for (var i=0; i < Ncells; i++) { // Ncells is the length of the square matrix (note 1-d length not total number of cells)
|
|
2018
|
+
for (var j=0; j < Ncells; j++) {
|
|
2019
|
+
|
|
2020
|
+
// Does coords (i,j) are in existing_coords?
|
|
2021
|
+
if ( existing_coords.indexOf(`(${i}, ${j})`) === -1) {
|
|
2022
|
+
out.push({ types: "", x1: i, y1: j, rank1: "", rank2: "" }); // if it doesnt exist, thats a blank cell, make the data there blank
|
|
2023
|
+
} else { //if that coordinate is full of data
|
|
2024
|
+
const indices_coords_in_exist_coords = which(rin(existing_coords, `(${i}, ${j})`)); //rin(arr1, arr2) = [foo is in arr2 for foo in arr1]. rin([3, 4, 5], [3]) = [true, false, false], then the which is returning the indices of the elements which are true. So in the end this is getting all the indices where '${i}, ${j})' appears in existing_coords. When there are ties, the same coordinate appears multiple times in a row in exisiting_coords and so indices_coords_in_exist_coords will be an array with multiple indices
|
|
2025
|
+
|
|
2026
|
+
for (let z=0; z < indices_coords_in_exist_coords.length; z++ ) {
|
|
2027
|
+
out.push({
|
|
2028
|
+
types: mixedelements[0]['types'][indices_coords_in_exist_coords[z]],
|
|
2029
|
+
x1: i,
|
|
2030
|
+
y1: j,
|
|
2031
|
+
rank1: mixedelements[0]['ranks'][indices_coords_in_exist_coords[z]],
|
|
2032
|
+
rank2: mixedelements[1]['ranks'][indices_coords_in_exist_coords[z]]
|
|
2033
|
+
});
|
|
2034
|
+
}
|
|
2035
|
+
}
|
|
2036
|
+
}
|
|
2037
|
+
}
|
|
2038
|
+
// group data by unique coordinates
|
|
2039
|
+
const agg_dat = group(out, d => `${d.x1}, ${d.y1}`);
|
|
2040
|
+
|
|
2041
|
+
return Array.from(agg_dat , ([ key, value ]) => {
|
|
2042
|
+
const x1 = +key.split(", ")[1]; // 2
|
|
2043
|
+
const y1 = +key.split(", ")[0]; // 7
|
|
2044
|
+
return {
|
|
2045
|
+
x1: x1,
|
|
2046
|
+
y1: y1,
|
|
2047
|
+
coord_on_diag: (y1+x1)/2,
|
|
2048
|
+
cos_dist: (x1-y1)**2,
|
|
2049
|
+
rank: value.map(d => d.types)[0] === "" ? "" : value.map(d => `(${d.rank1}, ${d.rank2})`)[0],
|
|
2050
|
+
rank_L: value.map(d => d.types)[0] === "" ? "" : extent$1(value.map(d => d.rank1)),
|
|
2051
|
+
rank_R: value.map(d => d.types)[0] === "" ? "" : extent$1(value.map(d => d.rank2)),
|
|
2052
|
+
value: value.map(d => d.types)[0] === "" ? 0 : value.length,
|
|
2053
|
+
types: value.map(d => d.types).join(', '),
|
|
2054
|
+
which_sys: x1 - y1 <= 0 ? "right" : "left"
|
|
2055
|
+
}
|
|
2056
|
+
})
|
|
2057
|
+
}
|
|
2058
|
+
|
|
2059
|
+
|
|
2060
|
+
// we expect wordshift to be of the form { divergence_elements: [ length of type ], normalization: float }
|
|
2061
|
+
function diamond_count(mixedelements, wordshift) {
|
|
2062
|
+
|
|
2063
|
+
let deltas = wordshift["divergence_elements"];
|
|
2064
|
+
let sorted_div = matlab_sort(deltas, true);
|
|
2065
|
+
let indices_deltas = sorted_div.orig_idx;
|
|
2066
|
+
|
|
2067
|
+
deltas = indices_deltas.map(e => deltas[e]);
|
|
2068
|
+
|
|
2069
|
+
|
|
2070
|
+
mixedelements[0]['types'] = indices_deltas.map(i => mixedelements[0]['types'][i]);
|
|
2071
|
+
mixedelements[0]['counts'] = indices_deltas.map(i => mixedelements[0]['counts'][i]);
|
|
2072
|
+
mixedelements[0]['ranks'] = indices_deltas.map(i => mixedelements[0]['ranks'][i]);
|
|
2073
|
+
mixedelements[0]['probs'] = indices_deltas.map(i => mixedelements[0]['probs'][i]);
|
|
2074
|
+
|
|
2075
|
+
mixedelements[1]['types'] = indices_deltas.map(i => mixedelements[1]['types'][i]);
|
|
2076
|
+
mixedelements[1]['counts'] = indices_deltas.map(i => mixedelements[1]['counts'][i]);
|
|
2077
|
+
mixedelements[1]['ranks'] = indices_deltas.map(i => mixedelements[1]['ranks'][i]);
|
|
2078
|
+
mixedelements[1]['probs'] = indices_deltas.map(i => mixedelements[1]['probs'][i]);
|
|
2079
|
+
|
|
2080
|
+
const deltas_loss = structuredClone$1(deltas);
|
|
2081
|
+
const deltas_gain = structuredClone$1(deltas);
|
|
2082
|
+
|
|
2083
|
+
which(mixedelements[0]['ranks'].map((d,i) => mixedelements[0]['ranks'][i] > mixedelements[1]['ranks'][i])).map(e => deltas_loss[e] = -1);
|
|
2084
|
+
which(mixedelements[0]['ranks'].map((d,i) => mixedelements[1]['ranks'][i] < mixedelements[1]['ranks'][i])).map(e => deltas_gain[e] = -1);
|
|
2085
|
+
|
|
2086
|
+
|
|
2087
|
+
const counts = diamond_counts(mixedelements);
|
|
2088
|
+
|
|
2089
|
+
return({'counts': counts, 'deltas': deltas, 'max_delta_loss': Math.max(...deltas_loss)})
|
|
1108
2090
|
}
|
|
1109
2091
|
|
|
1110
|
-
export { Dashboard, Diamond, DivergingBarChart, Legend,
|
|
2092
|
+
export { Dashboard, Diamond, DivergingBarChart, Legend, Wordshift, balanceDat, combElems, diamond_count, matlab_sort, rank_maxlog10, rank_turbulence_divergence, rin, tiedrank, which, wordShift_dat, zeros };
|