@compstats/core 0.2.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.
Files changed (98) hide show
  1. package/CHANGELOG.md +110 -0
  2. package/LICENSE +21 -0
  3. package/README.md +310 -0
  4. package/dist/3d.d.ts +33 -0
  5. package/dist/3d.d.ts.map +1 -0
  6. package/dist/3d.js +1984 -0
  7. package/dist/3d.js.map +22 -0
  8. package/dist/core/arith.d.ts +133 -0
  9. package/dist/core/arith.d.ts.map +1 -0
  10. package/dist/core/frame.d.ts +98 -0
  11. package/dist/core/frame.d.ts.map +1 -0
  12. package/dist/core/histogram.d.ts +68 -0
  13. package/dist/core/histogram.d.ts.map +1 -0
  14. package/dist/core/kde.d.ts +106 -0
  15. package/dist/core/kde.d.ts.map +1 -0
  16. package/dist/core/logit.d.ts +109 -0
  17. package/dist/core/logit.d.ts.map +1 -0
  18. package/dist/core/matrix.d.ts +135 -0
  19. package/dist/core/matrix.d.ts.map +1 -0
  20. package/dist/core/moderation.d.ts +127 -0
  21. package/dist/core/moderation.d.ts.map +1 -0
  22. package/dist/core/ols.d.ts +76 -0
  23. package/dist/core/ols.d.ts.map +1 -0
  24. package/dist/core/pca.d.ts +99 -0
  25. package/dist/core/pca.d.ts.map +1 -0
  26. package/dist/core/precision.d.ts +10 -0
  27. package/dist/core/precision.d.ts.map +1 -0
  28. package/dist/core/pretty.d.ts +51 -0
  29. package/dist/core/pretty.d.ts.map +1 -0
  30. package/dist/core/regression.d.ts +68 -0
  31. package/dist/core/regression.d.ts.map +1 -0
  32. package/dist/core/rng.d.ts +206 -0
  33. package/dist/core/rng.d.ts.map +1 -0
  34. package/dist/core/sampling.d.ts +157 -0
  35. package/dist/core/sampling.d.ts.map +1 -0
  36. package/dist/core/special.d.ts +92 -0
  37. package/dist/core/special.d.ts.map +1 -0
  38. package/dist/core/tdist.d.ts +53 -0
  39. package/dist/core/tdist.d.ts.map +1 -0
  40. package/dist/core/ttest.d.ts +146 -0
  41. package/dist/core/ttest.d.ts.map +1 -0
  42. package/dist/data/moderationData.d.ts +40 -0
  43. package/dist/data/moderationData.d.ts.map +1 -0
  44. package/dist/data/pcaDegenerate.d.ts +18 -0
  45. package/dist/data/pcaDegenerate.d.ts.map +1 -0
  46. package/dist/index.d.ts +66 -0
  47. package/dist/index.d.ts.map +1 -0
  48. package/dist/index.js +4195 -0
  49. package/dist/index.js.map +47 -0
  50. package/dist/interactive/controls.d.ts +97 -0
  51. package/dist/interactive/controls.d.ts.map +1 -0
  52. package/dist/interactive/logit.d.ts +57 -0
  53. package/dist/interactive/logit.d.ts.map +1 -0
  54. package/dist/interactive/matrixInverse.d.ts +86 -0
  55. package/dist/interactive/matrixInverse.d.ts.map +1 -0
  56. package/dist/interactive/moderation3d.d.ts +103 -0
  57. package/dist/interactive/moderation3d.d.ts.map +1 -0
  58. package/dist/interactive/pca.d.ts +90 -0
  59. package/dist/interactive/pca.d.ts.map +1 -0
  60. package/dist/interactive/regression.d.ts +57 -0
  61. package/dist/interactive/regression.d.ts.map +1 -0
  62. package/dist/interactive/sampling.d.ts +78 -0
  63. package/dist/interactive/sampling.d.ts.map +1 -0
  64. package/dist/interactive/scatter3d.d.ts +124 -0
  65. package/dist/interactive/scatter3d.d.ts.map +1 -0
  66. package/dist/interactive/tTest.d.ts +69 -0
  67. package/dist/interactive/tTest.d.ts.map +1 -0
  68. package/dist/interactive/target.d.ts +132 -0
  69. package/dist/interactive/target.d.ts.map +1 -0
  70. package/dist/plot/axes.d.ts +128 -0
  71. package/dist/plot/axes.d.ts.map +1 -0
  72. package/dist/plot/draw.d.ts +46 -0
  73. package/dist/plot/draw.d.ts.map +1 -0
  74. package/dist/plot/format.d.ts +33 -0
  75. package/dist/plot/format.d.ts.map +1 -0
  76. package/dist/plot/logit.d.ts +68 -0
  77. package/dist/plot/logit.d.ts.map +1 -0
  78. package/dist/plot/matrixInverse.d.ts +62 -0
  79. package/dist/plot/matrixInverse.d.ts.map +1 -0
  80. package/dist/plot/moderation3d.d.ts +135 -0
  81. package/dist/plot/moderation3d.d.ts.map +1 -0
  82. package/dist/plot/pca.d.ts +79 -0
  83. package/dist/plot/pca.d.ts.map +1 -0
  84. package/dist/plot/plotly.d.ts +209 -0
  85. package/dist/plot/plotly.d.ts.map +1 -0
  86. package/dist/plot/regression.d.ts +52 -0
  87. package/dist/plot/regression.d.ts.map +1 -0
  88. package/dist/plot/sampleCi.d.ts +82 -0
  89. package/dist/plot/sampleCi.d.ts.map +1 -0
  90. package/dist/plot/sampling.d.ts +159 -0
  91. package/dist/plot/sampling.d.ts.map +1 -0
  92. package/dist/plot/scatter3d.d.ts +164 -0
  93. package/dist/plot/scatter3d.d.ts.map +1 -0
  94. package/dist/plot/tTest.d.ts +49 -0
  95. package/dist/plot/tTest.d.ts.map +1 -0
  96. package/dist/plot/target.d.ts +55 -0
  97. package/dist/plot/target.d.ts.map +1 -0
  98. package/package.json +71 -0
package/CHANGELOG.md ADDED
@@ -0,0 +1,110 @@
1
+ # Changelog
2
+
3
+ All notable changes to `@compstats/core`. The R package this ports keeps its
4
+ own history in [`NEWS.md`](https://github.com/compstatslib/compstatslib/blob/main/NEWS.md).
5
+
6
+ ## 0.2.0
7
+
8
+ The first npm release. It follows the R package's own 0.8.0 release, which
9
+ settled the R public API before that package had users to break. The same
10
+ changes land here, for the same reason: nothing is published yet, so these are
11
+ renames rather than breaking changes with a deprecation cycle.
12
+
13
+ The number is 0.2.0, not 0.1.0, because 0.1.0 is a git tag that was never
14
+ published. It stays where it is, and the rename below is what moves the minor.
15
+
16
+ ### Breaking changes
17
+
18
+ * `plotRegr()` is renamed `plotRegression()`, matching R's rename of
19
+ `plot_regr()` to `plot_regression()`. Every other plot function already
20
+ carried the name of its interactive counterpart; this was the last one that
21
+ did not. `PlotRegrOptions` and `regrScale()` are renamed with it, to
22
+ `PlotRegressionOptions` and `regressionScale()`. There is no shim.
23
+
24
+ ### Added
25
+
26
+ * `rt()`, `rlnorm()` and `rcauchy()` draw from the Student t, lognormal and
27
+ Cauchy distributions, with R's parameter names — `df`, `meanlog`/`sdlog`,
28
+ `location`/`scale`. One departure: `rt()` takes a positive integer `df`
29
+ only, where R's gamma sampler accepts any positive real. Empirical
30
+ quantiles are checked against R's `qt` and `qlnorm` over 200000 draws.
31
+ * `mean()`, `median()` and `meanAbsoluteDeviation()`. `median()` is R's own
32
+ rule, the type-7 quantile at 0.5. `meanAbsoluteDeviation()` is *not* R's
33
+ `mad()`, which is the median absolute deviation from the median and scaled
34
+ by 1.4826; the name is written in full because the abbreviation covers both
35
+ statistics. The sampling demonstration offers the last two as choices of
36
+ statistic.
37
+ * `kernelDensity()` takes `from` and `to`, R's own arguments, to fix the
38
+ reported window instead of taking it from the data.
39
+ * `plotSampling()` takes `densityWindow`. The default, `"data"`, is
40
+ unchanged. `"frozen"` puts the grid of every curve on the drawn window,
41
+ which a population reaching far outside that window needs: at 512 grid
42
+ points over a range a thousand times the window, one step is wider than the
43
+ panel and the curve draws as a straight line.
44
+ * `plotRegression()` takes `xlim` and `ylim`, R's own arguments. Both still
45
+ default to R's `c(-5, 50)`, and the mean crosshair clamps into a window
46
+ that does not contain 0.
47
+ * The two options above reach `interactiveRegression()` and
48
+ `interactiveSampling()` with no work, because each interactive options type
49
+ extends the plot options type it forwards.
50
+
51
+ ### Bug fixes
52
+
53
+ * The sampling histogram is bounded by the window it draws in. A statistic
54
+ outside the shared window is clipped from the picture, so it must not set
55
+ the width of the histogram's cells either: one sample mean out at 800 made
56
+ every cell 100 units wide and left a single flat bar in a 124-wide panel.
57
+ The count in the panel label still reports the whole pile.
58
+
59
+ * `moderationSurface()` drops rows with missing values before fitting, as
60
+ R's `lm()` does with `na.action = na.omit`; it fit straight through NaN,
61
+ so one missing cell made every coefficient and all 225 surface heights
62
+ NaN. Fitted values and residuals keep input order with NaN marking the
63
+ dropped rows, a control is held at its finite mean (R's `hold_value()`
64
+ with `na.rm = TRUE`), and a model with no complete rows throws a
65
+ `RangeError`. One stated departure: R computes zlim with no `na.rm` and
66
+ fails on a missing outcome; the port draws what it fits.
67
+ * `moderation3dSpec()` refuses a surface with a non-finite height. A NaN
68
+ height field crashes WebGL inside plotly.js, and the crash poisons every
69
+ later 3D surface on the page; the spec now throws a `RangeError` before
70
+ the engine can see it.
71
+ * `plotMatrixInverse()` titles its axes `x` and `y`. R's `plot(NA, ...)`
72
+ deparsed its first argument into the titles, so the axes read "Index" and
73
+ "NA"; the port reproduced that by drawing no titles at all. R fixed it in
74
+ 0.8.0 and this follows.
75
+ * `linearRegression()`, `logisticRegression()`, and `principalComponents()`
76
+ drop points with a non-finite coordinate before fitting, as R's `na.omit`
77
+ does and as `moderationSurface()` already did. The first fit straight
78
+ through NaN, the second refused it with a `RangeError`, and the third
79
+ answered all-NaN components. Fitted values, linear predictors, and scores
80
+ keep input order with NaN marking the dropped points; an input with no
81
+ complete point returns null, the existing "nothing to fit" answer.
82
+ `logisticRegression()` no longer throws on a non-finite predictor, and its
83
+ 0-or-1 outcome rule now applies to the complete points alone. `logitScale()`
84
+ ignores a non-finite predictor too, so one missing value no longer poisons
85
+ the whole window.
86
+ * `scatter3dSpec()` and `moderation3dSpec()` emit scene axis titles in
87
+ Plotly's object form, `title: { text }`. Plotly v2 silently drops a
88
+ bare-string title, so no 3D plot ever showed its column names.
89
+ `PlotlyAxis.title` is typed to the object form for the same reason.
90
+
91
+ ### Other
92
+
93
+ * Spelling is en-US throughout, as the R package now declares. No exported
94
+ name and no string a user reads changed — every correction was prose or an
95
+ internal identifier.
96
+ * The package ships a LICENSE, a README and this changelog.
97
+ * `prepublishOnly` runs the test suite, the type check and the build, so a
98
+ publish from a fresh clone cannot ship a stale or missing `dist/`.
99
+ * GitHub Actions runs the tests, the type check and the build on every push
100
+ and pull request.
101
+
102
+ ## 0.1.0
103
+
104
+ Tagged in git, never published to npm.
105
+
106
+ The complete TypeScript port of the R package: all nine function families
107
+ across the three layers (`core/` statistics with no DOM, `plot/` renderers,
108
+ `interactive/` components), both bundled datasets exported from R, and a demo
109
+ page per family. The core statistics are asserted against conformance fixtures
110
+ computed in R.
package/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2017-2026 Soumya Ray
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
package/README.md ADDED
@@ -0,0 +1,310 @@
1
+ # @compstats/core
2
+
3
+ [![CI](https://github.com/compstatslib/compstatslib-ts/actions/workflows/ci.yml/badge.svg)](https://github.com/compstatslib/compstatslib-ts/actions/workflows/ci.yml)
4
+
5
+ Interactive gadgets and plotting functions for data sets and statistical
6
+ concepts, in two and three dimensions. This is the browser port of the R
7
+ package [`compstatslib`](https://github.com/compstatslib/compstatslib).
8
+
9
+ Some of it works on **your own data**. Explore any data frame as a rotatable
10
+ 3D point cloud. Fit a moderated (interaction) regression and rotate its
11
+ surface to see how the interaction twists it away from a plane. The rest
12
+ **simulates a concept** instead of plotting your data — sampling
13
+ distributions, confidence intervals, t-statistics, matrix inversion. That part
14
+ is built for class demonstrations, homework, and self-study.
15
+
16
+ The R original runs in RStudio. This port runs in a browser, with no R
17
+ installation and no server. The 2D plots draw on a plain Canvas 2D context.
18
+ The 3D plots draw through Plotly, behind a separate entry point, so a page
19
+ that shows only 2D never loads it.
20
+
21
+ ## Install
22
+
23
+ ```bash
24
+ npm install @compstats/core
25
+ # or
26
+ bun add @compstats/core
27
+ ```
28
+
29
+ Plotly is only needed for the 3D functions. See
30
+ [3D and Plotly](#3d-and-plotly) below.
31
+
32
+ ## Quick start
33
+
34
+ Give an interactive component a canvas. It draws at once, and it redraws on
35
+ every click.
36
+
37
+ ```html
38
+ <canvas id="plot" width="640" height="480"></canvas>
39
+
40
+ <script type="module">
41
+ import { interactiveRegression } from "@compstats/core";
42
+
43
+ const handle = interactiveRegression(document.querySelector("#plot"), {
44
+ onDone: (points) => console.log(points),
45
+ });
46
+
47
+ // Later: read the state, clear it, or stop listening.
48
+ handle.getPoints();
49
+ handle.reset();
50
+ handle.destroy();
51
+ </script>
52
+ ```
53
+
54
+ The plot functions draw the same picture from data you already hold, and
55
+ return what they computed:
56
+
57
+ ```js
58
+ import { plotRegression } from "@compstats/core";
59
+
60
+ const fit = plotRegression(canvas, [
61
+ { x: 1, y: 2 },
62
+ { x: 2, y: 4 },
63
+ { x: 3, y: 5 },
64
+ ]);
65
+
66
+ console.log(fit.slope, fit.rSquared);
67
+ ```
68
+
69
+ The statistics are separate from the drawing. Import them alone when you want
70
+ the numbers and not the picture:
71
+
72
+ ```js
73
+ import { linearRegression, principalComponents, tTestStats } from "@compstats/core";
74
+ ```
75
+
76
+ Nothing in the `core/` layer touches the DOM, so it also runs under Node or
77
+ Bun.
78
+
79
+ ## Use from a CDN
80
+
81
+ The main bundle is self-contained browser ESM with no imports of its own. A
82
+ page can load it directly, with no build step:
83
+
84
+ ```html
85
+ <script type="module">
86
+ import { interactiveTTest } from "https://esm.sh/@compstats/core";
87
+
88
+ interactiveTTest(document.querySelector("#demo"));
89
+ </script>
90
+ ```
91
+
92
+ jsDelivr and unpkg serve the same file:
93
+
94
+ ```js
95
+ import { interactiveTTest } from "https://cdn.jsdelivr.net/npm/@compstats/core/dist/index.js";
96
+ ```
97
+
98
+ ## 3D and Plotly
99
+
100
+ The 3D functions live behind the `@compstats/core/3d` entry point:
101
+
102
+ ```js
103
+ import { interactiveScatter3d, moderationData } from "@compstats/core/3d";
104
+ ```
105
+
106
+ That entry does not load Plotly either. It reaches the library through a
107
+ dynamic import the first time it draws. A caller that passes its own engine in
108
+ the `plotly` option never triggers that import:
109
+
110
+ ```html
111
+ <script src="https://cdn.jsdelivr.net/npm/plotly.js-dist-min"></script>
112
+
113
+ <script type="module">
114
+ import { interactiveScatter3d, moderationData } from "https://esm.sh/@compstats/core/3d";
115
+
116
+ const handle = interactiveScatter3d(
117
+ document.querySelector("#demo"),
118
+ moderationData,
119
+ { plotly: window.Plotly },
120
+ );
121
+ await handle.rendered();
122
+ </script>
123
+ ```
124
+
125
+ Pass `plotly` when you load the 3D entry from a raw file CDN such as jsDelivr,
126
+ because nothing there resolves the bare `plotly.js-dist-min` specifier. esm.sh
127
+ rewrites bare specifiers, so on esm.sh both ways work.
128
+
129
+ ## How the functions are organized
130
+
131
+ Every family has three parts, and you can use any one of them alone:
132
+
133
+ - a **core** function that computes the statistics and touches no DOM,
134
+ - a **plot** function that draws it on a target you give it,
135
+ - an **interactive** component that owns the input and hands each draw to the
136
+ plot function.
137
+
138
+ The families are grouped below by what they are *for*, because that varies
139
+ more than the interaction style does.
140
+
141
+ ### Data sets in 3D
142
+
143
+ These accept any data frame, with control over axes, color mapping, aspect
144
+ ratio, and camera. They come from `@compstats/core/3d`.
145
+
146
+ | Function | What it does |
147
+ | --- | --- |
148
+ | `interactiveScatter3d(target, data, opts?)` | Rotatable 3D point cloud, with pickers for x / y / z and color, and sliders for aspect, opacity, and marker size. |
149
+ | `plotScatter3d(target, data, opts?)` | The same point cloud from a fixed set of options. |
150
+ | `interactiveModeration3d(target, data, opts)` | Fitted moderation surface as a 3D wireframe, with two rotation sliders. |
151
+ | `plotModeration3d(target, data, opts)` | The same surface at a stated viewing angle. |
152
+ | `moderationSurface(data, opts)` | The fit and the prediction grid behind both, as plain numbers. |
153
+
154
+ ### 2D relationships
155
+
156
+ These plot x / y points you supply, together with a fitted model. They are
157
+ sized for small data — points clicked in by hand, or a modest table — and not
158
+ for arbitrary data. `plotRegression` draws in a window of -5 to 50 unless you
159
+ give it `xlim` and `ylim`, and the PCA functions expect points with an `x` and
160
+ a `y`.
161
+
162
+ | Function | What it does |
163
+ | --- | --- |
164
+ | `interactiveRegression(canvas, opts?)` | Click to add points. The line, the mean crosshair, and the statistics update on every click. |
165
+ | `plotRegression(target, points, opts?)` | The same picture from points you hold. Returns the fit. |
166
+ | `interactiveLogit(canvas, opts?)` | Click to add points. A logistic curve and its statistics update with them. |
167
+ | `plotLogit(target, points, opts?)` | The same picture from points you hold. |
168
+ | `interactivePca(canvas, opts?)` | Click to add points. The two component arrows appear from the third point and turn with every point after it. |
169
+ | `plotPca(target, points, opts?)` | The same picture, with optional mean centering. |
170
+ | `linearRegression(points)`, `logisticRegression(points, opts?)`, `principalComponents(points)` | The three fits, without a picture. |
171
+
172
+ ### Simulations and concept demonstrations
173
+
174
+ These do not plot your data. They simulate a process, or draw a geometric
175
+ object, so that a concept can be watched instead of described.
176
+
177
+ | Function | What it does |
178
+ | --- | --- |
179
+ | `interactiveTTest(container, opts?)` | Sliders for difference, standard deviation, sample size, and alpha. The null and alternative t distributions, the rejection region, and the power redraw as they move. |
180
+ | `plotTTest(target, opts?)` | The same picture from fixed parameters. Returns the statistics. |
181
+ | `interactiveSampling(container, population, opts?)` | Draw samples from a population and watch the sampling statistic build up across repetitions. |
182
+ | `plotSampling(target, population, opts?)` | One draw of the three-panel picture. |
183
+ | `plotSampleCi(target, opts?)` | Repeated samples from a distribution function, each with its confidence interval, so that coverage becomes visible. |
184
+ | `interactiveMatrixInverse(container, opts?)` | Four sliders for the entries of a 2x2 matrix. The matrix and its inverse are drawn as parallelograms. |
185
+ | `plotMatrixInverse(target, matrix)` | The same picture from one matrix. Returns the determinant and the inverse. |
186
+ | `machinePrecision()` | The smallest number the runtime can add to 1. |
187
+
188
+ ### Statistics without a picture
189
+
190
+ The R package never had to ship these. `mean()`, `sd()`, `quantile()`, `dt()`,
191
+ `rnorm()`, `density()`, `hist()`, `pretty()`, `solve()` and `lm.fit()` are all
192
+ in base R, and its functions call them. JavaScript has no statistics standard
193
+ library, so the port wrote them — and exports them, because an application
194
+ built on this package needs them for the same reason the package did.
195
+
196
+ | Group | Functions |
197
+ | --- | --- |
198
+ | Descriptives | `mean`, `median`, `sd`, `quantile`, `quantiles`, `meanAbsoluteDeviation` |
199
+ | Student t distribution | `dt`, `pt`, `qt`, with the `normalCdf`, `incompleteBeta` and `inverseIncompleteBeta` they stand on |
200
+ | Seeded random draws | `seededRng`, `runif`, `rnorm`, `rt`, `rlnorm`, `rcauchy`, `sampleWithoutReplacement` |
201
+ | Binning and density | `histogram`, `nclassSturges`, `kernelDensity`, `bwNrd0` |
202
+ | Axis ticks | `rPretty`, `prettyTicks` |
203
+ | Linear algebra | `leastSquares`, `determinant`, `invertMatrix` |
204
+
205
+ Each one follows its R counterpart, down to the rule and the argument names:
206
+ `quantile` is type 7, `nclassSturges` is Sturges' rule, `bwNrd0` is R's
207
+ `nrd0` bandwidth, `rPretty` is `pretty()`, and the samplers take R's own
208
+ parameters. The test suite pins them to values computed in R.
209
+
210
+ The draws take a generator you pass in, so a demonstration repeats exactly:
211
+
212
+ ```js
213
+ import { seededRng, rnorm, quantile } from "@compstats/core";
214
+
215
+ const rng = seededRng(42);
216
+ const draws = rnorm(rng, 1000, { mean: 100, sd: 15 });
217
+ quantile(draws, 0.975);
218
+ ```
219
+
220
+ ### Bundled data
221
+
222
+ `moderationData` (200 rows of `y`, `x`, `z`, `w`) and `pcaDegenerate` (16 rows
223
+ of `x`, `y`) are the same tables as in the R package, exported from R rather
224
+ than regenerated. Both are defaults, so a call with no data still gives a
225
+ working demonstration.
226
+
227
+ ### Targets
228
+
229
+ The click-to-add-points components take a `<canvas>`. The components that own
230
+ sliders or menus take a container element and build their controls inside it.
231
+ Each one also accepts an explicit `{ surface, element }` pair when you want to
232
+ place the drawing surface and the controls yourself.
233
+
234
+ ## Reproducing an interactive session
235
+
236
+ R's gadgets block until you click Done, and then print the `plot_*()` call
237
+ that reproduces the screen. Nothing blocks in a browser. Each component
238
+ returns a handle at once, and the handle carries the same state:
239
+
240
+ ```js
241
+ const handle = interactiveTTest(container);
242
+
243
+ handle.getValues(); // the state that reproduces the picture
244
+ handle.getStats(); // what the last draw computed
245
+ handle.done(); // hand the state to the onDone callback
246
+ handle.destroy(); // stop listening and remove what was built
247
+ ```
248
+
249
+ `getValues()` returns the options that draw the same picture again. Pass them
250
+ straight back to the matching plot function, or to the component itself. State
251
+ you would not retype has its own accessor: `getFit()` for PCA, `getState()`
252
+ for the accumulated sampling draws, `getSpec()` for the traces and layout of a
253
+ 3D draw.
254
+
255
+ ## Differences from the R package
256
+
257
+ The two packages compute the same statistics and draw the same pictures. The
258
+ R idioms that a browser has no answer for are handled like this:
259
+
260
+ - **Names.** `snake_case` becomes `camelCase`. `plot_regr()` is
261
+ `plotRegression()`, as it is in R since 0.8.0.
262
+ - **Signatures.** R's positional arguments and `...` become a data argument
263
+ and one options object.
264
+ - **Formulas.** `y ~ x * z` has no TypeScript counterpart. Name the columns
265
+ instead: `{ outcome: "y", iv: "x", mod: "z" }`.
266
+ - **Data frames.** Point sets are arrays of records. Bundled tables are
267
+ objects of columns.
268
+ - **Random numbers.** Draws take an injectable seeded generator, so a demo
269
+ repeats exactly. The stream does not match R's Mersenne Twister, and it is
270
+ not meant to.
271
+ - **Devices.** Every plot function takes an explicit target. There is no
272
+ current device.
273
+
274
+ One thing the port adds. It exports the statistical primitives that base R
275
+ hands the R package for free — descriptives, the t distribution, seeded
276
+ samplers, binning, density, axis ticks and small linear algebra, listed under
277
+ [Statistics without a picture](#statistics-without-a-picture). This is an
278
+ addition, not a divergence: each one follows its R counterpart's rule and is
279
+ tested against R's output.
280
+
281
+ The core statistics are asserted against values computed in R. The fixtures
282
+ live in the R package under `conformance-fixtures/`.
283
+
284
+ ## Development
285
+
286
+ ```bash
287
+ bun install
288
+ bun test
289
+ bun run typecheck
290
+ bun run build
291
+ bun run dev # demo site on http://localhost:3000
292
+ ```
293
+
294
+ Bun is the toolchain: runtime, package manager, test runner, and bundler. The
295
+ demo site runs one page per function family and is the fastest way to see a
296
+ change.
297
+
298
+ ## Contributors
299
+
300
+ `@compstats/core` and `compstatslib` are maintained by Soumya Ray.
301
+
302
+ Daniele Melotti is a co-author of the R package. Several of the plotting and
303
+ interactive functions grew out of work he did as a student under Soumya Ray's
304
+ supervision, and were then folded back into the package.
305
+
306
+ Issues and pull requests are welcome.
307
+
308
+ ## License
309
+
310
+ MIT. See [LICENSE](LICENSE).
package/dist/3d.d.ts ADDED
@@ -0,0 +1,33 @@
1
+ /**
2
+ * The 3D entry point: `@compstats/core/3d`.
3
+ *
4
+ * The two 3D families of the R package draw through Plotly.js, which is four
5
+ * megabytes of browser code. They therefore live behind this entry rather than
6
+ * the main one, so that a page that draws only 2D plots never loads them.
7
+ *
8
+ * Nothing here loads Plotly either. `loadPlotly()` reaches the library through
9
+ * a dynamic import, which runs the first time a plot is drawn; a caller who
10
+ * passes its own engine through the `plotly` option never triggers it at all.
11
+ *
12
+ * The core statistics and the bundled data of the 3D families are re-exported
13
+ * here, so that one import covers a 3D page.
14
+ */
15
+ export { loadPlotly } from "./plot/plotly";
16
+ export type { EyeCamera, PlotlyAxis, PlotlyCamera, PlotlyConfig, PlotlyHTMLElement, PlotlyLayout, PlotlyLike, PlotlyRelayoutEvent, PlotlyRelayoutUpdate, PlotlyScene, PlotlyTrace, Scatter3dMarker, Scatter3dTrace, SurfaceTrace, Vector3, } from "./plot/plotly";
17
+ export { DEFAULT_SCATTER3D_STYLE, plotScatter3d, scatter3dSpec, validateScatter3dStyle, } from "./plot/scatter3d";
18
+ export type { PlotScatter3dOptions, Scatter3dHandle, Scatter3dSpec, Scatter3dSpecOptions, Scatter3dStyle, Scatter3dTitles, } from "./plot/scatter3d";
19
+ export { interactiveScatter3d } from "./interactive/scatter3d";
20
+ export type { InteractiveScatter3dHandle, InteractiveScatter3dOptions, Scatter3dValues, } from "./interactive/scatter3d";
21
+ export { interactiveModeration3d } from "./interactive/moderation3d";
22
+ export type { InteractiveModeration3dHandle, InteractiveModeration3dOptions, Moderation3dValues, } from "./interactive/moderation3d";
23
+ export { resolvePlot3dTarget } from "./interactive/target";
24
+ export type { Plot3dPanel, Plot3dTarget, ResolvedPlot3dPanel, } from "./interactive/target";
25
+ export { cameraFromRotations, moderation3dSpec, plotModeration3d, } from "./plot/moderation3d";
26
+ export type { Moderation3dHandle, Moderation3dSpec, Moderation3dViewOptions, PlotModeration3dOptions, } from "./plot/moderation3d";
27
+ export { moderationSurface } from "./core/moderation";
28
+ export type { ModerationOptions, ModerationSurface, ModerationTerm, } from "./core/moderation";
29
+ export { frameRows, isNumericColumn, numericColumns, requireNumericColumn, requireThreeNumericColumns, } from "./core/frame";
30
+ export type { Column, DataFrame } from "./core/frame";
31
+ export { moderationData } from "./data/moderationData";
32
+ export type { ModerationData } from "./data/moderationData";
33
+ //# sourceMappingURL=3d.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"3d.d.ts","sourceRoot":"","sources":["../src/3d.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;GAaG;AAEH,OAAO,EAAE,UAAU,EAAE,MAAM,eAAe,CAAC;AAC3C,YAAY,EACV,SAAS,EACT,UAAU,EACV,YAAY,EACZ,YAAY,EACZ,iBAAiB,EACjB,YAAY,EACZ,UAAU,EACV,mBAAmB,EACnB,oBAAoB,EACpB,WAAW,EACX,WAAW,EACX,eAAe,EACf,cAAc,EACd,YAAY,EACZ,OAAO,GACR,MAAM,eAAe,CAAC;AAEvB,OAAO,EACL,uBAAuB,EACvB,aAAa,EACb,aAAa,EACb,sBAAsB,GACvB,MAAM,kBAAkB,CAAC;AAC1B,YAAY,EACV,oBAAoB,EACpB,eAAe,EACf,aAAa,EACb,oBAAoB,EACpB,cAAc,EACd,eAAe,GAChB,MAAM,kBAAkB,CAAC;AAE1B,OAAO,EAAE,oBAAoB,EAAE,MAAM,yBAAyB,CAAC;AAC/D,YAAY,EACV,0BAA0B,EAC1B,2BAA2B,EAC3B,eAAe,GAChB,MAAM,yBAAyB,CAAC;AAEjC,OAAO,EAAE,uBAAuB,EAAE,MAAM,4BAA4B,CAAC;AACrE,YAAY,EACV,6BAA6B,EAC7B,8BAA8B,EAC9B,kBAAkB,GACnB,MAAM,4BAA4B,CAAC;AAEpC,OAAO,EAAE,mBAAmB,EAAE,MAAM,sBAAsB,CAAC;AAC3D,YAAY,EACV,WAAW,EACX,YAAY,EACZ,mBAAmB,GACpB,MAAM,sBAAsB,CAAC;AAE9B,OAAO,EACL,mBAAmB,EACnB,gBAAgB,EAChB,gBAAgB,GACjB,MAAM,qBAAqB,CAAC;AAC7B,YAAY,EACV,kBAAkB,EAClB,gBAAgB,EAChB,uBAAuB,EACvB,uBAAuB,GACxB,MAAM,qBAAqB,CAAC;AAE7B,OAAO,EAAE,iBAAiB,EAAE,MAAM,mBAAmB,CAAC;AACtD,YAAY,EACV,iBAAiB,EACjB,iBAAiB,EACjB,cAAc,GACf,MAAM,mBAAmB,CAAC;AAE3B,OAAO,EACL,SAAS,EACT,eAAe,EACf,cAAc,EACd,oBAAoB,EACpB,0BAA0B,GAC3B,MAAM,cAAc,CAAC;AACtB,YAAY,EAAE,MAAM,EAAE,SAAS,EAAE,MAAM,cAAc,CAAC;AAEtD,OAAO,EAAE,cAAc,EAAE,MAAM,uBAAuB,CAAC;AACvD,YAAY,EAAE,cAAc,EAAE,MAAM,uBAAuB,CAAC"}