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/_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
@@ -0,0 +1,11 @@
1
+ from __future__ import annotations
2
+
3
+ from typing import Any
4
+
5
+
6
+ def sql(expr: str) -> dict[str, Any]:
7
+ return {"sql": expr}
8
+
9
+
10
+ def channels(**kwargs: str) -> dict[str, str]:
11
+ return dict(kwargs)
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)