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.
Files changed (63) hide show
  1. hvplot/__init__.py +322 -0
  2. hvplot/_version.py +16 -0
  3. hvplot/backend_transforms.py +329 -0
  4. hvplot/converter.py +2855 -0
  5. hvplot/cudf.py +26 -0
  6. hvplot/dask.py +42 -0
  7. hvplot/data/crime.csv +56 -0
  8. hvplot/datasets.yaml +48 -0
  9. hvplot/fugue.py +64 -0
  10. hvplot/ibis.py +21 -0
  11. hvplot/intake.py +32 -0
  12. hvplot/interactive.py +968 -0
  13. hvplot/networkx.py +625 -0
  14. hvplot/pandas.py +30 -0
  15. hvplot/plotting/__init__.py +63 -0
  16. hvplot/plotting/andrews_curves.py +99 -0
  17. hvplot/plotting/core.py +2288 -0
  18. hvplot/plotting/lag_plot.py +34 -0
  19. hvplot/plotting/parallel_coordinates.py +85 -0
  20. hvplot/plotting/scatter_matrix.py +220 -0
  21. hvplot/polars.py +21 -0
  22. hvplot/sample_data.py +30 -0
  23. hvplot/streamz.py +21 -0
  24. hvplot/tests/__init__.py +0 -0
  25. hvplot/tests/conftest.py +44 -0
  26. hvplot/tests/data/README.md +5 -0
  27. hvplot/tests/data/RGB-red.byte.tif +0 -0
  28. hvplot/tests/plotting/__init__.py +0 -0
  29. hvplot/tests/plotting/testcore.py +108 -0
  30. hvplot/tests/plotting/testohlc.py +34 -0
  31. hvplot/tests/plotting/testscattermatrix.py +138 -0
  32. hvplot/tests/test_links.py +99 -0
  33. hvplot/tests/testbackend_transforms.py +89 -0
  34. hvplot/tests/testcharts.py +452 -0
  35. hvplot/tests/testfugue.py +46 -0
  36. hvplot/tests/testgeo.py +468 -0
  37. hvplot/tests/testgeowithoutgv.py +60 -0
  38. hvplot/tests/testgridplots.py +259 -0
  39. hvplot/tests/testhelp.py +75 -0
  40. hvplot/tests/testibis.py +17 -0
  41. hvplot/tests/testinteractive.py +1442 -0
  42. hvplot/tests/testnetworkx.py +26 -0
  43. hvplot/tests/testoperations.py +385 -0
  44. hvplot/tests/testoptions.py +596 -0
  45. hvplot/tests/testoverrides.py +74 -0
  46. hvplot/tests/testpanel.py +70 -0
  47. hvplot/tests/testpatch.py +135 -0
  48. hvplot/tests/testplotting.py +69 -0
  49. hvplot/tests/teststreaming.py +28 -0
  50. hvplot/tests/testtransforms.py +39 -0
  51. hvplot/tests/testui.py +383 -0
  52. hvplot/tests/testutil.py +378 -0
  53. hvplot/tests/util.py +82 -0
  54. hvplot/ui.py +1032 -0
  55. hvplot/util.py +677 -0
  56. hvplot/utilities.py +129 -0
  57. hvplot/xarray.py +62 -0
  58. hvplot-0.9.3a1.dist-info/LICENSE +29 -0
  59. hvplot-0.9.3a1.dist-info/METADATA +243 -0
  60. hvplot-0.9.3a1.dist-info/RECORD +63 -0
  61. hvplot-0.9.3a1.dist-info/WHEEL +5 -0
  62. hvplot-0.9.3a1.dist-info/entry_points.txt +2 -0
  63. hvplot-0.9.3a1.dist-info/top_level.txt +1 -0
@@ -0,0 +1,26 @@
1
+ from unittest import TestCase, SkipTest
2
+
3
+ try:
4
+ import numpy as np
5
+ import networkx as nx
6
+ import hvplot.networkx as hvnx
7
+ except ImportError:
8
+ raise SkipTest('NetworkX not available')
9
+
10
+
11
+ class TestOptions(TestCase):
12
+ def setUp(self):
13
+ # Create nodes (1-10) in unsorted order
14
+ nodes = np.array([1, 4, 5, 10, 8, 9, 3, 7, 2, 6])
15
+ edges = list(zip(nodes[:-1], nodes[1:]))
16
+
17
+ g = nx.Graph()
18
+ g.add_nodes_from(nodes)
19
+ g.add_edges_from(edges)
20
+
21
+ self.nodes = nodes
22
+ self.g = g
23
+
24
+ def test_nodes_are_not_sorted(self):
25
+ plot = hvnx.draw(self.g)
26
+ assert all(self.nodes == plot.nodes.dimension_values(2))
@@ -0,0 +1,385 @@
1
+ import sys
2
+
3
+ from unittest import SkipTest
4
+ from parameterized import parameterized
5
+
6
+ import holoviews as hv
7
+ import hvplot.pandas # noqa
8
+ import numpy as np
9
+ import pandas as pd
10
+ import pytest
11
+
12
+ from holoviews import Store, render
13
+ from holoviews.element import Image, QuadMesh, Points
14
+ from holoviews.core.spaces import DynamicMap
15
+ from holoviews.core.overlay import Overlay
16
+ from holoviews.element.chart import Scatter
17
+ from holoviews.element.comparison import ComparisonTestCase
18
+ from hvplot.converter import HoloViewsConverter
19
+ from hvplot.tests.util import makeTimeDataFrame
20
+ from packaging.version import Version
21
+
22
+
23
+ class TestDatashader(ComparisonTestCase):
24
+ def setUp(self):
25
+ try:
26
+ import datashader # noqa
27
+ except ImportError:
28
+ raise SkipTest('Datashader not available')
29
+ if sys.maxsize < 2**32:
30
+ raise SkipTest('Datashader does not support 32-bit systems')
31
+ import hvplot.pandas # noqa
32
+
33
+ self.df = pd.DataFrame(
34
+ [[1, 2, 'A', 0.1], [3, 4, 'B', 0.2], [5, 6, 'C', 0.3]],
35
+ columns=['x', 'y', 'category', 'number'],
36
+ )
37
+
38
+ def test_rasterize_by_cat(self):
39
+ from datashader.reductions import count_cat
40
+
41
+ dmap = self.df.hvplot.scatter('x', 'y', by='category', rasterize=True)
42
+ agg = dmap.callback.inputs[0].callback.operation.p.aggregator
43
+ self.assertIsInstance(agg, count_cat)
44
+ self.assertEqual(agg.column, 'category')
45
+
46
+ def test_rasterize_by_cat_agg(self):
47
+ from datashader.reductions import count_cat
48
+
49
+ dmap = self.df.hvplot.scatter('x', 'y', aggregator=count_cat('category'), rasterize=True)
50
+ agg = dmap.callback.inputs[0].callback.operation.p.aggregator
51
+ self.assertIsInstance(agg, count_cat)
52
+ self.assertEqual(agg.column, 'category')
53
+
54
+ @parameterized.expand([('rasterize',), ('datashade',)])
55
+ def test_color_dim_with_default_agg(self, operation):
56
+ from datashader.reductions import mean
57
+
58
+ dmap = self.df.hvplot.scatter('x', 'y', c='number', **{operation: True})
59
+ agg = dmap.callback.inputs[0].callback.operation.p.aggregator
60
+ self.assertIsInstance(agg, mean)
61
+ self.assertEqual(agg.column, 'number')
62
+
63
+ @parameterized.expand([('rasterize',), ('datashade',)])
64
+ def test_color_dim_with_string_agg(self, operation):
65
+ from datashader.reductions import sum
66
+
67
+ dmap = self.df.hvplot.scatter('x', 'y', c='number', aggregator='sum', **{operation: True})
68
+ agg = dmap.callback.inputs[0].callback.operation.p.aggregator
69
+ self.assertIsInstance(agg, sum)
70
+ self.assertEqual(agg.column, 'number')
71
+
72
+ @parameterized.expand([('rasterize',), ('datashade',)])
73
+ def test_color_dim_also_an_axis(self, operation):
74
+ from datashader.reductions import mean
75
+
76
+ original_data = self.df.copy(deep=True)
77
+ dmap = self.df.hvplot.scatter('x', 'y', c='y', **{operation: True})
78
+ agg = dmap.callback.inputs[0].callback.operation.p.aggregator
79
+ self.assertIsInstance(agg, mean)
80
+ self.assertEqual(agg.column, '_color')
81
+ assert original_data.equals(self.df)
82
+
83
+ def test_rasterize_color_dim_with_new_column_gets_default_cmap(self):
84
+ plot = self.df.hvplot.scatter('x', 'y', c='y', dynamic=False, rasterize=True)
85
+ opts = Store.lookup_options('bokeh', plot, 'style').kwargs
86
+ self.assertEqual(opts.get('cmap'), 'kbc_r')
87
+
88
+ def test_rasterize_default_cmap(self):
89
+ plot = self.df.hvplot.scatter('x', 'y', dynamic=False, rasterize=True)
90
+ opts = Store.lookup_options('bokeh', plot, 'style').kwargs
91
+ self.assertEqual(opts.get('cmap'), 'kbc_r')
92
+
93
+ def test_rasterize_default_colorbar(self):
94
+ plot = self.df.hvplot.scatter('x', 'y', dynamic=False, rasterize=True)
95
+ opts = Store.lookup_options('bokeh', plot, 'plot').kwargs
96
+ self.assertTrue(opts.get('colorbar'))
97
+
98
+ def test_rasterize_default_colorbar_with_cmap(self):
99
+ cmap = 'Reds'
100
+ plot = self.df.hvplot.scatter('x', 'y', dynamic=False, rasterize=True, cmap=cmap)
101
+ opts = Store.lookup_options('bokeh', plot, 'style').kwargs
102
+ self.assertEqual(opts.get('cmap'), cmap)
103
+ opts = Store.lookup_options('bokeh', plot, 'plot').kwargs
104
+ self.assertTrue(opts.get('colorbar'))
105
+
106
+ def test_rasterize_set_clim(self):
107
+ plot = self.df.hvplot.scatter('x', 'y', dynamic=False, rasterize=True, clim=(1, 4))
108
+ opts = Store.lookup_options('bokeh', plot, 'plot').kwargs
109
+ self.assertEqual(opts.get('clim'), (1, 4))
110
+
111
+ @parameterized.expand([('aspect',), ('data_aspect',)])
112
+ def test_aspect_with_datashade(self, opt):
113
+ plot = self.df.hvplot(x='x', y='y', datashade=True, **{opt: 2})
114
+ opts = Store.lookup_options('bokeh', plot[()], 'plot').kwargs
115
+ self.assertEqual(opts[opt], 2)
116
+ self.assertEqual(opts.get('height'), None)
117
+ self.assertEqual(opts.get('frame_height'), None)
118
+
119
+ @parameterized.expand([('aspect',), ('data_aspect',)])
120
+ def test_aspect_with_datashade_and_dynamic_is_false(self, opt):
121
+ plot = self.df.hvplot(x='x', y='y', datashade=True, dynamic=False, **{opt: 2})
122
+ opts = Store.lookup_options('bokeh', plot[()], 'plot').kwargs
123
+ self.assertEqual(opts[opt], 2)
124
+ self.assertEqual(opts.get('height'), None)
125
+ self.assertEqual(opts.get('frame_height'), None)
126
+
127
+ @parameterized.expand([('aspect',), ('data_aspect',)])
128
+ def test_aspect_and_frame_height_with_datashade(self, opt):
129
+ plot = self.df.hvplot(x='x', y='y', frame_height=150, datashade=True, **{opt: 2})
130
+ opts = Store.lookup_options('bokeh', plot[()], 'plot').kwargs
131
+ self.assertEqual(opts[opt], 2)
132
+ self.assertEqual(opts.get('frame_height'), 150)
133
+ self.assertEqual(opts.get('height'), None)
134
+ self.assertEqual(opts.get('frame_width'), None)
135
+
136
+ @parameterized.expand([('aspect',), ('data_aspect',)])
137
+ def test_aspect_and_frame_height_with_datashade_and_dynamic_is_false(self, opt):
138
+ plot = self.df.hvplot(
139
+ x='x', y='y', frame_height=150, datashade=True, dynamic=False, **{opt: 2}
140
+ )
141
+ opts = Store.lookup_options('bokeh', plot[()], 'plot').kwargs
142
+ self.assertEqual(opts[opt], 2)
143
+ self.assertEqual(opts.get('frame_height'), 150)
144
+ self.assertEqual(opts.get('height'), None)
145
+ self.assertEqual(opts.get('frame_width'), None)
146
+
147
+ def test_cmap_can_be_color_key(self):
148
+ color_key = {'A': '#ff0000', 'B': '#00ff00', 'C': '#0000ff'}
149
+ self.df.hvplot.points(x='x', y='y', by='category', cmap=color_key, datashade=True)
150
+ with self.assertRaises(TypeError):
151
+ self.df.hvplot.points(
152
+ x='x', y='y', by='category', datashade=True, cmap='kbc_r', color_key=color_key
153
+ )
154
+
155
+ def test_when_datashade_is_true_set_hover_to_false_by_default(self):
156
+ plot = self.df.hvplot(x='x', y='y', datashade=True)
157
+ opts = Store.lookup_options('bokeh', plot[()], 'plot').kwargs
158
+ assert 'hover' not in opts.get('tools')
159
+
160
+ def test_when_datashade_is_true_hover_can_still_be_true(self):
161
+ plot = self.df.hvplot(x='x', y='y', datashade=True, hover=True)
162
+ opts = Store.lookup_options('bokeh', plot[()], 'plot').kwargs
163
+ assert 'hover' in opts.get('tools')
164
+
165
+ def test_xlim_affects_x_range(self):
166
+ data = pd.DataFrame(np.random.randn(100).cumsum())
167
+ img = data.hvplot(xlim=(0, 20000), datashade=True, dynamic=False)
168
+ assert img.range(0) == (0, 20000)
169
+
170
+ @parameterized.expand([('scatter',), ('line',), ('area',)])
171
+ def test_wide_charts_categorically_shaded_explicit_ys(self, kind):
172
+ df = makeTimeDataFrame()
173
+ plot = makeTimeDataFrame().hvplot(y=list(df.columns), datashade=True, kind=kind)
174
+ expected_cmap = HoloViewsConverter._default_cmaps['categorical']
175
+ assert plot.callback.inputs[0].callback.operation.p.cmap == expected_cmap
176
+ assert plot.callback.inputs[0].callback.operation.p.aggregator.column == 'Variable'
177
+
178
+ @parameterized.expand([('scatter',), ('line',), ('area',)])
179
+ def test_wide_charts_categorically_shaded_implicit_ys(self, kind):
180
+ plot = makeTimeDataFrame().hvplot(datashade=True, kind=kind)
181
+ expected_cmap = HoloViewsConverter._default_cmaps['categorical']
182
+ assert plot.callback.inputs[0].callback.operation.p.cmap == expected_cmap
183
+ assert plot.callback.inputs[0].callback.operation.p.aggregator.column == 'Variable'
184
+
185
+ def test_tidy_charts_categorically_datashade_by(self):
186
+ cat_col = 'category'
187
+ plot = self.df.hvplot.scatter('x', 'y', by=cat_col, datashade=True)
188
+ expected_cmap = HoloViewsConverter._default_cmaps['categorical']
189
+ assert plot.callback.inputs[0].callback.operation.p.cmap == expected_cmap
190
+ assert plot.callback.inputs[0].callback.operation.p.aggregator.column == cat_col
191
+
192
+ @pytest.mark.xfail(
193
+ reason='Assume this is fixed: https://github.com/holoviz/holoviews/issues/6187'
194
+ )
195
+ def test_tidy_charts_categorically_rasterized_by(self):
196
+ cat_col = 'category'
197
+ plot = self.df.hvplot.scatter('x', 'y', by=cat_col, rasterize=True)
198
+ expected_cmap = HoloViewsConverter._default_cmaps['categorical']
199
+ opts = Store.lookup_options('bokeh', plot[()], 'style').kwargs
200
+ # Failing line
201
+ assert opts.get('cmap') == expected_cmap
202
+
203
+ assert plot.callback.inputs[0].callback.operation.p.aggregator.column == cat_col
204
+
205
+ def test_tidy_charts_categorically_rasterized_aggregator_count_cat(self):
206
+ cat_col = 'category'
207
+ from datashader.reductions import count_cat
208
+
209
+ plot = self.df.hvplot.scatter('x', 'y', aggregator=count_cat(cat_col), rasterize=True)
210
+ expected_cmap = HoloViewsConverter._default_cmaps['categorical']
211
+ opts = Store.lookup_options('bokeh', plot[()], 'style').kwargs
212
+ assert opts.get('cmap') == expected_cmap
213
+ assert plot.callback.inputs[0].callback.operation.p.aggregator.column == cat_col
214
+
215
+ def test_rasterize_cnorm(self):
216
+ expected = 'eq_hist'
217
+ plot = self.df.hvplot(x='x', y='y', rasterize=True, cnorm=expected)
218
+ opts = Store.lookup_options('bokeh', plot[()], 'plot').kwargs
219
+ assert opts.get('cnorm') == expected
220
+
221
+ def test_datashade_cnorm(self):
222
+ expected = 'eq_hist'
223
+ plot = self.df.hvplot(x='x', y='y', datashade=True, cnorm=expected)
224
+ actual = plot.callback.inputs[0].callback.operation.p['cnorm']
225
+ assert actual == expected
226
+
227
+ def test_rasterize_rescale_discrete_levels(self):
228
+ expected = False
229
+ plot = self.df.hvplot(
230
+ x='x', y='y', rasterize=True, cnorm='eq_hist', rescale_discrete_levels=expected
231
+ )
232
+ opts = Store.lookup_options('bokeh', plot[()], 'plot').kwargs
233
+ assert opts.get('rescale_discrete_levels') is expected
234
+
235
+ def test_datashade_rescale_discrete_levels(self):
236
+ expected = False
237
+ plot = self.df.hvplot(
238
+ x='x', y='y', datashade=True, cnorm='eq_hist', rescale_discrete_levels=expected
239
+ )
240
+ actual = plot.callback.inputs[0].callback.operation.p['rescale_discrete_levels']
241
+ assert actual is expected
242
+
243
+ def test_datashade_rescale_discrete_levels_default_True(self):
244
+ expected = True
245
+ plot = self.df.hvplot(x='x', y='y', datashade=True, cnorm='eq_hist')
246
+ actual = plot.callback.inputs[0].callback.operation.p['rescale_discrete_levels']
247
+ assert actual is expected
248
+
249
+ def test_rasterize_by(self):
250
+ if Version(hv.__version__) < Version('1.18.0a1'):
251
+ raise SkipTest('hv.ImageStack introduced after 1.18.0a1')
252
+
253
+ from holoviews.element import ImageStack
254
+
255
+ expected = 'category'
256
+ plot = self.df.hvplot(x='x', y='y', by=expected, rasterize=True, dynamic=False)
257
+ assert isinstance(plot, ImageStack)
258
+ assert plot.opts['cmap'] == HoloViewsConverter._default_cmaps['categorical']
259
+
260
+ def test_rasterize_aggregator_count_cat(self):
261
+ if Version(hv.__version__) < Version('1.18.0a1'):
262
+ raise SkipTest('hv.ImageStack introduced after 1.18.0a1')
263
+
264
+ from holoviews.element import ImageStack
265
+ from datashader.reductions import count_cat
266
+
267
+ expected = 'category'
268
+ plot = self.df.hvplot(
269
+ x='x', y='y', aggregator=count_cat(expected), rasterize=True, width=999, dynamic=False
270
+ )
271
+ assert isinstance(plot, ImageStack)
272
+ assert plot.opts['width'] == 999
273
+ assert plot.opts['cmap'] == HoloViewsConverter._default_cmaps['categorical']
274
+
275
+ def test_rasterize_single_y_in_list_linear_cmap(self):
276
+ # Regression, see https://github.com/holoviz/hvplot/issues/1210
277
+ plot = self.df.hvplot.line(y=['y'], rasterize=True)
278
+ opts = Store.lookup_options('bokeh', plot[()], 'style').kwargs
279
+ assert opts.get('cmap') == 'kbc_r'
280
+
281
+ def test_resample_when_error_unset_operation(self):
282
+ with pytest.raises(ValueError, match='At least one resampling operation'):
283
+ self.df.hvplot(x='x', y='y', resample_when=10)
284
+
285
+ @parameterized.expand([('rasterize',), ('datashade',)])
286
+ def test_operation_resample_when(self, operation):
287
+ df = pd.DataFrame(
288
+ np.random.multivariate_normal((0, 0), [[0.1, 0.1], [0.1, 1.0]], (5000,))
289
+ ).rename({0: 'x', 1: 'y'}, axis=1)
290
+ dmap = df.hvplot.scatter('x', 'y', resample_when=1000, **{operation: True})
291
+ assert isinstance(dmap, DynamicMap)
292
+
293
+ render(dmap) # trigger dynamicmap
294
+ overlay = dmap.items()[0][1]
295
+ assert isinstance(overlay, Overlay)
296
+
297
+ image = overlay.get(0)
298
+ assert isinstance(image, Image)
299
+ assert len(image.data) > 0
300
+
301
+ scatter = overlay.get(1)
302
+ assert isinstance(scatter, Scatter)
303
+ assert len(scatter.data) == 0
304
+
305
+ @parameterized.expand([('points', Points), ('scatter', Scatter)])
306
+ def test_downsample_resample_when(self, kind, eltype):
307
+ df = pd.DataFrame(
308
+ np.random.multivariate_normal((0, 0), [[0.1, 0.1], [0.1, 1.0]], (5000,))
309
+ ).rename({0: 'x', 1: 'y'}, axis=1)
310
+ dmap = df.hvplot(kind=kind, x='x', y='y', resample_when=1000, downsample=True)
311
+ assert isinstance(dmap, DynamicMap)
312
+
313
+ render(dmap) # trigger dynamicmap
314
+ overlay = dmap.items()[0][1]
315
+ assert isinstance(overlay, Overlay)
316
+
317
+ downsampled = overlay.get(0)
318
+ assert isinstance(downsampled, eltype)
319
+ assert len(downsampled) > 0
320
+
321
+ element = overlay.get(1)
322
+ assert isinstance(element, eltype)
323
+ assert len(element) == 0
324
+
325
+
326
+ class TestChart2D(ComparisonTestCase):
327
+ def setUp(self):
328
+ try:
329
+ import xarray as xr
330
+ import datashader as ds # noqa
331
+ except ImportError:
332
+ raise SkipTest('xarray or datashader not available')
333
+ if sys.maxsize < 2**32:
334
+ raise SkipTest('Datashader does not support 32-bit systems')
335
+ import hvplot.xarray # noqa
336
+
337
+ data = np.arange(0, 60).reshape(6, 10)
338
+ x = np.arange(10)
339
+ y = np.arange(6)
340
+ self.da = xr.DataArray(data, coords={'y': y, 'x': x}, dims=('y', 'x'))
341
+
342
+ @parameterized.expand([('image', Image), ('quadmesh', QuadMesh)])
343
+ def test_plot_resolution(self, kind, element):
344
+ plot = self.da.hvplot(kind=kind)
345
+ assert all(plot.data.x.diff('x').round(0) == 1)
346
+ assert all(plot.data.y.diff('y').round(0) == 1)
347
+
348
+ @parameterized.expand([('image', Image), ('quadmesh', QuadMesh)])
349
+ def test_plot_resolution_with_rasterize(self, kind, element):
350
+ plot = self.da.hvplot(kind=kind, dynamic=False, rasterize=True, x_sampling=5, y_sampling=2)
351
+ assert all(plot.data.x.diff('x').round(0) == 5)
352
+ assert all(plot.data.y.diff('y').round(0) == 2)
353
+
354
+
355
+ class TestDownsample(ComparisonTestCase):
356
+ def setUp(self):
357
+ import hvplot.pandas # noqa
358
+
359
+ self.df = pd.DataFrame(np.random.random(100))
360
+
361
+ def test_downsample_default(self):
362
+ from holoviews.operation.downsample import downsample1d
363
+
364
+ plot = self.df.hvplot.line(downsample=True)
365
+
366
+ assert isinstance(plot.callback.operation, downsample1d)
367
+ assert plot.callback.operation.algorithm == 'lttb'
368
+
369
+ def test_downsample_opts(self):
370
+ plot = self.df.hvplot.line(
371
+ downsample=True, width=100, height=50, x_sampling=5, xlim=(0, 5)
372
+ )
373
+
374
+ assert plot.callback.operation.p.width == 100
375
+ assert plot.callback.operation.p.height == 50
376
+ assert plot.callback.operation.p.x_sampling == 5
377
+ assert plot.callback.operation.p.x_range == (0, 5)
378
+
379
+ def test_downsample_algorithm_minmax(self):
380
+ from holoviews.operation.downsample import downsample1d
381
+
382
+ plot = self.df.hvplot.line(downsample='minmax')
383
+
384
+ assert isinstance(plot.callback.operation, downsample1d)
385
+ assert plot.callback.operation_kwargs['algorithm'] == 'minmax'