hvplot 0.9.3a1__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.
- hvplot/__init__.py +322 -0
- hvplot/_version.py +16 -0
- hvplot/backend_transforms.py +329 -0
- hvplot/converter.py +2855 -0
- hvplot/cudf.py +26 -0
- hvplot/dask.py +42 -0
- hvplot/data/crime.csv +56 -0
- hvplot/datasets.yaml +48 -0
- hvplot/fugue.py +64 -0
- hvplot/ibis.py +21 -0
- hvplot/intake.py +32 -0
- hvplot/interactive.py +968 -0
- hvplot/networkx.py +625 -0
- hvplot/pandas.py +30 -0
- hvplot/plotting/__init__.py +63 -0
- hvplot/plotting/andrews_curves.py +99 -0
- hvplot/plotting/core.py +2288 -0
- hvplot/plotting/lag_plot.py +34 -0
- hvplot/plotting/parallel_coordinates.py +85 -0
- hvplot/plotting/scatter_matrix.py +220 -0
- hvplot/polars.py +21 -0
- hvplot/sample_data.py +30 -0
- hvplot/streamz.py +21 -0
- hvplot/tests/__init__.py +0 -0
- hvplot/tests/conftest.py +44 -0
- hvplot/tests/data/README.md +5 -0
- hvplot/tests/data/RGB-red.byte.tif +0 -0
- hvplot/tests/plotting/__init__.py +0 -0
- hvplot/tests/plotting/testcore.py +108 -0
- hvplot/tests/plotting/testohlc.py +34 -0
- hvplot/tests/plotting/testscattermatrix.py +138 -0
- hvplot/tests/test_links.py +99 -0
- hvplot/tests/testbackend_transforms.py +89 -0
- hvplot/tests/testcharts.py +452 -0
- hvplot/tests/testfugue.py +46 -0
- hvplot/tests/testgeo.py +468 -0
- hvplot/tests/testgeowithoutgv.py +60 -0
- hvplot/tests/testgridplots.py +259 -0
- hvplot/tests/testhelp.py +75 -0
- hvplot/tests/testibis.py +17 -0
- hvplot/tests/testinteractive.py +1442 -0
- hvplot/tests/testnetworkx.py +26 -0
- hvplot/tests/testoperations.py +385 -0
- hvplot/tests/testoptions.py +596 -0
- hvplot/tests/testoverrides.py +74 -0
- hvplot/tests/testpanel.py +70 -0
- hvplot/tests/testpatch.py +135 -0
- hvplot/tests/testplotting.py +69 -0
- hvplot/tests/teststreaming.py +28 -0
- hvplot/tests/testtransforms.py +39 -0
- hvplot/tests/testui.py +383 -0
- hvplot/tests/testutil.py +378 -0
- hvplot/tests/util.py +82 -0
- hvplot/ui.py +1032 -0
- hvplot/util.py +677 -0
- hvplot/utilities.py +129 -0
- hvplot/xarray.py +62 -0
- hvplot-0.9.3a1.dist-info/LICENSE +29 -0
- hvplot-0.9.3a1.dist-info/METADATA +243 -0
- hvplot-0.9.3a1.dist-info/RECORD +63 -0
- hvplot-0.9.3a1.dist-info/WHEEL +5 -0
- hvplot-0.9.3a1.dist-info/entry_points.txt +2 -0
- hvplot-0.9.3a1.dist-info/top_level.txt +1 -0
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
import numpy as np
|
|
2
|
+
import pandas as pd
|
|
3
|
+
|
|
4
|
+
from ..util import with_hv_extension
|
|
5
|
+
from .core import hvPlotTabular
|
|
6
|
+
|
|
7
|
+
|
|
8
|
+
@with_hv_extension
|
|
9
|
+
def lag_plot(data, lag=1, **kwds):
|
|
10
|
+
"""Lag plot for time series.
|
|
11
|
+
|
|
12
|
+
Parameters:
|
|
13
|
+
-----------
|
|
14
|
+
data: Time series
|
|
15
|
+
lag: lag of the scatter plot, default 1
|
|
16
|
+
kwds: hvplot.scatter options, optional
|
|
17
|
+
|
|
18
|
+
Returns:
|
|
19
|
+
--------
|
|
20
|
+
obj : HoloViews object
|
|
21
|
+
The HoloViews representation of the plot.
|
|
22
|
+
"""
|
|
23
|
+
if lag != int(lag) or int(lag) <= 0:
|
|
24
|
+
raise ValueError('lag must be a positive integer')
|
|
25
|
+
lag = int(lag)
|
|
26
|
+
|
|
27
|
+
values = data.values
|
|
28
|
+
y1 = 'y(t)'
|
|
29
|
+
y2 = f'y(t + {lag})'
|
|
30
|
+
lags = pd.DataFrame({y1: values[:-lag].T.ravel(), y2: values[lag:].T.ravel()})
|
|
31
|
+
if isinstance(data, pd.DataFrame):
|
|
32
|
+
lags['variable'] = np.repeat(data.columns, lags.shape[0] / data.shape[1])
|
|
33
|
+
kwds['c'] = 'variable'
|
|
34
|
+
return hvPlotTabular(lags)(y1, y2, kind='scatter', **kwds)
|
|
@@ -0,0 +1,85 @@
|
|
|
1
|
+
import holoviews as hv
|
|
2
|
+
import colorcet as cc
|
|
3
|
+
|
|
4
|
+
from ..backend_transforms import _transfer_opts_cur_backend
|
|
5
|
+
from ..util import with_hv_extension
|
|
6
|
+
|
|
7
|
+
|
|
8
|
+
@with_hv_extension
|
|
9
|
+
def parallel_coordinates(
|
|
10
|
+
data,
|
|
11
|
+
class_column,
|
|
12
|
+
cols=None,
|
|
13
|
+
alpha=0.5,
|
|
14
|
+
width=600,
|
|
15
|
+
height=300,
|
|
16
|
+
var_name='variable',
|
|
17
|
+
value_name='value',
|
|
18
|
+
cmap=None,
|
|
19
|
+
colormap=None,
|
|
20
|
+
**kwds,
|
|
21
|
+
):
|
|
22
|
+
"""
|
|
23
|
+
Parallel coordinates plotting.
|
|
24
|
+
|
|
25
|
+
To show a set of points in an n-dimensional space, a backdrop is drawn
|
|
26
|
+
consisting of n parallel lines. A point in n-dimensional space is
|
|
27
|
+
represented as a polyline with vertices on the parallel axes; the
|
|
28
|
+
position of the vertex on the i-th axis corresponds to the i-th coordinate
|
|
29
|
+
of the point.
|
|
30
|
+
|
|
31
|
+
Parameters
|
|
32
|
+
----------
|
|
33
|
+
frame: DataFrame
|
|
34
|
+
class_column: str
|
|
35
|
+
Column name containing class names
|
|
36
|
+
cols: list, optional
|
|
37
|
+
A list of column names to use
|
|
38
|
+
alpha: float, optional
|
|
39
|
+
The transparency of the lines
|
|
40
|
+
cmap/colormap: str or colormap object
|
|
41
|
+
Colormap to use for groups
|
|
42
|
+
|
|
43
|
+
Returns
|
|
44
|
+
-------
|
|
45
|
+
obj : HoloViews object
|
|
46
|
+
The HoloViews representation of the plot.
|
|
47
|
+
|
|
48
|
+
See Also
|
|
49
|
+
--------
|
|
50
|
+
pandas.plotting.parallel_coordinates : matplotlib version of this routine
|
|
51
|
+
"""
|
|
52
|
+
# Transform the dataframe to be used in Vega-Lite
|
|
53
|
+
if cols is not None:
|
|
54
|
+
data = data[list(cols) + [class_column]]
|
|
55
|
+
cols = data.columns
|
|
56
|
+
df = data.reset_index()
|
|
57
|
+
index = (set(df.columns) - set(cols)).pop()
|
|
58
|
+
assert index in df.columns
|
|
59
|
+
df = df.melt([index, class_column], var_name=var_name, value_name=value_name)
|
|
60
|
+
|
|
61
|
+
labelled = [] if var_name == 'variable' else ['x']
|
|
62
|
+
if value_name != 'value':
|
|
63
|
+
labelled.append('y')
|
|
64
|
+
options = {
|
|
65
|
+
'Curve': dict(kwds, labelled=labelled, alpha=alpha, width=width, height=height),
|
|
66
|
+
'Overlay': dict(legend_limit=5000),
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
dataset = hv.Dataset(df)
|
|
70
|
+
groups = dataset.to(hv.Curve, var_name, value_name).overlay(index).items()
|
|
71
|
+
|
|
72
|
+
if cmap and colormap:
|
|
73
|
+
raise TypeError('Only specify one of `cmap` and `colormap`.')
|
|
74
|
+
cmap = cmap or colormap or cc.palette['glasbey_category10']
|
|
75
|
+
colors = hv.plotting.util.process_cmap(cmap, categorical=True, ncolors=len(groups))
|
|
76
|
+
|
|
77
|
+
el = hv.Overlay(
|
|
78
|
+
[
|
|
79
|
+
curve.relabel(k).options('Curve', color=c, backend='bokeh')
|
|
80
|
+
for c, (k, v) in zip(colors, groups)
|
|
81
|
+
for curve in v
|
|
82
|
+
]
|
|
83
|
+
).options(options, backend='bokeh')
|
|
84
|
+
el = _transfer_opts_cur_backend(el)
|
|
85
|
+
return el
|
|
@@ -0,0 +1,220 @@
|
|
|
1
|
+
from functools import partial
|
|
2
|
+
import warnings
|
|
3
|
+
|
|
4
|
+
import holoviews as _hv
|
|
5
|
+
import numpy as _np
|
|
6
|
+
|
|
7
|
+
from packaging.version import Version
|
|
8
|
+
|
|
9
|
+
from ..backend_transforms import _transfer_opts_cur_backend
|
|
10
|
+
from ..converter import HoloViewsConverter
|
|
11
|
+
from ..util import with_hv_extension, _convert_col_names_to_str
|
|
12
|
+
|
|
13
|
+
|
|
14
|
+
@with_hv_extension
|
|
15
|
+
def scatter_matrix(
|
|
16
|
+
data,
|
|
17
|
+
c=None,
|
|
18
|
+
chart='scatter',
|
|
19
|
+
diagonal='hist',
|
|
20
|
+
alpha=0.5,
|
|
21
|
+
nonselection_alpha=0.1,
|
|
22
|
+
tools=None,
|
|
23
|
+
cmap=None,
|
|
24
|
+
colormap=None,
|
|
25
|
+
diagonal_kwds=None,
|
|
26
|
+
hist_kwds=None,
|
|
27
|
+
density_kwds=None,
|
|
28
|
+
datashade=False,
|
|
29
|
+
rasterize=False,
|
|
30
|
+
dynspread=False,
|
|
31
|
+
spread=False,
|
|
32
|
+
**kwds,
|
|
33
|
+
):
|
|
34
|
+
"""
|
|
35
|
+
Scatter matrix of numeric columns.
|
|
36
|
+
|
|
37
|
+
A scatter_matrix shows all the pairwise relationships between the columns.
|
|
38
|
+
Each non-diagonal plots the corresponding columns against each other,
|
|
39
|
+
while the diagonal plot shows the distribution of each individual column.
|
|
40
|
+
|
|
41
|
+
This function is closely modelled on :func:`pandas.plotting.scatter_matrix`.
|
|
42
|
+
|
|
43
|
+
Parameters:
|
|
44
|
+
-----------
|
|
45
|
+
data: DataFrame
|
|
46
|
+
The data to plot. Every column is compared to every other column.
|
|
47
|
+
c: str, optional
|
|
48
|
+
Column to color by
|
|
49
|
+
chart: str, optional
|
|
50
|
+
Chart type for the off-diagonal plots (one of 'scatter', 'bivariate', 'hexbin')
|
|
51
|
+
diagonal: str, optional
|
|
52
|
+
Chart type for the diagonal plots (one of 'hist', 'kde')
|
|
53
|
+
alpha: float, optional
|
|
54
|
+
Transparency level for the off-diagonal plots
|
|
55
|
+
nonselection_alpha: float, optional
|
|
56
|
+
Transparency level for nonselected object in the off-diagonal plots
|
|
57
|
+
tools: list of str, optional
|
|
58
|
+
Interaction tools to include
|
|
59
|
+
Defaults are 'box_select' and 'lasso_select'
|
|
60
|
+
cmap/colormap: str or colormap object, optional
|
|
61
|
+
Colormap to use when ``c`` is set.
|
|
62
|
+
Default is `Category10 <https://github.com/d3/d3-3.x-api-reference/blob/master/Ordinal-Scales.md#category10>`.
|
|
63
|
+
diagonal_kwds/hist_kwds/density_kwds: dict, optional
|
|
64
|
+
Keyword options for the diagonal plots
|
|
65
|
+
datashade (default=False):
|
|
66
|
+
Whether to apply rasterization and shading (colormapping) using
|
|
67
|
+
the Datashader library, returning an RGB object instead of
|
|
68
|
+
individual points
|
|
69
|
+
rasterize (default=False):
|
|
70
|
+
Whether to apply rasterization using the Datashader library,
|
|
71
|
+
returning an aggregated Image (to be colormapped by the
|
|
72
|
+
plotting backend) instead of individual points
|
|
73
|
+
dynspread (default=False):
|
|
74
|
+
For plots generated with datashade=True or rasterize=True,
|
|
75
|
+
automatically increase the point size when the data is sparse
|
|
76
|
+
so that individual points become more visible.
|
|
77
|
+
kwds supported include ``max_px``, ``threshold``, ``shape``, ``how`` and ``mask``.
|
|
78
|
+
spread (default=False):
|
|
79
|
+
Make plots generated with datashade=True or rasterize=True
|
|
80
|
+
increase the point size to make points more visible, by
|
|
81
|
+
applying a fixed spreading of a certain number of cells/pixels. kwds
|
|
82
|
+
supported include: ``px``, ``shape``, ``how`` and ``mask``.
|
|
83
|
+
kwds: Keyword options for the off-diagonal plots and datashader's spreading , optional
|
|
84
|
+
|
|
85
|
+
Returns:
|
|
86
|
+
--------
|
|
87
|
+
obj : HoloViews object
|
|
88
|
+
The HoloViews representation of the plot.
|
|
89
|
+
|
|
90
|
+
See Also
|
|
91
|
+
--------
|
|
92
|
+
:func:`pandas.plotting.scatter_matrix` : Equivalent pandas function.
|
|
93
|
+
"""
|
|
94
|
+
|
|
95
|
+
data = _hv.Dataset(_convert_col_names_to_str(data))
|
|
96
|
+
supported = list(HoloViewsConverter._kind_mapping)
|
|
97
|
+
if diagonal not in supported:
|
|
98
|
+
raise ValueError(f'diagonal type must be one of: {supported}, found {diagonal}')
|
|
99
|
+
if chart not in supported:
|
|
100
|
+
raise ValueError(f'Chart type must be one of: {supported}, found {chart}')
|
|
101
|
+
diagonal = HoloViewsConverter._kind_mapping[diagonal]
|
|
102
|
+
chart = HoloViewsConverter._kind_mapping[chart]
|
|
103
|
+
|
|
104
|
+
if rasterize or datashade:
|
|
105
|
+
try:
|
|
106
|
+
import datashader # noqa
|
|
107
|
+
except ImportError:
|
|
108
|
+
raise ImportError('rasterize and datashade require datashader to be installed.')
|
|
109
|
+
from ..util import hv_version
|
|
110
|
+
|
|
111
|
+
if hv_version <= Version('1.14.6'):
|
|
112
|
+
warnings.warn(
|
|
113
|
+
'Versions of holoviews before 1.14.7 did not support '
|
|
114
|
+
'dynamic update of rasterized/datashaded scatter matrix. '
|
|
115
|
+
'Update holoviews to a newer version.'
|
|
116
|
+
)
|
|
117
|
+
|
|
118
|
+
if rasterize and datashade:
|
|
119
|
+
raise ValueError('Choose to either rasterize or datashade the scatter matrix, not both.')
|
|
120
|
+
|
|
121
|
+
if not rasterize and not datashade and (spread or dynspread):
|
|
122
|
+
raise ValueError('dynspread or spread need rasterize or datashade to be set to True.')
|
|
123
|
+
|
|
124
|
+
if rasterize:
|
|
125
|
+
import holoviews.operation.datashader as hd
|
|
126
|
+
|
|
127
|
+
if dynspread or spread:
|
|
128
|
+
if hd.ds_version < Version('0.12.0'):
|
|
129
|
+
raise RuntimeError(
|
|
130
|
+
'Any version of datashader less than 0.12.0 does '
|
|
131
|
+
'not support rasterize with dynspread or spread.'
|
|
132
|
+
)
|
|
133
|
+
|
|
134
|
+
# remove datashade kwds
|
|
135
|
+
if datashade or rasterize:
|
|
136
|
+
import holoviews.operation.datashader as hd
|
|
137
|
+
|
|
138
|
+
ds_kwds = {}
|
|
139
|
+
if 'aggregator' in kwds:
|
|
140
|
+
ds_kwds['aggregator'] = kwds.pop('aggregator')
|
|
141
|
+
|
|
142
|
+
# remove dynspread kwds
|
|
143
|
+
sp_kwds = {}
|
|
144
|
+
if dynspread:
|
|
145
|
+
if 'max_px' in kwds:
|
|
146
|
+
sp_kwds['max_px'] = kwds.pop('max_px')
|
|
147
|
+
if 'threshold' in kwds:
|
|
148
|
+
sp_kwds['threshold'] = kwds.pop('threshold')
|
|
149
|
+
if 'shape' in kwds:
|
|
150
|
+
sp_kwds['shape'] = kwds.pop('shape')
|
|
151
|
+
if 'how' in kwds:
|
|
152
|
+
sp_kwds['how'] = kwds.pop('how')
|
|
153
|
+
if 'mask' in kwds:
|
|
154
|
+
sp_kwds['mask'] = kwds.pop('mask')
|
|
155
|
+
if spread:
|
|
156
|
+
if 'px' in kwds:
|
|
157
|
+
sp_kwds['px'] = kwds.pop('px')
|
|
158
|
+
if 'shape' in kwds:
|
|
159
|
+
sp_kwds['shape'] = kwds.pop('shape')
|
|
160
|
+
if 'how' in kwds:
|
|
161
|
+
sp_kwds['how'] = kwds.pop('how')
|
|
162
|
+
if 'mask' in kwds:
|
|
163
|
+
sp_kwds['mask'] = kwds.pop('mask')
|
|
164
|
+
|
|
165
|
+
tools = tools or ['box_select', 'lasso_select']
|
|
166
|
+
chart_opts = dict(alpha=alpha, tools=tools, nonselection_alpha=nonselection_alpha, **kwds)
|
|
167
|
+
if c:
|
|
168
|
+
if cmap and colormap:
|
|
169
|
+
raise TypeError('Only specify `cmap` or `colormap`.')
|
|
170
|
+
ncolors = len(_np.unique(data.dimension_values(c)))
|
|
171
|
+
cmap = cmap or colormap or 'Category10'
|
|
172
|
+
cmap = _hv.plotting.util.process_cmap(cmap, ncolors=ncolors, categorical=True)
|
|
173
|
+
chart_opts['cmap'] = cmap
|
|
174
|
+
|
|
175
|
+
# get initial scatter matrix. No color.
|
|
176
|
+
grid = _hv.operation.gridmatrix(data, diagonal_type=diagonal, chart_type=chart)
|
|
177
|
+
|
|
178
|
+
if c:
|
|
179
|
+
# change colors for scatter matrix
|
|
180
|
+
chart_opts['color'] = c
|
|
181
|
+
# Add color vdim to each plot.
|
|
182
|
+
grid = grid.map(lambda x: x.clone(vdims=x.vdims + [c]), 'Scatter')
|
|
183
|
+
# create a new scatter matrix with groups for each catetory, so now the histogram will
|
|
184
|
+
# show separate colors for each group.
|
|
185
|
+
groups = _hv.operation.gridmatrix(
|
|
186
|
+
data.groupby(c).overlay(), chart_type=chart, diagonal_type=diagonal
|
|
187
|
+
)
|
|
188
|
+
# take the correct layer from each Overlay object within the scatter matrix.
|
|
189
|
+
grid = (grid * groups).map(
|
|
190
|
+
lambda x: x.get(0) if isinstance(x.get(0), chart) else x.get(1), _hv.Overlay
|
|
191
|
+
)
|
|
192
|
+
|
|
193
|
+
if (
|
|
194
|
+
(diagonal_kwds and hist_kwds)
|
|
195
|
+
or (diagonal_kwds and density_kwds)
|
|
196
|
+
or (hist_kwds and density_kwds)
|
|
197
|
+
):
|
|
198
|
+
raise TypeError('Specify at most one of `diagonal_kwds`, `hist_kwds`, or `density_kwds`.')
|
|
199
|
+
|
|
200
|
+
diagonal_opts = diagonal_kwds or hist_kwds or density_kwds or {}
|
|
201
|
+
# set the histogram colors
|
|
202
|
+
if c:
|
|
203
|
+
diagonal_opts['fill_color'] = _hv.Cycle(cmap)
|
|
204
|
+
# actually changing to the same color scheme for both scatter and histogram plots.
|
|
205
|
+
grid = grid.options(
|
|
206
|
+
{chart.__name__: chart_opts, diagonal.__name__: diagonal_opts},
|
|
207
|
+
backend='bokeh',
|
|
208
|
+
)
|
|
209
|
+
|
|
210
|
+
# Perform datashade options after all the coloring is finished.
|
|
211
|
+
if datashade or rasterize:
|
|
212
|
+
aggregatefn = hd.datashade if datashade else hd.rasterize
|
|
213
|
+
grid = grid.map(partial(aggregatefn, **ds_kwds), specs=chart)
|
|
214
|
+
if spread or dynspread:
|
|
215
|
+
spreadfn = hd.dynspread if dynspread else (hd.spread if spread else lambda z, **_: z)
|
|
216
|
+
eltype = _hv.RGB if datashade else _hv.Image
|
|
217
|
+
grid = grid.map(partial(spreadfn, **sp_kwds), specs=eltype)
|
|
218
|
+
|
|
219
|
+
grid = _transfer_opts_cur_backend(grid)
|
|
220
|
+
return grid
|
hvplot/polars.py
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
"""Adds the `.hvplot` method to pl.DataFrame, pl.LazyFrame and pl.Series"""
|
|
2
|
+
|
|
3
|
+
from hvplot import post_patch
|
|
4
|
+
from hvplot.plotting.core import hvPlotTabularPolars
|
|
5
|
+
|
|
6
|
+
|
|
7
|
+
def patch(name='hvplot', extension='bokeh', logo=False):
|
|
8
|
+
try:
|
|
9
|
+
import polars as pl
|
|
10
|
+
except ImportError:
|
|
11
|
+
raise ImportError(
|
|
12
|
+
'Could not patch plotting API onto Polars. Polars could not be imported.'
|
|
13
|
+
)
|
|
14
|
+
pl.api.register_dataframe_namespace(name)(hvPlotTabularPolars)
|
|
15
|
+
pl.api.register_series_namespace(name)(hvPlotTabularPolars)
|
|
16
|
+
pl.api.register_lazyframe_namespace(name)(hvPlotTabularPolars)
|
|
17
|
+
|
|
18
|
+
post_patch(extension, logo)
|
|
19
|
+
|
|
20
|
+
|
|
21
|
+
patch()
|
hvplot/sample_data.py
ADDED
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
"""
|
|
2
|
+
Loads hvPlot sample data using intake catalogue.
|
|
3
|
+
"""
|
|
4
|
+
|
|
5
|
+
import os
|
|
6
|
+
|
|
7
|
+
try:
|
|
8
|
+
from intake import open_catalog
|
|
9
|
+
import intake_parquet # noqa
|
|
10
|
+
import intake_xarray # noqa
|
|
11
|
+
import s3fs # noqa
|
|
12
|
+
except ImportError:
|
|
13
|
+
raise ImportError(
|
|
14
|
+
"""Loading hvPlot sample data requires:
|
|
15
|
+
* intake
|
|
16
|
+
* intake-parquet
|
|
17
|
+
* intake-xarray
|
|
18
|
+
* s3fs
|
|
19
|
+
Install these using conda or pip before loading data."""
|
|
20
|
+
)
|
|
21
|
+
|
|
22
|
+
_file_path = os.path.dirname(__file__)
|
|
23
|
+
_cat_path = os.path.join(_file_path, 'datasets.yaml')
|
|
24
|
+
|
|
25
|
+
# Load catalogue
|
|
26
|
+
catalogue = open_catalog(_cat_path)
|
|
27
|
+
|
|
28
|
+
# Add catalogue entries to namespace
|
|
29
|
+
for _c in catalogue:
|
|
30
|
+
globals()[_c] = catalogue[_c]
|
hvplot/streamz.py
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
def patch(name='hvplot', extension='bokeh', logo=False):
|
|
2
|
+
from . import hvPlotTabular, post_patch
|
|
3
|
+
|
|
4
|
+
try:
|
|
5
|
+
import streamz.dataframe as sdf
|
|
6
|
+
except ImportError:
|
|
7
|
+
raise ImportError(
|
|
8
|
+
'Could not patch plotting API onto streamz. Streamz could not be imported.'
|
|
9
|
+
)
|
|
10
|
+
_patch_plot = lambda self: hvPlotTabular(self) # noqa: E731
|
|
11
|
+
_patch_plot.__doc__ = hvPlotTabular.__call__.__doc__
|
|
12
|
+
patch_property = property(_patch_plot)
|
|
13
|
+
setattr(sdf.DataFrame, name, patch_property)
|
|
14
|
+
setattr(sdf.DataFrames, name, patch_property)
|
|
15
|
+
setattr(sdf.Series, name, patch_property)
|
|
16
|
+
setattr(sdf.Seriess, name, patch_property)
|
|
17
|
+
|
|
18
|
+
post_patch(extension, logo)
|
|
19
|
+
|
|
20
|
+
|
|
21
|
+
patch()
|
hvplot/tests/__init__.py
ADDED
|
File without changes
|
hvplot/tests/conftest.py
ADDED
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
import dask
|
|
2
|
+
|
|
3
|
+
optional_markers = {
|
|
4
|
+
'geo': {
|
|
5
|
+
'help': 'Run the tests that require GeoViews',
|
|
6
|
+
'marker-descr': 'Geo test marker',
|
|
7
|
+
'skip-reason': 'Test only runs with the --geo option.',
|
|
8
|
+
},
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
|
|
12
|
+
def pytest_addoption(parser):
|
|
13
|
+
for marker, info in optional_markers.items():
|
|
14
|
+
parser.addoption(
|
|
15
|
+
'--{}'.format(marker), action='store_true', default=False, help=info['help']
|
|
16
|
+
)
|
|
17
|
+
|
|
18
|
+
|
|
19
|
+
def pytest_configure(config):
|
|
20
|
+
for marker, info in optional_markers.items():
|
|
21
|
+
config.addinivalue_line('markers', '{}: {}'.format(marker, info['marker-descr']))
|
|
22
|
+
|
|
23
|
+
|
|
24
|
+
def pytest_collection_modifyitems(config, items):
|
|
25
|
+
skipped, selected = [], []
|
|
26
|
+
markers = [m for m in optional_markers if config.getoption(f'--{m}')]
|
|
27
|
+
empty = not markers
|
|
28
|
+
for item in items:
|
|
29
|
+
if empty and any(m in item.keywords for m in optional_markers):
|
|
30
|
+
skipped.append(item)
|
|
31
|
+
elif empty:
|
|
32
|
+
selected.append(item)
|
|
33
|
+
elif not empty and any(m in item.keywords for m in markers):
|
|
34
|
+
selected.append(item)
|
|
35
|
+
else:
|
|
36
|
+
skipped.append(item)
|
|
37
|
+
|
|
38
|
+
config.hook.pytest_deselected(items=skipped)
|
|
39
|
+
items[:] = selected
|
|
40
|
+
|
|
41
|
+
|
|
42
|
+
# From Dask 2024.3.0 they now use `dask_expr` by default
|
|
43
|
+
# https://github.com/dask/dask/issues/10995
|
|
44
|
+
dask.config.set({'dataframe.query-planning': False})
|
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
# Test data
|
|
2
|
+
|
|
3
|
+
Test files required by the test suite:
|
|
4
|
+
|
|
5
|
+
* The RGB-red.byte.tif file was obtained from [rasterio](https://github.com/rasterio/rasterio) test suite and downsampled to reduce its size. The original image is derived from USGS Landsat 7 ETM imagery and is licensed under the [CC0 1.0 Universal (CC0 1.0) Public Domain Dedication](https://creativecommons.org/publicdomain/zero/1.0/).
|
|
Binary file
|
|
File without changes
|
|
@@ -0,0 +1,108 @@
|
|
|
1
|
+
from packaging.version import Version
|
|
2
|
+
from unittest import SkipTest
|
|
3
|
+
|
|
4
|
+
import numpy as np
|
|
5
|
+
import pandas as pd
|
|
6
|
+
import hvplot.pandas # noqa
|
|
7
|
+
import pytest
|
|
8
|
+
|
|
9
|
+
from hvplot import hvPlotTabular
|
|
10
|
+
from hvplot.tests.util import makeDataFrame
|
|
11
|
+
|
|
12
|
+
try:
|
|
13
|
+
import polars as pl
|
|
14
|
+
import hvplot.polars # noqa
|
|
15
|
+
|
|
16
|
+
skip_polar = False
|
|
17
|
+
except ImportError:
|
|
18
|
+
|
|
19
|
+
class pl:
|
|
20
|
+
DataFrame = None
|
|
21
|
+
LazyFrame = None
|
|
22
|
+
Series = None
|
|
23
|
+
|
|
24
|
+
skip_polar = True
|
|
25
|
+
|
|
26
|
+
try:
|
|
27
|
+
import dask.dataframe as dd
|
|
28
|
+
import hvplot.dask # noqa
|
|
29
|
+
except ImportError:
|
|
30
|
+
dd = None
|
|
31
|
+
|
|
32
|
+
|
|
33
|
+
TYPES = {t for t in dir(hvPlotTabular) if not t.startswith('_') and t != 'explorer'}
|
|
34
|
+
FRAME_TYPES = TYPES - {'bivariate', 'heatmap', 'hexbin', 'labels', 'vectorfield'}
|
|
35
|
+
SERIES_TYPES = FRAME_TYPES - {'points', 'polygons', 'ohlc', 'paths'}
|
|
36
|
+
frame_kinds = pytest.mark.parametrize('kind', sorted(FRAME_TYPES))
|
|
37
|
+
series_kinds = pytest.mark.parametrize('kind', sorted(SERIES_TYPES))
|
|
38
|
+
|
|
39
|
+
y_combinations = pytest.mark.parametrize(
|
|
40
|
+
'y',
|
|
41
|
+
(
|
|
42
|
+
['A', 'B', 'C', 'D'],
|
|
43
|
+
('A', 'B', 'C', 'D'),
|
|
44
|
+
{'A', 'B', 'C', 'D'},
|
|
45
|
+
np.array(['A', 'B', 'C', 'D']),
|
|
46
|
+
pd.Index(['A', 'B', 'C', 'D']),
|
|
47
|
+
pd.Series(['A', 'B', 'C', 'D']),
|
|
48
|
+
),
|
|
49
|
+
ids=lambda x: type(x).__name__,
|
|
50
|
+
)
|
|
51
|
+
|
|
52
|
+
|
|
53
|
+
@frame_kinds
|
|
54
|
+
@y_combinations
|
|
55
|
+
def test_dataframe_pandas(kind, y):
|
|
56
|
+
df = makeDataFrame()
|
|
57
|
+
df.hvplot(y=y, kind=kind)
|
|
58
|
+
|
|
59
|
+
|
|
60
|
+
@series_kinds
|
|
61
|
+
def test_series_pandas(kind):
|
|
62
|
+
ser = pd.Series(np.random.rand(10), name='A')
|
|
63
|
+
ser.hvplot(kind=kind)
|
|
64
|
+
|
|
65
|
+
|
|
66
|
+
@pytest.mark.skipif(dd is None, reason='dask not installed')
|
|
67
|
+
@frame_kinds
|
|
68
|
+
@y_combinations
|
|
69
|
+
def test_dataframe_dask(kind, y):
|
|
70
|
+
df = dd.from_pandas(makeDataFrame(), npartitions=2)
|
|
71
|
+
assert isinstance(df, dd.DataFrame)
|
|
72
|
+
df.hvplot(y=y, kind=kind)
|
|
73
|
+
|
|
74
|
+
|
|
75
|
+
@pytest.mark.skipif(dd is None, reason='dask not installed')
|
|
76
|
+
@series_kinds
|
|
77
|
+
def test_series_dask(kind):
|
|
78
|
+
ser = dd.from_pandas(pd.Series(np.random.rand(10), name='A'), npartitions=2)
|
|
79
|
+
assert isinstance(ser, dd.Series)
|
|
80
|
+
ser.hvplot(kind=kind)
|
|
81
|
+
|
|
82
|
+
|
|
83
|
+
@pytest.mark.skipif(skip_polar, reason='polars not installed')
|
|
84
|
+
@pytest.mark.parametrize('cast', (pl.DataFrame, pl.LazyFrame))
|
|
85
|
+
@frame_kinds
|
|
86
|
+
@y_combinations
|
|
87
|
+
def test_dataframe_polars(kind, y, cast):
|
|
88
|
+
df = cast(makeDataFrame())
|
|
89
|
+
assert isinstance(df, cast)
|
|
90
|
+
df.hvplot(y=y, kind=kind)
|
|
91
|
+
|
|
92
|
+
|
|
93
|
+
@pytest.mark.skipif(skip_polar, reason='polars not installed')
|
|
94
|
+
@series_kinds
|
|
95
|
+
def test_series_polars(kind):
|
|
96
|
+
ser = pl.Series(values=np.random.rand(10), name='A')
|
|
97
|
+
assert isinstance(ser, pl.Series)
|
|
98
|
+
ser.hvplot(kind=kind)
|
|
99
|
+
|
|
100
|
+
|
|
101
|
+
@pytest.mark.skipif(skip_polar, reason='polars not installed')
|
|
102
|
+
@series_kinds
|
|
103
|
+
def test_series_polars_downstream(kind):
|
|
104
|
+
if Version(pl.__version__) < Version('0.20.3'):
|
|
105
|
+
raise SkipTest('plot namespace in Polars introduced in 0.20.3')
|
|
106
|
+
ser = pl.Series(values=np.random.rand(10), name='A')
|
|
107
|
+
assert isinstance(ser, pl.Series)
|
|
108
|
+
ser.plot(kind=kind)
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
import pandas as pd
|
|
2
|
+
import hvplot.pandas # noqa
|
|
3
|
+
|
|
4
|
+
|
|
5
|
+
df = pd.DataFrame(
|
|
6
|
+
{
|
|
7
|
+
'Open': [100.00, 101.25, 102.75],
|
|
8
|
+
'High': [104.10, 105.50, 110.00],
|
|
9
|
+
'Low': [94.00, 97.10, 99.20],
|
|
10
|
+
'Close': [101.15, 99.70, 109.50],
|
|
11
|
+
'Volume': [10012, 5000, 18000],
|
|
12
|
+
},
|
|
13
|
+
index=[pd.Timestamp('2022-08-01'), pd.Timestamp('2022-08-03'), pd.Timestamp('2022-08-04')],
|
|
14
|
+
)
|
|
15
|
+
|
|
16
|
+
ohlc_cols = ['Open', 'High', 'Low', 'Close']
|
|
17
|
+
|
|
18
|
+
|
|
19
|
+
def test_ohlc_hover_cols():
|
|
20
|
+
plot = df.hvplot.ohlc(y=ohlc_cols, hover_cols=['Volume'])
|
|
21
|
+
segments = plot.Segments.I
|
|
22
|
+
assert 'Volume' in segments
|
|
23
|
+
tooltips = segments.opts.get('plot').kwargs['tools'][0].tooltips
|
|
24
|
+
assert len(tooltips) == len(df.columns) + 1
|
|
25
|
+
assert tooltips[-1] == ('Volume', '@Volume')
|
|
26
|
+
|
|
27
|
+
|
|
28
|
+
def test_ohlc_hover_cols_all():
|
|
29
|
+
plot = df.hvplot.ohlc(y=ohlc_cols, hover_cols='all')
|
|
30
|
+
segments = plot.Segments.I
|
|
31
|
+
assert 'Volume' in segments
|
|
32
|
+
tooltips = segments.opts.get('plot').kwargs['tools'][0].tooltips
|
|
33
|
+
assert len(tooltips) == len(df.columns) + 1
|
|
34
|
+
assert tooltips[-1] == ('Volume', '@Volume')
|