@uwdata/mosaic-plot 0.8.0 → 0.9.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.
@@ -163,3 +163,91 @@ export function qt(p, dof) {
163
163
  x = Math.sqrt((dof * (1 - x)) / x);
164
164
  return p > 0.5 ? x : -x;
165
165
  }
166
+
167
+ /**
168
+ * Approximate inverse error function.
169
+ * @param {number} x
170
+ * @returns {number}
171
+ */
172
+ export function erfinv(x) {
173
+ // Implementation from "Approximating the erfinv function" by Mike Giles,
174
+ // GPU Computing Gems, volume 2, 2010.
175
+ // Ported from Apache Commons Math, http://www.apache.org/licenses/LICENSE-2.0
176
+
177
+ // beware that the logarithm argument must be
178
+ // computed as (1.0 - x) * (1.0 + x),
179
+ // it must NOT be simplified as 1.0 - x * x as this
180
+ // would induce rounding errors near the boundaries +/-1
181
+ let w = - Math.log((1 - x) * (1 + x));
182
+ let p;
183
+
184
+ if (w < 6.25) {
185
+ w -= 3.125;
186
+ p = -3.6444120640178196996e-21;
187
+ p = -1.685059138182016589e-19 + p * w;
188
+ p = 1.2858480715256400167e-18 + p * w;
189
+ p = 1.115787767802518096e-17 + p * w;
190
+ p = -1.333171662854620906e-16 + p * w;
191
+ p = 2.0972767875968561637e-17 + p * w;
192
+ p = 6.6376381343583238325e-15 + p * w;
193
+ p = -4.0545662729752068639e-14 + p * w;
194
+ p = -8.1519341976054721522e-14 + p * w;
195
+ p = 2.6335093153082322977e-12 + p * w;
196
+ p = -1.2975133253453532498e-11 + p * w;
197
+ p = -5.4154120542946279317e-11 + p * w;
198
+ p = 1.051212273321532285e-09 + p * w;
199
+ p = -4.1126339803469836976e-09 + p * w;
200
+ p = -2.9070369957882005086e-08 + p * w;
201
+ p = 4.2347877827932403518e-07 + p * w;
202
+ p = -1.3654692000834678645e-06 + p * w;
203
+ p = -1.3882523362786468719e-05 + p * w;
204
+ p = 0.0001867342080340571352 + p * w;
205
+ p = -0.00074070253416626697512 + p * w;
206
+ p = -0.0060336708714301490533 + p * w;
207
+ p = 0.24015818242558961693 + p * w;
208
+ p = 1.6536545626831027356 + p * w;
209
+ } else if (w < 16.0) {
210
+ w = Math.sqrt(w) - 3.25;
211
+ p = 2.2137376921775787049e-09;
212
+ p = 9.0756561938885390979e-08 + p * w;
213
+ p = -2.7517406297064545428e-07 + p * w;
214
+ p = 1.8239629214389227755e-08 + p * w;
215
+ p = 1.5027403968909827627e-06 + p * w;
216
+ p = -4.013867526981545969e-06 + p * w;
217
+ p = 2.9234449089955446044e-06 + p * w;
218
+ p = 1.2475304481671778723e-05 + p * w;
219
+ p = -4.7318229009055733981e-05 + p * w;
220
+ p = 6.8284851459573175448e-05 + p * w;
221
+ p = 2.4031110387097893999e-05 + p * w;
222
+ p = -0.0003550375203628474796 + p * w;
223
+ p = 0.00095328937973738049703 + p * w;
224
+ p = -0.0016882755560235047313 + p * w;
225
+ p = 0.0024914420961078508066 + p * w;
226
+ p = -0.0037512085075692412107 + p * w;
227
+ p = 0.005370914553590063617 + p * w;
228
+ p = 1.0052589676941592334 + p * w;
229
+ p = 3.0838856104922207635 + p * w;
230
+ } else if (Number.isFinite(w)) {
231
+ w = Math.sqrt(w) - 5.0;
232
+ p = -2.7109920616438573243e-11;
233
+ p = -2.5556418169965252055e-10 + p * w;
234
+ p = 1.5076572693500548083e-09 + p * w;
235
+ p = -3.7894654401267369937e-09 + p * w;
236
+ p = 7.6157012080783393804e-09 + p * w;
237
+ p = -1.4960026627149240478e-08 + p * w;
238
+ p = 2.9147953450901080826e-08 + p * w;
239
+ p = -6.7711997758452339498e-08 + p * w;
240
+ p = 2.2900482228026654717e-07 + p * w;
241
+ p = -9.9298272942317002539e-07 + p * w;
242
+ p = 4.5260625972231537039e-06 + p * w;
243
+ p = -1.9681778105531670567e-05 + p * w;
244
+ p = 7.5995277030017761139e-05 + p * w;
245
+ p = -0.00021503011930044477347 + p * w;
246
+ p = -0.00013871931833623122026 + p * w;
247
+ p = 1.0103004648645343977 + p * w;
248
+ p = 4.8499064014085844221 + p * w;
249
+ } else {
250
+ p = Infinity;
251
+ }
252
+ return p * x;
253
+ }
@@ -1,7 +1,6 @@
1
1
  import * as Plot from '@observablehq/plot';
2
2
  import { setAttributes } from './plot-attributes.js';
3
3
  import { Fixed } from './symbols.js';
4
- import { isArrowTable } from '@uwdata/mosaic-core';
5
4
 
6
5
  const OPTIONS_ONLY_MARKS = new Set([
7
6
  'frame',
@@ -10,6 +9,19 @@ const OPTIONS_ONLY_MARKS = new Set([
10
9
  'graticule'
11
10
  ]);
12
11
 
12
+ // @ts-ignore
13
+ const SELECT_TRANSFORMS = new Map([
14
+ ['first', Plot.selectFirst],
15
+ ['last', Plot.selectLast],
16
+ ['maxX', Plot.selectMaxX],
17
+ ['maxY', Plot.selectMaxY],
18
+ ['minX', Plot.selectMinX],
19
+ ['minY', Plot.selectMinY],
20
+ ['nearest', Plot.pointer],
21
+ ['nearestX', Plot.pointerX],
22
+ ['nearestXY', Plot.pointerY]
23
+ ]);
24
+
13
25
  // construct Plot output
14
26
  // see https://github.com/observablehq/plot
15
27
  export async function plotRenderer(plot) {
@@ -24,27 +36,13 @@ export async function plotRenderer(plot) {
24
36
  const indices = [];
25
37
  for (const mark of marks) {
26
38
  for (const { type, data, options } of mark.plotSpecs()) {
27
- if (OPTIONS_ONLY_MARKS.has(type)) {
28
- spec.marks.push(Plot[type](options));
29
- } else if (isArrowTable(data)) {
30
- // optimized calls to Plot for Arrow:
31
- // https://github.com/observablehq/plot/issues/191#issuecomment-2010986851
32
- const opts = Object.fromEntries(
33
- Object.entries(options).map(([k, v]) => {
34
- let val = v;
35
- if (typeof v === 'string') {
36
- val = data.getChild(v) ?? v;
37
- } else if (typeof v === 'object') {
38
- const value = data.getChild(v.value);
39
- val = value ? {value} : v;
40
- }
41
- return [k, val]
42
- })
43
- );
44
- spec.marks.push(Plot[type]({length: data.numRows}, opts));
45
- } else {
46
- spec.marks.push(Plot[type](data, options));
47
- }
39
+ // prepare mark options
40
+ const { select, ...rest } = options;
41
+ const opt = SELECT_TRANSFORMS.get(select)?.(rest) ?? rest;
42
+ const arg = OPTIONS_ONLY_MARKS.has(type) ? [opt] : [data, opt];
43
+
44
+ // instantiate Plot mark and add to spec
45
+ spec.marks.push(Plot[type](...arg));
48
46
  indices.push(mark.index);
49
47
  }
50
48
  }
@@ -165,6 +163,7 @@ function annotateMarks(svg, indices) {
165
163
  }
166
164
 
167
165
  function getType(data, channel) {
166
+ if (!data) return;
168
167
  const { columns } = data;
169
168
  const col = columns[channel] ?? columns[channel+'1'] ?? columns[channel+'2'];
170
169
  if (col) {
@@ -1,7 +1,9 @@
1
1
  import { Transform } from '../symbols.js';
2
2
  import { channelScale } from '../marks/util/channel-scale.js';
3
3
 
4
- const EXTENT = new Set(['rectY-x', 'rectX-y', 'rect-x', 'rect-y']);
4
+ const EXTENT = new Set([
5
+ 'rectY-x', 'rectX-y', 'rect-x', 'rect-y', 'ruleY-x', 'ruleX-y'
6
+ ]);
5
7
 
6
8
  export function bin(field, options = { steps: 25 }) {
7
9
  const fn = (mark, channel) => {