vgplot 0.29.0__py3-none-any.whl
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.
- vgplot/__init__.py +102 -0
- vgplot/_generated/__init__.py +10 -0
- vgplot/_generated/attributes.py +1293 -0
- vgplot/_generated/encodings.py +252 -0
- vgplot/_generated/marks.py +4124 -0
- vgplot/_types.py +29 -0
- vgplot/data.py +55 -0
- vgplot/encodings.py +11 -0
- vgplot/params.py +90 -0
- vgplot/plot.py +546 -0
- vgplot/spec.py +304 -0
- vgplot/util.py +14 -0
- vgplot-0.29.0.dist-info/METADATA +136 -0
- vgplot-0.29.0.dist-info/RECORD +15 -0
- vgplot-0.29.0.dist-info/WHEEL +4 -0
vgplot/spec.py
ADDED
|
@@ -0,0 +1,304 @@
|
|
|
1
|
+
from __future__ import annotations
|
|
2
|
+
|
|
3
|
+
import inspect
|
|
4
|
+
import json
|
|
5
|
+
from typing import Any
|
|
6
|
+
|
|
7
|
+
from .util import omit_none
|
|
8
|
+
from .params import _ParamBase
|
|
9
|
+
from .data import DataDef
|
|
10
|
+
from .plot import _encode_component
|
|
11
|
+
|
|
12
|
+
|
|
13
|
+
def _caller_locals() -> dict[str, Any]:
|
|
14
|
+
"""Local variables of the caller of the method invoking this helper.
|
|
15
|
+
|
|
16
|
+
Returns an empty mapping when the frame is unavailable (e.g. on Python
|
|
17
|
+
implementations without ``sys._getframe`` support).
|
|
18
|
+
"""
|
|
19
|
+
frame = inspect.currentframe()
|
|
20
|
+
method = frame.f_back if frame is not None else None
|
|
21
|
+
caller = method.f_back if method is not None else None
|
|
22
|
+
return caller.f_locals if caller is not None else {}
|
|
23
|
+
|
|
24
|
+
|
|
25
|
+
def _collect_params(node: Any) -> list[_ParamBase]:
|
|
26
|
+
"""Recursively collect all _ParamBase instances in a view tree."""
|
|
27
|
+
if isinstance(node, _ParamBase):
|
|
28
|
+
return [node]
|
|
29
|
+
if isinstance(node, View):
|
|
30
|
+
return _collect_params(node._view)
|
|
31
|
+
if isinstance(node, dict):
|
|
32
|
+
found = []
|
|
33
|
+
for v in node.values():
|
|
34
|
+
found.extend(_collect_params(v))
|
|
35
|
+
return found
|
|
36
|
+
if isinstance(node, list):
|
|
37
|
+
found = []
|
|
38
|
+
for item in node:
|
|
39
|
+
found.extend(_collect_params(item))
|
|
40
|
+
return found
|
|
41
|
+
return []
|
|
42
|
+
|
|
43
|
+
|
|
44
|
+
def _collect_datadefs(node: Any) -> list[DataDef]:
|
|
45
|
+
"""Recursively collect all DataDef instances in a view tree."""
|
|
46
|
+
if isinstance(node, DataDef):
|
|
47
|
+
return [node]
|
|
48
|
+
if isinstance(node, View):
|
|
49
|
+
return _collect_datadefs(node._view)
|
|
50
|
+
if isinstance(node, dict):
|
|
51
|
+
found = []
|
|
52
|
+
for v in node.values():
|
|
53
|
+
found.extend(_collect_datadefs(v))
|
|
54
|
+
return found
|
|
55
|
+
if isinstance(node, list):
|
|
56
|
+
found = []
|
|
57
|
+
for item in node:
|
|
58
|
+
found.extend(_collect_datadefs(item))
|
|
59
|
+
return found
|
|
60
|
+
return []
|
|
61
|
+
|
|
62
|
+
|
|
63
|
+
class Spec:
|
|
64
|
+
def __init__(
|
|
65
|
+
self,
|
|
66
|
+
*,
|
|
67
|
+
data: dict[str, Any] | None = None,
|
|
68
|
+
data_names: dict[int, str] | None = None,
|
|
69
|
+
params: dict[str, Any] | None = None,
|
|
70
|
+
plotDefaults: dict[str, Any] | None = None,
|
|
71
|
+
plot_defaults: dict[str, Any] | None = None,
|
|
72
|
+
config: dict[str, Any] | None = None,
|
|
73
|
+
view: dict[str, Any] | None = None,
|
|
74
|
+
**extra: Any,
|
|
75
|
+
) -> None:
|
|
76
|
+
# Serialize any DataDef values in data and build id→name mapping
|
|
77
|
+
resolved_data: dict[str, Any] = {}
|
|
78
|
+
resolved_data_names: dict[int, str] = dict(data_names or {})
|
|
79
|
+
for name, val in (data or {}).items():
|
|
80
|
+
if isinstance(val, DataDef):
|
|
81
|
+
resolved_data_names[id(val)] = name
|
|
82
|
+
resolved_data[name] = val.to_dict()
|
|
83
|
+
else:
|
|
84
|
+
resolved_data[name] = val
|
|
85
|
+
self.data = resolved_data or None
|
|
86
|
+
self.data_names = resolved_data_names
|
|
87
|
+
self.params = params
|
|
88
|
+
self.plotDefaults = plotDefaults or plot_defaults
|
|
89
|
+
self.config = config
|
|
90
|
+
self.view = view or {}
|
|
91
|
+
self.extra = extra
|
|
92
|
+
|
|
93
|
+
def to_dict(self) -> dict[str, Any]:
|
|
94
|
+
# Build a reverse lookup: id(param_object) -> param_name, so that
|
|
95
|
+
# _ParamBase instances appearing in the view resolve to "$name" refs.
|
|
96
|
+
param_names: dict[int, str] = {}
|
|
97
|
+
serialized_params: dict[str, Any] = {}
|
|
98
|
+
# First pass: register all named params
|
|
99
|
+
for name, p in (self.params or {}).items():
|
|
100
|
+
if isinstance(p, _ParamBase):
|
|
101
|
+
param_names[id(p)] = name
|
|
102
|
+
|
|
103
|
+
# Second pass: auto-name any _ParamBase in the view not yet registered,
|
|
104
|
+
# skipping names already taken by explicit params.
|
|
105
|
+
used = set(param_names.values()) | set(self.params or {})
|
|
106
|
+
counter = 0
|
|
107
|
+
for obj in _collect_params(self.view):
|
|
108
|
+
if id(obj) not in param_names:
|
|
109
|
+
while f"_param{counter}" in used:
|
|
110
|
+
counter += 1
|
|
111
|
+
param_names[id(obj)] = f"_param{counter}"
|
|
112
|
+
counter += 1
|
|
113
|
+
|
|
114
|
+
# Third pass: serialize all known params
|
|
115
|
+
view_params = {id(obj): obj for obj in _collect_params(self.view)}
|
|
116
|
+
all_params = dict(self.params or {})
|
|
117
|
+
for obj_id, name in param_names.items():
|
|
118
|
+
if name not in all_params and obj_id in view_params:
|
|
119
|
+
all_params[name] = view_params[obj_id]
|
|
120
|
+
for name, p in all_params.items():
|
|
121
|
+
if isinstance(p, _ParamBase):
|
|
122
|
+
serialized_params[name] = p.param_def(param_names=param_names)
|
|
123
|
+
else:
|
|
124
|
+
serialized_params[name] = p
|
|
125
|
+
|
|
126
|
+
# Build data_names lookup and auto-register any unnamed DataDefs in the view
|
|
127
|
+
data_names = dict(self.data_names)
|
|
128
|
+
extra_data: dict[str, Any] = {}
|
|
129
|
+
used = set(data_names.values()) | set(self.data or {})
|
|
130
|
+
counter = 0
|
|
131
|
+
for obj in _collect_datadefs(self.view):
|
|
132
|
+
if id(obj) not in data_names:
|
|
133
|
+
while f"_data{counter}" in used:
|
|
134
|
+
counter += 1
|
|
135
|
+
auto_name = f"_data{counter}"
|
|
136
|
+
data_names[id(obj)] = auto_name
|
|
137
|
+
extra_data[auto_name] = obj.to_dict()
|
|
138
|
+
counter += 1
|
|
139
|
+
merged_data = {**(self.data or {}), **extra_data} or None
|
|
140
|
+
|
|
141
|
+
base: dict[str, Any] = {}
|
|
142
|
+
if self.config:
|
|
143
|
+
base["config"] = self.config
|
|
144
|
+
if merged_data:
|
|
145
|
+
base["data"] = merged_data
|
|
146
|
+
if serialized_params:
|
|
147
|
+
base["params"] = serialized_params
|
|
148
|
+
if self.plotDefaults:
|
|
149
|
+
base["plotDefaults"] = self.plotDefaults
|
|
150
|
+
base.update(_encode_component(self.view, param_names, data_names))
|
|
151
|
+
base.update(omit_none(self.extra))
|
|
152
|
+
return base
|
|
153
|
+
|
|
154
|
+
def to_json(self, **kwargs: Any) -> str:
|
|
155
|
+
return json.dumps(self.to_dict(), **kwargs)
|
|
156
|
+
|
|
157
|
+
def _repr_mimebundle_(self, **kwargs):
|
|
158
|
+
try:
|
|
159
|
+
from mosaic_widget import MosaicWidget
|
|
160
|
+
except ImportError:
|
|
161
|
+
return {"text/plain": repr(self)}
|
|
162
|
+
widget = MosaicWidget(self.to_dict())
|
|
163
|
+
return widget._repr_mimebundle_(**kwargs)
|
|
164
|
+
|
|
165
|
+
def show(self, con=None, data=None):
|
|
166
|
+
try:
|
|
167
|
+
from mosaic_widget import MosaicWidget
|
|
168
|
+
from IPython.display import display
|
|
169
|
+
except ImportError as e:
|
|
170
|
+
raise ImportError("pip install mosaic-widget") from e
|
|
171
|
+
widget = MosaicWidget(self.to_dict(), con=con, data=data)
|
|
172
|
+
display(widget)
|
|
173
|
+
|
|
174
|
+
|
|
175
|
+
class View:
|
|
176
|
+
"""
|
|
177
|
+
A composable view returned by plot(), vconcat(), hconcat() etc.
|
|
178
|
+
Behaves like Spec but discovers data and params from the caller's
|
|
179
|
+
frame at display/export time rather than at construction time.
|
|
180
|
+
"""
|
|
181
|
+
|
|
182
|
+
def __init__(
|
|
183
|
+
self,
|
|
184
|
+
view: dict[str, Any],
|
|
185
|
+
*,
|
|
186
|
+
data: dict[str, Any] | None = None,
|
|
187
|
+
plotDefaults: dict[str, Any] | None = None,
|
|
188
|
+
plot_defaults: dict[str, Any] | None = None,
|
|
189
|
+
config: dict[str, Any] | None = None,
|
|
190
|
+
**extra: Any,
|
|
191
|
+
) -> None:
|
|
192
|
+
self._view = view
|
|
193
|
+
self._data = data # explicit overrides for renamed data variables
|
|
194
|
+
self._plotDefaults = plotDefaults or plot_defaults
|
|
195
|
+
self._config = config
|
|
196
|
+
self._extra = extra
|
|
197
|
+
|
|
198
|
+
def _build_spec(self, caller_locals: dict[str, Any]) -> Spec:
|
|
199
|
+
explicit_ids = {
|
|
200
|
+
id(v) for v in (self._data or {}).values() if isinstance(v, DataDef)
|
|
201
|
+
}
|
|
202
|
+
frame_data: dict[str, Any] = {
|
|
203
|
+
name: obj
|
|
204
|
+
for name, obj in caller_locals.items()
|
|
205
|
+
if isinstance(obj, DataDef)
|
|
206
|
+
and not name.startswith("_")
|
|
207
|
+
and id(obj) not in explicit_ids
|
|
208
|
+
}
|
|
209
|
+
merged_data = {**(self._data or {}), **frame_data} or None
|
|
210
|
+
frame_params: dict[str, Any] = {
|
|
211
|
+
name: obj
|
|
212
|
+
for name, obj in caller_locals.items()
|
|
213
|
+
if isinstance(obj, _ParamBase) and not name.startswith("_")
|
|
214
|
+
}
|
|
215
|
+
return Spec(
|
|
216
|
+
data=merged_data,
|
|
217
|
+
params=frame_params or None,
|
|
218
|
+
plotDefaults=self._plotDefaults,
|
|
219
|
+
config=self._config,
|
|
220
|
+
view=self._view,
|
|
221
|
+
**self._extra,
|
|
222
|
+
)
|
|
223
|
+
|
|
224
|
+
def to_dict(self, _context: dict[str, Any] | None = None) -> dict[str, Any]:
|
|
225
|
+
locals_ = _context if _context is not None else _caller_locals()
|
|
226
|
+
return self._build_spec(locals_).to_dict()
|
|
227
|
+
|
|
228
|
+
def to_json(self, _context: dict[str, Any] | None = None, **kwargs: Any) -> str:
|
|
229
|
+
locals_ = _context if _context is not None else _caller_locals()
|
|
230
|
+
return self._build_spec(locals_).to_json(**kwargs)
|
|
231
|
+
|
|
232
|
+
def show(self, con: Any = None, data: Any = None) -> None:
|
|
233
|
+
self._build_spec(_caller_locals()).show(con=con, data=data)
|
|
234
|
+
|
|
235
|
+
def _repr_mimebundle_(self, **kwargs: Any):
|
|
236
|
+
# Walk up frames to find the one where this View object lives
|
|
237
|
+
frame = inspect.currentframe()
|
|
238
|
+
frame = frame.f_back if frame is not None else None
|
|
239
|
+
while frame is not None:
|
|
240
|
+
if any(v is self for v in frame.f_locals.values()):
|
|
241
|
+
break
|
|
242
|
+
frame = frame.f_back
|
|
243
|
+
locals_ = frame.f_locals if frame is not None else {}
|
|
244
|
+
return self._build_spec(locals_)._repr_mimebundle_(**kwargs)
|
|
245
|
+
|
|
246
|
+
|
|
247
|
+
_VIEW_KEYS = {"plot", "vconcat", "hconcat", "hspace", "vspace", "input"}
|
|
248
|
+
|
|
249
|
+
|
|
250
|
+
def spec(
|
|
251
|
+
*args: Any,
|
|
252
|
+
data: dict[str, Any] | None = None,
|
|
253
|
+
params: dict[str, Any] | None = None,
|
|
254
|
+
plotDefaults: dict[str, Any] | None = None,
|
|
255
|
+
plot_defaults: dict[str, Any] | None = None,
|
|
256
|
+
config: dict[str, Any] | None = None,
|
|
257
|
+
view: dict[str, Any] | None = None,
|
|
258
|
+
**extra: Any,
|
|
259
|
+
) -> Spec:
|
|
260
|
+
"""Assemble a Spec from a view plus data sources and params.
|
|
261
|
+
|
|
262
|
+
A positional dict holding a view key (plot/vconcat/hconcat/...) is used as
|
|
263
|
+
the view; any other positional dict is used as data. DataDef and param
|
|
264
|
+
objects bound to local variables in the caller are discovered automatically
|
|
265
|
+
by name unless passed explicitly via data= or params=.
|
|
266
|
+
"""
|
|
267
|
+
for arg in args:
|
|
268
|
+
if isinstance(arg, dict) and _VIEW_KEYS.intersection(arg):
|
|
269
|
+
view = arg
|
|
270
|
+
elif isinstance(arg, dict):
|
|
271
|
+
data = arg
|
|
272
|
+
|
|
273
|
+
# Inspect caller frame to discover DataDef and _ParamBase objects by variable name.
|
|
274
|
+
caller_locals = _caller_locals()
|
|
275
|
+
|
|
276
|
+
# Collect DataDef objects not already covered by the explicit data= argument.
|
|
277
|
+
explicit_ids = {id(v) for v in (data or {}).values() if isinstance(v, DataDef)}
|
|
278
|
+
frame_data: dict[str, Any] = {
|
|
279
|
+
name: obj
|
|
280
|
+
for name, obj in caller_locals.items()
|
|
281
|
+
if isinstance(obj, DataDef)
|
|
282
|
+
and not name.startswith("_")
|
|
283
|
+
and id(obj) not in explicit_ids
|
|
284
|
+
}
|
|
285
|
+
merged_data = {**(data or {}), **frame_data} or None
|
|
286
|
+
|
|
287
|
+
# Collect _ParamBase objects when params were not passed explicitly.
|
|
288
|
+
if params is None:
|
|
289
|
+
frame_params: dict[str, Any] = {
|
|
290
|
+
name: obj
|
|
291
|
+
for name, obj in caller_locals.items()
|
|
292
|
+
if isinstance(obj, _ParamBase) and not name.startswith("_")
|
|
293
|
+
}
|
|
294
|
+
params = frame_params or None
|
|
295
|
+
|
|
296
|
+
return Spec(
|
|
297
|
+
data=merged_data,
|
|
298
|
+
params=params,
|
|
299
|
+
plotDefaults=plotDefaults,
|
|
300
|
+
plot_defaults=plot_defaults,
|
|
301
|
+
config=config,
|
|
302
|
+
view=view,
|
|
303
|
+
**extra,
|
|
304
|
+
)
|
vgplot/util.py
ADDED
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
from typing import Any
|
|
2
|
+
|
|
3
|
+
|
|
4
|
+
def camelize(key: str) -> str:
|
|
5
|
+
"""Convert snake_case to lowerCamelCase."""
|
|
6
|
+
if not key:
|
|
7
|
+
return key
|
|
8
|
+
parts = key.split("_")
|
|
9
|
+
return parts[0] + "".join(p[:1].upper() + p[1:] for p in parts[1:])
|
|
10
|
+
|
|
11
|
+
|
|
12
|
+
def omit_none(d: dict[str, Any]) -> dict[str, Any]:
|
|
13
|
+
"""Return a copy without None values."""
|
|
14
|
+
return {k: v for k, v in d.items() if v is not None}
|
|
@@ -0,0 +1,136 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: vgplot
|
|
3
|
+
Version: 0.29.0
|
|
4
|
+
Summary: A Python API for authoring Mosaic vgplot visualizations
|
|
5
|
+
Project-URL: homepage, https://github.com/uwdata/mosaic
|
|
6
|
+
Requires-Python: >=3.10
|
|
7
|
+
Description-Content-Type: text/markdown
|
|
8
|
+
|
|
9
|
+
# vgplot
|
|
10
|
+
|
|
11
|
+
[](https://pypi.org/project/vgplot/)
|
|
12
|
+
|
|
13
|
+
A Python API for authoring [Mosaic](https://uwdata.github.io/mosaic/) visualizations. Build declarative, interactive plots backed by DuckDB — in notebooks, as JSON specs, or as part of a data pipeline.
|
|
14
|
+
|
|
15
|
+
`vgplot` produces Mosaic `View` objects that can be rendered with [`mosaic-widget`](https://pypi.org/project/mosaic-widget/) or exported to JSON for use in a browser. Data sources and parameters defined as local variables are automatically discovered at render time.
|
|
16
|
+
|
|
17
|
+
## Installation
|
|
18
|
+
|
|
19
|
+
```bash
|
|
20
|
+
pip install vgplot
|
|
21
|
+
```
|
|
22
|
+
|
|
23
|
+
To render visualizations in the widget, install the widget:
|
|
24
|
+
|
|
25
|
+
```bash
|
|
26
|
+
pip install mosaic-widget
|
|
27
|
+
```
|
|
28
|
+
|
|
29
|
+
## Usage
|
|
30
|
+
|
|
31
|
+
### File-based data
|
|
32
|
+
|
|
33
|
+
Load data from a file using `vg.parquet()`, `vg.csv()`, or `vg.table()`, pass it directly to a mark, then call `view.show()` or `view`:
|
|
34
|
+
|
|
35
|
+
```python
|
|
36
|
+
import vgplot as vg
|
|
37
|
+
|
|
38
|
+
athletes = vg.parquet("data/athletes.parquet")
|
|
39
|
+
|
|
40
|
+
view = vg.plot(
|
|
41
|
+
vg.dot(athletes, x="weight", y="height", fill="sex", opacity=0.5),
|
|
42
|
+
vg.width(600),
|
|
43
|
+
vg.height(400),
|
|
44
|
+
)
|
|
45
|
+
|
|
46
|
+
view
|
|
47
|
+
```
|
|
48
|
+
|
|
49
|
+
### Interactive selections
|
|
50
|
+
|
|
51
|
+
Params and selections are first-class objects. Declare them before the view so they can be referenced by multiple marks or interactors:
|
|
52
|
+
|
|
53
|
+
```python
|
|
54
|
+
import vgplot as vg
|
|
55
|
+
|
|
56
|
+
flights = vg.parquet("data/flights-200k.parquet")
|
|
57
|
+
brush = vg.selection.crossfilter()
|
|
58
|
+
|
|
59
|
+
view = vg.vconcat(
|
|
60
|
+
vg.plot(
|
|
61
|
+
vg.rect_y(flights, x=vg.bin("delay"), y=vg.count(),
|
|
62
|
+
filter_by=brush, fill="steelblue",
|
|
63
|
+
inset_left=0.5, inset_right=0.5),
|
|
64
|
+
vg.interval_x(bind=brush),
|
|
65
|
+
vg.x_domain("Fixed"),
|
|
66
|
+
vg.x_label("Arrival Delay (min)"),
|
|
67
|
+
vg.height(200),
|
|
68
|
+
),
|
|
69
|
+
vg.plot(
|
|
70
|
+
vg.rect_y(flights, x=vg.bin("time"), y=vg.count(),
|
|
71
|
+
filter_by=brush, fill="steelblue",
|
|
72
|
+
inset_left=0.5, inset_right=0.5),
|
|
73
|
+
vg.interval_x(bind=brush),
|
|
74
|
+
vg.x_domain("Fixed"),
|
|
75
|
+
vg.x_label("Departure Time (hour)"),
|
|
76
|
+
vg.height(200),
|
|
77
|
+
),
|
|
78
|
+
)
|
|
79
|
+
|
|
80
|
+
view
|
|
81
|
+
```
|
|
82
|
+
|
|
83
|
+
### Scalar params and input widgets
|
|
84
|
+
|
|
85
|
+
Use `vg.param()` for scalar parameters bound to input controls:
|
|
86
|
+
|
|
87
|
+
```python
|
|
88
|
+
import vgplot as vg
|
|
89
|
+
|
|
90
|
+
walk = vg.parquet("data/random-walk.parquet")
|
|
91
|
+
bias = vg.param(0)
|
|
92
|
+
|
|
93
|
+
view = vg.vconcat(
|
|
94
|
+
vg.slider(label="Bias", bind=bias, min=0, max=1000, step=1),
|
|
95
|
+
vg.plot(
|
|
96
|
+
vg.area_y(walk, x="t", y=vg.sql("v + $bias")),
|
|
97
|
+
vg.width(680),
|
|
98
|
+
vg.height(200),
|
|
99
|
+
),
|
|
100
|
+
)
|
|
101
|
+
|
|
102
|
+
view
|
|
103
|
+
```
|
|
104
|
+
|
|
105
|
+
## Key concepts
|
|
106
|
+
|
|
107
|
+
| Concept | Python API |
|
|
108
|
+
|---|---|
|
|
109
|
+
| File-based data | `vg.parquet(path)`, `vg.csv(path)`, `vg.spatial(path)`, `vg.table(query)` |
|
|
110
|
+
| Mark | `vg.dot(...)`, `vg.bar_y(...)`, `vg.area_y(...)`, `vg.line_y(...)`, … |
|
|
111
|
+
| Aggregation / transform | `vg.count()`, `vg.bin("col")`, `vg.avg("col")`, `vg.sum("col")`, … |
|
|
112
|
+
| SQL expression | `vg.sql("expr")` — use `$param` to interpolate a param, e.g. `vg.sql("v + $bias")` |
|
|
113
|
+
| Plot attributes | `vg.width(n)`, `vg.height(n)`, `vg.x_label("…")`, `vg.color_scheme("…")`, … |
|
|
114
|
+
| Interactor | `vg.interval_x(...)`, `vg.interval_xy(...)`, `vg.region(...)`, `vg.highlight(...)`, … |
|
|
115
|
+
| Layout | `vg.vconcat(...)`, `vg.hconcat(...)`, `vg.vspace(n)`, `vg.hspace(n)` |
|
|
116
|
+
| Crossfilter selection | `vg.selection.crossfilter()` |
|
|
117
|
+
| Intersect / union selection | `vg.selection.intersect()`, `vg.selection.union()` |
|
|
118
|
+
| Scalar param | `vg.param(value)` |
|
|
119
|
+
| Input widgets | `vg.slider(...)`, `vg.menu(...)`, `vg.select(...)`, `vg.checkbox(...)` |
|
|
120
|
+
| Named data reference | `vg.source("table_name")` |
|
|
121
|
+
| Render | `view.show()` or `view` as last cell expression in notebooks |
|
|
122
|
+
|
|
123
|
+
Option names match the [vgplot API reference](https://uwdata.github.io/mosaic/api/), but in snake_case. For example, `xDomain` → `x_domain`, `colorScheme` → `color_scheme`, `filterBy` → `filter_by`.
|
|
124
|
+
|
|
125
|
+
Any mark or directive not listed above is also accessible by its snake_case name — `vg.regression_y(...)` and `vg.x_tick_rotate(45)` work without explicit exports.
|
|
126
|
+
|
|
127
|
+
## Exporting specs
|
|
128
|
+
|
|
129
|
+
`view.to_dict()` returns a plain Python dictionary. `view.to_json()` returns a JSON string:
|
|
130
|
+
|
|
131
|
+
```python
|
|
132
|
+
from pprint import pprint
|
|
133
|
+
|
|
134
|
+
pprint(view.to_dict())
|
|
135
|
+
print(view.to_json(indent=2))
|
|
136
|
+
```
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
vgplot/__init__.py,sha256=uALjBohruCjzzzXLOENDPbfYgCC5u7j2KLnTXaUcAHw,1678
|
|
2
|
+
vgplot/_types.py,sha256=cs5FgHnBKmcx9HaH4AWOaBZkMR3Vlg2CR4QXcv_qmWE,870
|
|
3
|
+
vgplot/data.py,sha256=VgG62a806C0bYo--sdpqK8r4pLZdeEKeUwhIJ3k_bTs,1493
|
|
4
|
+
vgplot/encodings.py,sha256=sb_TcBzClBL3c9IID8OSGVExCYYE7pB35bRaJt680ns,197
|
|
5
|
+
vgplot/params.py,sha256=d2copQfOHEu29cyS49_dgQSIe6ouU3_TSiafXUbFqg4,2724
|
|
6
|
+
vgplot/plot.py,sha256=2ScCoEDgYog3MZWMKXvNtCE1Cnd41xVyCI8guGCbehw,13583
|
|
7
|
+
vgplot/spec.py,sha256=MzI60-5rwu-UDCd1cn8oqj1Vl7FkCLwdEvPSWwF5MWs,11074
|
|
8
|
+
vgplot/util.py,sha256=3HQBJaXyCmM680xHvpmE4OaGSf1Nm7_PpbIUGs1WP4k,394
|
|
9
|
+
vgplot/_generated/__init__.py,sha256=S_iBHL2x70pcqk1OY-pw3xoXvSEcaxjpjpmN4n-zCxI,421
|
|
10
|
+
vgplot/_generated/attributes.py,sha256=Ghgp-geFLefbwD9awAs8ja2bHd0MiKTirrJyT5bSJMo,46270
|
|
11
|
+
vgplot/_generated/encodings.py,sha256=OcktD1tX2zqOb7X3XSZ6GNCpsNQW5B3pjF_vwzja_I4,8081
|
|
12
|
+
vgplot/_generated/marks.py,sha256=z_iM_BZ7FCtjCgWuv9NRnW8g1tFg56NKQpQ4wV8Q48Q,137136
|
|
13
|
+
vgplot-0.29.0.dist-info/METADATA,sha256=ZZqIFGtZaRQ2Ki-Acc8ZZ-4uE4XOeTOimdz4DoqYJYw,4414
|
|
14
|
+
vgplot-0.29.0.dist-info/WHEEL,sha256=lCkmxWfQsSc9CfIClYeavTdQeEX2toPqufh9gI35EQA,87
|
|
15
|
+
vgplot-0.29.0.dist-info/RECORD,,
|