svelteplot 0.7.1-pr-280.14 → 0.7.1-pr-280.16
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.
|
@@ -17,10 +17,13 @@ type DensityOptions<T> = {
|
|
|
17
17
|
*/
|
|
18
18
|
interval?: number | string;
|
|
19
19
|
/**
|
|
20
|
-
*
|
|
20
|
+
* If true, the density values will be trimmed to the range of the data.
|
|
21
21
|
*/
|
|
22
22
|
trim?: boolean;
|
|
23
|
-
|
|
23
|
+
/**
|
|
24
|
+
* If true, the density values will be cumulative.
|
|
25
|
+
*/
|
|
26
|
+
cumulative?: false | 1 | -1;
|
|
24
27
|
};
|
|
25
28
|
/**
|
|
26
29
|
* One-dimensional kernel density estimation
|
|
@@ -102,11 +102,12 @@ function roundToTerminating(x, sig = 2) {
|
|
|
102
102
|
}
|
|
103
103
|
function density1d(independent, { data, weight, ...channels }, options = {}) {
|
|
104
104
|
const densityChannel = independent === 'x' ? 'y' : 'x';
|
|
105
|
-
const { kernel, bandwidth, interval, trim, channel } = {
|
|
105
|
+
const { kernel, bandwidth, interval, trim, channel, cumulative } = {
|
|
106
106
|
kernel: 'epanechnikov',
|
|
107
107
|
bandwidth: bandwidthSilverman,
|
|
108
108
|
interval: undefined,
|
|
109
109
|
trim: false,
|
|
110
|
+
cumulative: false,
|
|
110
111
|
channel: densityChannel,
|
|
111
112
|
...options
|
|
112
113
|
};
|
|
@@ -143,7 +144,7 @@ function density1d(independent, { data, weight, ...channels }, options = {}) {
|
|
|
143
144
|
const res = groupFacetsAndZ(resolvedData, channels, (items, groupProps) => {
|
|
144
145
|
const values = items.map((d) => d[VALUE]);
|
|
145
146
|
const weights = items.map((d) => d[WEIGHT]);
|
|
146
|
-
let kdeValues = kde1d(values, weights, atValues, k, bw)
|
|
147
|
+
let kdeValues = kde1d(values, weights, atValues, k, bw, cumulative)
|
|
147
148
|
.filter(([x, density]) => x != null && !isNaN(density))
|
|
148
149
|
.sort((a, b) => a[0] - b[0]);
|
|
149
150
|
if (!trim) {
|
|
@@ -165,16 +166,16 @@ function density1d(independent, { data, weight, ...channels }, options = {}) {
|
|
|
165
166
|
[independent]: CHANNELS[independent],
|
|
166
167
|
[channel]: CHANNELS[densityChannel],
|
|
167
168
|
...res,
|
|
168
|
-
[ORIGINAL_NAME_KEYS[densityChannel]]: 'Density',
|
|
169
|
+
[ORIGINAL_NAME_KEYS[densityChannel]]: cumulative === false ? 'Density' : 'CDF',
|
|
169
170
|
[ORIGINAL_NAME_KEYS[independent]]: typeof channels[independent] === 'string' ? channels[independent] : undefined,
|
|
170
171
|
sort: [{ channel: CHANNELS[independent], order: 'ascending' }],
|
|
171
172
|
data: outData
|
|
172
173
|
};
|
|
173
174
|
}
|
|
174
|
-
function kde1d(values, weights, atValues, kernel, bw) {
|
|
175
|
+
function kde1d(values, weights, atValues, kernel, bw, cumulative) {
|
|
175
176
|
const n = values.length;
|
|
176
177
|
const weightSum = weights.reduce((a, b) => a + b, 0);
|
|
177
|
-
|
|
178
|
+
const densities = atValues.map((x) => {
|
|
178
179
|
let sum = 0;
|
|
179
180
|
for (let i = 0; i < n; i++) {
|
|
180
181
|
const u = (x - values[i]) / bw;
|
|
@@ -182,6 +183,38 @@ function kde1d(values, weights, atValues, kernel, bw) {
|
|
|
182
183
|
}
|
|
183
184
|
return [x, sum / (weightSum * bw)];
|
|
184
185
|
});
|
|
186
|
+
if (!cumulative)
|
|
187
|
+
return densities;
|
|
188
|
+
const totalArea = densities.reduce((acc, curr, i) => {
|
|
189
|
+
if (i === 0)
|
|
190
|
+
return acc;
|
|
191
|
+
const dx = densities[i][0] - densities[i - 1][0];
|
|
192
|
+
return acc + ((densities[i - 1][1] + curr[1]) / 2) * dx;
|
|
193
|
+
}, 0);
|
|
194
|
+
if (totalArea === 0)
|
|
195
|
+
return densities;
|
|
196
|
+
if (cumulative === -1) {
|
|
197
|
+
let area = 0;
|
|
198
|
+
const cdf = new Array(densities.length);
|
|
199
|
+
for (let i = densities.length - 1; i >= 0; i--) {
|
|
200
|
+
if (i < densities.length - 1) {
|
|
201
|
+
const dx = densities[i + 1][0] - densities[i][0];
|
|
202
|
+
area += ((densities[i + 1][1] + densities[i][1]) / 2) * dx;
|
|
203
|
+
}
|
|
204
|
+
cdf[i] = [densities[i][0], area / totalArea];
|
|
205
|
+
}
|
|
206
|
+
return cdf;
|
|
207
|
+
}
|
|
208
|
+
let area = 0;
|
|
209
|
+
const cdf = new Array(densities.length);
|
|
210
|
+
for (let i = 0; i < densities.length; i++) {
|
|
211
|
+
if (i > 0) {
|
|
212
|
+
const dx = densities[i][0] - densities[i - 1][0];
|
|
213
|
+
area += ((densities[i - 1][1] + densities[i][1]) / 2) * dx;
|
|
214
|
+
}
|
|
215
|
+
cdf[i] = [densities[i][0], area / totalArea];
|
|
216
|
+
}
|
|
217
|
+
return cdf;
|
|
185
218
|
}
|
|
186
219
|
function maybeKernel(kernel) {
|
|
187
220
|
if (typeof kernel === 'function')
|