linny-r 1.5.4 → 1.5.5
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/package.json
CHANGED
package/static/linny-r.css
CHANGED
@@ -360,11 +360,15 @@ class GUIExperimentManager extends ExperimentManager {
|
|
360
360
|
this.params_div.style.display = 'block';
|
361
361
|
const tr = [];
|
362
362
|
for(let i = 0; i < x.dimensions.length; i++) {
|
363
|
+
const pi = 'd' + i;
|
363
364
|
tr.push(['<tr class="dataset',
|
364
|
-
|
365
|
-
'
|
366
|
-
|
367
|
-
|
365
|
+
// Highlight selected dimension with background color.
|
366
|
+
(this.selected_parameter == pi ? ' sel-set' : ''),
|
367
|
+
// Show dimension in bold purple if it is a plot dimension.
|
368
|
+
(x.plot_dimensions.indexOf(i) >= 0 ? ' def-sel' : ''),
|
369
|
+
'" onclick="EXPERIMENT_MANAGER.selectParameter(\'', pi,
|
370
|
+
// Click selects, shift-click will also toggle plot/no plot.
|
371
|
+
'\', event.shiftKey);"><td>', setString(x.dimensions[i]),
|
368
372
|
'</td></tr>'].join(''));
|
369
373
|
}
|
370
374
|
this.dimension_table.innerHTML = tr.join('');
|
@@ -635,11 +639,13 @@ class GUIExperimentManager extends ExperimentManager {
|
|
635
639
|
} else {
|
636
640
|
rsp = '';
|
637
641
|
}
|
638
|
-
// Calculate the dimension selector index
|
642
|
+
// Calculate the dimension selector index.
|
639
643
|
const dsi = Math.floor(
|
640
644
|
i / rowsperdim[j]) % this.clean_rows[j].length;
|
641
645
|
lth += ['<th', rsp, ' class="scen-hdr" style="background-color: ',
|
642
|
-
'rgba(100, 170, 255, ', 1 - j * bstep,
|
646
|
+
'rgba(100, 170, 255, ', 1 - j * bstep,
|
647
|
+
')" onclick="EXPERIMENT_MANAGER.toggleChartRow(', i,
|
648
|
+
', ', rowsperdim[j], ', event.shiftKey);">',
|
643
649
|
this.clean_rows[j][dsi], '</th>'].join('');
|
644
650
|
}
|
645
651
|
}
|
@@ -661,22 +667,29 @@ class GUIExperimentManager extends ExperimentManager {
|
|
661
667
|
}
|
662
668
|
}
|
663
669
|
|
664
|
-
toggleChartRow(r, n, shift) {
|
670
|
+
toggleChartRow(r, n=1, shift=false) {
|
665
671
|
// Toggle `n` consecutive rows, starting at row `r` (0 = top), to be
|
666
|
-
// (no longer) part of the chart combination set
|
672
|
+
// (no longer) part of the chart combination set.
|
673
|
+
// @@TO DO: shift-key indicates "add row(s) to selection"
|
667
674
|
const
|
668
675
|
x = this.selected_experiment,
|
669
|
-
// Let `
|
670
|
-
|
671
|
-
|
672
|
-
|
673
|
-
|
674
|
-
|
675
|
-
|
676
|
-
|
677
|
-
|
678
|
-
|
679
|
-
|
676
|
+
// Let `first` be the number of the first run on row `r`.
|
677
|
+
ncols = this.nr_of_configurations,
|
678
|
+
nrows = x.combinations.length / ncols;
|
679
|
+
if(x && r < nrows) {
|
680
|
+
// NOTE: First cell in rows determines ADD or REMOVE.
|
681
|
+
const add = shift || x.chart_combinations.indexOf(r) < 0;
|
682
|
+
if(!shift) x.chart_combinations.length = 0;
|
683
|
+
for(let i = 0; i < ncols; i++) {
|
684
|
+
for(let j = 0; j < n; j++) {
|
685
|
+
const
|
686
|
+
c = r + j + i * nrows,
|
687
|
+
ic = x.chart_combinations.indexOf(c);
|
688
|
+
if(add) {
|
689
|
+
if(ic < 0) x.chart_combinations.push(c);
|
690
|
+
} else {
|
691
|
+
if(ic >= 0) x.chart_combinations.splice(ic, 1);
|
692
|
+
}
|
680
693
|
}
|
681
694
|
}
|
682
695
|
this.updateData();
|
@@ -1048,10 +1061,22 @@ N = ${rr.N}, vector length = ${rr.vector.length}` : '')].join('');
|
|
1048
1061
|
}
|
1049
1062
|
}
|
1050
1063
|
|
1051
|
-
selectParameter(p) {
|
1064
|
+
selectParameter(p, shift=false) {
|
1065
|
+
const dim = p.startsWith('d');
|
1052
1066
|
this.selected_parameter = p;
|
1053
|
-
this.focal_table = (
|
1054
|
-
|
1067
|
+
this.focal_table = (dim ? this.dimension_table : this.chart_table);
|
1068
|
+
if(dim && shift) {
|
1069
|
+
const
|
1070
|
+
x = this.selected_experiment,
|
1071
|
+
di = parseInt(p.substring(1)),
|
1072
|
+
pi = x.plot_dimensions.indexOf(di);
|
1073
|
+
if(pi < 0) {
|
1074
|
+
x.plot_dimensions.push(di);
|
1075
|
+
} else {
|
1076
|
+
x.plot_dimensions.splice(pi, 1);
|
1077
|
+
}
|
1078
|
+
if(CHART_MANAGER.runs_stat) CHART_MANAGER.updateDialog();
|
1079
|
+
}
|
1055
1080
|
this.updateDialog();
|
1056
1081
|
}
|
1057
1082
|
|
@@ -9522,13 +9522,26 @@ class Chart {
|
|
9522
9522
|
rh = height - rt - margin - font_height,
|
9523
9523
|
// Keep track of the number of visible chart variables
|
9524
9524
|
vv = 0;
|
9525
|
-
// Reserve vertical space for title (if shown)
|
9525
|
+
// Reserve vertical space for title (if shown).
|
9526
9526
|
if(this.show_title) {
|
9527
9527
|
// NOTE: use title font size 120% of default
|
9528
9528
|
const th = 1.2 * font_height + margin;
|
9529
9529
|
rt += th;
|
9530
9530
|
rh -= th;
|
9531
9531
|
}
|
9532
|
+
// If run result statistics are plotted, reserve vertical space for
|
9533
|
+
// bar chart run dimension selectors.
|
9534
|
+
const
|
9535
|
+
selx = EXPERIMENT_MANAGER.selected_experiment,
|
9536
|
+
stat_bars = CHART_MANAGER.runs_stat;
|
9537
|
+
if(stat_bars) {
|
9538
|
+
if(selx) {
|
9539
|
+
// First plot dimension will replace run numbers, so only reserve
|
9540
|
+
// space for additional plot dimensions.
|
9541
|
+
const dh = 1.2 * font_height * (selx.plot_dimensions.length - 1);
|
9542
|
+
if(dh > 0) rh -= dh;
|
9543
|
+
}
|
9544
|
+
}
|
9532
9545
|
if(this.variables.length > 0) {
|
9533
9546
|
// Count visible variables and estimate total width of their names
|
9534
9547
|
// as well as the width of the longest name
|
@@ -9584,7 +9597,7 @@ class Chart {
|
|
9584
9597
|
if(v.visible) {
|
9585
9598
|
// Add arrow indicating sort direction to name if applicable.
|
9586
9599
|
const vn = v.displayName + CHART_MANAGER.sort_arrows[v.sorted];
|
9587
|
-
if(v.stacked || this.histogram) {
|
9600
|
+
if(v.stacked || this.histogram || stat_bars) {
|
9588
9601
|
this.addSVG(['<rect x="', x, '" y="', y - sym_size + 2,
|
9589
9602
|
'" width="', sym_size, '" height="', sym_size,
|
9590
9603
|
'" fill="', v.color,'" fill-opacity="0.35" stroke="',
|
@@ -9612,10 +9625,7 @@ class Chart {
|
|
9612
9625
|
|
9613
9626
|
// NOTE: chart may display experiment run results, rather than MODEL results
|
9614
9627
|
let runnrs = '';
|
9615
|
-
const
|
9616
|
-
selx = EXPERIMENT_MANAGER.selected_experiment,
|
9617
|
-
runs = EXPERIMENT_MANAGER.selectedRuns(this),
|
9618
|
-
stat_bars = CHART_MANAGER.runs_stat;
|
9628
|
+
const runs = EXPERIMENT_MANAGER.selectedRuns(this);
|
9619
9629
|
if(runs.length > 0) {
|
9620
9630
|
const stat = (stat_bars ?
|
9621
9631
|
EXPERIMENT_MANAGER.selectedStatisticName + ' for ': '');
|
@@ -9786,7 +9796,10 @@ class Chart {
|
|
9786
9796
|
}
|
9787
9797
|
|
9788
9798
|
if(time_steps > 0) {
|
9789
|
-
let dx = 0,
|
9799
|
+
let dx = 0,
|
9800
|
+
dy = 0,
|
9801
|
+
x = 0,
|
9802
|
+
y = rt + rh + font_height;
|
9790
9803
|
if(this.histogram) {
|
9791
9804
|
// Draw bin boundaries along the horizontal axis
|
9792
9805
|
dx = rw / this.bins;
|
@@ -9818,8 +9831,18 @@ class Chart {
|
|
9818
9831
|
'" x2="', x, '" y2="', rt + rh + 3,
|
9819
9832
|
'" stroke="black" stroke-width="1.5"/>']);
|
9820
9833
|
}
|
9821
|
-
|
9822
|
-
|
9834
|
+
if(selx.plot_dimensions.length > 0) {
|
9835
|
+
// Draw run selectors for each plot dimension above each other.
|
9836
|
+
const ac = selx.combinations[runs[i]];
|
9837
|
+
let pdy = y;
|
9838
|
+
for(let j = 0; j < selx.plot_dimensions.length; j++) {
|
9839
|
+
this.addText(x - dx / 2, pdy, ac[selx.plot_dimensions[j]]);
|
9840
|
+
pdy += font_height;
|
9841
|
+
}
|
9842
|
+
} else {
|
9843
|
+
// Draw experiment number in middle of its horizontal area.
|
9844
|
+
this.addText(x - dx / 2, y, '#' + runs[i]);
|
9845
|
+
}
|
9823
9846
|
x += dx;
|
9824
9847
|
}
|
9825
9848
|
} else {
|
@@ -10850,6 +10873,7 @@ class Experiment {
|
|
10850
10873
|
this.dimensions = [];
|
10851
10874
|
this.charts = [];
|
10852
10875
|
this.actual_dimensions = [];
|
10876
|
+
this.plot_dimensions = [];
|
10853
10877
|
this.combinations = [];
|
10854
10878
|
this.variables = [];
|
10855
10879
|
this.configuration_dims = 0;
|
@@ -11058,7 +11082,8 @@ class Experiment {
|
|
11058
11082
|
'"><title>', xmlEncoded(this.title),
|
11059
11083
|
'</title><notes>', xmlEncoded(this.comments),
|
11060
11084
|
'</notes><dimensions>', d,
|
11061
|
-
'</dimensions><
|
11085
|
+
'</dimensions><plot-dimensions>', this.plot_dimensions.join(','),
|
11086
|
+
'</plot-dimensions><chart-titles>', ct,
|
11062
11087
|
'</chart-titles><settings-selectors>', ss,
|
11063
11088
|
'</settings-selectors><settings-dimensions>', sd,
|
11064
11089
|
'</settings-dimensions><combination-selectors>', cs,
|
@@ -11103,6 +11128,13 @@ class Experiment {
|
|
11103
11128
|
}
|
11104
11129
|
}
|
11105
11130
|
}
|
11131
|
+
n = nodeContentByTag(node, 'plot-dimensions');
|
11132
|
+
if(n) {
|
11133
|
+
this.plot_dimensions = n.split(',');
|
11134
|
+
for(let i = 0; i < this.plot_dimensions.length; i++) {
|
11135
|
+
this.plot_dimensions[i] = parseInt(this.plot_dimensions[i]);
|
11136
|
+
}
|
11137
|
+
}
|
11106
11138
|
n = childNodeByTag(node, 'chart-titles');
|
11107
11139
|
if(n && n.childNodes) {
|
11108
11140
|
for(let i = 0; i < n.childNodes.length; i++) {
|
@@ -590,9 +590,64 @@ function mergeDistinct(list, into) {
|
|
590
590
|
}
|
591
591
|
}
|
592
592
|
|
593
|
+
function iteratorSet(list) {
|
594
|
+
// Returns TRUE iff list is something like ['i=1', 'i=2', 'i=3'].
|
595
|
+
if(list.length === 0) return false;
|
596
|
+
// Analyze the first element: must start with i=, j= or k=.
|
597
|
+
const
|
598
|
+
parts = list[0].split('='),
|
599
|
+
iterator = parts[0];
|
600
|
+
if(parts.length !== 2 || 'ijk'.indexOf(iterator) < 0) return false;
|
601
|
+
// Left-hand part must be an integer number: the first iterator value.
|
602
|
+
const first = parts[1] - 0;
|
603
|
+
if(first != parts[1]) return false;
|
604
|
+
// If OK, generate the list one would expect.
|
605
|
+
const
|
606
|
+
series = [],
|
607
|
+
last = first + list.length - 1;
|
608
|
+
for(let i = first; i <= last; i++) {
|
609
|
+
series.push(iterator + '=' + i);
|
610
|
+
}
|
611
|
+
// Then compare with the list to be tested.
|
612
|
+
if(list.join(',') === series.join(',')) {
|
613
|
+
// If match, return a shorthand string like 'i=1, ..., i=5'.
|
614
|
+
// NOTE: No ellipsis if fewer than 4 steps.
|
615
|
+
if(list.length < 4) return `{${list.join(', ')}}`;
|
616
|
+
return `{${list[0]}, ..., ${list[list.length - 1]}}`;
|
617
|
+
}
|
618
|
+
return false;
|
619
|
+
}
|
620
|
+
|
621
|
+
function integerSet(list) {
|
622
|
+
// Returns TRUE iff all elements in list evaluate as integer numbers.
|
623
|
+
if(list.length === 0) return false;
|
624
|
+
for(let i = 0; i < list.length; i++) {
|
625
|
+
if(list[i] - 0 != list[i]) return false;
|
626
|
+
}
|
627
|
+
return true;
|
628
|
+
}
|
629
|
+
|
593
630
|
function setString(sl) {
|
594
631
|
// Returns elements of stringlist `sl` in set notation
|
595
|
-
|
632
|
+
if(integerSet(sl)) {
|
633
|
+
// If all set elements are integers, return a range shorthand.
|
634
|
+
const sorted = sl.slice().sort();
|
635
|
+
let i = 0,
|
636
|
+
j = 1;
|
637
|
+
while(i < sorted.length) {
|
638
|
+
while(j < sorted.length && sorted[j] - sorted[j - 1] === 1) j++;
|
639
|
+
if(j - i > 2) {
|
640
|
+
sorted[i] += ', ... , ' + sorted[j - 1];
|
641
|
+
sorted.splice(i + 1, j - i - 1);
|
642
|
+
j = i + 1;
|
643
|
+
}
|
644
|
+
i = j;
|
645
|
+
j++;
|
646
|
+
}
|
647
|
+
return '{' + sorted.join(', ') + '}';
|
648
|
+
}
|
649
|
+
// Otherwise, return an iterator set shorthand, or the complete set.
|
650
|
+
return iteratorSet(sl) || '{' + sl.join(', ') + '}';
|
596
651
|
}
|
597
652
|
|
598
653
|
function tupelString(sl) {
|