perspective-python 3.0.0rc1__cp39-abi3-win_amd64.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.
- perspective/__init__.py +78 -0
- perspective/extension/finos-perspective-nbextension.json +5 -0
- perspective/handlers/__init__.py +26 -0
- perspective/handlers/aiohttp.py +54 -0
- perspective/handlers/starlette.py +51 -0
- perspective/handlers/tornado.py +61 -0
- perspective/perspective.pyd +0 -0
- perspective/templates/exported_widget.html.jinja +35 -0
- perspective/tests/__init__.py +11 -0
- perspective/tests/conftest.py +268 -0
- perspective/tests/core/__init__.py +11 -0
- perspective/tests/core/test_async.py +436 -0
- perspective/tests/core/test_threadpool.py +48 -0
- perspective/tests/server/__init__.py +11 -0
- perspective/tests/server/test_server.py +1062 -0
- perspective/tests/server/test_session.py +55 -0
- perspective/tests/single_threaded/test_single_threaded.py +61 -0
- perspective/tests/table/__init__.py +11 -0
- perspective/tests/table/arrow/date32.arrow +0 -0
- perspective/tests/table/arrow/date64.arrow +0 -0
- perspective/tests/table/arrow/dict.arrow +0 -0
- perspective/tests/table/arrow/dict_update.arrow +0 -0
- perspective/tests/table/arrow/int_float_str.arrow +0 -0
- perspective/tests/table/arrow/int_float_str_file.arrow +0 -0
- perspective/tests/table/arrow/int_float_str_update.arrow +0 -0
- perspective/tests/table/object_sequence.py +402 -0
- perspective/tests/table/test_delete.py +124 -0
- perspective/tests/table/test_exception.py +53 -0
- perspective/tests/table/test_leaks.py +54 -0
- perspective/tests/table/test_ports.py +178 -0
- perspective/tests/table/test_remove.py +102 -0
- perspective/tests/table/test_table.py +610 -0
- perspective/tests/table/test_table_arrow.py +452 -0
- perspective/tests/table/test_table_datetime.py +2409 -0
- perspective/tests/table/test_table_infer.py +201 -0
- perspective/tests/table/test_table_limit.py +43 -0
- perspective/tests/table/test_table_numpy.py +1022 -0
- perspective/tests/table/test_table_pandas.py +1018 -0
- perspective/tests/table/test_to_arrow.py +414 -0
- perspective/tests/table/test_to_arrow_lz4.py +33 -0
- perspective/tests/table/test_to_format.py +1024 -0
- perspective/tests/table/test_update.py +545 -0
- perspective/tests/table/test_update_arrow.py +980 -0
- perspective/tests/table/test_update_numpy.py +252 -0
- perspective/tests/table/test_update_pandas.py +211 -0
- perspective/tests/table/test_view.py +2235 -0
- perspective/tests/table/test_view_expression.py +1940 -0
- perspective/tests/viewer/__init__.py +11 -0
- perspective/tests/viewer/test_validate.py +70 -0
- perspective/tests/viewer/test_viewer.py +245 -0
- perspective/tests/widget/__init__.py +11 -0
- perspective/tests/widget/test_widget.py +278 -0
- perspective/tests/widget/test_widget_pandas.py +453 -0
- perspective/viewer/__init__.py +15 -0
- perspective/viewer/validate.py +22 -0
- perspective/viewer/viewer.py +331 -0
- perspective/viewer/viewer_traitlets.py +101 -0
- perspective/widget/__init__.py +16 -0
- perspective/widget/widget.py +269 -0
- perspective.data/data/share/jupyter/labextensions/@finos/perspective-jupyterlab/install.json +5 -0
- perspective.data/data/share/jupyter/labextensions/@finos/perspective-jupyterlab/package.json +81 -0
- perspective.data/data/share/jupyter/labextensions/@finos/perspective-jupyterlab/static/253.6f17b87bb4eb1e656365.js +18 -0
- perspective.data/data/share/jupyter/labextensions/@finos/perspective-jupyterlab/static/253.6f17b87bb4eb1e656365.js.LICENSE.txt +59 -0
- perspective.data/data/share/jupyter/labextensions/@finos/perspective-jupyterlab/static/905.d3bbc3d5954582d507bb.js +1 -0
- perspective.data/data/share/jupyter/labextensions/@finos/perspective-jupyterlab/static/remoteEntry.7044010cbbf2a7208035.js +1 -0
- perspective.data/data/share/jupyter/labextensions/@finos/perspective-jupyterlab/static/style.js +4 -0
- perspective.data/data/share/jupyter/labextensions/@finos/perspective-jupyterlab/static/third-party-licenses.json +16 -0
- perspective_python-3.0.0rc1.dist-info/METADATA +13 -0
- perspective_python-3.0.0rc1.dist-info/RECORD +70 -0
- perspective_python-3.0.0rc1.dist-info/WHEEL +4 -0
|
@@ -0,0 +1,331 @@
|
|
|
1
|
+
# ┏━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┓
|
|
2
|
+
# ┃ ██████ ██████ ██████ █ █ █ █ █ █▄ ▀███ █ ┃
|
|
3
|
+
# ┃ ▄▄▄▄▄█ █▄▄▄▄▄ ▄▄▄▄▄█ ▀▀▀▀▀█▀▀▀▀▀ █ ▀▀▀▀▀█ ████████▌▐███ ███▄ ▀█ █ ▀▀▀▀▀ ┃
|
|
4
|
+
# ┃ █▀▀▀▀▀ █▀▀▀▀▀ █▀██▀▀ ▄▄▄▄▄ █ ▄▄▄▄▄█ ▄▄▄▄▄█ ████████▌▐███ █████▄ █ ▄▄▄▄▄ ┃
|
|
5
|
+
# ┃ █ ██████ █ ▀█▄ █ ██████ █ ███▌▐███ ███████▄ █ ┃
|
|
6
|
+
# ┣━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┫
|
|
7
|
+
# ┃ Copyright (c) 2017, the Perspective Authors. ┃
|
|
8
|
+
# ┃ ╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌ ┃
|
|
9
|
+
# ┃ This file is part of the Perspective library, distributed under the terms ┃
|
|
10
|
+
# ┃ of the [Apache License 2.0](https://www.apache.org/licenses/LICENSE-2.0). ┃
|
|
11
|
+
# ┗━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┛
|
|
12
|
+
|
|
13
|
+
from random import random
|
|
14
|
+
from .viewer_traitlets import PerspectiveTraitlets
|
|
15
|
+
import perspective
|
|
16
|
+
|
|
17
|
+
# from .. import Server
|
|
18
|
+
|
|
19
|
+
# ─ │ ┌ ┬ ┐
|
|
20
|
+
# ┄ ┆ ├ ┼ ┤ ╲ ╱
|
|
21
|
+
# ┈ ┊ └ ┴ ┘
|
|
22
|
+
# ━ ┃ ┏ ┳ ┓ ┏ ┯ ┓ ┏ ┳ ┓ ┏ ┯ ┓
|
|
23
|
+
# ┅ ┇ ┣ ╋ ┫ ┣ ┿ ┫ ┠ ╂ ┨ ┠ ┼ ┨
|
|
24
|
+
# ┉ ┋ ┗ ┻ ┛ ┗ ┷ ┛ ┗ ┻ ┛ ┗ ┷ ┛
|
|
25
|
+
|
|
26
|
+
# global_server = PySyncServer()
|
|
27
|
+
|
|
28
|
+
|
|
29
|
+
class PerspectiveViewer(PerspectiveTraitlets, object):
|
|
30
|
+
"""PerspectiveViewer wraps the `perspective.Table` API and exposes an API
|
|
31
|
+
around creating views, loading data, and updating data.
|
|
32
|
+
"""
|
|
33
|
+
|
|
34
|
+
# Viewer attributes that should be saved in `save()` and restored using
|
|
35
|
+
# `restore()`. Symmetric to `PERSISTENT_ATTRIBUTES` in `perspective-viewer`.
|
|
36
|
+
PERSISTENT_ATTRIBUTES = (
|
|
37
|
+
"group_by",
|
|
38
|
+
"split_by",
|
|
39
|
+
"filter",
|
|
40
|
+
"sort",
|
|
41
|
+
"aggregates",
|
|
42
|
+
"columns",
|
|
43
|
+
"expressions",
|
|
44
|
+
"plugin",
|
|
45
|
+
"plugin_config",
|
|
46
|
+
"theme",
|
|
47
|
+
"settings",
|
|
48
|
+
"title",
|
|
49
|
+
"version",
|
|
50
|
+
)
|
|
51
|
+
|
|
52
|
+
def __init__(
|
|
53
|
+
self,
|
|
54
|
+
plugin="Datagrid",
|
|
55
|
+
columns=None,
|
|
56
|
+
group_by=None,
|
|
57
|
+
split_by=None,
|
|
58
|
+
aggregates=None,
|
|
59
|
+
sort=None,
|
|
60
|
+
filter=None,
|
|
61
|
+
expressions=None,
|
|
62
|
+
plugin_config=None,
|
|
63
|
+
settings=True,
|
|
64
|
+
theme=None,
|
|
65
|
+
title=None,
|
|
66
|
+
# ignored, here for restore compatibility
|
|
67
|
+
version=None,
|
|
68
|
+
):
|
|
69
|
+
"""Initialize an instance of `PerspectiveViewer` with the given viewer
|
|
70
|
+
configuration. Do not pass a `Table` or data into the constructor -
|
|
71
|
+
use the :func:`load()` method to provide the viewer with data.
|
|
72
|
+
|
|
73
|
+
Keyword Arguments:
|
|
74
|
+
columns (:obj:`list` of :obj:`str`): A list of column names to be
|
|
75
|
+
visible to the user.
|
|
76
|
+
group_by (:obj:`list` of :obj:`str`): A list of column names to
|
|
77
|
+
use as group by.
|
|
78
|
+
split_by (:obj:`list` of :obj:`str`): A list of column names
|
|
79
|
+
to use as split by.
|
|
80
|
+
aggregates (:obj:`dict` of :obj:`str` to :obj:`str`): A dictionary
|
|
81
|
+
of column names to aggregate types, which specify aggregates
|
|
82
|
+
for individual columns.
|
|
83
|
+
sort (:obj:`list` of :obj:`list` of :obj:`str`): A list of lists,
|
|
84
|
+
each list containing a column name and a sort direction
|
|
85
|
+
(``asc``, ``desc``, ``asc abs``, ``desc abs``, ``col asc``,
|
|
86
|
+
``col desc``, ``col asc abs``, ``col desc abs``).
|
|
87
|
+
filter (:obj:`list` of :obj:`list` of :obj:`str`): A list of lists,
|
|
88
|
+
each list containing a column name, a filter comparator, and a
|
|
89
|
+
value to filter by.
|
|
90
|
+
expressions (:obj:`list` of :obj:`str`): A list of string
|
|
91
|
+
expressions which are applied to the view.
|
|
92
|
+
plugin (:obj:`str`/:obj:`perspective.Plugin`): Which plugin to
|
|
93
|
+
select by default.
|
|
94
|
+
plugin_config (:obj:`dict`): A configuration for the plugin, i.e.
|
|
95
|
+
the datagrid plugin or a chart plugin.
|
|
96
|
+
settings(:obj:`bool`): Whether the perspective query settings
|
|
97
|
+
panel should be open.
|
|
98
|
+
theme (:obj:`str`): The color theme to use.
|
|
99
|
+
version (:obj:`str`): The version this configuration is restored from.
|
|
100
|
+
This should only be used when restoring a configuration,
|
|
101
|
+
and should not be set manually.
|
|
102
|
+
|
|
103
|
+
Examples:
|
|
104
|
+
>>> viewer = PerspectiveViewer(
|
|
105
|
+
... aggregates={"a": "avg"},
|
|
106
|
+
... group_by=["a"],
|
|
107
|
+
... sort=[["b", "desc"]],
|
|
108
|
+
... filter=[["a", ">", 1]],
|
|
109
|
+
... expressions=["\"a\" + 100"]
|
|
110
|
+
... )
|
|
111
|
+
"""
|
|
112
|
+
|
|
113
|
+
# The Table under management by this viewer and its
|
|
114
|
+
# attached PerspectiveManager
|
|
115
|
+
self._table = None
|
|
116
|
+
self._client = None
|
|
117
|
+
|
|
118
|
+
# Viewer configuration
|
|
119
|
+
self.plugin = plugin # validate_plugin(plugin)
|
|
120
|
+
self.columns = columns or [] # validate_columns(columns) or []
|
|
121
|
+
self.group_by = group_by or [] # validate_group_by(group_by) or []
|
|
122
|
+
self.split_by = split_by or [] # validate_split_by(split_by) or []
|
|
123
|
+
self.aggregates = aggregates or {} # validate_aggregates(aggregates) or {}
|
|
124
|
+
self.sort = sort or [] # validate_sort(sort) or []
|
|
125
|
+
self.filter = filter or [] # validate_filter(filter) or []
|
|
126
|
+
self.expressions = expressions or {} # validate_expressions(expressions) or {}
|
|
127
|
+
self.plugin_config = (
|
|
128
|
+
plugin_config or {}
|
|
129
|
+
) # validate_plugin_config(plugin_config) or {}
|
|
130
|
+
self.settings = settings
|
|
131
|
+
self.theme = theme
|
|
132
|
+
self.title = title
|
|
133
|
+
|
|
134
|
+
def new_proxy_session(self, cb):
|
|
135
|
+
return perspective.ProxySession(self._client, cb)
|
|
136
|
+
|
|
137
|
+
@property
|
|
138
|
+
def client(self):
|
|
139
|
+
"""Returns the ``perspective.Client`` under management by the viewer."""
|
|
140
|
+
return self._client
|
|
141
|
+
|
|
142
|
+
@property
|
|
143
|
+
def table(self):
|
|
144
|
+
"""Returns the ``perspective.Table`` under management by the viewer."""
|
|
145
|
+
return self._table
|
|
146
|
+
|
|
147
|
+
def load(self, data, **options):
|
|
148
|
+
"""Given a ``perspective.Table``, a ``perspective.View``,
|
|
149
|
+
or data that can be handled by ``perspective.Table``, pass it to the
|
|
150
|
+
viewer. Like `__init__`, load accepts a `perspective.Table`, a dataset,
|
|
151
|
+
or a schema.
|
|
152
|
+
|
|
153
|
+
``load()`` resets the state of the viewer :
|
|
154
|
+
|
|
155
|
+
* If a ``perspective.Table`` has already been loaded, ``**options`` is
|
|
156
|
+
ignored as the options already set on the ``Table`` take precedence.
|
|
157
|
+
|
|
158
|
+
* If a ``perspective.View`` is loaded, the options on the
|
|
159
|
+
``perspective.Table`` linked to the view take precedence.
|
|
160
|
+
|
|
161
|
+
If data is passed in, a ``perspective.Table`` is automatically created
|
|
162
|
+
by this method, and the options passed to ``**config`` are extended to
|
|
163
|
+
the new Table. If the widget already has a dataset, and the new data
|
|
164
|
+
has different columns to the old one, then the widget state (pivots,
|
|
165
|
+
sort, etc.) is cleared to prevent applying settings on columns that
|
|
166
|
+
don't exist.
|
|
167
|
+
|
|
168
|
+
Args:
|
|
169
|
+
data (:obj:`Table`|:obj:`View`|:obj:`dict`|:obj:`list`|:obj:`pandas.DataFrame`|:obj:`bytes`|:obj:`str`): a
|
|
170
|
+
`perspective.Table` instance, a `perspective.View` instance, or
|
|
171
|
+
a dataset to be loaded in the viewer.
|
|
172
|
+
|
|
173
|
+
Keyword Arguments:
|
|
174
|
+
name (:obj:`str`): An optional name to reference the table by so it can
|
|
175
|
+
be accessed from the front-end. If not provided, a name will
|
|
176
|
+
be generated.
|
|
177
|
+
index (:obj:`str`): A column name to be used as the primary key.
|
|
178
|
+
Ignored if a ``Table`` or ``View`` is supplied.
|
|
179
|
+
limit (:obj:`int`): A upper limit on the number of rows in the Table.
|
|
180
|
+
Cannot be set at the same time as `index`. Ignored if a
|
|
181
|
+
``Table`` or ``View`` is supplied.
|
|
182
|
+
|
|
183
|
+
Examples:
|
|
184
|
+
>>> from perspective import Table, PerspectiveViewer
|
|
185
|
+
>>> data = {"a": [1, 2, 3]}
|
|
186
|
+
>>> tbl = Table(data)
|
|
187
|
+
>>> viewer = PerspectiveViewer()
|
|
188
|
+
>>> viewer.load(tbl)
|
|
189
|
+
>>> viewer.load(data, index="a") # viewer state is reset
|
|
190
|
+
>>> viewer2 = PerspectiveViewer()
|
|
191
|
+
>>> viewer2.load(tbl.view())
|
|
192
|
+
|
|
193
|
+
"""
|
|
194
|
+
name = options.pop("name", str(random()))
|
|
195
|
+
|
|
196
|
+
# Reset the viewer when `load()` is called multiple times.
|
|
197
|
+
if self.table is not None:
|
|
198
|
+
self.reset()
|
|
199
|
+
|
|
200
|
+
if isinstance(data, perspective.Table):
|
|
201
|
+
self._table = data
|
|
202
|
+
self._client = data.get_client()
|
|
203
|
+
name = self._table.get_name()
|
|
204
|
+
elif isinstance(data, perspective.View):
|
|
205
|
+
raise TypeError(
|
|
206
|
+
"Views cannot be loaded directly, load a table or raw data instead"
|
|
207
|
+
)
|
|
208
|
+
else:
|
|
209
|
+
client = perspective.Server().new_local_client()
|
|
210
|
+
self._table = client.table(data, name=name, **options)
|
|
211
|
+
self._client = client
|
|
212
|
+
|
|
213
|
+
# If the user does not set columns to show, synchronize viewer state
|
|
214
|
+
# with dataset.
|
|
215
|
+
if len(self.columns) == 0:
|
|
216
|
+
self.columns = self.table.columns()
|
|
217
|
+
|
|
218
|
+
# Assigning to this traitlet signals the frontend viewer to connect to the
|
|
219
|
+
# table we're hosting.
|
|
220
|
+
self.table_name = self.table.get_name()
|
|
221
|
+
|
|
222
|
+
def update(self, data):
|
|
223
|
+
"""Update the table under management by the viewer with new data.
|
|
224
|
+
This function follows the semantics of `Table.update()`, and will be
|
|
225
|
+
affected by whether an index is set on the underlying table.
|
|
226
|
+
|
|
227
|
+
Args:
|
|
228
|
+
data (:obj:`dict`|:obj:`list`|:obj:`pandas.DataFrame`): the
|
|
229
|
+
update data for the table.
|
|
230
|
+
"""
|
|
231
|
+
self.table.update(data)
|
|
232
|
+
|
|
233
|
+
def clear(self):
|
|
234
|
+
"""Clears the rows of this viewer's ``Table``."""
|
|
235
|
+
if self.table is not None:
|
|
236
|
+
self.table.clear()
|
|
237
|
+
|
|
238
|
+
def replace(self, data):
|
|
239
|
+
"""Replaces the rows of this viewer's `Table` with new data.
|
|
240
|
+
|
|
241
|
+
Args:
|
|
242
|
+
data (:obj:`dict`|:obj:`list`|:obj:`pandas.DataFrame`): new data
|
|
243
|
+
to set into the table - must conform to the table's schema.
|
|
244
|
+
"""
|
|
245
|
+
if self.table is not None:
|
|
246
|
+
self.table.replace(data)
|
|
247
|
+
|
|
248
|
+
def save(self):
|
|
249
|
+
"""Get the viewer's attributes as a dictionary, symmetric with `restore`
|
|
250
|
+
so that a viewer's configuration can be reproduced."""
|
|
251
|
+
return {
|
|
252
|
+
attr: getattr(self, attr)
|
|
253
|
+
for attr in PerspectiveViewer.PERSISTENT_ATTRIBUTES
|
|
254
|
+
}
|
|
255
|
+
|
|
256
|
+
def restore(self, **kwargs):
|
|
257
|
+
"""Restore a given set of attributes, passed as kwargs
|
|
258
|
+
(e.g. dictionary). Symmetric with `save` so that a given viewer's
|
|
259
|
+
configuration can be reproduced."""
|
|
260
|
+
for k, v in kwargs.items():
|
|
261
|
+
if k in PerspectiveViewer.PERSISTENT_ATTRIBUTES:
|
|
262
|
+
setattr(self, k, v)
|
|
263
|
+
|
|
264
|
+
def to_kwargs(self):
|
|
265
|
+
"""Get the viewer's attributes as a list of kwargs, which can be passed to
|
|
266
|
+
the viewer constructor"""
|
|
267
|
+
attrs = self.save()
|
|
268
|
+
defaults = {
|
|
269
|
+
"columns": [],
|
|
270
|
+
"group_by": [],
|
|
271
|
+
"split_by": [],
|
|
272
|
+
"aggregates": {},
|
|
273
|
+
"sort": [],
|
|
274
|
+
"filter": [],
|
|
275
|
+
"expressions": {},
|
|
276
|
+
"plugin_config": {},
|
|
277
|
+
"version": "2.10.0",
|
|
278
|
+
}
|
|
279
|
+
kwargs = {}
|
|
280
|
+
for key, default in defaults.items():
|
|
281
|
+
if attrs.get(key) != default:
|
|
282
|
+
kwargs[key] = attrs[key]
|
|
283
|
+
return ", ".join(
|
|
284
|
+
["{}={}".format(attr, repr(val)) for attr, val in kwargs.items()]
|
|
285
|
+
)
|
|
286
|
+
|
|
287
|
+
def reset(self):
|
|
288
|
+
"""Resets the viewer's attributes and state, but does not delete or
|
|
289
|
+
modify the underlying `Table`.
|
|
290
|
+
|
|
291
|
+
Example:
|
|
292
|
+
widget = PerspectiveWidget(data, group_by=["date"], plugin=Plugin.XBAR)
|
|
293
|
+
widget.reset()
|
|
294
|
+
widget.plugin #
|
|
295
|
+
"""
|
|
296
|
+
self.group_by = []
|
|
297
|
+
self.split_by = []
|
|
298
|
+
self.filter = []
|
|
299
|
+
self.sort = []
|
|
300
|
+
self.expressions = {}
|
|
301
|
+
self.aggregates = {}
|
|
302
|
+
self.columns = []
|
|
303
|
+
self.plugin = "Datagrid"
|
|
304
|
+
self.plugin_config = {}
|
|
305
|
+
|
|
306
|
+
def delete(self, delete_table=True):
|
|
307
|
+
"""Delete the Viewer's data and clears its internal state. If
|
|
308
|
+
``delete_table`` is True, the underlying `perspective.Table` and the
|
|
309
|
+
internal `View` object will be deleted.
|
|
310
|
+
|
|
311
|
+
Args:
|
|
312
|
+
delete_table (:obj:`bool`) : whether the underlying `Table` will be
|
|
313
|
+
deleted. Defaults to True.
|
|
314
|
+
"""
|
|
315
|
+
if delete_table:
|
|
316
|
+
# XXX(tom): TODO implement delete
|
|
317
|
+
# Delete all created views on the widget's manager instance
|
|
318
|
+
# for view in self.manager._views.values():
|
|
319
|
+
# view.delete()
|
|
320
|
+
|
|
321
|
+
# Reset view cache
|
|
322
|
+
# self.manager._views = {}
|
|
323
|
+
|
|
324
|
+
# Delete table
|
|
325
|
+
raise RuntimeError("XXX(tom): delete not implemented")
|
|
326
|
+
self.table.delete()
|
|
327
|
+
self.manager._tables.pop(self.table_name)
|
|
328
|
+
self.table = None
|
|
329
|
+
self.table_name = None
|
|
330
|
+
|
|
331
|
+
self.reset()
|
|
@@ -0,0 +1,101 @@
|
|
|
1
|
+
# ┏━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┓
|
|
2
|
+
# ┃ ██████ ██████ ██████ █ █ █ █ █ █▄ ▀███ █ ┃
|
|
3
|
+
# ┃ ▄▄▄▄▄█ █▄▄▄▄▄ ▄▄▄▄▄█ ▀▀▀▀▀█▀▀▀▀▀ █ ▀▀▀▀▀█ ████████▌▐███ ███▄ ▀█ █ ▀▀▀▀▀ ┃
|
|
4
|
+
# ┃ █▀▀▀▀▀ █▀▀▀▀▀ █▀██▀▀ ▄▄▄▄▄ █ ▄▄▄▄▄█ ▄▄▄▄▄█ ████████▌▐███ █████▄ █ ▄▄▄▄▄ ┃
|
|
5
|
+
# ┃ █ ██████ █ ▀█▄ █ ██████ █ ███▌▐███ ███████▄ █ ┃
|
|
6
|
+
# ┣━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┫
|
|
7
|
+
# ┃ Copyright (c) 2017, the Perspective Authors. ┃
|
|
8
|
+
# ┃ ╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌ ┃
|
|
9
|
+
# ┃ This file is part of the Perspective library, distributed under the terms ┃
|
|
10
|
+
# ┃ of the [Apache License 2.0](https://www.apache.org/licenses/LICENSE-2.0). ┃
|
|
11
|
+
# ┗━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┛
|
|
12
|
+
|
|
13
|
+
from traitlets import HasTraits, Unicode, List, Bool, Dict, validate, Enum
|
|
14
|
+
|
|
15
|
+
import importlib
|
|
16
|
+
|
|
17
|
+
__version__ = importlib.metadata.version("perspective-python")
|
|
18
|
+
|
|
19
|
+
from .validate import (
|
|
20
|
+
validate_version,
|
|
21
|
+
)
|
|
22
|
+
|
|
23
|
+
|
|
24
|
+
class PerspectiveTraitlets(HasTraits):
|
|
25
|
+
"""Define the traitlet interface with `PerspectiveJupyterWidget` on the
|
|
26
|
+
front end. Attributes which are set here are synchronized between the
|
|
27
|
+
front-end and back-end.
|
|
28
|
+
|
|
29
|
+
Examples:
|
|
30
|
+
>>> widget = perspective.PerspectiveWidget(
|
|
31
|
+
... data, group_by=["a", "b", "c"])
|
|
32
|
+
PerspectiveWidget(group_by=["a", "b", "c"])
|
|
33
|
+
>>> widget.split_by=["b"]
|
|
34
|
+
>>> widget
|
|
35
|
+
PerspectiveWidget(group_by=["a", "b", "c"], split_by=["b"])
|
|
36
|
+
"""
|
|
37
|
+
|
|
38
|
+
# `perspective-viewer` options
|
|
39
|
+
plugin = Unicode("Datagrid").tag(sync=True)
|
|
40
|
+
columns = List(default_value=[]).tag(sync=True)
|
|
41
|
+
group_by = List(trait=Unicode(), default_value=[]).tag(sync=True, o=True)
|
|
42
|
+
split_by = List(trait=Unicode(), default_value=[]).tag(sync=True)
|
|
43
|
+
aggregates = Dict(default_value={}).tag(sync=True)
|
|
44
|
+
sort = List(default_value=[]).tag(sync=True)
|
|
45
|
+
filter = List(default_value=[]).tag(sync=True)
|
|
46
|
+
expressions = Dict(default_value=[]).tag(sync=True)
|
|
47
|
+
plugin_config = Dict(default_value={}).tag(sync=True)
|
|
48
|
+
settings = Bool(True).tag(sync=True)
|
|
49
|
+
theme = Unicode("Pro Light", allow_none=True).tag(sync=True)
|
|
50
|
+
|
|
51
|
+
# used to tell the frontend which table to connect to
|
|
52
|
+
table_name = Unicode(None, allow_none=True).tag(sync=True)
|
|
53
|
+
|
|
54
|
+
server = Bool(False).tag(sync=True)
|
|
55
|
+
binding_mode = Enum(("server", "client-server"), default="server").tag(sync=True)
|
|
56
|
+
title = Unicode(None, allow_none=True).tag(sync=True)
|
|
57
|
+
version = Unicode(__version__).tag(sync=True)
|
|
58
|
+
|
|
59
|
+
# @validate("plugin")
|
|
60
|
+
# def _validate_plugin(self, proposal):
|
|
61
|
+
# return validate_plugin(proposal.value)
|
|
62
|
+
|
|
63
|
+
# @validate("columns")
|
|
64
|
+
# def _validate_columns(self, proposal):
|
|
65
|
+
# return validate_columns(proposal.value)
|
|
66
|
+
|
|
67
|
+
# @validate("group_by")
|
|
68
|
+
# def _validate_group_by(self, proposal):
|
|
69
|
+
# return validate_group_by(proposal.value)
|
|
70
|
+
|
|
71
|
+
# @validate("split_by")
|
|
72
|
+
# def _validate_split_by(self, proposal):
|
|
73
|
+
# return validate_split_by(proposal.value)
|
|
74
|
+
|
|
75
|
+
# @validate("aggregates")
|
|
76
|
+
# def _validate_aggregates(self, proposal):
|
|
77
|
+
# return validate_aggregates(proposal.value)
|
|
78
|
+
|
|
79
|
+
# @validate("sort")
|
|
80
|
+
# def _validate_sort(self, proposal):
|
|
81
|
+
# return validate_sort(proposal.value)
|
|
82
|
+
|
|
83
|
+
# @validate("filter")
|
|
84
|
+
# def _validate_filter(self, proposal):
|
|
85
|
+
# return validate_filter(proposal.value)
|
|
86
|
+
|
|
87
|
+
# @validate("expressions")
|
|
88
|
+
# def _validate_expressions(self, proposal):
|
|
89
|
+
# return validate_expressions(proposal.value)
|
|
90
|
+
|
|
91
|
+
# @validate("plugin_config")
|
|
92
|
+
# def _validate_plugin_config(self, proposal):
|
|
93
|
+
# return validate_plugin_config(proposal.value)
|
|
94
|
+
|
|
95
|
+
# @validate("title")
|
|
96
|
+
# def _validate_title(self, proposal):
|
|
97
|
+
# return validate_title(proposal.value)
|
|
98
|
+
|
|
99
|
+
@validate("version")
|
|
100
|
+
def _validate_version(self, proposal):
|
|
101
|
+
return validate_version(proposal.value)
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
# ┏━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┓
|
|
2
|
+
# ┃ ██████ ██████ ██████ █ █ █ █ █ █▄ ▀███ █ ┃
|
|
3
|
+
# ┃ ▄▄▄▄▄█ █▄▄▄▄▄ ▄▄▄▄▄█ ▀▀▀▀▀█▀▀▀▀▀ █ ▀▀▀▀▀█ ████████▌▐███ ███▄ ▀█ █ ▀▀▀▀▀ ┃
|
|
4
|
+
# ┃ █▀▀▀▀▀ █▀▀▀▀▀ █▀██▀▀ ▄▄▄▄▄ █ ▄▄▄▄▄█ ▄▄▄▄▄█ ████████▌▐███ █████▄ █ ▄▄▄▄▄ ┃
|
|
5
|
+
# ┃ █ ██████ █ ▀█▄ █ ██████ █ ███▌▐███ ███████▄ █ ┃
|
|
6
|
+
# ┣━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┫
|
|
7
|
+
# ┃ Copyright (c) 2017, the Perspective Authors. ┃
|
|
8
|
+
# ┃ ╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌ ┃
|
|
9
|
+
# ┃ This file is part of the Perspective library, distributed under the terms ┃
|
|
10
|
+
# ┃ of the [Apache License 2.0](https://www.apache.org/licenses/LICENSE-2.0). ┃
|
|
11
|
+
# ┗━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┛
|
|
12
|
+
|
|
13
|
+
from .widget import PerspectiveWidget, set_jupyter_html_export
|
|
14
|
+
|
|
15
|
+
|
|
16
|
+
__all__ = ["PerspectiveWidget", "set_jupyter_html_export"]
|