linny-r 1.5.8 → 1.6.0
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 +1 -1
- package/static/index.html +7 -3
- package/static/linny-r.css +19 -0
- package/static/scripts/linny-r-gui-actor-manager.js +3 -3
- package/static/scripts/linny-r-gui-chart-manager.js +10 -9
- package/static/scripts/linny-r-gui-controller.js +2 -1
- package/static/scripts/linny-r-gui-dataset-manager.js +17 -49
- package/static/scripts/linny-r-gui-documentation-manager.js +40 -20
- package/static/scripts/linny-r-gui-equation-manager.js +17 -4
- package/static/scripts/linny-r-gui-experiment-manager.js +41 -23
- package/static/scripts/linny-r-gui-expression-editor.js +26 -21
- package/static/scripts/linny-r-gui-monitor.js +4 -4
- package/static/scripts/linny-r-model.js +248 -77
- package/static/scripts/linny-r-utils.js +50 -11
- package/static/scripts/linny-r-vm.js +582 -290
package/package.json
CHANGED
package/static/index.html
CHANGED
@@ -304,8 +304,12 @@ SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
|
304
304
|
</svg>
|
305
305
|
</div>
|
306
306
|
</main>
|
307
|
-
<!--
|
308
|
-
in
|
307
|
+
<!-- The footer displays the status bar with X/Y coordinates, zoom
|
308
|
+
in/out buttons, buttons for moving forward/backward in time, and
|
309
|
+
the status line that displays info, notifications, warnings, and
|
310
|
+
error messages. The set-up progress bar shows a growing colored
|
311
|
+
needle indicating progress of making Simplex tableau and input
|
312
|
+
file for the solver.
|
309
313
|
-->
|
310
314
|
<footer>
|
311
315
|
<div id="set-up-progress">
|
@@ -2238,7 +2242,7 @@ NOTE: * and ? will be interpreted as wildcards"
|
|
2238
2242
|
</div>
|
2239
2243
|
<div id="viewer-selectors">
|
2240
2244
|
<label>Variable:</label>
|
2241
|
-
<select id="viewer-variable"
|
2245
|
+
<select id="viewer-variable">
|
2242
2246
|
</select>
|
2243
2247
|
<label>Statistic:</label>
|
2244
2248
|
<select id="viewer-statistic">
|
package/static/linny-r.css
CHANGED
@@ -2366,6 +2366,24 @@ td.equation-selector {
|
|
2366
2366
|
text-overflow: ellipsis;
|
2367
2367
|
}
|
2368
2368
|
|
2369
|
+
td.method {
|
2370
|
+
color: #1080e0;
|
2371
|
+
font-weight: bold;
|
2372
|
+
}
|
2373
|
+
|
2374
|
+
td.no-object {
|
2375
|
+
color: #80a0c0;
|
2376
|
+
font-weight: normal;
|
2377
|
+
}
|
2378
|
+
|
2379
|
+
td.compile-issue {
|
2380
|
+
color: #e00000;
|
2381
|
+
}
|
2382
|
+
|
2383
|
+
td.compute-issue {
|
2384
|
+
color: #f08000;
|
2385
|
+
}
|
2386
|
+
|
2369
2387
|
td.wildcard {
|
2370
2388
|
color: #400080;
|
2371
2389
|
}
|
@@ -3558,6 +3576,7 @@ td.sa-not-run {
|
|
3558
3576
|
#viewer-variable {
|
3559
3577
|
font-size: 10px;
|
3560
3578
|
max-width: calc(100% - 160px);
|
3579
|
+
margin-right: 10px;
|
3561
3580
|
}
|
3562
3581
|
|
3563
3582
|
#sensitivity-statistic,
|
@@ -304,15 +304,15 @@ class ActorManager {
|
|
304
304
|
if(a.displayName != ali[1]) a.rename(ali[1]);
|
305
305
|
// Set its round flags
|
306
306
|
a.round_flags = ali[2];
|
307
|
-
// Double-check: parse expression if weight has been changed
|
307
|
+
// Double-check: parse expression if weight has been changed.
|
308
308
|
if(a.weight.text != ali[3]) {
|
309
|
-
xp.expr = ali[3];
|
309
|
+
xp.expr = monoSpacedVariables(ali[3]);
|
310
310
|
xp.compile();
|
311
311
|
if(xp.error) {
|
312
312
|
UI.warningInvalidWeightExpression(a, xp.error);
|
313
313
|
ok = false;
|
314
314
|
} else {
|
315
|
-
a.weight.update(
|
315
|
+
a.weight.update(ali[3]);
|
316
316
|
}
|
317
317
|
}
|
318
318
|
// Update import/export status
|
@@ -574,7 +574,7 @@ class GUIChartManager extends ChartManager {
|
|
574
574
|
}
|
575
575
|
|
576
576
|
cloneChart() {
|
577
|
-
//
|
577
|
+
// Create a new chart that is identical to the current one.
|
578
578
|
if(this.chart_index >= 0) {
|
579
579
|
let c = MODEL.charts[this.chart_index],
|
580
580
|
nt = c.title + '-copy';
|
@@ -582,7 +582,7 @@ class GUIChartManager extends ChartManager {
|
|
582
582
|
nt += '-copy';
|
583
583
|
}
|
584
584
|
const nc = MODEL.addChart(nt);
|
585
|
-
// Copy properties of c to nc
|
585
|
+
// Copy properties of `c` to `nc`;
|
586
586
|
nc.histogram = c.histogram;
|
587
587
|
nc.bins = c.bins;
|
588
588
|
nc.show_title = c.show_title;
|
@@ -609,7 +609,7 @@ class GUIChartManager extends ChartManager {
|
|
609
609
|
}
|
610
610
|
|
611
611
|
toggleRunStat() {
|
612
|
-
//
|
612
|
+
// Toggle the Boolean property that signals charts that they must
|
613
613
|
// plot the selected statistic for the selected runs if they are
|
614
614
|
// part of the selected experiment chart set.
|
615
615
|
this.setRunsStat(!this.runs_stat);
|
@@ -618,16 +618,17 @@ class GUIChartManager extends ChartManager {
|
|
618
618
|
}
|
619
619
|
|
620
620
|
deleteChart() {
|
621
|
-
//
|
621
|
+
// Delete the shown chart (if any).
|
622
622
|
if(this.chart_index >= 0) {
|
623
|
-
// NOTE:
|
623
|
+
// NOTE: Do not delete the default chart, but clear it instead.
|
624
624
|
if(MODEL.charts[this.chart_index].title === this.new_chart_title) {
|
625
625
|
MODEL.charts[this.chart_index].reset();
|
626
626
|
} else {
|
627
627
|
MODEL.charts.splice(this.chart_index, 1);
|
628
628
|
this.chart_index = -1;
|
629
629
|
}
|
630
|
-
// Also update the experiment viewer
|
630
|
+
// Also update the experiment viewer, because this chart may be
|
631
|
+
// one of the output charts of the selected experiment.
|
631
632
|
UI.updateControllerDialogs('CFX');
|
632
633
|
}
|
633
634
|
}
|
@@ -689,8 +690,8 @@ class GUIChartManager extends ChartManager {
|
|
689
690
|
}
|
690
691
|
|
691
692
|
addVariable(eq='') {
|
692
|
-
//
|
693
|
-
// NOTE:
|
693
|
+
// Add the variable specified by the add-variable-dialog to the chart.
|
694
|
+
// NOTE: When defined, `eq` is the selector of the equation to be added.
|
694
695
|
if(this.chart_index >= 0) {
|
695
696
|
let o = '',
|
696
697
|
a = eq;
|
@@ -698,7 +699,7 @@ class GUIChartManager extends ChartManager {
|
|
698
699
|
o = this.add_variable_modal.selectedOption('name').text;
|
699
700
|
a = this.add_variable_modal.selectedOption('attr').text;
|
700
701
|
}
|
701
|
-
// NOTE:
|
702
|
+
// NOTE: When equation is added, object specifier is empty string.
|
702
703
|
if(!o && a) o = UI.EQUATIONS_DATASET_NAME;
|
703
704
|
this.variable_index = MODEL.charts[this.chart_index].addVariable(o, a);
|
704
705
|
if(this.variable_index >= 0) {
|
@@ -2608,10 +2608,11 @@ class GUIController extends Controller {
|
|
2608
2608
|
document.body.className = '';
|
2609
2609
|
}
|
2610
2610
|
|
2611
|
-
setProgressNeedle(fraction) {
|
2611
|
+
setProgressNeedle(fraction, color='#500080') {
|
2612
2612
|
// Shows a thin purple line just above the status line to indicate progress
|
2613
2613
|
const el = document.getElementById('set-up-progress-bar');
|
2614
2614
|
el.style.width = Math.round(Math.max(0, Math.min(1, fraction)) * 100) + '%';
|
2615
|
+
el.style.backgroundColor = color;
|
2615
2616
|
}
|
2616
2617
|
|
2617
2618
|
hideStayOnTopDialogs() {
|
@@ -486,12 +486,14 @@ class GUIDatasetManager extends DatasetManager {
|
|
486
486
|
m = sd.modifiers[UI.nameToID(msl[i])],
|
487
487
|
wild = m.hasWildcards,
|
488
488
|
defsel = (m.selector === sd.default_selector),
|
489
|
+
issue = (m.expression.compile_issue ? ' compile-issue' :
|
490
|
+
(m.expression.compute_issue ? ' compute-issue' : '')),
|
489
491
|
clk = '" onclick="DATASET_MANAGER.selectModifier(event, \'' +
|
490
492
|
m.selector + '\'';
|
491
493
|
if(m === sm) smid += i;
|
492
494
|
ml.push(['<tr id="dsmtr', i, '" class="dataset-modif',
|
493
495
|
(m === sm ? ' sel-set' : ''),
|
494
|
-
'"><td class="dataset-selector',
|
496
|
+
'"><td class="dataset-selector', issue,
|
495
497
|
(wild ? ' wildcard' : ''),
|
496
498
|
'" title="Shift-click to ', (defsel ? 'clear' : 'set as'),
|
497
499
|
' default modifier',
|
@@ -499,7 +501,10 @@ class GUIDatasetManager extends DatasetManager {
|
|
499
501
|
(defsel ? '<img src="images/solve.png" style="height: 14px;' +
|
500
502
|
' width: 14px; margin: 0 1px -3px -1px;">' : ''),
|
501
503
|
(wild ? wildcardFormat(m.selector, true) : m.selector),
|
502
|
-
'</td><td class="dataset-expression',
|
504
|
+
'</td><td class="dataset-expression', issue,
|
505
|
+
(issue ? '"title="' +
|
506
|
+
safeDoubleQuotes(m.expression.compile_issue ||
|
507
|
+
m.expression.compute_issue) : ''),
|
503
508
|
clk, ');">', m.expression.text, '</td></tr>'].join(''));
|
504
509
|
}
|
505
510
|
this.modifier_table.innerHTML = ml.join('');
|
@@ -654,14 +659,14 @@ class GUIDatasetManager extends DatasetManager {
|
|
654
659
|
}
|
655
660
|
|
656
661
|
renameDataset() {
|
657
|
-
//
|
662
|
+
// Change the name of the selected dataset.
|
658
663
|
if(this.selected_dataset) {
|
659
664
|
const
|
660
665
|
inp = this.rename_modal.element('name'),
|
661
666
|
n = UI.cleanName(inp.value);
|
662
|
-
// Show modeler the "cleaned" new name
|
667
|
+
// Show modeler the "cleaned" new name.
|
663
668
|
inp.value = n;
|
664
|
-
// Then try to rename -- this may generate a warning
|
669
|
+
// Then try to rename -- this may generate a warning.
|
665
670
|
if(this.selected_dataset.rename(n)) {
|
666
671
|
this.rename_modal.hide();
|
667
672
|
if(EXPERIMENT_MANAGER.selected_experiment) {
|
@@ -670,59 +675,22 @@ class GUIDatasetManager extends DatasetManager {
|
|
670
675
|
UI.updateControllerDialogs('CDEFJX');
|
671
676
|
}
|
672
677
|
} else if(this.selected_prefix_row) {
|
673
|
-
// Create a list of datasets to be renamed
|
678
|
+
// Create a list of datasets to be renamed.
|
674
679
|
let e = this.rename_modal.element('name'),
|
675
680
|
prefix = e.value.trim();
|
676
681
|
e.focus();
|
677
|
-
// Trim trailing colon if user
|
682
|
+
// Trim trailing colon if user added it.
|
678
683
|
while(prefix.endsWith(':')) prefix = prefix.slice(0, -1);
|
679
|
-
// NOTE:
|
684
|
+
// NOTE: Prefix may be empty string, but otherwise should be a
|
685
|
+
// valid name.
|
680
686
|
if(prefix && !UI.validName(prefix)) {
|
681
687
|
UI.warn('Invalid prefix');
|
682
688
|
return;
|
683
689
|
}
|
684
|
-
// Now add the colon-plus-space prefix separator
|
690
|
+
// Now add the colon-plus-space prefix separator.
|
685
691
|
prefix += UI.PREFIXER;
|
686
|
-
|
687
|
-
|
688
|
-
key = oldpref.toLowerCase().split(UI.PREFIXER).join(':_'),
|
689
|
-
newkey = prefix.toLowerCase().split(UI.PREFIXER).join(':_'),
|
690
|
-
dsl = [];
|
691
|
-
// No change if new prefix is identical to old prefix
|
692
|
-
if(oldpref !== prefix) {
|
693
|
-
for(let k in MODEL.datasets) if(MODEL.datasets.hasOwnProperty(k)) {
|
694
|
-
if(k.startsWith(key)) dsl.push(k);
|
695
|
-
}
|
696
|
-
// NOTE: no check needed for mere upper/lower case changes
|
697
|
-
if(newkey !== key) {
|
698
|
-
let nc = 0;
|
699
|
-
for(let i = 0; i < dsl.length; i++) {
|
700
|
-
let nk = newkey + dsl[i].substring(key.length);
|
701
|
-
if(MODEL.datasets[nk]) nc++;
|
702
|
-
}
|
703
|
-
if(nc) {
|
704
|
-
UI.warn('Renaming ' + pluralS(dsl.length, 'dataset').toLowerCase() +
|
705
|
-
' would cause ' + pluralS(nc, 'name conflict'));
|
706
|
-
return;
|
707
|
-
}
|
708
|
-
}
|
709
|
-
// Reset counts of effects of a rename operation
|
710
|
-
this.entity_count = 0;
|
711
|
-
this.expression_count = 0;
|
712
|
-
// Rename datasets one by one, suppressing notifications
|
713
|
-
for(let i = 0; i < dsl.length; i++) {
|
714
|
-
const d = MODEL.datasets[dsl[i]];
|
715
|
-
d.rename(d.displayName.replace(oldpref, prefix), false);
|
716
|
-
}
|
717
|
-
let msg = 'Renamed ' + pluralS(dsl.length, 'dataset').toLowerCase();
|
718
|
-
if(MODEL.variable_count) msg += ', and updated ' +
|
719
|
-
pluralS(MODEL.variable_count, 'variable') + ' in ' +
|
720
|
-
pluralS(MODEL.expression_count, 'expression');
|
721
|
-
UI.notify(msg);
|
722
|
-
if(EXPERIMENT_MANAGER.selected_experiment) {
|
723
|
-
EXPERIMENT_MANAGER.selected_experiment.inferVariables();
|
724
|
-
}
|
725
|
-
UI.updateControllerDialogs('CDEFJX');
|
692
|
+
// Perform the renaming operation.
|
693
|
+
if(MODEL.renamePrefixedDatasets(this.selectedPrefix, prefix)) {
|
726
694
|
this.selectPrefixRow(prefix);
|
727
695
|
}
|
728
696
|
}
|
@@ -309,30 +309,50 @@ class DocumentationManager {
|
|
309
309
|
}
|
310
310
|
|
311
311
|
update(e, shift) {
|
312
|
-
// Display name of entity under cursor on the infoline, and details
|
313
|
-
// the documentation dialog
|
312
|
+
// Display name of entity under cursor on the infoline, and details
|
313
|
+
// in the documentation dialog.
|
314
314
|
if(!e) return;
|
315
|
-
|
316
|
-
et = e.type,
|
315
|
+
let et = e.type,
|
317
316
|
edn = e.displayName;
|
318
|
-
|
317
|
+
if(et === 'Equation' && e.selector.startsWith(':')) et = 'Method';
|
318
|
+
// TO DO: when debugging, display additional data for nodes on the
|
319
|
+
// infoline.
|
319
320
|
UI.setMessage(
|
320
321
|
e instanceof NodeBox ? e.infoLineName : `<em>${et}:</em> ${edn}`);
|
321
|
-
// NOTE:
|
322
|
-
// to rapidly browse comments without having to click on
|
323
|
-
// release the shift key to move to the documentation
|
324
|
-
// Moreover, the documentation dialog must be visible,
|
325
|
-
// have the `comments` property
|
326
|
-
|
327
|
-
|
328
|
-
|
329
|
-
|
330
|
-
|
331
|
-
|
332
|
-
|
333
|
-
|
334
|
-
|
335
|
-
|
322
|
+
// NOTE: Update the dialog ONLY when shift is pressed. This permits
|
323
|
+
// modelers to rapidly browse comments without having to click on
|
324
|
+
// entities, and then release the shift key to move to the documentation
|
325
|
+
// dialog to edit. Moreover, the documentation dialog must be visible,
|
326
|
+
// and the entity must have the `comments` property.
|
327
|
+
// NOTE: Equations constitute an exception, as DatasetModifiers do
|
328
|
+
// not have the `comments` property. Now that methods can be defined
|
329
|
+
// (since version 1.6.0), the documentation window displays the eligible
|
330
|
+
// prefixes when the cursor is Shift-moved over the name of a method
|
331
|
+
// (in the Equation Manager).
|
332
|
+
if(!this.editing && shift && this.visible) {
|
333
|
+
if(e.hasOwnProperty('comments')) {
|
334
|
+
this.title.innerHTML = `<em>${et}:</em> ${edn}`;
|
335
|
+
this.entity = e;
|
336
|
+
this.markup = (e.comments ? e.comments : '');
|
337
|
+
this.editor.value = this.markup;
|
338
|
+
this.viewer.innerHTML = this.markdown;
|
339
|
+
this.edit_btn.classList.remove('disab');
|
340
|
+
this.edit_btn.classList.add('enab');
|
341
|
+
// NOTE: permit documentation of the model by raising the dialog
|
342
|
+
if(this.entity === MODEL) this.dialog.style.zIndex = 101;
|
343
|
+
} else if(e instanceof DatasetModifier) {
|
344
|
+
this.title.innerHTML = e.selector;
|
345
|
+
this.viewer.innerHTML = 'Method <tt>' + e.selector +
|
346
|
+
'</tt> does not apply to any entity';
|
347
|
+
if(e.expression.eligible_prefixes) {
|
348
|
+
const el = Object.keys(e.expression.eligible_prefixes)
|
349
|
+
.sort(compareSelectors);
|
350
|
+
if(el.length > 0) this.viewer.innerHTML = 'Method <tt>' +
|
351
|
+
e.selector + '</tt> applies to ' +
|
352
|
+
pluralS(el.length, 'prefixed entity group').toLowerCase() +
|
353
|
+
':<ul><li>' + el.join('</li><li>') + '</li></ul>';
|
354
|
+
}
|
355
|
+
}
|
336
356
|
}
|
337
357
|
}
|
338
358
|
|
@@ -139,16 +139,27 @@ class EquationManager {
|
|
139
139
|
const
|
140
140
|
m = ed.modifiers[UI.nameToID(msl[i])],
|
141
141
|
wild = (m.selector.indexOf('??') >= 0),
|
142
|
+
method = m.selector.startsWith(':'),
|
143
|
+
issue = (m.expression.compile_issue ? ' compile-issue' :
|
144
|
+
(m.expression.compute_issue ? ' compute-issue' : '')),
|
142
145
|
clk = '" onclick="EQUATION_MANAGER.selectModifier(event, \'' +
|
143
|
-
m.selector + '\''
|
146
|
+
m.selector + '\'',
|
147
|
+
mover = (method ? ' onmouseover="EQUATION_MANAGER.showInfo(\'' +
|
148
|
+
m.identifier + '\', event.shiftKey);"' : '');
|
144
149
|
if(m === sm) smid += i;
|
145
150
|
ml.push(['<tr id="eqmtr', i, '" class="dataset-modif',
|
146
151
|
(m === sm ? ' sel-set' : ''),
|
147
152
|
'"><td class="equation-selector',
|
148
|
-
(
|
149
|
-
|
153
|
+
(method ? ' method' : ''),
|
154
|
+
// Display in gray when method cannot be applied
|
155
|
+
(m.expression.noMethodObject ? ' no-object' : ''),
|
156
|
+
(m.expression.isStatic ? '' : ' it'), issue,
|
157
|
+
(wild ? ' wildcard' : ''), clk, ', false);"', mover, '>',
|
150
158
|
(wild ? wildcardFormat(m.selector) : m.selector),
|
151
|
-
'</td><td class="equation-expression',
|
159
|
+
'</td><td class="equation-expression', issue,
|
160
|
+
(issue ? '"title="' +
|
161
|
+
safeDoubleQuotes(m.expression.compile_issue ||
|
162
|
+
m.expression.compute_issue) : ''),
|
152
163
|
clk, ');">', m.expression.text, '</td></tr>'].join(''));
|
153
164
|
}
|
154
165
|
this.table.innerHTML = ml.join('');
|
@@ -164,6 +175,8 @@ class EquationManager {
|
|
164
175
|
|
165
176
|
showInfo(id, shift) {
|
166
177
|
// @@TO DO: Display documentation for the equation => extra comments field?
|
178
|
+
const d = MODEL.equations_dataset.modifiers[id];
|
179
|
+
if(d) DOCUMENTATION_MANAGER.update(d, shift);
|
167
180
|
}
|
168
181
|
|
169
182
|
selectModifier(event, id, x=true) {
|
@@ -114,11 +114,14 @@ class GUIExperimentManager extends ExperimentManager {
|
|
114
114
|
document.getElementById('xv-download-btn').addEventListener(
|
115
115
|
'click', () => EXPERIMENT_MANAGER.promptForDownload());
|
116
116
|
// The viewer's drop-down selectors
|
117
|
-
document.getElementById('viewer-variable')
|
117
|
+
this.viewer_variable = document.getElementById('viewer-variable');
|
118
|
+
this.viewer_variable.addEventListener(
|
118
119
|
'change', () => EXPERIMENT_MANAGER.setVariable());
|
119
|
-
document.getElementById('viewer-statistic')
|
120
|
+
this.viewer_statistic = document.getElementById('viewer-statistic');
|
121
|
+
this.viewer_statistic.addEventListener(
|
120
122
|
'change', () => EXPERIMENT_MANAGER.setStatistic());
|
121
|
-
document.getElementById('viewer-scale')
|
123
|
+
this.viewer_scale = document.getElementById('viewer-scale');
|
124
|
+
this.viewer_scale.addEventListener(
|
122
125
|
'change', () => EXPERIMENT_MANAGER.setScale());
|
123
126
|
// The spin buttons
|
124
127
|
document.getElementById('xp-cd-minus').addEventListener(
|
@@ -272,12 +275,12 @@ class GUIExperimentManager extends ExperimentManager {
|
|
272
275
|
|
273
276
|
updateDialog() {
|
274
277
|
this.updateChartList();
|
275
|
-
// Warn modeler if no meaningful experiments can be defined
|
278
|
+
// Warn modeler if no meaningful experiments can be defined.
|
276
279
|
if(MODEL.outcomeNames.length === 0 && this.suitable_charts.length === 0) {
|
277
280
|
this.default_message.style.display = 'block';
|
278
281
|
this.params_div.style.display = 'none';
|
279
282
|
this.selected_experiment = null;
|
280
|
-
// Disable experiment dialog menu buttons
|
283
|
+
// Disable experiment dialog menu buttons.
|
281
284
|
UI.disableButtons('xp-new xp-rename xp-view xp-delete xp-ignore');
|
282
285
|
} else {
|
283
286
|
this.default_message.style.display = 'none';
|
@@ -388,7 +391,7 @@ class GUIExperimentManager extends ExperimentManager {
|
|
388
391
|
x.charts[i].title, '</td></tr>'].join(''));
|
389
392
|
}
|
390
393
|
this.chart_table.innerHTML = tr.join('');
|
391
|
-
// Do not show viewer unless at least 1 dependent variable has been defined
|
394
|
+
// Do not show viewer unless at least 1 dependent variable has been defined.
|
392
395
|
if(x.charts.length === 0 && MODEL.outcomeNames.length === 0) canview = false;
|
393
396
|
if(tr.length >= this.suitable_charts.length) {
|
394
397
|
document.getElementById('xp-c-add-btn').classList.add('v-disab');
|
@@ -409,7 +412,7 @@ class GUIExperimentManager extends ExperimentManager {
|
|
409
412
|
dbtn.classList.add('v-disab');
|
410
413
|
cbtn.classList.add('v-disab');
|
411
414
|
}
|
412
|
-
// Enable viewing only if > 1 dimensions and > 1 outcome variables
|
415
|
+
// Enable viewing only if > 1 dimensions and > 1 outcome variables.
|
413
416
|
if(canview) {
|
414
417
|
UI.enableButtons('xp-view');
|
415
418
|
} else {
|
@@ -478,38 +481,51 @@ class GUIExperimentManager extends ExperimentManager {
|
|
478
481
|
if(x) {
|
479
482
|
this.design.style.display = 'none';
|
480
483
|
document.getElementById('viewer-title').innerHTML = x.title;
|
481
|
-
|
484
|
+
this.viewer_statistic.value = x.selected_statistic;
|
482
485
|
this.updateViewerVariable();
|
483
486
|
// NOTE: calling updateSpinner with dir=0 will update without changes
|
484
487
|
this.updateSpinner('c', 0);
|
485
488
|
this.drawTable();
|
486
|
-
|
489
|
+
this.viewer_scale.value = x.selected_scale;
|
487
490
|
this.setColorScale(x.selected_color_scale);
|
488
491
|
this.viewer.style.display = 'block';
|
489
492
|
}
|
490
493
|
}
|
491
494
|
|
492
495
|
updateViewerVariable() {
|
493
|
-
// Update the variable drop-down selector of the viewer
|
496
|
+
// Update the variable drop-down selector of the viewer.
|
494
497
|
const x = this.selected_experiment;
|
495
498
|
if(x) {
|
496
499
|
x.inferVariables();
|
497
500
|
const
|
498
501
|
ol = [],
|
499
|
-
|
502
|
+
ov = MODEL.outcomeNames,
|
503
|
+
vl = [...ov];
|
500
504
|
for(let i = 0; i < x.variables.length; i++) {
|
501
|
-
|
505
|
+
const
|
506
|
+
vn = x.variables[i].displayName,
|
507
|
+
oi = ov.indexOf(vn);
|
508
|
+
// If an outcome dataset or equation is plotted in an experiment
|
509
|
+
// chart, remove its name from the outcome variable list.
|
510
|
+
if(oi >= 0) ov.splice(oi, 1);
|
511
|
+
addDistinct(vn, vl);
|
502
512
|
}
|
503
513
|
vl.sort((a, b) => UI.compareFullNames(a, b));
|
504
514
|
for(let i = 0; i < vl.length; i++) {
|
505
|
-
|
506
|
-
|
507
|
-
|
508
|
-
|
509
|
-
|
510
|
-
|
511
|
-
|
515
|
+
const vn = vl[i];
|
516
|
+
// NOTE: FireFox selector dropdown areas have a pale gray
|
517
|
+
// background that darkens when color is set, so always set it
|
518
|
+
// to white (like Chrome). Then set color of outcome variables
|
519
|
+
// to fuchsia to differentiate from variables for which time
|
520
|
+
// series are stored as experiment run results.
|
521
|
+
ol.push(['<option value="', vn, '" style="background-color: white',
|
522
|
+
(ov.indexOf(vn) >= 0 ? '; color: #b00080"' : '"'),
|
523
|
+
(vn == x.selected_variable ? ' selected="selected"' : ''),
|
524
|
+
'>', vn, '</option>'].join(''));
|
512
525
|
}
|
526
|
+
this.viewer_variable.innerHTML = ol.join('');
|
527
|
+
// Initially, select the first variable on the list.
|
528
|
+
if(x.selected_variable === '') x.selected_variable = vl[0];
|
513
529
|
}
|
514
530
|
}
|
515
531
|
|
@@ -684,8 +700,10 @@ class GUIExperimentManager extends ExperimentManager {
|
|
684
700
|
for(let j = 0; j < n; j++) {
|
685
701
|
const
|
686
702
|
c = r + j + i * nrows,
|
703
|
+
run = x.runs[c],
|
687
704
|
ic = x.chart_combinations.indexOf(c);
|
688
|
-
|
705
|
+
// NOTE: Only add if run has been executed and stored.
|
706
|
+
if(add && run) {
|
689
707
|
if(ic < 0) x.chart_combinations.push(c);
|
690
708
|
} else {
|
691
709
|
if(ic >= 0) x.chart_combinations.splice(ic, 1);
|
@@ -952,7 +970,7 @@ N = ${rr.N}, vector length = ${rr.vector.length}` : '')].join('');
|
|
952
970
|
// Update view for selected variable
|
953
971
|
const x = this.selected_experiment;
|
954
972
|
if(x) {
|
955
|
-
x.selected_variable =
|
973
|
+
x.selected_variable = this.viewer_variable.value;
|
956
974
|
this.updateData();
|
957
975
|
}
|
958
976
|
}
|
@@ -961,7 +979,7 @@ N = ${rr.N}, vector length = ${rr.vector.length}` : '')].join('');
|
|
961
979
|
// Update view for selected variable.
|
962
980
|
const x = this.selected_experiment;
|
963
981
|
if(x) {
|
964
|
-
x.selected_statistic =
|
982
|
+
x.selected_statistic = this.viewer_statistic.value;
|
965
983
|
this.updateData();
|
966
984
|
// NOTE: Update of Chart Manager is needed only when it is showing
|
967
985
|
// run statistics.
|
@@ -1027,7 +1045,7 @@ N = ${rr.N}, vector length = ${rr.vector.length}` : '')].join('');
|
|
1027
1045
|
// Update view for selected scale
|
1028
1046
|
const x = this.selected_experiment;
|
1029
1047
|
if(x) {
|
1030
|
-
x.selected_scale =
|
1048
|
+
x.selected_scale = this.viewer_scale.value;
|
1031
1049
|
this.updateData();
|
1032
1050
|
// NOTE: Update of Chart Manager is needed when it is showing
|
1033
1051
|
// run statistics because solver times may be plotted.
|