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/_types.py
ADDED
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
from collections.abc import Sequence
|
|
2
|
+
from datetime import date
|
|
3
|
+
from typing import Any
|
|
4
|
+
|
|
5
|
+
from .data import DataDef
|
|
6
|
+
from .params import _ParamBase
|
|
7
|
+
from .plot import FromRef
|
|
8
|
+
|
|
9
|
+
# Value unions: wide enough for column names, constants, param references,
|
|
10
|
+
# dates, and transform dicts; narrow enough that passing a Mark or View
|
|
11
|
+
# where a value belongs is a type error.
|
|
12
|
+
ChannelValue = (
|
|
13
|
+
str | float | bool | date | dict[str, Any] | Sequence[Any] | _ParamBase | None
|
|
14
|
+
)
|
|
15
|
+
AttrValue = (
|
|
16
|
+
str | float | bool | date | dict[str, Any] | Sequence[Any] | _ParamBase | None
|
|
17
|
+
)
|
|
18
|
+
MarkData = str | FromRef | DataDef | dict[str, Any] | Sequence[Any] | _ParamBase | None
|
|
19
|
+
TransformArg = str | float | bool | _ParamBase
|
|
20
|
+
|
|
21
|
+
|
|
22
|
+
class _Unset:
|
|
23
|
+
"""Sentinel for mark channels that were not passed (distinct from None)."""
|
|
24
|
+
|
|
25
|
+
def __repr__(self) -> str:
|
|
26
|
+
return "UNSET"
|
|
27
|
+
|
|
28
|
+
|
|
29
|
+
UNSET: Any = _Unset()
|
vgplot/data.py
ADDED
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
from __future__ import annotations
|
|
2
|
+
|
|
3
|
+
from dataclasses import dataclass
|
|
4
|
+
from typing import Any
|
|
5
|
+
|
|
6
|
+
|
|
7
|
+
@dataclass
|
|
8
|
+
class DataDef:
|
|
9
|
+
payload: dict[str, Any]
|
|
10
|
+
|
|
11
|
+
def to_dict(self) -> dict[str, Any]:
|
|
12
|
+
return self.payload
|
|
13
|
+
|
|
14
|
+
|
|
15
|
+
def parquet(file: str, select: Any = None, where: Any = None, **kwargs: Any) -> DataDef:
|
|
16
|
+
payload: dict[str, Any] = {"type": "parquet", "file": file}
|
|
17
|
+
if select is not None:
|
|
18
|
+
payload["select"] = select
|
|
19
|
+
if where is not None:
|
|
20
|
+
payload["where"] = where
|
|
21
|
+
payload.update(kwargs)
|
|
22
|
+
return DataDef(payload)
|
|
23
|
+
|
|
24
|
+
|
|
25
|
+
def csv(file: str, **kwargs: Any) -> DataDef:
|
|
26
|
+
return DataDef({"type": "csv", "file": file, **kwargs})
|
|
27
|
+
|
|
28
|
+
|
|
29
|
+
def spatial(file: str, layer: str | None = None, **kwargs: Any) -> DataDef:
|
|
30
|
+
payload: dict[str, Any] = {"type": "spatial", "file": file}
|
|
31
|
+
if layer is not None:
|
|
32
|
+
payload["layer"] = layer
|
|
33
|
+
payload.update(kwargs)
|
|
34
|
+
return DataDef(payload)
|
|
35
|
+
|
|
36
|
+
|
|
37
|
+
def table(query: str) -> DataDef:
|
|
38
|
+
return DataDef({"type": "table", "query": query})
|
|
39
|
+
|
|
40
|
+
|
|
41
|
+
def json(data: Any = None, file: str | None = None, **kwargs: Any) -> DataDef:
|
|
42
|
+
payload: dict[str, Any] = {"type": "json"}
|
|
43
|
+
if file is not None:
|
|
44
|
+
payload["file"] = file
|
|
45
|
+
if data is not None:
|
|
46
|
+
payload["data"] = data
|
|
47
|
+
payload.update(kwargs)
|
|
48
|
+
return DataDef(payload)
|
|
49
|
+
|
|
50
|
+
|
|
51
|
+
def data(**named_defs: DataDef) -> dict[str, Any]:
|
|
52
|
+
out: dict[str, Any] = {}
|
|
53
|
+
for k, v in named_defs.items():
|
|
54
|
+
out[k] = v.to_dict() if hasattr(v, "to_dict") else v
|
|
55
|
+
return out
|
vgplot/encodings.py
ADDED
vgplot/params.py
ADDED
|
@@ -0,0 +1,90 @@
|
|
|
1
|
+
from __future__ import annotations
|
|
2
|
+
|
|
3
|
+
from datetime import date
|
|
4
|
+
from typing import Any
|
|
5
|
+
|
|
6
|
+
|
|
7
|
+
def _resolve(v: Any, param_names: dict[int, str] | None) -> Any:
|
|
8
|
+
"""Recursively resolve _ParamBase objects to "$name" ref strings."""
|
|
9
|
+
if param_names is None:
|
|
10
|
+
return v
|
|
11
|
+
if isinstance(v, _ParamBase):
|
|
12
|
+
name = param_names.get(id(v))
|
|
13
|
+
return f"${name}" if name is not None else v
|
|
14
|
+
if isinstance(v, list):
|
|
15
|
+
return [_resolve(x, param_names) for x in v]
|
|
16
|
+
if isinstance(v, dict):
|
|
17
|
+
return {k: _resolve(val, param_names) for k, val in v.items()}
|
|
18
|
+
return v
|
|
19
|
+
|
|
20
|
+
|
|
21
|
+
class _ParamBase:
|
|
22
|
+
"""Base for Param and Selection instances used as param ref tokens."""
|
|
23
|
+
|
|
24
|
+
def param_def(self, *, param_names: dict[int, str] | None = None) -> Any:
|
|
25
|
+
raise NotImplementedError
|
|
26
|
+
|
|
27
|
+
|
|
28
|
+
class ParamValue(_ParamBase):
|
|
29
|
+
def __init__(self, value: Any = None) -> None:
|
|
30
|
+
self._value = value
|
|
31
|
+
|
|
32
|
+
def param_def(self, *, param_names: dict[int, str] | None = None) -> Any:
|
|
33
|
+
if isinstance(self._value, date):
|
|
34
|
+
return {"date": self._value.isoformat()}
|
|
35
|
+
return self._value
|
|
36
|
+
|
|
37
|
+
def __repr__(self) -> str:
|
|
38
|
+
return f"param.value({self._value!r})"
|
|
39
|
+
|
|
40
|
+
|
|
41
|
+
class ParamArray(_ParamBase):
|
|
42
|
+
def __init__(self, values: list) -> None:
|
|
43
|
+
self._values = list(values)
|
|
44
|
+
|
|
45
|
+
def param_def(self, *, param_names: dict[int, str] | None = None) -> Any:
|
|
46
|
+
return [_resolve(v, param_names) for v in self._values]
|
|
47
|
+
|
|
48
|
+
def __repr__(self) -> str:
|
|
49
|
+
return f"param.array({self._values!r})"
|
|
50
|
+
|
|
51
|
+
|
|
52
|
+
class SelectionDef(_ParamBase):
|
|
53
|
+
def __init__(self, select: str, **opts: Any) -> None:
|
|
54
|
+
self._select = select
|
|
55
|
+
self._opts = {k: v for k, v in opts.items() if v is not None}
|
|
56
|
+
|
|
57
|
+
def param_def(self, *, param_names: dict[int, str] | None = None) -> Any:
|
|
58
|
+
d: dict = {"select": self._select}
|
|
59
|
+
d.update(_resolve(self._opts, param_names))
|
|
60
|
+
return d
|
|
61
|
+
|
|
62
|
+
def __repr__(self) -> str:
|
|
63
|
+
opts = ", ".join(f"{k}={v!r}" for k, v in self._opts.items())
|
|
64
|
+
return f"selection.{self._select}({opts})"
|
|
65
|
+
|
|
66
|
+
|
|
67
|
+
def param(value: Any = None) -> _ParamBase:
|
|
68
|
+
if isinstance(value, list):
|
|
69
|
+
return ParamArray(value)
|
|
70
|
+
return ParamValue(value)
|
|
71
|
+
|
|
72
|
+
|
|
73
|
+
class selection:
|
|
74
|
+
"""Namespace for creating selection params."""
|
|
75
|
+
|
|
76
|
+
@staticmethod
|
|
77
|
+
def intersect(**opts: Any) -> SelectionDef:
|
|
78
|
+
return SelectionDef("intersect", **opts)
|
|
79
|
+
|
|
80
|
+
@staticmethod
|
|
81
|
+
def crossfilter(**opts: Any) -> SelectionDef:
|
|
82
|
+
return SelectionDef("crossfilter", **opts)
|
|
83
|
+
|
|
84
|
+
@staticmethod
|
|
85
|
+
def union(**opts: Any) -> SelectionDef:
|
|
86
|
+
return SelectionDef("union", **opts)
|
|
87
|
+
|
|
88
|
+
@staticmethod
|
|
89
|
+
def single(**opts: Any) -> SelectionDef:
|
|
90
|
+
return SelectionDef("single", **opts)
|