modist 0.1.0__tar.gz
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.
- modist-0.1.0/PKG-INFO +121 -0
- modist-0.1.0/README.md +90 -0
- modist-0.1.0/pyproject.toml +42 -0
- modist-0.1.0/src/modist/__init__.py +21 -0
- modist-0.1.0/src/modist/_base.py +60 -0
- modist-0.1.0/src/modist/beta.py +41 -0
- modist-0.1.0/src/modist/gamma.py +43 -0
- modist-0.1.0/src/modist/normal.py +42 -0
- modist-0.1.0/src/modist/py.typed +0 -0
- modist-0.1.0/src/modist/static/beta.js +2097 -0
- modist-0.1.0/src/modist/static/gamma.js +2133 -0
- modist-0.1.0/src/modist/static/normal.js +2092 -0
- modist-0.1.0/src/modist/styles.css +71 -0
modist-0.1.0/PKG-INFO
ADDED
|
@@ -0,0 +1,121 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: modist
|
|
3
|
+
Version: 0.1.0
|
|
4
|
+
Summary: Interactive distribution widgets for marimo, in the style of wigglystuff
|
|
5
|
+
Keywords: marimo,anywidget,statistics,distribution,visualization
|
|
6
|
+
Author: Will Dean
|
|
7
|
+
Author-email: Will Dean <wd60622@gmail.com>
|
|
8
|
+
License-Expression: MIT
|
|
9
|
+
Classifier: Development Status :: 4 - Beta
|
|
10
|
+
Classifier: Intended Audience :: Science/Research
|
|
11
|
+
Classifier: License :: OSI Approved :: MIT License
|
|
12
|
+
Classifier: Programming Language :: Python :: 3
|
|
13
|
+
Classifier: Programming Language :: Python :: 3.12
|
|
14
|
+
Classifier: Programming Language :: Python :: 3.13
|
|
15
|
+
Classifier: Programming Language :: Python :: 3.14
|
|
16
|
+
Classifier: Topic :: Scientific/Engineering :: Visualization
|
|
17
|
+
Requires-Dist: anywidget>=0.11.0
|
|
18
|
+
Requires-Dist: pytest>=8 ; extra == 'dev'
|
|
19
|
+
Requires-Dist: marimo>=0.9 ; extra == 'dev'
|
|
20
|
+
Requires-Dist: conjugate-models ; extra == 'dev'
|
|
21
|
+
Requires-Dist: pymc>=5.10 ; extra == 'pymc'
|
|
22
|
+
Requires-Dist: scipy>=1.12 ; extra == 'scipy'
|
|
23
|
+
Requires-Python: >=3.12, <3.15
|
|
24
|
+
Project-URL: Documentation, https://github.com/williambdean/modist#readme
|
|
25
|
+
Project-URL: Homepage, https://github.com/williambdean/modist
|
|
26
|
+
Project-URL: Repository, https://github.com/williambdean/modist
|
|
27
|
+
Provides-Extra: dev
|
|
28
|
+
Provides-Extra: pymc
|
|
29
|
+
Provides-Extra: scipy
|
|
30
|
+
Description-Content-Type: text/markdown
|
|
31
|
+
|
|
32
|
+
# `modist`
|
|
33
|
+
|
|
34
|
+
Interactive distribution widgets for [marimo](https://marimo.io), in the style
|
|
35
|
+
of [`koaning/wigglystuff`](https://github.com/koaning/wigglystuff). Drag the
|
|
36
|
+
density curve to shape a distribution, then feed the params straight into a
|
|
37
|
+
distribution constructor with a single splat.
|
|
38
|
+
|
|
39
|
+
## Install
|
|
40
|
+
|
|
41
|
+
```sh
|
|
42
|
+
uv add modist # or: uv pip install modist (pip install modist)
|
|
43
|
+
```
|
|
44
|
+
|
|
45
|
+
## Quickstart
|
|
46
|
+
|
|
47
|
+
```python
|
|
48
|
+
import marimo as mo
|
|
49
|
+
import modist as md
|
|
50
|
+
|
|
51
|
+
w = mo.ui.anywidget(md.Normal())
|
|
52
|
+
w
|
|
53
|
+
```
|
|
54
|
+
|
|
55
|
+
```python
|
|
56
|
+
params = w.value # {'mu': ..., 'sigma': ...}
|
|
57
|
+
```
|
|
58
|
+
|
|
59
|
+
```python
|
|
60
|
+
import pymc as pm
|
|
61
|
+
dist = pm.Normal.dist(**params) # or pm.Beta / pm.Gamma
|
|
62
|
+
```
|
|
63
|
+
|
|
64
|
+
## Families
|
|
65
|
+
|
|
66
|
+
| Widget | Params | Domain | Drag affordances |
|
|
67
|
+
| ---------------------------- | ------------- | ----------------- | ------------------------- |
|
|
68
|
+
| [`Normal`](src/modist/normal.py) | `mu`, `sigma` | free | mean line → `mu`, ±1σ squares → `sigma` |
|
|
69
|
+
| [`Beta`](src/modist/beta.py) | `alpha`, `beta` | fixed `[0, 1]` | mean line → translate, q25/q75 squares → concentrate |
|
|
70
|
+
| [`Gamma`](src/modist/gamma.py) | `alpha`, `beta` | edge pinned at 0 | mean line → translate, q25/q75 squares → reshape |
|
|
71
|
+
|
|
72
|
+
`alpha`/`beta` follow the [PyMC](https://www.pymc.io) / statistics convention
|
|
73
|
+
(`Gamma`'s `beta` is the **rate**, not scipy's `scale`). The lazy `.scipy` and
|
|
74
|
+
`.pymc` adapters map to the right parametrization automatically:
|
|
75
|
+
|
|
76
|
+
```python
|
|
77
|
+
n = md.Normal(mu=2.0, sigma=3.0)
|
|
78
|
+
n.scipy # <scipy.stats.norm> via loc=/scale=
|
|
79
|
+
n.pymc # pm.Normal.dist(mu=2.0, sigma=3.0)
|
|
80
|
+
|
|
81
|
+
g = md.Gamma(alpha=2.0, beta=3.0)
|
|
82
|
+
g.scipy # scipy.stats.gamma(a=2.0, scale=1/3) -- rate handled for you
|
|
83
|
+
```
|
|
84
|
+
|
|
85
|
+
`w.value` is a plain dict of the synced traits, so `pm.X.dist(**w.value)` works
|
|
86
|
+
with no conversion.
|
|
87
|
+
|
|
88
|
+
## How it works
|
|
89
|
+
|
|
90
|
+
Each family is its own anywidget class with a small set of synced parameter
|
|
91
|
+
traits (no `x_min`/`x_max`/`n_points`). The view — SVG scaffold, pan/zoom,
|
|
92
|
+
draggable hit lines, and per-family math — lives in a self-contained ESM module.
|
|
93
|
+
|
|
94
|
+
Source JS lives in [`js/`](js/) (`js/base.js` shared scaffold + one family file,
|
|
95
|
+
all importing a vendored copy of [jStat](https://jstat.github.io/) for
|
|
96
|
+
`pdf`/`cdf`/quantile math). Anywidget delivers `_esm` as a Blob URL, which
|
|
97
|
+
cannot resolve relative imports, so [esbuild](https://esbuild.github.io)
|
|
98
|
+
bundles each family (jStat inlined) into the committed `src/modist/static/*.js`
|
|
99
|
+
files — the same pattern wigglystuff uses for its JS-heavy widgets.
|
|
100
|
+
|
|
101
|
+
### Rebuilding the JS
|
|
102
|
+
|
|
103
|
+
```sh
|
|
104
|
+
make js # esbuild js/*.js -> src/modist/static/*.js
|
|
105
|
+
make js-watch # rebuild on every edit (for anywidget hot-reload dev)
|
|
106
|
+
```
|
|
107
|
+
|
|
108
|
+
Requires a local esbuild (`npm install --no-save esbuild`).
|
|
109
|
+
|
|
110
|
+
## Development
|
|
111
|
+
|
|
112
|
+
```sh
|
|
113
|
+
make venv # creates .venv with dev deps + esbuild
|
|
114
|
+
make test # pytest
|
|
115
|
+
npm run test:js # Playwright JS integration probes (headless Chromium)
|
|
116
|
+
```
|
|
117
|
+
|
|
118
|
+
## Acknowledgements
|
|
119
|
+
|
|
120
|
+
- [jStat](https://jstat.github.io/) — JavaScript statistics library (MIT), vendored and bundled for the pdf/cdf/quantile math.
|
|
121
|
+
- [wigglystuff](https://github.com/koaning/wigglystuff) — the interaction and architecture model (one class per family, prebuilt ESM per class).
|
modist-0.1.0/README.md
ADDED
|
@@ -0,0 +1,90 @@
|
|
|
1
|
+
# `modist`
|
|
2
|
+
|
|
3
|
+
Interactive distribution widgets for [marimo](https://marimo.io), in the style
|
|
4
|
+
of [`koaning/wigglystuff`](https://github.com/koaning/wigglystuff). Drag the
|
|
5
|
+
density curve to shape a distribution, then feed the params straight into a
|
|
6
|
+
distribution constructor with a single splat.
|
|
7
|
+
|
|
8
|
+
## Install
|
|
9
|
+
|
|
10
|
+
```sh
|
|
11
|
+
uv add modist # or: uv pip install modist (pip install modist)
|
|
12
|
+
```
|
|
13
|
+
|
|
14
|
+
## Quickstart
|
|
15
|
+
|
|
16
|
+
```python
|
|
17
|
+
import marimo as mo
|
|
18
|
+
import modist as md
|
|
19
|
+
|
|
20
|
+
w = mo.ui.anywidget(md.Normal())
|
|
21
|
+
w
|
|
22
|
+
```
|
|
23
|
+
|
|
24
|
+
```python
|
|
25
|
+
params = w.value # {'mu': ..., 'sigma': ...}
|
|
26
|
+
```
|
|
27
|
+
|
|
28
|
+
```python
|
|
29
|
+
import pymc as pm
|
|
30
|
+
dist = pm.Normal.dist(**params) # or pm.Beta / pm.Gamma
|
|
31
|
+
```
|
|
32
|
+
|
|
33
|
+
## Families
|
|
34
|
+
|
|
35
|
+
| Widget | Params | Domain | Drag affordances |
|
|
36
|
+
| ---------------------------- | ------------- | ----------------- | ------------------------- |
|
|
37
|
+
| [`Normal`](src/modist/normal.py) | `mu`, `sigma` | free | mean line → `mu`, ±1σ squares → `sigma` |
|
|
38
|
+
| [`Beta`](src/modist/beta.py) | `alpha`, `beta` | fixed `[0, 1]` | mean line → translate, q25/q75 squares → concentrate |
|
|
39
|
+
| [`Gamma`](src/modist/gamma.py) | `alpha`, `beta` | edge pinned at 0 | mean line → translate, q25/q75 squares → reshape |
|
|
40
|
+
|
|
41
|
+
`alpha`/`beta` follow the [PyMC](https://www.pymc.io) / statistics convention
|
|
42
|
+
(`Gamma`'s `beta` is the **rate**, not scipy's `scale`). The lazy `.scipy` and
|
|
43
|
+
`.pymc` adapters map to the right parametrization automatically:
|
|
44
|
+
|
|
45
|
+
```python
|
|
46
|
+
n = md.Normal(mu=2.0, sigma=3.0)
|
|
47
|
+
n.scipy # <scipy.stats.norm> via loc=/scale=
|
|
48
|
+
n.pymc # pm.Normal.dist(mu=2.0, sigma=3.0)
|
|
49
|
+
|
|
50
|
+
g = md.Gamma(alpha=2.0, beta=3.0)
|
|
51
|
+
g.scipy # scipy.stats.gamma(a=2.0, scale=1/3) -- rate handled for you
|
|
52
|
+
```
|
|
53
|
+
|
|
54
|
+
`w.value` is a plain dict of the synced traits, so `pm.X.dist(**w.value)` works
|
|
55
|
+
with no conversion.
|
|
56
|
+
|
|
57
|
+
## How it works
|
|
58
|
+
|
|
59
|
+
Each family is its own anywidget class with a small set of synced parameter
|
|
60
|
+
traits (no `x_min`/`x_max`/`n_points`). The view — SVG scaffold, pan/zoom,
|
|
61
|
+
draggable hit lines, and per-family math — lives in a self-contained ESM module.
|
|
62
|
+
|
|
63
|
+
Source JS lives in [`js/`](js/) (`js/base.js` shared scaffold + one family file,
|
|
64
|
+
all importing a vendored copy of [jStat](https://jstat.github.io/) for
|
|
65
|
+
`pdf`/`cdf`/quantile math). Anywidget delivers `_esm` as a Blob URL, which
|
|
66
|
+
cannot resolve relative imports, so [esbuild](https://esbuild.github.io)
|
|
67
|
+
bundles each family (jStat inlined) into the committed `src/modist/static/*.js`
|
|
68
|
+
files — the same pattern wigglystuff uses for its JS-heavy widgets.
|
|
69
|
+
|
|
70
|
+
### Rebuilding the JS
|
|
71
|
+
|
|
72
|
+
```sh
|
|
73
|
+
make js # esbuild js/*.js -> src/modist/static/*.js
|
|
74
|
+
make js-watch # rebuild on every edit (for anywidget hot-reload dev)
|
|
75
|
+
```
|
|
76
|
+
|
|
77
|
+
Requires a local esbuild (`npm install --no-save esbuild`).
|
|
78
|
+
|
|
79
|
+
## Development
|
|
80
|
+
|
|
81
|
+
```sh
|
|
82
|
+
make venv # creates .venv with dev deps + esbuild
|
|
83
|
+
make test # pytest
|
|
84
|
+
npm run test:js # Playwright JS integration probes (headless Chromium)
|
|
85
|
+
```
|
|
86
|
+
|
|
87
|
+
## Acknowledgements
|
|
88
|
+
|
|
89
|
+
- [jStat](https://jstat.github.io/) — JavaScript statistics library (MIT), vendored and bundled for the pdf/cdf/quantile math.
|
|
90
|
+
- [wigglystuff](https://github.com/koaning/wigglystuff) — the interaction and architecture model (one class per family, prebuilt ESM per class).
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
[project]
|
|
2
|
+
name = "modist"
|
|
3
|
+
version = "0.1.0"
|
|
4
|
+
description = "Interactive distribution widgets for marimo, in the style of wigglystuff"
|
|
5
|
+
readme = "README.md"
|
|
6
|
+
authors = [
|
|
7
|
+
{ name = "Will Dean", email = "wd60622@gmail.com" }
|
|
8
|
+
]
|
|
9
|
+
license = "MIT"
|
|
10
|
+
keywords = [
|
|
11
|
+
"marimo",
|
|
12
|
+
"anywidget",
|
|
13
|
+
"statistics",
|
|
14
|
+
"distribution",
|
|
15
|
+
"visualization",
|
|
16
|
+
]
|
|
17
|
+
classifiers = [
|
|
18
|
+
"Development Status :: 4 - Beta",
|
|
19
|
+
"Intended Audience :: Science/Research",
|
|
20
|
+
"License :: OSI Approved :: MIT License",
|
|
21
|
+
"Programming Language :: Python :: 3",
|
|
22
|
+
"Programming Language :: Python :: 3.12",
|
|
23
|
+
"Programming Language :: Python :: 3.13",
|
|
24
|
+
"Programming Language :: Python :: 3.14",
|
|
25
|
+
"Topic :: Scientific/Engineering :: Visualization",
|
|
26
|
+
]
|
|
27
|
+
requires-python = ">=3.12,<3.15"
|
|
28
|
+
dependencies = ["anywidget>=0.11.0"]
|
|
29
|
+
|
|
30
|
+
[project.urls]
|
|
31
|
+
Homepage = "https://github.com/williambdean/modist"
|
|
32
|
+
Repository = "https://github.com/williambdean/modist"
|
|
33
|
+
Documentation = "https://github.com/williambdean/modist#readme"
|
|
34
|
+
|
|
35
|
+
[project.optional-dependencies]
|
|
36
|
+
scipy = ["scipy>=1.12"]
|
|
37
|
+
pymc = ["pymc>=5.10"]
|
|
38
|
+
dev = ["pytest>=8", "marimo>=0.9", "conjugate-models"]
|
|
39
|
+
|
|
40
|
+
[build-system]
|
|
41
|
+
requires = ["uv_build>=0.8.22,<0.9.0"]
|
|
42
|
+
build-backend = "uv_build"
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
"""modist - interactive distribution widgets for marimo.
|
|
2
|
+
|
|
3
|
+
Each widget renders a draggable density curve. The synced parameter traits
|
|
4
|
+
make ``mo.ui.anywidget(w).value`` a dict that splats directly into a
|
|
5
|
+
distribution constructor, e.g. ``pm.Normal.dist(**w.value)``.
|
|
6
|
+
|
|
7
|
+
Families
|
|
8
|
+
--------
|
|
9
|
+
- :class:`Normal` -- ``mu`` / ``sigma``
|
|
10
|
+
- :class:`Beta` -- ``alpha`` / ``beta`` (fixed [0, 1])
|
|
11
|
+
- :class:`Gamma` -- ``alpha`` / ``beta`` (shape / rate, edge at 0)
|
|
12
|
+
"""
|
|
13
|
+
|
|
14
|
+
from ._base import DistMixin
|
|
15
|
+
from .beta import Beta
|
|
16
|
+
from .gamma import Gamma
|
|
17
|
+
from .normal import Normal
|
|
18
|
+
|
|
19
|
+
__all__ = ["Normal", "Beta", "Gamma", "DistMixin"]
|
|
20
|
+
|
|
21
|
+
__version__ = "0.1.0"
|
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
"""Shared lazy adapters for modist widgets.
|
|
2
|
+
|
|
3
|
+
Each widget exposes a ``params`` dict of its canonical synced traits plus lazy
|
|
4
|
+
``.scipy`` and ``.pymc`` attributes that construct a frozen scipy distribution
|
|
5
|
+
or a pymc distribution from those params. Imports happen only on first access.
|
|
6
|
+
"""
|
|
7
|
+
|
|
8
|
+
from __future__ import annotations
|
|
9
|
+
|
|
10
|
+
from typing import Any, Dict
|
|
11
|
+
|
|
12
|
+
|
|
13
|
+
class DistMixin:
|
|
14
|
+
"""Provides ``params`` plus lazy ``.scipy`` / ``.pymc`` distribution adapters."""
|
|
15
|
+
|
|
16
|
+
# Family subclasses set these:
|
|
17
|
+
_param_names: tuple[str, ...] = ()
|
|
18
|
+
_dist_name: str = ""
|
|
19
|
+
|
|
20
|
+
@property
|
|
21
|
+
def params(self) -> Dict[str, float]:
|
|
22
|
+
"""The canonical parameters of this distribution (the synced traits)."""
|
|
23
|
+
return {name: getattr(self, name) for name in self._param_names}
|
|
24
|
+
|
|
25
|
+
@property
|
|
26
|
+
def scipy(self) -> Any:
|
|
27
|
+
"""A frozen ``scipy.stats`` distribution for the current params (lazy import)."""
|
|
28
|
+
from scipy import stats # type: ignore[import-not-found]
|
|
29
|
+
|
|
30
|
+
return self._make_scipy(stats)
|
|
31
|
+
|
|
32
|
+
@property
|
|
33
|
+
def pymc(self) -> Any:
|
|
34
|
+
"""A ``pymc`` distribution object from the current params (lazy import)."""
|
|
35
|
+
import pymc as pm # type: ignore[import-not-found]
|
|
36
|
+
|
|
37
|
+
dist = getattr(pm, self._dist_name)
|
|
38
|
+
return dist.dist(**self.params)
|
|
39
|
+
|
|
40
|
+
def create_variable(self, name: str) -> Any:
|
|
41
|
+
"""A symbolic pymc distribution whose parameters are named pytensor
|
|
42
|
+
scalars (``{name}_{param}``), ready for ``pm.compile`` with
|
|
43
|
+
``pytensor.graph.traversal.explicit_graph_inputs``.
|
|
44
|
+
|
|
45
|
+
This is the compiled-input counterpart to :attr:`pymc`/:attr:`params`:
|
|
46
|
+
instead of baking the current values in, each parameter becomes a
|
|
47
|
+
``pt.scalar(f"{name}_{param}")`` so the graph can be compiled once and
|
|
48
|
+
re-called with new values without rebuilding. E.g.
|
|
49
|
+
|
|
50
|
+
``w_int.create_variable("intercept")`` gives ``pm.Normal.dist(
|
|
51
|
+
mu=pt.scalar("intercept_mu"), sigma=pt.scalar("intercept_sigma"))``.
|
|
52
|
+
"""
|
|
53
|
+
import pymc as pm # type: ignore[import-not-found]
|
|
54
|
+
import pytensor.tensor as pt # type: ignore[import-not-found]
|
|
55
|
+
|
|
56
|
+
kwargs = {p: pt.scalar(f"{name}_{p}") for p in self._param_names}
|
|
57
|
+
return getattr(pm, self._dist_name).dist(**kwargs)
|
|
58
|
+
|
|
59
|
+
def _make_scipy(self, stats: Any) -> Any:
|
|
60
|
+
raise NotImplementedError
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
"""Interactive Beta distribution widget on the fixed [0, 1] domain.
|
|
2
|
+
|
|
3
|
+
Drag the mean line to translate (at a fixed concentration) or either ``q25`` /
|
|
4
|
+
``q75`` square to concentrate / spread out. Synced ``alpha`` / ``beta`` traits
|
|
5
|
+
make ``mo.ui.anywidget(...).value`` splat into ``pm.Beta.dist(**w.value)``.
|
|
6
|
+
|
|
7
|
+
Examples
|
|
8
|
+
--------
|
|
9
|
+
>>> import marimo as mo
|
|
10
|
+
>>> import modist as md
|
|
11
|
+
>>> w = mo.ui.anywidget(md.Beta(alpha=2, beta=2))
|
|
12
|
+
>>> w
|
|
13
|
+
>>> params = w.value # {'alpha': ..., 'beta': ...}
|
|
14
|
+
"""
|
|
15
|
+
|
|
16
|
+
from __future__ import annotations
|
|
17
|
+
|
|
18
|
+
from pathlib import Path
|
|
19
|
+
|
|
20
|
+
import anywidget
|
|
21
|
+
import traitlets
|
|
22
|
+
|
|
23
|
+
from ._base import DistMixin
|
|
24
|
+
|
|
25
|
+
_ESM = Path(__file__).parent / "static" / "beta.js"
|
|
26
|
+
_CSS = Path(__file__).parent / "styles.css"
|
|
27
|
+
|
|
28
|
+
|
|
29
|
+
class Beta(DistMixin, anywidget.AnyWidget):
|
|
30
|
+
"""An interactive Beta distribution with draggable mean and concentration."""
|
|
31
|
+
|
|
32
|
+
_esm = _ESM
|
|
33
|
+
_css = _CSS
|
|
34
|
+
_param_names = ("alpha", "beta")
|
|
35
|
+
_dist_name = "Beta"
|
|
36
|
+
|
|
37
|
+
alpha = traitlets.Float(2.0).tag(sync=True)
|
|
38
|
+
beta = traitlets.Float(2.0).tag(sync=True)
|
|
39
|
+
|
|
40
|
+
def _make_scipy(self, stats):
|
|
41
|
+
return stats.beta(a=self.alpha, b=self.beta)
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
"""Interactive Gamma distribution widget, left edge pinned at 0.
|
|
2
|
+
|
|
3
|
+
Drag the mean line to translate (at a fixed shape) or either ``q25`` / ``q75``
|
|
4
|
+
square to reshape. ``alpha`` is the shape and ``beta`` the rate (pymc / stats
|
|
5
|
+
convention, not the scipy ``scale``). Synced traits make
|
|
6
|
+
``mo.ui.anywidget(...).value`` splat into ``pm.Gamma.dist(**w.value)``.
|
|
7
|
+
|
|
8
|
+
Examples
|
|
9
|
+
--------
|
|
10
|
+
>>> import marimo as mo
|
|
11
|
+
>>> import modist as md
|
|
12
|
+
>>> w = mo.ui.anywidget(md.Gamma(alpha=2, beta=2))
|
|
13
|
+
>>> w
|
|
14
|
+
>>> params = w.value # {'alpha': ..., 'beta': ...}
|
|
15
|
+
"""
|
|
16
|
+
|
|
17
|
+
from __future__ import annotations
|
|
18
|
+
|
|
19
|
+
from pathlib import Path
|
|
20
|
+
|
|
21
|
+
import anywidget
|
|
22
|
+
import traitlets
|
|
23
|
+
|
|
24
|
+
from ._base import DistMixin
|
|
25
|
+
|
|
26
|
+
_ESM = Path(__file__).parent / "static" / "gamma.js"
|
|
27
|
+
_CSS = Path(__file__).parent / "styles.css"
|
|
28
|
+
|
|
29
|
+
|
|
30
|
+
class Gamma(DistMixin, anywidget.AnyWidget):
|
|
31
|
+
"""An interactive Gamma distribution with draggable mean and shape."""
|
|
32
|
+
|
|
33
|
+
_esm = _ESM
|
|
34
|
+
_css = _CSS
|
|
35
|
+
_param_names = ("alpha", "beta")
|
|
36
|
+
_dist_name = "Gamma"
|
|
37
|
+
|
|
38
|
+
alpha = traitlets.Float(2.0).tag(sync=True)
|
|
39
|
+
beta = traitlets.Float(2.0).tag(sync=True)
|
|
40
|
+
|
|
41
|
+
def _make_scipy(self, stats):
|
|
42
|
+
# scipy gamma parametrizes by (shape, scale); here beta is the rate.
|
|
43
|
+
return stats.gamma(a=self.alpha, scale=1.0 / self.beta)
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
"""Interactive Normal distribution widget.
|
|
2
|
+
|
|
3
|
+
A draggable Normal curve: drag the mean line to reposition, or either of the
|
|
4
|
+
``\u00b11\u03c3`` squares to reshape the spread. The synced ``mu`` / ``sigma``
|
|
5
|
+
traits make ``mo.ui.anywidget(...).value`` splat directly into a distribution
|
|
6
|
+
constructor, e.g. ``pm.Normal.dist(**w.value)``.
|
|
7
|
+
|
|
8
|
+
Examples
|
|
9
|
+
--------
|
|
10
|
+
>>> import marimo as mo
|
|
11
|
+
>>> import modist as md
|
|
12
|
+
>>> w = mo.ui.anywidget(md.Normal(mu=0, sigma=1))
|
|
13
|
+
>>> w
|
|
14
|
+
>>> params = w.value # {'mu': ..., 'sigma': ...}
|
|
15
|
+
"""
|
|
16
|
+
|
|
17
|
+
from __future__ import annotations
|
|
18
|
+
|
|
19
|
+
from pathlib import Path
|
|
20
|
+
|
|
21
|
+
import anywidget
|
|
22
|
+
import traitlets
|
|
23
|
+
|
|
24
|
+
from ._base import DistMixin
|
|
25
|
+
|
|
26
|
+
_ESM = Path(__file__).parent / "static" / "normal.js"
|
|
27
|
+
_CSS = Path(__file__).parent / "styles.css"
|
|
28
|
+
|
|
29
|
+
|
|
30
|
+
class Normal(DistMixin, anywidget.AnyWidget):
|
|
31
|
+
"""An interactive Normal distribution with draggable mean and spread."""
|
|
32
|
+
|
|
33
|
+
_esm = _ESM
|
|
34
|
+
_css = _CSS
|
|
35
|
+
_param_names = ("mu", "sigma")
|
|
36
|
+
_dist_name = "Normal"
|
|
37
|
+
|
|
38
|
+
mu = traitlets.Float(0.0).tag(sync=True)
|
|
39
|
+
sigma = traitlets.Float(1.0).tag(sync=True)
|
|
40
|
+
|
|
41
|
+
def _make_scipy(self, stats):
|
|
42
|
+
return stats.norm(loc=self.mu, scale=self.sigma)
|
|
File without changes
|