@decidables/detectable-elements 0.1.2 → 0.2.1
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/CHANGELOG.md +42 -0
- package/README.md +529 -406
- package/lib/detectableElements.esm.js +721 -310
- package/lib/detectableElements.esm.js.map +1 -1
- package/lib/detectableElements.esm.min.js +198 -108
- package/lib/detectableElements.esm.min.js.map +1 -1
- package/lib/detectableElements.umd.js +723 -309
- package/lib/detectableElements.umd.js.map +1 -1
- package/lib/detectableElements.umd.min.js +204 -114
- package/lib/detectableElements.umd.min.js.map +1 -1
- package/package.json +4 -4
- package/src/components/detectable-control.js +2 -1
- package/src/components/detectable-response.js +26 -11
- package/src/components/detectable-table.js +30 -13
- package/src/components/rdk-task.js +1 -1
- package/src/components/roc-space.js +2 -2
- package/src/components/sdt-model.js +10 -10
- package/src/equations/hfa2ppv.js +121 -0
- package/src/equations/hmfacr2acc.js +1 -1
- package/src/equations/index.js +2 -0
- package/src/equations/mcr2fomr.js +121 -0
- package/src/equations/sdt-equation.js +15 -0
- package/src/examples/index.js +1 -0
- package/src/examples/multiple.js +76 -0
- package/src/examples/sdt-example.js +2 -3
- package/src/examples/unequal.js +4 -6
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@decidables/detectable-elements",
|
|
3
|
-
"version": "0.1
|
|
3
|
+
"version": "0.2.1",
|
|
4
4
|
"description": "detectable-elements: Web Components for visualizing Signal Detection Theory",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"web component",
|
|
@@ -56,11 +56,11 @@
|
|
|
56
56
|
"gulp": "^4.0.2"
|
|
57
57
|
},
|
|
58
58
|
"dependencies": {
|
|
59
|
-
"@decidables/decidables-elements": "^0.
|
|
60
|
-
"@decidables/detectable-math": "^0.1.
|
|
59
|
+
"@decidables/decidables-elements": "^0.3.1",
|
|
60
|
+
"@decidables/detectable-math": "^0.1.2",
|
|
61
61
|
"d3": "^7.3.0",
|
|
62
62
|
"jstat": "^1.9.5",
|
|
63
63
|
"lit": "^2.2.1"
|
|
64
64
|
},
|
|
65
|
-
"gitHead": "
|
|
65
|
+
"gitHead": "269fba00d14e58101b4bf26974411298c162869b"
|
|
66
66
|
}
|
|
@@ -81,7 +81,7 @@ export default class DetectableControl extends DetectableElement {
|
|
|
81
81
|
this.duration = undefined;
|
|
82
82
|
this.coherence = undefined;
|
|
83
83
|
this.payoff = undefined;
|
|
84
|
-
this.colors = ['none', 'accuracy', 'stimulus', 'response', 'outcome'];
|
|
84
|
+
this.colors = ['none', 'accuracy', 'stimulus', 'response', 'outcome', 'all'];
|
|
85
85
|
this.color = undefined;
|
|
86
86
|
this.zRoc = undefined;
|
|
87
87
|
this.run = false;
|
|
@@ -239,6 +239,7 @@ export default class DetectableControl extends DetectableElement {
|
|
|
239
239
|
<decidables-toggle-option name="toggle" value="stimulus" ?checked=${this.color === 'stimulus'}>Stimulus</decidables-toggle-option>
|
|
240
240
|
<decidables-toggle-option name="toggle" value="response" ?checked=${this.color === 'response'}>Response</decidables-toggle-option>
|
|
241
241
|
<decidables-toggle-option name="toggle" value="outcome" ?checked=${this.color === 'outcome'}>Outcome</decidables-toggle-option>
|
|
242
|
+
<decidables-toggle-option name="toggle" value="all" ?checked=${this.color === 'all'}>All</decidables-toggle-option>
|
|
242
243
|
</decidables-toggle>
|
|
243
244
|
`
|
|
244
245
|
: html``}
|
|
@@ -302,6 +302,11 @@ export default class DetectableResponse extends DetectableElement {
|
|
|
302
302
|
border: 1px solid var(---color-element-border);
|
|
303
303
|
}
|
|
304
304
|
|
|
305
|
+
:host([payoff="trial"]) .feedback,
|
|
306
|
+
:host([payoff="total"]) .feedback {
|
|
307
|
+
height: 5rem;
|
|
308
|
+
}
|
|
309
|
+
|
|
305
310
|
.feedback.h {
|
|
306
311
|
background-color: var(---color-h-light);
|
|
307
312
|
}
|
|
@@ -337,17 +342,12 @@ export default class DetectableResponse extends DetectableElement {
|
|
|
337
342
|
line-height: 1.15;
|
|
338
343
|
}
|
|
339
344
|
|
|
340
|
-
:host([payoff="trial"]) .feedback,
|
|
341
|
-
:host([payoff="total"]) .feedback {
|
|
342
|
-
height: 4rem;
|
|
343
|
-
}
|
|
344
|
-
|
|
345
345
|
/* Payoff feedback */
|
|
346
|
-
.
|
|
346
|
+
.total {
|
|
347
347
|
text-align: center;
|
|
348
348
|
}
|
|
349
349
|
|
|
350
|
-
.
|
|
350
|
+
.total .label {
|
|
351
351
|
font-weight: 600;
|
|
352
352
|
}
|
|
353
353
|
`,
|
|
@@ -355,6 +355,21 @@ export default class DetectableResponse extends DetectableElement {
|
|
|
355
355
|
}
|
|
356
356
|
|
|
357
357
|
render() {
|
|
358
|
+
const payoffFormatter = new Intl.NumberFormat('en-US', {
|
|
359
|
+
style: 'currency',
|
|
360
|
+
currency: 'USD',
|
|
361
|
+
minimumFractionDigits: 0,
|
|
362
|
+
maximumFractionDigits: 0,
|
|
363
|
+
});
|
|
364
|
+
const payoffFormat = (number) => {
|
|
365
|
+
return payoffFormatter.formatToParts(number).map(({type, value}) => {
|
|
366
|
+
if (type === 'minusSign') {
|
|
367
|
+
return '−';
|
|
368
|
+
}
|
|
369
|
+
return value;
|
|
370
|
+
}).reduce((string, part) => { return string + part; });
|
|
371
|
+
};
|
|
372
|
+
|
|
358
373
|
return html`
|
|
359
374
|
<div class="holder">
|
|
360
375
|
<div class="responses">
|
|
@@ -394,15 +409,15 @@ export default class DetectableResponse extends DetectableElement {
|
|
|
394
409
|
? html`<span class="outcome">Error</span>`
|
|
395
410
|
: html`<span class="outcome">No<br>Response</span>`
|
|
396
411
|
: ''}
|
|
397
|
-
${(this.payoff === 'trial' || this.payoff === 'total')
|
|
398
|
-
? html`<span class="payoff">${this.trialPayoff}</span>`
|
|
412
|
+
${((this.state === 'feedback') && (this.payoff === 'trial' || this.payoff === 'total'))
|
|
413
|
+
? html`<span class="payoff">${payoffFormat(this.trialPayoff)}</span>`
|
|
399
414
|
: html``}
|
|
400
415
|
</div>`
|
|
401
416
|
: html``}
|
|
402
417
|
${(this.payoff === 'total')
|
|
403
418
|
? html`
|
|
404
|
-
<div class="
|
|
405
|
-
<span class="label">Total: </span><span class="value">${this.totalPayoff}</span>
|
|
419
|
+
<div class="total">
|
|
420
|
+
<span class="label">Total: </span><span class="value">${payoffFormat(this.totalPayoff)}</span>
|
|
406
421
|
</div>`
|
|
407
422
|
: html``}
|
|
408
423
|
</div>`
|
|
@@ -118,8 +118,8 @@ export default class DetectableTable extends DetectableElement {
|
|
|
118
118
|
this.summaries = ['stimulusRates', 'responseRates', 'accuracy'];
|
|
119
119
|
this.summary = new Set();
|
|
120
120
|
|
|
121
|
-
this.colors = ['none', 'accuracy', 'stimulus', 'response', 'outcome'];
|
|
122
|
-
this.color = '
|
|
121
|
+
this.colors = ['none', 'accuracy', 'stimulus', 'response', 'outcome', 'all'];
|
|
122
|
+
this.color = 'all';
|
|
123
123
|
|
|
124
124
|
this.h = 40;
|
|
125
125
|
this.m = 60;
|
|
@@ -318,7 +318,7 @@ export default class DetectableTable extends DetectableElement {
|
|
|
318
318
|
|
|
319
319
|
/* Color schemes & Table emphasis */
|
|
320
320
|
|
|
321
|
-
/* (Default)
|
|
321
|
+
/* (Default) All color scheme */
|
|
322
322
|
.h {
|
|
323
323
|
background: var(---color-h-light);
|
|
324
324
|
border-top: 2px solid var(---color-element-emphasis);
|
|
@@ -417,6 +417,15 @@ export default class DetectableTable extends DetectableElement {
|
|
|
417
417
|
background: var(---color-element-background);
|
|
418
418
|
}
|
|
419
419
|
|
|
420
|
+
/* Outcome color scheme */
|
|
421
|
+
:host([color="outcome"]) .hr,
|
|
422
|
+
:host([color="outcome"]) .far,
|
|
423
|
+
:host([color="outcome"]) .ppv,
|
|
424
|
+
:host([color="outcome"]) .fomr,
|
|
425
|
+
:host([color="outcome"]) .acc {
|
|
426
|
+
background: var(---color-element-background);
|
|
427
|
+
}
|
|
428
|
+
|
|
420
429
|
/* No color scheme */
|
|
421
430
|
:host([color="none"]) .cr,
|
|
422
431
|
:host([color="none"]) .fa,
|
|
@@ -440,6 +449,14 @@ export default class DetectableTable extends DetectableElement {
|
|
|
440
449
|
minimumFractionDigits: 0,
|
|
441
450
|
maximumFractionDigits: 0,
|
|
442
451
|
});
|
|
452
|
+
const payoffFormat = (number) => {
|
|
453
|
+
return payoffFormatter.formatToParts(number).map(({type, value}) => {
|
|
454
|
+
if (type === 'minusSign') {
|
|
455
|
+
return '−';
|
|
456
|
+
}
|
|
457
|
+
return value;
|
|
458
|
+
}).reduce((string, part) => { return string + part; });
|
|
459
|
+
};
|
|
443
460
|
|
|
444
461
|
this.alignState();
|
|
445
462
|
let h;
|
|
@@ -455,25 +472,25 @@ export default class DetectableTable extends DetectableElement {
|
|
|
455
472
|
h = html`
|
|
456
473
|
<decidables-spinner ?disabled=${!this.interactive} min="0" .value="${this.h}" @input=${this.hInput.bind(this)}>
|
|
457
474
|
<span>Hits</span>
|
|
458
|
-
${this.payoff ? html`<span class="payoff">${
|
|
475
|
+
${this.payoff ? html`<span class="payoff">${payoffFormat(this.hPayoff)}</span>` : html``}
|
|
459
476
|
</decidables-spinner>
|
|
460
477
|
`;
|
|
461
478
|
m = html`
|
|
462
479
|
<decidables-spinner ?disabled=${!this.interactive} min="0" .value="${this.m}" @input=${this.mInput.bind(this)}>
|
|
463
480
|
<span>Misses</span>
|
|
464
|
-
${this.payoff ? html`<span class="payoff">${
|
|
481
|
+
${this.payoff ? html`<span class="payoff">${payoffFormat(this.mPayoff)}</span>` : html``}
|
|
465
482
|
</decidables-spinner>
|
|
466
483
|
`;
|
|
467
484
|
fa = html`
|
|
468
485
|
<decidables-spinner ?disabled=${!this.interactive} min="0" .value="${this.fa}" @input=${this.faInput.bind(this)}>
|
|
469
486
|
<span>False Alarms</span>
|
|
470
|
-
${this.payoff ? html`<span class="payoff">${
|
|
487
|
+
${this.payoff ? html`<span class="payoff">${payoffFormat(this.faPayoff)}</span>` : html``}
|
|
471
488
|
</decidables-spinner>
|
|
472
489
|
`;
|
|
473
490
|
cr = html`
|
|
474
491
|
<decidables-spinner ?disabled=${!this.interactive} min="0" .value="${this.cr}" @input=${this.crInput.bind(this)}>
|
|
475
492
|
<span>Correct Rejections</span>
|
|
476
|
-
${this.payoff ? html`<span class="payoff">${
|
|
493
|
+
${this.payoff ? html`<span class="payoff">${payoffFormat(this.crPayoff)}</span>` : html``}
|
|
477
494
|
</decidables-spinner>
|
|
478
495
|
`;
|
|
479
496
|
hr = html`
|
|
@@ -503,13 +520,13 @@ export default class DetectableTable extends DetectableElement {
|
|
|
503
520
|
`;
|
|
504
521
|
} else {
|
|
505
522
|
h = html`<span>Hits</span>
|
|
506
|
-
${this.payoff ? html`<span class="payoff">${
|
|
523
|
+
${this.payoff ? html`<span class="payoff">${payoffFormat(this.hPayoff)}</span>` : html``}`;
|
|
507
524
|
m = html`<span>Misses</span>
|
|
508
|
-
${this.payoff ? html`<span class="payoff">${
|
|
525
|
+
${this.payoff ? html`<span class="payoff">${payoffFormat(this.mPayoff)}</span>` : html``}`;
|
|
509
526
|
fa = html`<span>False Alarms</span>
|
|
510
|
-
${this.payoff ? html`<span class="payoff">${
|
|
527
|
+
${this.payoff ? html`<span class="payoff">${payoffFormat(this.faPayoff)}</span>` : html``}`;
|
|
511
528
|
cr = html`<span>Correct Rejections</span>
|
|
512
|
-
${this.payoff ? html`<span class="payoff">${
|
|
529
|
+
${this.payoff ? html`<span class="payoff">${payoffFormat(this.crPayoff)}</span>` : html``}`;
|
|
513
530
|
hr = html`<span>Hit Rate</span>`;
|
|
514
531
|
far = html`<span>False Alarm Rate</span>`;
|
|
515
532
|
acc = html`<span>Accuracy</span>`;
|
|
@@ -527,10 +544,10 @@ export default class DetectableTable extends DetectableElement {
|
|
|
527
544
|
</tr>
|
|
528
545
|
<tr>
|
|
529
546
|
<th class="th th-sub" scope="col">
|
|
530
|
-
|
|
547
|
+
‘Present’
|
|
531
548
|
</th>
|
|
532
549
|
<th class="th th-sub" scope="col">
|
|
533
|
-
|
|
550
|
+
‘Absent’
|
|
534
551
|
</th>
|
|
535
552
|
</tr>
|
|
536
553
|
</thead>
|
|
@@ -367,7 +367,7 @@ export default class ROCSpace extends DetectableElement {
|
|
|
367
367
|
.point .label {
|
|
368
368
|
font-size: 0.75rem;
|
|
369
369
|
|
|
370
|
-
dominant-baseline:
|
|
370
|
+
dominant-baseline: central;
|
|
371
371
|
text-anchor: middle;
|
|
372
372
|
|
|
373
373
|
fill: var(---color-text-inverse);
|
|
@@ -376,7 +376,7 @@ export default class ROCSpace extends DetectableElement {
|
|
|
376
376
|
];
|
|
377
377
|
}
|
|
378
378
|
|
|
379
|
-
render() {
|
|
379
|
+
render() { /* eslint-disable-line class-methods-use-this */
|
|
380
380
|
return html`
|
|
381
381
|
${DetectableElement.svgFilters}
|
|
382
382
|
`;
|
|
@@ -473,7 +473,7 @@ export default class SDTModel extends DetectableElement {
|
|
|
473
473
|
];
|
|
474
474
|
}
|
|
475
475
|
|
|
476
|
-
render() {
|
|
476
|
+
render() { /* eslint-disable-line class-methods-use-this */
|
|
477
477
|
return html`
|
|
478
478
|
${DetectableElement.svgFilters}
|
|
479
479
|
`;
|
|
@@ -643,7 +643,7 @@ export default class SDTModel extends DetectableElement {
|
|
|
643
643
|
})
|
|
644
644
|
.on('drag', (event, datum) => {
|
|
645
645
|
this.drag = true;
|
|
646
|
-
let muS = this.muS;
|
|
646
|
+
let muS = this.muS; /* eslint-disable-line prefer-destructuring */
|
|
647
647
|
if (this.interactive) {
|
|
648
648
|
muS = xScale.invert(event.x);
|
|
649
649
|
// Clamp Signal Curve to stay visible
|
|
@@ -653,7 +653,7 @@ export default class SDTModel extends DetectableElement {
|
|
|
653
653
|
? xScale.domain()[1]
|
|
654
654
|
: muS;
|
|
655
655
|
}
|
|
656
|
-
let hS = this.hS;
|
|
656
|
+
let hS = this.hS; /* eslint-disable-line prefer-destructuring */
|
|
657
657
|
if (this.unequal) {
|
|
658
658
|
hS = yScale.invert(event.y);
|
|
659
659
|
// Clamp Signal Curve to stay visible
|
|
@@ -849,7 +849,7 @@ export default class SDTModel extends DetectableElement {
|
|
|
849
849
|
.on('keydown', this.interactive
|
|
850
850
|
? (event) => {
|
|
851
851
|
if (['ArrowRight', 'ArrowLeft'].includes(event.key)) {
|
|
852
|
-
let muN = this.muN;
|
|
852
|
+
let muN = this.muN; /* eslint-disable-line prefer-destructuring */
|
|
853
853
|
switch (event.key) {
|
|
854
854
|
case 'ArrowRight':
|
|
855
855
|
muN += event.shiftKey ? 0.01 : 0.1;
|
|
@@ -1044,7 +1044,7 @@ export default class SDTModel extends DetectableElement {
|
|
|
1044
1044
|
.on('keydown.sensitivity', this.interactive
|
|
1045
1045
|
? (event) => {
|
|
1046
1046
|
if (['ArrowRight', 'ArrowLeft'].includes(event.key)) {
|
|
1047
|
-
let muS = this.muS;
|
|
1047
|
+
let muS = this.muS; /* eslint-disable-line prefer-destructuring */
|
|
1048
1048
|
switch (event.key) {
|
|
1049
1049
|
case 'ArrowRight':
|
|
1050
1050
|
muS += event.shiftKey ? 0.01 : 0.1;
|
|
@@ -1072,7 +1072,7 @@ export default class SDTModel extends DetectableElement {
|
|
|
1072
1072
|
.on('keydown.variance', this.unequal
|
|
1073
1073
|
? (event) => {
|
|
1074
1074
|
if (['ArrowUp', 'ArrowDown'].includes(event.key)) {
|
|
1075
|
-
let hS = this.hS;
|
|
1075
|
+
let hS = this.hS; /* eslint-disable-line prefer-destructuring */
|
|
1076
1076
|
switch (event.key) {
|
|
1077
1077
|
case 'ArrowUp':
|
|
1078
1078
|
hS += event.shiftKey ? 0.002 : 0.02;
|
|
@@ -1326,7 +1326,7 @@ export default class SDTModel extends DetectableElement {
|
|
|
1326
1326
|
);
|
|
1327
1327
|
return (time) => {
|
|
1328
1328
|
element.d = interpolateD(time);
|
|
1329
|
-
d3.select(element).text(
|
|
1329
|
+
d3.select(element).text(d3.format('.3')(element.d));
|
|
1330
1330
|
};
|
|
1331
1331
|
});
|
|
1332
1332
|
// EXIT
|
|
@@ -1384,7 +1384,7 @@ export default class SDTModel extends DetectableElement {
|
|
|
1384
1384
|
);
|
|
1385
1385
|
return (time) => {
|
|
1386
1386
|
element.c = interpolateC(time);
|
|
1387
|
-
d3.select(element).text(
|
|
1387
|
+
d3.select(element).text(d3.format('.3')(element.c));
|
|
1388
1388
|
};
|
|
1389
1389
|
});
|
|
1390
1390
|
// EXIT
|
|
@@ -1450,7 +1450,7 @@ export default class SDTModel extends DetectableElement {
|
|
|
1450
1450
|
);
|
|
1451
1451
|
return (time) => {
|
|
1452
1452
|
element.s = interpolateS(time);
|
|
1453
|
-
d3.select(element).text(
|
|
1453
|
+
d3.select(element).text(d3.format('.3')(element.s));
|
|
1454
1454
|
};
|
|
1455
1455
|
});
|
|
1456
1456
|
// EXIT
|
|
@@ -1480,7 +1480,7 @@ export default class SDTModel extends DetectableElement {
|
|
|
1480
1480
|
.call(dragThreshold)
|
|
1481
1481
|
.on('keydown', (event) => {
|
|
1482
1482
|
if (['ArrowRight', 'ArrowLeft'].includes(event.key)) {
|
|
1483
|
-
let l = this.l;
|
|
1483
|
+
let l = this.l; /* eslint-disable-line prefer-destructuring */
|
|
1484
1484
|
switch (event.key) {
|
|
1485
1485
|
case 'ArrowRight':
|
|
1486
1486
|
l += event.shiftKey ? 0.01 : 0.1;
|
|
@@ -0,0 +1,121 @@
|
|
|
1
|
+
|
|
2
|
+
import {html} from 'lit';
|
|
3
|
+
|
|
4
|
+
import '@decidables/decidables-elements/spinner';
|
|
5
|
+
import SDTMath from '@decidables/detectable-math';
|
|
6
|
+
|
|
7
|
+
import SDTEquation from './sdt-equation';
|
|
8
|
+
|
|
9
|
+
/*
|
|
10
|
+
SDTEquationHFa2Ppv element
|
|
11
|
+
<sdt-equation-hm2hr>
|
|
12
|
+
|
|
13
|
+
Attributes:
|
|
14
|
+
Hits; Misses; Hit Rate;
|
|
15
|
+
*/
|
|
16
|
+
export default class SDTEquationHFa2Ppv extends SDTEquation {
|
|
17
|
+
static get properties() {
|
|
18
|
+
return {
|
|
19
|
+
h: {
|
|
20
|
+
attribute: 'hits',
|
|
21
|
+
type: Number,
|
|
22
|
+
reflect: true,
|
|
23
|
+
},
|
|
24
|
+
fa: {
|
|
25
|
+
attribute: 'false-alarms',
|
|
26
|
+
type: Number,
|
|
27
|
+
reflect: true,
|
|
28
|
+
},
|
|
29
|
+
ppv: {
|
|
30
|
+
attribute: false,
|
|
31
|
+
type: Number,
|
|
32
|
+
reflect: false,
|
|
33
|
+
},
|
|
34
|
+
};
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
constructor() {
|
|
38
|
+
super();
|
|
39
|
+
this.h = 0;
|
|
40
|
+
this.fa = 0;
|
|
41
|
+
this.alignState();
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
alignState() {
|
|
45
|
+
this.ppv = SDTMath.hFa2Ppv(this.h, this.fa);
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
sendEvent() {
|
|
49
|
+
this.dispatchEvent(new CustomEvent('sdt-equation-hfa2ppv-change', {
|
|
50
|
+
detail: {
|
|
51
|
+
h: this.h,
|
|
52
|
+
fa: this.fa,
|
|
53
|
+
ppv: this.ppv,
|
|
54
|
+
},
|
|
55
|
+
bubbles: true,
|
|
56
|
+
}));
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
hInput(event) {
|
|
60
|
+
this.h = parseInt(event.target.value, 10);
|
|
61
|
+
this.alignState();
|
|
62
|
+
this.sendEvent();
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
faInput(event) {
|
|
66
|
+
this.fa = parseInt(event.target.value, 10);
|
|
67
|
+
this.alignState();
|
|
68
|
+
this.sendEvent();
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
render() {
|
|
72
|
+
this.alignState();
|
|
73
|
+
let h;
|
|
74
|
+
let fa;
|
|
75
|
+
let ppv;
|
|
76
|
+
if (this.numeric) {
|
|
77
|
+
h = html`
|
|
78
|
+
<decidables-spinner class="h" ?disabled=${!this.interactive} min="0" .value="${this.h}" @input=${this.hInput.bind(this)}>
|
|
79
|
+
<var>Hits</var>
|
|
80
|
+
</decidables-spinner>
|
|
81
|
+
`;
|
|
82
|
+
fa = html`
|
|
83
|
+
<decidables-spinner class="fa" ?disabled=${!this.interactive} min="0" .value="${this.fa}" @input=${this.faInput.bind(this)}>
|
|
84
|
+
<var>False Alarms</var>
|
|
85
|
+
</decidables-spinner>
|
|
86
|
+
`;
|
|
87
|
+
ppv = html`
|
|
88
|
+
<decidables-spinner class="ppv" disabled min="0" max="1" step=".001" .value="${+this.ppv.toFixed(3)}">
|
|
89
|
+
<var>Positive Predictive Value</var>
|
|
90
|
+
</decidables-spinner>
|
|
91
|
+
`;
|
|
92
|
+
} else {
|
|
93
|
+
h = html`<var class="h">Hits</var>`;
|
|
94
|
+
fa = html`<var class="fa">False Alarms</var>`;
|
|
95
|
+
ppv = html`<var class="ppv">Positive Predictive Value</var>`;
|
|
96
|
+
}
|
|
97
|
+
return html`
|
|
98
|
+
<div class="holder">
|
|
99
|
+
<table class="equation">
|
|
100
|
+
<tbody>
|
|
101
|
+
<tr>
|
|
102
|
+
<td rowspan="2">
|
|
103
|
+
${ppv}<span class="equals">=</span>
|
|
104
|
+
</td>
|
|
105
|
+
<td class="underline">
|
|
106
|
+
${h}
|
|
107
|
+
</td>
|
|
108
|
+
</tr>
|
|
109
|
+
<tr>
|
|
110
|
+
<td>
|
|
111
|
+
${h}<span class="plus">+</span>${fa}
|
|
112
|
+
</td>
|
|
113
|
+
</tr>
|
|
114
|
+
</tbody>
|
|
115
|
+
</table>
|
|
116
|
+
</div>
|
|
117
|
+
`;
|
|
118
|
+
}
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
customElements.define('sdt-equation-hfa2ppv', SDTEquationHFa2Ppv);
|
|
@@ -149,7 +149,7 @@ export default class SDTEquationHMFaCr2Acc extends SDTEquation {
|
|
|
149
149
|
</tr>
|
|
150
150
|
<tr>
|
|
151
151
|
<td>
|
|
152
|
-
${h}<span class="plus">+</span>${
|
|
152
|
+
${h}<span class="plus">+</span>${cr}<span class="plus">+</span>${m}<span class="plus">+</span>${fa}
|
|
153
153
|
</td>
|
|
154
154
|
</tr>
|
|
155
155
|
</tbody>
|
package/src/equations/index.js
CHANGED
|
@@ -2,7 +2,9 @@
|
|
|
2
2
|
export {default as SDTEquationDC2Far} from './dc2far';
|
|
3
3
|
export {default as SDTEquationDC2Hr} from './dc2hr';
|
|
4
4
|
export {default as SDTEquationFaCr2Far} from './facr2far';
|
|
5
|
+
export {default as SDTEquationHFa2Ppv} from './hfa2ppv';
|
|
5
6
|
export {default as SDTEquationHM2Hr} from './hm2hr';
|
|
6
7
|
export {default as SDTEquationHMFaCr2Acc} from './hmfacr2acc';
|
|
7
8
|
export {default as SDTEquationHrFar2C} from './hrfar2c';
|
|
8
9
|
export {default as SDTEquationHrFar2D} from './hrfar2d';
|
|
10
|
+
export {default as SDTEquationMCr2Fomr} from './mcr2fomr';
|
|
@@ -0,0 +1,121 @@
|
|
|
1
|
+
|
|
2
|
+
import {html} from 'lit';
|
|
3
|
+
|
|
4
|
+
import '@decidables/decidables-elements/spinner';
|
|
5
|
+
import SDTMath from '@decidables/detectable-math';
|
|
6
|
+
|
|
7
|
+
import SDTEquation from './sdt-equation';
|
|
8
|
+
|
|
9
|
+
/*
|
|
10
|
+
SDTEquationMCr2Fomr element
|
|
11
|
+
<sdt-equation-mcr2fomr>
|
|
12
|
+
|
|
13
|
+
Attributes:
|
|
14
|
+
Hits; Misses; Hit Rate;
|
|
15
|
+
*/
|
|
16
|
+
export default class SDTEquationMCr2Fomr extends SDTEquation {
|
|
17
|
+
static get properties() {
|
|
18
|
+
return {
|
|
19
|
+
m: {
|
|
20
|
+
attribute: 'misses',
|
|
21
|
+
type: Number,
|
|
22
|
+
reflect: true,
|
|
23
|
+
},
|
|
24
|
+
cr: {
|
|
25
|
+
attribute: 'correct-rejections',
|
|
26
|
+
type: Number,
|
|
27
|
+
reflect: true,
|
|
28
|
+
},
|
|
29
|
+
fomr: {
|
|
30
|
+
attribute: false,
|
|
31
|
+
type: Number,
|
|
32
|
+
reflect: false,
|
|
33
|
+
},
|
|
34
|
+
};
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
constructor() {
|
|
38
|
+
super();
|
|
39
|
+
this.m = 0;
|
|
40
|
+
this.cr = 0;
|
|
41
|
+
this.alignState();
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
alignState() {
|
|
45
|
+
this.fomr = SDTMath.mCr2Fomr(this.m, this.cr);
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
sendEvent() {
|
|
49
|
+
this.dispatchEvent(new CustomEvent('sdt-equation-mcr2fomr-change', {
|
|
50
|
+
detail: {
|
|
51
|
+
m: this.m,
|
|
52
|
+
cr: this.cr,
|
|
53
|
+
fomr: this.fomr,
|
|
54
|
+
},
|
|
55
|
+
bubbles: true,
|
|
56
|
+
}));
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
mInput(event) {
|
|
60
|
+
this.m = parseInt(event.target.value, 10);
|
|
61
|
+
this.alignState();
|
|
62
|
+
this.sendEvent();
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
crInput(event) {
|
|
66
|
+
this.cr = parseInt(event.target.value, 10);
|
|
67
|
+
this.alignState();
|
|
68
|
+
this.sendEvent();
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
render() {
|
|
72
|
+
this.alignState();
|
|
73
|
+
let m;
|
|
74
|
+
let cr;
|
|
75
|
+
let fomr;
|
|
76
|
+
if (this.numeric) {
|
|
77
|
+
m = html`
|
|
78
|
+
<decidables-spinner class="m" ?disabled=${!this.interactive} min="0" .value="${this.m}" @input=${this.mInput.bind(this)}>
|
|
79
|
+
<var>Misses</var>
|
|
80
|
+
</decidables-spinner>
|
|
81
|
+
`;
|
|
82
|
+
cr = html`
|
|
83
|
+
<decidables-spinner class="cr" ?disabled=${!this.interactive} min="0" .value="${this.cr}" @input=${this.crInput.bind(this)}>
|
|
84
|
+
<var>Correct Rejections</var>
|
|
85
|
+
</decidables-spinner>
|
|
86
|
+
`;
|
|
87
|
+
fomr = html`
|
|
88
|
+
<decidables-spinner class="fomr" disabled min="0" max="1" step=".001" .value="${+this.fomr.toFixed(3)}">
|
|
89
|
+
<var>False Omission Rate</var>
|
|
90
|
+
</decidables-spinner>
|
|
91
|
+
`;
|
|
92
|
+
} else {
|
|
93
|
+
m = html`<var class="m">Misses</var>`;
|
|
94
|
+
cr = html`<var class="cr">Correct Rejections</var>`;
|
|
95
|
+
fomr = html`<var class="fomr">False Omission Rate</var>`;
|
|
96
|
+
}
|
|
97
|
+
return html`
|
|
98
|
+
<div class="holder">
|
|
99
|
+
<table class="equation">
|
|
100
|
+
<tbody>
|
|
101
|
+
<tr>
|
|
102
|
+
<td rowspan="2">
|
|
103
|
+
${fomr}<span class="equals">=</span>
|
|
104
|
+
</td>
|
|
105
|
+
<td class="underline">
|
|
106
|
+
${m}
|
|
107
|
+
</td>
|
|
108
|
+
</tr>
|
|
109
|
+
<tr>
|
|
110
|
+
<td>
|
|
111
|
+
${m}<span class="plus">+</span>${cr}
|
|
112
|
+
</td>
|
|
113
|
+
</tr>
|
|
114
|
+
</tbody>
|
|
115
|
+
</table>
|
|
116
|
+
</div>
|
|
117
|
+
`;
|
|
118
|
+
}
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
customElements.define('sdt-equation-mcr2fomr', SDTEquationMCr2Fomr);
|
|
@@ -45,6 +45,7 @@ export default class SDTEquation extends DetectableElement {
|
|
|
45
45
|
/* Overall <table> */
|
|
46
46
|
.equation {
|
|
47
47
|
text-align: center;
|
|
48
|
+
white-space: nowrap;
|
|
48
49
|
|
|
49
50
|
border-collapse: collapse;
|
|
50
51
|
|
|
@@ -64,6 +65,10 @@ export default class SDTEquation extends DetectableElement {
|
|
|
64
65
|
font-style: normal;
|
|
65
66
|
}
|
|
66
67
|
|
|
68
|
+
var {
|
|
69
|
+
border-radius: var(---border-radius);
|
|
70
|
+
}
|
|
71
|
+
|
|
67
72
|
.tight {
|
|
68
73
|
padding: 0;
|
|
69
74
|
}
|
|
@@ -89,6 +94,8 @@ export default class SDTEquation extends DetectableElement {
|
|
|
89
94
|
padding: 0.125rem 0.375rem 0.375rem;
|
|
90
95
|
|
|
91
96
|
vertical-align: middle;
|
|
97
|
+
|
|
98
|
+
border-radius: var(---border-radius);
|
|
92
99
|
}
|
|
93
100
|
|
|
94
101
|
.bottom {
|
|
@@ -112,6 +119,14 @@ export default class SDTEquation extends DetectableElement {
|
|
|
112
119
|
background: var(---color-fa-light);
|
|
113
120
|
}
|
|
114
121
|
|
|
122
|
+
.ppv {
|
|
123
|
+
background: var(---color-present-light);
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
.fomr {
|
|
127
|
+
background: var(---color-absent-light);
|
|
128
|
+
}
|
|
129
|
+
|
|
115
130
|
.acc {
|
|
116
131
|
background: var(---color-acc-light);
|
|
117
132
|
}
|
package/src/examples/index.js
CHANGED
|
@@ -3,4 +3,5 @@ export {default as SDTExampleDoubleInteractive} from './double-interactive';
|
|
|
3
3
|
export {default as SDTExampleHuman} from './human';
|
|
4
4
|
export {default as SDTExampleInteractive} from './interactive';
|
|
5
5
|
export {default as SDTExampleModel} from './model';
|
|
6
|
+
export {default as SDTExampleMultiple} from './multiple';
|
|
6
7
|
export {default as SDTExampleUnequal} from './unequal';
|