edfcore 0.6.32 → 0.6.34
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/constants.d.ts +1 -1
- package/dist/constants.js +1 -1
- package/dist/format-report.d.ts.map +1 -1
- package/dist/format-report.js +30 -7
- package/dist/format-report.js.map +1 -1
- package/docs/CHANGELOG.md +32 -0
- package/package.json +1 -1
- package/src/constants.ts +1 -1
- package/src/format-report.ts +32 -8
package/dist/constants.d.ts
CHANGED
|
@@ -109,5 +109,5 @@ export declare const SIGNAL_FIELD_BLOCK_OFFSETS: {
|
|
|
109
109
|
readonly reserved: 224;
|
|
110
110
|
};
|
|
111
111
|
/** Published package version. Kept in sync with package.json by a test. */
|
|
112
|
-
export declare const VERSION = "0.6.
|
|
112
|
+
export declare const VERSION = "0.6.34";
|
|
113
113
|
//# sourceMappingURL=constants.d.ts.map
|
package/dist/constants.js
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"format-report.d.ts","sourceRoot":"","sources":["../src/format-report.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;GAaG;AAMH,OAAO,KAAK,EAAE,SAAS,EAAE,mBAAmB,EAAE,gBAAgB,EAAE,MAAM,YAAY,CAAC;AAKnF;;;;;GAKG;AACH,wBAAgB,sBAAsB,CACpC,MAAM,EAAE,gBAAgB,EACxB,OAAO,CAAC,EAAE,mBAAmB,GAC5B,MAAM,
|
|
1
|
+
{"version":3,"file":"format-report.d.ts","sourceRoot":"","sources":["../src/format-report.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;GAaG;AAMH,OAAO,KAAK,EAAE,SAAS,EAAE,mBAAmB,EAAE,gBAAgB,EAAE,MAAM,YAAY,CAAC;AAKnF;;;;;GAKG;AACH,wBAAgB,sBAAsB,CACpC,MAAM,EAAE,gBAAgB,EACxB,OAAO,CAAC,EAAE,mBAAmB,GAC5B,MAAM,CAuGR;AAED,qFAAqF;AACrF,YAAY,EAAE,SAAS,EAAE,CAAC"}
|
package/dist/format-report.js
CHANGED
|
@@ -63,18 +63,41 @@ export function formatValidationReport(report, options) {
|
|
|
63
63
|
if (report.signalStats.length > 0) {
|
|
64
64
|
lines.push('');
|
|
65
65
|
lines.push('observed sample ranges:');
|
|
66
|
-
|
|
66
|
+
/*
|
|
67
|
+
* The range and the count are sized from the rows, not left to fall where they land.
|
|
68
|
+
*
|
|
69
|
+
* An observed range is as wide as the numbers in it, and those differ per channel: on the
|
|
70
|
+
* PhysioNet polysomnogram the seven rows read `-2048..1819`, `-54..1905` and `136..980`, so
|
|
71
|
+
* the word `over` sat at three different columns in one block and the sample counts under it
|
|
72
|
+
* at three more. It is the same defect as the sample rate (0.6.23), the signal index (0.6.24)
|
|
73
|
+
* and the event clock (0.6.25) — a value wider than the space it was given — in the fourth
|
|
74
|
+
* formatter, and the same fix: measure the rows first.
|
|
75
|
+
*
|
|
76
|
+
* The count is right-aligned because it is a number and the eye compares magnitudes down a
|
|
77
|
+
* column. A single-signal file has one row, so its widths are its own and its output does not
|
|
78
|
+
* move.
|
|
79
|
+
*/
|
|
80
|
+
const rows = report.signalStats.map((stats) => {
|
|
67
81
|
const signal = header?.signals[stats.signalIndex];
|
|
68
82
|
// Through `printable` for the reason `formatHeader` does it: a label is arbitrary bytes
|
|
69
83
|
// from the file, and one holding a newline would open a row naming a signal that does not
|
|
70
84
|
// exist — in a conformance report, which is read precisely because the file is suspect.
|
|
71
85
|
const name = signal === undefined ? `signal ${stats.signalIndex}` : printable(signal.label);
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
:
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
86
|
+
return {
|
|
87
|
+
name: name.slice(0, 20).padEnd(21),
|
|
88
|
+
range: `${stats.observedDigitalMin}..${stats.observedDigitalMax}`,
|
|
89
|
+
count: stats.sampleCount.toLocaleString('en-US'),
|
|
90
|
+
noun: plural('sample', stats.sampleCount),
|
|
91
|
+
overflow: stats.outOfDigitalRangeCount > 0
|
|
92
|
+
? ` ${stats.outOfDigitalRangeCount} outside the declared range`
|
|
93
|
+
: '',
|
|
94
|
+
};
|
|
95
|
+
});
|
|
96
|
+
const rangeWidth = Math.max(...rows.map((row) => row.range.length));
|
|
97
|
+
const countWidth = Math.max(...rows.map((row) => row.count.length));
|
|
98
|
+
for (const row of rows) {
|
|
99
|
+
lines.push(` ${row.name}${row.range.padEnd(rangeWidth)} over ${row.count.padStart(countWidth)} ` +
|
|
100
|
+
`${row.noun}${row.overflow}`);
|
|
78
101
|
}
|
|
79
102
|
}
|
|
80
103
|
if (report.diagnostics.length > 0) {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"format-report.js","sourceRoot":"","sources":["../src/format-report.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;GAaG;AAEH,OAAO,EAAE,sBAAsB,EAAE,iBAAiB,EAAE,MAAM,yBAAyB,CAAC;AACpF,OAAO,EAAE,oBAAoB,EAAE,MAAM,0BAA0B,CAAC;AAChE,OAAO,EAAE,MAAM,EAAE,SAAS,EAAE,MAAM,mBAAmB,CAAC;AACtD,OAAO,EAAE,SAAS,EAAE,MAAM,qBAAqB,CAAC;AAGhD,+EAA+E;AAC/E,MAAM,iBAAiB,GAAG,EAAE,CAAC;AAE7B;;;;;GAKG;AACH,MAAM,UAAU,sBAAsB,CACpC,MAAwB,EACxB,OAA6B;IAE7B,MAAM,KAAK,GAAa,EAAE,CAAC;IAC3B,MAAM,MAAM,GAAG,OAAO,EAAE,MAAM,CAAC;IAE/B,+FAA+F;IAC/F,iGAAiG;IACjG,0DAA0D;IAC1D,sBAAsB,CAAC,OAAO,EAAE,YAAY,CAAC,CAAC;IAE9C,8EAA8E;IAC9E,MAAM,OAAO,GAAG,oBAAoB,CAAC,MAAM,CAAC,WAAW,CAAC,CAAC;IAEzD,MAAM,OAAO,GAAG,MAAM,CAAC,EAAE,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,MAAM,CAAC;IAC5C,MAAM,UAAU,GACd,OAAO,CAAC,KAAK,KAAK,CAAC;QACjB,CAAC,CAAC,gBAAgB;QAClB,CAAC,CACG;YACE,CAAC,OAAO,CAAC,MAAM,EAAE,OAAO,CAAC;YACzB,CAAC,OAAO,CAAC,QAAQ,EAAE,SAAS,CAAC;YAC7B,CAAC,OAAO,CAAC,KAAK,EAAE,MAAM,CAAC;SAE1B;aACE,MAAM,CAAC,CAAC,CAAC,KAAK,CAAC,EAAE,EAAE,CAAC,KAAK,GAAG,CAAC,CAAC;YAC/B,qFAAqF;YACrF,4DAA4D;YAC5D,oFAAoF;YACpF,oFAAoF;YACpF,wFAAwF;aACvF,GAAG,CAAC,CAAC,CAAC,KAAK,EAAE,QAAQ,CAAC,EAAE,EAAE,CAAC,SAAS,CAAC,KAAK,EAAE,QAAQ,CAAC,CAAC;aACtD,IAAI,CAAC,IAAI,CAAC,CAAC;IACpB,KAAK,CAAC,IAAI,CAAC,GAAG,OAAO,MAAM,UAAU,EAAE,CAAC,CAAC;IACzC,KAAK,CAAC,IAAI,CACR,WAAW,SAAS,CAAC,MAAM,CAAC,cAAc,EAAE,QAAQ,CAAC,IAAI;QACvD,QAAQ,MAAM,CAAC,SAAS,CAAC,cAAc,CAAC,OAAO,CAAC,IAAI,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,SAAS,CAAC,EAAE,CACzF,CAAC;IAEF,IAAI,OAAO,CAAC,MAAM,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;QAC9B,KAAK,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC;QACf,KAAK,CAAC,IAAI,CAAC,UAAU,CAAC,CAAC;QACvB,gFAAgF;QAChF,KAAK,MAAM,EAAE,IAAI,EAAE,KAAK,EAAE,IAAI,OAAO,CAAC,MAAM,EAAE,CAAC;YAC7C,KAAK,CAAC,IAAI,CAAC,KAAK,MAAM,CAAC,KAAK,CAAC,CAAC,QAAQ,CAAC,CAAC,CAAC,KAAK,IAAI,EAAE,CAAC,CAAC;QACxD,CAAC;IACH,CAAC;IAED,IAAI,MAAM,CAAC,WAAW,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;QAClC,KAAK,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC;QACf,KAAK,CAAC,IAAI,CAAC,yBAAyB,CAAC,CAAC;QACtC,
|
|
1
|
+
{"version":3,"file":"format-report.js","sourceRoot":"","sources":["../src/format-report.ts"],"names":[],"mappings":"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"}
|
package/docs/CHANGELOG.md
CHANGED
|
@@ -6,6 +6,38 @@ alone does not tell you whether you were affected.
|
|
|
6
6
|
edfcore is pre-1.0. Patch releases have carried behaviour changes where the old behaviour was a
|
|
7
7
|
defect; those are called out below.
|
|
8
8
|
|
|
9
|
+
## 0.6.34
|
|
10
|
+
|
|
11
|
+
- **Fixed** the observed-ranges block in `edfcore validate` falling where the numbers left it. The
|
|
12
|
+
range went straight after the padded label and the sample count straight after that, so both
|
|
13
|
+
columns moved per row. On the PhysioNet polysomnogram that is seven rows and three offsets:
|
|
14
|
+
`-2048..1819 over 7,950,000 samples`, `-54..1905 over 79,500 samples`, `136..980 over 79,500
|
|
15
|
+
samples`.
|
|
16
|
+
- That block exists so a reader can compare channels down a column — it is called "observed sample
|
|
17
|
+
ranges" — and it was the one output where comparing meant re-finding the number on every line.
|
|
18
|
+
- Same defect as the sample rate (0.6.23), the signal index (0.6.24) and the event clock (0.6.25),
|
|
19
|
+
in the fourth and last formatter that lays out a table: a value wider than the space it was
|
|
20
|
+
given. Same fix: measure the rows first. The count is right-aligned, because it is a number and
|
|
21
|
+
magnitudes compare down a column; the range is left-aligned, because `min..max` has no single
|
|
22
|
+
place to hang.
|
|
23
|
+
- A single-signal file has one row, so its widths are its own and its report is byte for byte what
|
|
24
|
+
it was.
|
|
25
|
+
|
|
26
|
+
## 0.6.33
|
|
27
|
+
|
|
28
|
+
- **Added** a sixteenth shape to the `AWKWARD` matrix: BDF+D, 24-bit samples and a discontinuity in
|
|
29
|
+
one file. The matrix held both halves and never together — every BDF shape in it ran end to end,
|
|
30
|
+
and every discontinuous shape was 16-bit EDF — so a three-byte stride and a chunk boundary that
|
|
31
|
+
is not the nominal grid had never met.
|
|
32
|
+
- They meet in one arithmetic. A read across a gap resolves a record range per contiguous run, and
|
|
33
|
+
each run's bytes are addressed as `headerByteLength + record * recordByteLength +
|
|
34
|
+
signal.recordByteOffset`, where every term is a multiple of `bytesPerSample` — 3 here and 2
|
|
35
|
+
everywhere else in the matrix — and a sign extension that is right for a 16-bit sample is wrong
|
|
36
|
+
for a 24-bit one. An off-by-one in either would show on this file and on no other.
|
|
37
|
+
- Thirty sweeps run over the matrix and all of them pass over it. `twenty-four-bits-across-a-gap.
|
|
38
|
+
test.ts` checks the crossing is real rather than nominal: two segments, a seven-second hole, and
|
|
39
|
+
the same samples through `readWindow` across the join as through the whole record range.
|
|
40
|
+
|
|
9
41
|
## 0.6.32
|
|
10
42
|
|
|
11
43
|
- **Added** a fifteenth shape to the `AWKWARD` matrix: a file with two annotation channels of
|
package/package.json
CHANGED
package/src/constants.ts
CHANGED
package/src/format-report.ts
CHANGED
|
@@ -80,20 +80,44 @@ export function formatValidationReport(
|
|
|
80
80
|
if (report.signalStats.length > 0) {
|
|
81
81
|
lines.push('');
|
|
82
82
|
lines.push('observed sample ranges:');
|
|
83
|
-
|
|
83
|
+
/*
|
|
84
|
+
* The range and the count are sized from the rows, not left to fall where they land.
|
|
85
|
+
*
|
|
86
|
+
* An observed range is as wide as the numbers in it, and those differ per channel: on the
|
|
87
|
+
* PhysioNet polysomnogram the seven rows read `-2048..1819`, `-54..1905` and `136..980`, so
|
|
88
|
+
* the word `over` sat at three different columns in one block and the sample counts under it
|
|
89
|
+
* at three more. It is the same defect as the sample rate (0.6.23), the signal index (0.6.24)
|
|
90
|
+
* and the event clock (0.6.25) — a value wider than the space it was given — in the fourth
|
|
91
|
+
* formatter, and the same fix: measure the rows first.
|
|
92
|
+
*
|
|
93
|
+
* The count is right-aligned because it is a number and the eye compares magnitudes down a
|
|
94
|
+
* column. A single-signal file has one row, so its widths are its own and its output does not
|
|
95
|
+
* move.
|
|
96
|
+
*/
|
|
97
|
+
const rows = report.signalStats.map((stats) => {
|
|
84
98
|
const signal = header?.signals[stats.signalIndex];
|
|
85
99
|
// Through `printable` for the reason `formatHeader` does it: a label is arbitrary bytes
|
|
86
100
|
// from the file, and one holding a newline would open a row naming a signal that does not
|
|
87
101
|
// exist — in a conformance report, which is read precisely because the file is suspect.
|
|
88
102
|
const name = signal === undefined ? `signal ${stats.signalIndex}` : printable(signal.label);
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
103
|
+
return {
|
|
104
|
+
name: name.slice(0, 20).padEnd(21),
|
|
105
|
+
range: `${stats.observedDigitalMin}..${stats.observedDigitalMax}`,
|
|
106
|
+
count: stats.sampleCount.toLocaleString('en-US'),
|
|
107
|
+
noun: plural('sample', stats.sampleCount),
|
|
108
|
+
overflow:
|
|
109
|
+
stats.outOfDigitalRangeCount > 0
|
|
110
|
+
? ` ${stats.outOfDigitalRangeCount} outside the declared range`
|
|
111
|
+
: '',
|
|
112
|
+
};
|
|
113
|
+
});
|
|
114
|
+
const rangeWidth = Math.max(...rows.map((row) => row.range.length));
|
|
115
|
+
const countWidth = Math.max(...rows.map((row) => row.count.length));
|
|
116
|
+
|
|
117
|
+
for (const row of rows) {
|
|
93
118
|
lines.push(
|
|
94
|
-
` ${name.
|
|
95
|
-
|
|
96
|
-
`${plural('sample', stats.sampleCount)}${overflow}`,
|
|
119
|
+
` ${row.name}${row.range.padEnd(rangeWidth)} over ${row.count.padStart(countWidth)} ` +
|
|
120
|
+
`${row.noun}${row.overflow}`,
|
|
97
121
|
);
|
|
98
122
|
}
|
|
99
123
|
}
|