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,596 @@
1
+ import hvplot
2
+ import holoviews as hv
3
+ import numpy as np
4
+ import pandas as pd
5
+ import pytest
6
+ import xarray as xr
7
+
8
+ from holoviews import Store
9
+ from holoviews.core.options import Options, OptionTree
10
+
11
+
12
+ @pytest.fixture(scope='class')
13
+ def load_pandas_accessor():
14
+ import hvplot.pandas # noqa
15
+
16
+
17
+ @pytest.fixture(scope='class')
18
+ def load_xarray_accessor():
19
+ import hvplot.xarray # noqa
20
+
21
+
22
+ @pytest.fixture(params=['bokeh', 'matplotlib', 'plotly'], scope='class')
23
+ def backend(request):
24
+ backend = request.param
25
+ backend_copy = Store.current_backend
26
+ if backend not in Store.registry:
27
+ hvplot.extension(backend, compatibility='bokeh')
28
+ Store.set_current_backend(backend)
29
+ store_copy = OptionTree(sorted(Store.options().items()), groups=Options._option_groups)
30
+ yield backend
31
+ Store.options(val=store_copy)
32
+ Store._custom_options = {k: {} for k in Store._custom_options.keys()}
33
+ Store.set_current_backend(backend_copy)
34
+
35
+
36
+ @pytest.fixture(scope='module')
37
+ def df():
38
+ return pd.DataFrame(
39
+ [[1, 2, 'A', 0.1], [3, 4, 'B', 0.2], [5, 6, 'C', 0.3]],
40
+ columns=['x', 'y', 'category', 'number'],
41
+ )
42
+
43
+
44
+ @pytest.fixture(scope='module')
45
+ def symmetric_df():
46
+ return pd.DataFrame([[1, 2, -1], [3, 4, 0], [5, 6, 1]], columns=['x', 'y', 'number'])
47
+
48
+
49
+ @pytest.mark.usefixtures('load_pandas_accessor')
50
+ class TestOptions:
51
+ @pytest.mark.parametrize(
52
+ 'backend',
53
+ [
54
+ 'bokeh',
55
+ pytest.param(
56
+ 'matplotlib',
57
+ marks=pytest.mark.xfail(
58
+ reason='legend_position not supported w/ matplotlib for scatter'
59
+ ),
60
+ ),
61
+ pytest.param(
62
+ 'plotly',
63
+ marks=pytest.mark.xfail(
64
+ reason='legend_position not supported w/ plotly for scatter'
65
+ ),
66
+ ),
67
+ ],
68
+ indirect=True,
69
+ )
70
+ def test_scatter_legend_position(self, df, backend):
71
+ plot = df.hvplot.scatter('x', 'y', c='category', legend='left')
72
+ opts = Store.lookup_options(backend, plot, 'plot')
73
+ assert opts.kwargs['legend_position'] == 'left'
74
+
75
+ @pytest.mark.parametrize(
76
+ 'backend',
77
+ [
78
+ 'bokeh',
79
+ 'matplotlib',
80
+ pytest.param(
81
+ 'plotly',
82
+ marks=pytest.mark.xfail(reason='legend_position not supported w/ plotly for hist'),
83
+ ),
84
+ ],
85
+ indirect=True,
86
+ )
87
+ def test_histogram_by_category_legend_position(self, df, backend):
88
+ plot = df.hvplot.hist('y', by='category', legend='left')
89
+ opts = Store.lookup_options(backend, plot, 'plot')
90
+ assert opts.kwargs['legend_position'] == 'left'
91
+
92
+ @pytest.mark.parametrize('kind', ['scatter', 'points'])
93
+ def test_logz(self, df, kind, backend):
94
+ plot = df.hvplot('x', 'y', c='x', logz=True, kind=kind)
95
+ opts = Store.lookup_options(backend, plot, 'plot')
96
+ assert opts.kwargs['logz'] is True
97
+
98
+ @pytest.mark.parametrize('kind', ['scatter', 'points'])
99
+ def test_color_dim(self, df, kind, backend):
100
+ plot = df.hvplot('x', 'y', c='number', kind=kind)
101
+ opts = Store.lookup_options(backend, plot, 'style')
102
+ assert opts.kwargs['color'] == 'number'
103
+ assert 'number' in plot.vdims
104
+
105
+ @pytest.mark.parametrize('kind', ['scatter', 'points'])
106
+ def test_size_dim(self, df, kind, backend):
107
+ plot = df.hvplot('x', 'y', s='number', kind=kind)
108
+ opts = Store.lookup_options(backend, plot, 'style')
109
+ if backend in ['bokeh', 'plotly']:
110
+ param = 'size'
111
+ elif backend == 'matplotlib':
112
+ param = 's'
113
+ assert opts.kwargs[param] == 'number'
114
+ assert 'number' in plot.vdims
115
+
116
+ @pytest.mark.parametrize(
117
+ 'backend',
118
+ [
119
+ 'bokeh',
120
+ pytest.param(
121
+ 'matplotlib',
122
+ marks=pytest.mark.xfail(reason='cannot map a dim to alpha w/ matplotlib'),
123
+ ),
124
+ pytest.param(
125
+ 'plotly', marks=pytest.mark.xfail(reason='cannot map a dim to alpha w/ plotly')
126
+ ),
127
+ ],
128
+ indirect=True,
129
+ )
130
+ @pytest.mark.parametrize('kind', ['scatter', 'points'])
131
+ def test_alpha_dim(self, df, kind, backend):
132
+ plot = df.hvplot('x', 'y', alpha='number', kind=kind)
133
+ opts = Store.lookup_options(backend, plot, 'style')
134
+ assert opts.kwargs['alpha'] == 'number'
135
+ assert 'number' in plot.vdims
136
+ # Special matplotlib code to trigger an error that happens on render
137
+ if backend == 'matplotlib':
138
+ mpl_renderer = hv.Store.renderers['matplotlib']
139
+ mpl_renderer.get_plot(plot)
140
+
141
+ @pytest.mark.parametrize('kind', ['scatter', 'points'])
142
+ def test_marker_dim(self, df, kind, backend):
143
+ plot = df.hvplot('x', 'y', marker='category', kind=kind)
144
+ opts = Store.lookup_options(backend, plot, 'style')
145
+ assert opts.kwargs['marker'] == 'category'
146
+ assert 'category' in plot.vdims
147
+
148
+ @pytest.mark.parametrize('kind', ['scatter', 'points'])
149
+ def test_color_dim_overlay(self, df, kind, backend):
150
+ plot = df.hvplot('x', 'y', c='number', by='category', kind=kind)
151
+ opts = Store.lookup_options(backend, plot.last, 'style')
152
+ assert opts.kwargs['color'] == 'number'
153
+ assert 'number' in plot.last.vdims
154
+
155
+ @pytest.mark.parametrize('kind', ['scatter', 'points'])
156
+ def test_size_dim_overlay(self, df, kind, backend):
157
+ plot = df.hvplot('x', 'y', s='number', by='category', kind=kind)
158
+ opts = Store.lookup_options(backend, plot.last, 'style')
159
+ if backend in ['bokeh', 'plotly']:
160
+ param = 'size'
161
+ elif backend == 'matplotlib':
162
+ param = 's'
163
+ assert opts.kwargs[param] == 'number'
164
+ assert 'number' in plot.last.vdims
165
+
166
+ @pytest.mark.parametrize(
167
+ 'backend',
168
+ [
169
+ 'bokeh',
170
+ 'matplotlib',
171
+ pytest.param(
172
+ 'plotly', marks=pytest.mark.xfail(reason='cannot map a dim to alpha w/ plotly')
173
+ ),
174
+ ],
175
+ indirect=True,
176
+ )
177
+ @pytest.mark.parametrize('kind', ['scatter', 'points'])
178
+ def test_alpha_dim_overlay(self, df, kind, backend):
179
+ plot = df.hvplot('x', 'y', alpha='number', by='category', kind=kind)
180
+ opts = Store.lookup_options(backend, plot.last, 'style')
181
+ assert opts.kwargs['alpha'] == 'number'
182
+ assert 'number' in plot.last.vdims
183
+
184
+ def test_hvplot_defaults(self, df, backend):
185
+ plot = df.hvplot.scatter('x', 'y', c='category')
186
+ opts = Store.lookup_options(backend, plot, 'plot')
187
+ if backend == 'bokeh':
188
+ assert opts.kwargs['height'] == 300
189
+ assert opts.kwargs['width'] == 700
190
+ elif backend == 'matplotlib':
191
+ assert opts.kwargs['aspect'] == pytest.approx(2.333333)
192
+ assert opts.kwargs['fig_size'] == pytest.approx(233.333333)
193
+ if backend == 'bokeh':
194
+ assert opts.kwargs['responsive'] is False
195
+ assert opts.kwargs['shared_axes'] is True
196
+ # legend_position shouldn't only be for Bokeh
197
+ assert opts.kwargs['legend_position'] == 'right'
198
+ assert opts.kwargs['show_grid'] is False
199
+ assert opts.kwargs['show_legend'] is True
200
+ assert opts.kwargs['logx'] is False
201
+ assert opts.kwargs['logy'] is False
202
+ assert opts.kwargs.get('logz') is None
203
+
204
+ @pytest.mark.parametrize(
205
+ 'backend',
206
+ [
207
+ 'bokeh',
208
+ pytest.param(
209
+ 'matplotlib',
210
+ marks=pytest.mark.xfail(reason='default opts not supported w/ matplotlib'),
211
+ ),
212
+ pytest.param(
213
+ 'plotly', marks=pytest.mark.xfail(reason='default opts not supported w/ plotly')
214
+ ),
215
+ ],
216
+ indirect=True,
217
+ )
218
+ def test_holoviews_defined_default_opts(self, df, backend):
219
+ hv.opts.defaults(hv.opts.Scatter(height=400, width=900, show_grid=True))
220
+ plot = df.hvplot.scatter('x', 'y', c='category')
221
+ opts = Store.lookup_options(backend, plot, 'plot')
222
+ # legend_position shouldn't apply only to bokeh
223
+ if backend == 'bokeh':
224
+ assert opts.kwargs['legend_position'] == 'right'
225
+ assert opts.kwargs['show_grid'] is True
226
+ assert opts.kwargs['height'] == 400
227
+ assert opts.kwargs['width'] == 900
228
+
229
+ @pytest.mark.parametrize(
230
+ 'backend',
231
+ [
232
+ 'bokeh',
233
+ pytest.param(
234
+ 'matplotlib',
235
+ marks=pytest.mark.xfail(reason='default opts not supported w/ matplotlib'),
236
+ ),
237
+ pytest.param(
238
+ 'plotly', marks=pytest.mark.xfail(reason='default opts not supported w/ plotly')
239
+ ),
240
+ ],
241
+ indirect=True,
242
+ )
243
+ def test_holoviews_defined_default_opts_overwritten_in_call(self, df, backend):
244
+ hv.opts.defaults(hv.opts.Scatter(height=400, width=900, show_grid=True))
245
+ plot = df.hvplot.scatter('x', 'y', c='category', width=300, legend='left')
246
+ opts = Store.lookup_options(backend, plot, 'plot')
247
+ # legend_position shouldn't apply only to bokeh
248
+ if backend == 'bokeh':
249
+ assert opts.kwargs['legend_position'] == 'left'
250
+ assert opts.kwargs['show_grid'] is True
251
+ assert opts.kwargs['height'] == 400
252
+ assert opts.kwargs['width'] == 300
253
+
254
+ @pytest.mark.parametrize(
255
+ 'backend',
256
+ [
257
+ 'bokeh',
258
+ pytest.param(
259
+ 'matplotlib',
260
+ marks=pytest.mark.xfail(
261
+ reason='default opts not supported not supported w/ matplotlib'
262
+ ),
263
+ ),
264
+ pytest.param(
265
+ 'plotly',
266
+ marks=pytest.mark.xfail(
267
+ reason='default opts not supported not supported w/ plotly'
268
+ ),
269
+ ),
270
+ ],
271
+ indirect=True,
272
+ )
273
+ def test_holoviews_defined_default_opts_are_not_mutable(self, df, backend):
274
+ hv.opts.defaults(hv.opts.Scatter(tools=['tap']))
275
+ plot = df.hvplot.scatter('x', 'y', c='category')
276
+ opts = Store.lookup_options(backend, plot, 'plot')
277
+ assert opts.kwargs['tools'] == ['tap', 'hover']
278
+ default_opts = Store.options(backend=backend)['Scatter'].groups['plot'].options
279
+ assert default_opts['tools'] == ['tap']
280
+
281
+ def test_axis_set_to_visible_by_default(self, df, backend):
282
+ plot = df.hvplot.scatter('x', 'y', c='category')
283
+ opts = Store.lookup_options(backend, plot, 'plot')
284
+ assert 'xaxis' not in opts.kwargs
285
+ assert 'yaxis' not in opts.kwargs
286
+
287
+ def test_axis_set_to_none(self, df, backend):
288
+ plot = df.hvplot.scatter('x', 'y', c='category', xaxis=None, yaxis=None)
289
+ opts = Store.lookup_options(backend, plot, 'plot')
290
+ assert opts.kwargs['xaxis'] is None
291
+ assert opts.kwargs['yaxis'] is None
292
+
293
+ def test_axis_set_to_false(self, df, backend):
294
+ plot = df.hvplot.scatter('x', 'y', c='category', xaxis=False, yaxis=False)
295
+ opts = Store.lookup_options(backend, plot, 'plot')
296
+ assert opts.kwargs['xaxis'] is None
297
+ assert opts.kwargs['yaxis'] is None
298
+
299
+ def test_axis_set_to_none_in_holoviews_opts_default(self, df, backend):
300
+ hv.opts.defaults(hv.opts.Scatter(xaxis=None, yaxis=None))
301
+ plot = df.hvplot.scatter('x', 'y', c='category')
302
+ opts = Store.lookup_options(backend, plot, 'plot')
303
+ assert opts.kwargs['xaxis'] is None
304
+ assert opts.kwargs['yaxis'] is None
305
+
306
+ @pytest.mark.xfail
307
+ def test_axis_set_to_none_in_holoviews_opts_default_overwrite_in_call(self, df, backend):
308
+ hv.opts.defaults(hv.opts.Scatter(xaxis=None, yaxis=None))
309
+ plot = df.hvplot.scatter('x', 'y', c='category', xaxis=True, yaxis=True)
310
+ opts = Store.lookup_options(backend, plot, 'plot')
311
+ assert 'xaxis' not in opts.kwargs
312
+ assert 'yaxis' not in opts.kwargs
313
+
314
+ def test_loglog_opts(self, df, backend):
315
+ plot = df.hvplot.scatter('x', 'y', c='category', loglog=True)
316
+ opts = Store.lookup_options(backend, plot, 'plot')
317
+ assert opts.kwargs['logx'] is True
318
+ assert opts.kwargs['logy'] is True
319
+ assert opts.kwargs.get('logz') is None
320
+
321
+ def test_logy_opts(self, df, backend):
322
+ plot = df.hvplot.scatter('x', 'y', c='category', logy=True)
323
+ opts = Store.lookup_options(backend, plot, 'plot')
324
+ assert opts.kwargs['logx'] is False
325
+ assert opts.kwargs['logy'] is True
326
+ assert opts.kwargs.get('logz') is None
327
+
328
+ @pytest.mark.parametrize(
329
+ 'backend',
330
+ [
331
+ 'bokeh',
332
+ pytest.param(
333
+ 'matplotlib',
334
+ marks=pytest.mark.xfail(reason='default opts not supported w/ matplotlib'),
335
+ ),
336
+ pytest.param(
337
+ 'plotly', marks=pytest.mark.xfail(reason='defaykt opts not supported w/ plotly')
338
+ ),
339
+ ],
340
+ indirect=True,
341
+ )
342
+ def test_holoviews_defined_default_opts_logx(self, df, backend):
343
+ hv.opts.defaults(hv.opts.Scatter(logx=True))
344
+ plot = df.hvplot.scatter('x', 'y', c='category')
345
+ opts = Store.lookup_options(backend, plot, 'plot')
346
+ assert opts.kwargs['logx'] is True
347
+ assert opts.kwargs['logy'] is False
348
+ assert opts.kwargs.get('logz') is None
349
+
350
+ def test_holoviews_defined_default_opts_logx_overwritten_in_call(self, df, backend):
351
+ hv.opts.defaults(hv.opts.Scatter(logx=True))
352
+ plot = df.hvplot.scatter('x', 'y', c='category', logx=False)
353
+ opts = Store.lookup_options(backend, plot, 'plot')
354
+ assert opts.kwargs['logx'] is False
355
+ assert opts.kwargs['logy'] is False
356
+ assert opts.kwargs.get('logz') is None
357
+
358
+ def test_hvplot_default_cat_cmap_opts(self, df, backend):
359
+ import colorcet as cc
360
+
361
+ plot = df.hvplot.scatter('x', 'y', c='category')
362
+ opts = Store.lookup_options(backend, plot, 'style')
363
+ assert opts.kwargs['cmap'] == cc.palette['glasbey_category10']
364
+
365
+ def test_hvplot_default_num_cmap_opts(self, df, backend):
366
+ plot = df.hvplot.scatter('x', 'y', c='number')
367
+ opts = Store.lookup_options(backend, plot, 'style')
368
+ assert opts.kwargs['cmap'] == 'kbc_r'
369
+
370
+ def test_cmap_opts_by_type(self, df, backend):
371
+ plot = df.hvplot.scatter('x', 'y', c='number', cmap='diverging')
372
+ opts = Store.lookup_options(backend, plot, 'style')
373
+ assert opts.kwargs['cmap'] == 'coolwarm'
374
+
375
+ def test_cmap_opts_by_name(self, df, backend):
376
+ plot = df.hvplot.scatter('x', 'y', c='number', cmap='fire')
377
+ opts = Store.lookup_options(backend, plot, 'style')
378
+ assert opts.kwargs['cmap'] == 'fire'
379
+
380
+ def test_colormap_opts_by_name(self, df, backend):
381
+ plot = df.hvplot.scatter('x', 'y', c='number', colormap='fire')
382
+ opts = Store.lookup_options(backend, plot, 'style')
383
+ assert opts.kwargs['cmap'] == 'fire'
384
+
385
+ def test_cmap_opts_as_a_list(self, df, backend):
386
+ plot = df.hvplot.scatter('x', 'y', c='number', cmap=['red', 'blue', 'green'])
387
+ opts = Store.lookup_options(backend, plot, 'style')
388
+ assert opts.kwargs['cmap'] == ['red', 'blue', 'green']
389
+
390
+ @pytest.mark.parametrize(
391
+ ('opt', 'backend'),
392
+ [
393
+ ('aspect', 'bokeh'),
394
+ ('aspect', 'matplotlib'),
395
+ ('aspect', 'plotly'),
396
+ ('data_aspect', 'bokeh'),
397
+ ('data_aspect', 'matplotlib'),
398
+ pytest.param(
399
+ 'data_aspect',
400
+ 'plotly',
401
+ marks=pytest.mark.xfail(reason='data_aspect not supported w/ plotly'),
402
+ ),
403
+ ],
404
+ indirect=['backend'],
405
+ )
406
+ def test_aspect(self, df, opt, backend):
407
+ plot = df.hvplot(x='x', y='y', **{opt: 2})
408
+ opts = Store.lookup_options(backend, plot, 'plot').kwargs
409
+ assert opts[opt] == 2
410
+ if backend in ['bokeh', 'matplotlib']:
411
+ assert opts.get('width') is None
412
+ assert opts.get('height') is None
413
+ elif backend == 'matplotlib':
414
+ assert opts.get('fig_size') is None
415
+
416
+ @pytest.mark.parametrize(
417
+ ('opt', 'backend'),
418
+ [
419
+ ('aspect', 'bokeh'),
420
+ ('aspect', 'matplotlib'),
421
+ ('aspect', 'plotly'),
422
+ ('data_aspect', 'bokeh'),
423
+ ('data_aspect', 'matplotlib'),
424
+ pytest.param(
425
+ 'data_aspect',
426
+ 'plotly',
427
+ marks=pytest.mark.xfail(reason='data_aspect not supported w/ plotly'),
428
+ ),
429
+ ],
430
+ indirect=['backend'],
431
+ )
432
+ def test_aspect_and_width(self, df, opt, backend):
433
+ plot = df.hvplot(x='x', y='y', width=150, **{opt: 2})
434
+ opts = hv.Store.lookup_options(backend, plot, 'plot').kwargs
435
+ assert opts[opt] == 2
436
+ if backend in ['bokeh', 'plotly']:
437
+ assert opts.get('width') == 150
438
+ assert opts.get('height') is None
439
+ elif backend == 'matplotlib':
440
+ assert opts.get('fig_size') == pytest.approx(50.0)
441
+
442
+ def test_symmetric_dataframe(self, backend):
443
+ import pandas as pd
444
+
445
+ df = pd.DataFrame([[1, 2, -1], [3, 4, 0], [5, 6, 1]], columns=['x', 'y', 'number'])
446
+ plot = df.hvplot.scatter('x', 'y', c='number')
447
+ plot_opts = Store.lookup_options(backend, plot, 'plot')
448
+ assert plot_opts.kwargs['symmetric'] is True
449
+ style_opts = Store.lookup_options(backend, plot, 'style')
450
+ assert style_opts.kwargs['cmap'] == 'coolwarm'
451
+
452
+ def test_symmetric_is_deduced_dataframe(self, symmetric_df, backend):
453
+ plot = symmetric_df.hvplot.scatter('x', 'y', c='number')
454
+ plot_opts = Store.lookup_options(backend, plot, 'plot')
455
+ assert plot_opts.kwargs['symmetric'] is True
456
+ style_opts = Store.lookup_options(backend, plot, 'style')
457
+ assert style_opts.kwargs['cmap'] == 'coolwarm'
458
+
459
+ def test_symmetric_from_opts(self, df, backend):
460
+ plot = df.hvplot.scatter('x', 'y', c='number', symmetric=True)
461
+ plot_opts = Store.lookup_options(backend, plot, 'plot')
462
+ assert plot_opts.kwargs['symmetric'] is True
463
+ style_opts = Store.lookup_options(backend, plot, 'style')
464
+ assert style_opts.kwargs['cmap'] == 'coolwarm'
465
+
466
+ def test_symmetric_from_opts_does_not_deduce(self, symmetric_df, backend):
467
+ plot = symmetric_df.hvplot.scatter('x', 'y', c='number', symmetric=False)
468
+ plot_opts = Store.lookup_options(backend, plot, 'plot')
469
+ assert plot_opts.kwargs['symmetric'] is False
470
+ style_opts = Store.lookup_options(backend, plot, 'style')
471
+ assert style_opts.kwargs['cmap'] == 'kbc_r'
472
+
473
+ def test_if_clim_is_set_symmetric_is_not_deduced(self, symmetric_df, backend):
474
+ plot = symmetric_df.hvplot.scatter('x', 'y', c='number', clim=(-1, 1))
475
+ plot_opts = Store.lookup_options(backend, plot, 'plot')
476
+ assert plot_opts.kwargs.get('symmetric') is None
477
+ style_opts = Store.lookup_options(backend, plot, 'style')
478
+ assert style_opts.kwargs['cmap'] == 'kbc_r'
479
+
480
+ @pytest.mark.parametrize(
481
+ 'backend',
482
+ [
483
+ 'bokeh',
484
+ 'matplotlib',
485
+ pytest.param(
486
+ 'plotly',
487
+ marks=pytest.mark.xfail(
488
+ reason='bandwidth, cut, levels not supported w/ plotly for bivariate'
489
+ ),
490
+ ),
491
+ ],
492
+ indirect=True,
493
+ )
494
+ def test_bivariate_opts(self, df, backend):
495
+ plot = df.hvplot.bivariate('x', 'y', bandwidth=0.2, cut=1, levels=5, filled=True)
496
+ opts = Store.lookup_options(backend, plot, 'plot')
497
+ assert opts.kwargs['bandwidth'] == 0.2
498
+ assert opts.kwargs['cut'] == 1
499
+ assert opts.kwargs['levels'] == 5
500
+ assert opts.kwargs['filled'] is True
501
+
502
+ def test_kde_opts(self, df, backend):
503
+ plot = df.hvplot.kde('x', bandwidth=0.2, cut=1, filled=True)
504
+ opts = Store.lookup_options(backend, plot, 'plot')
505
+ assert opts.kwargs['bandwidth'] == 0.2
506
+ assert opts.kwargs['cut'] == 1
507
+ assert opts.kwargs['filled'] is True
508
+
509
+ def test_bgcolor(self, df, backend):
510
+ plot = df.hvplot.scatter('x', 'y', bgcolor='black')
511
+ opts = Store.lookup_options(backend, plot, 'plot')
512
+ assert opts.kwargs['bgcolor'] == 'black'
513
+
514
+
515
+ @pytest.fixture(scope='module')
516
+ def da():
517
+ return xr.DataArray(
518
+ data=np.arange(16).reshape((2, 2, 2, 2)),
519
+ coords={'time': [0, 1], 'y': [0, 1], 'x': [0, 1], 'band': [0, 1]},
520
+ dims=['time', 'y', 'x', 'band'],
521
+ name='test',
522
+ )
523
+
524
+
525
+ @pytest.fixture(scope='module')
526
+ def da2():
527
+ return xr.DataArray(
528
+ data=np.arange(27).reshape((3, 3, 3)),
529
+ coords={'y': [0, 1, 2], 'x': [0, 1, 2]},
530
+ dims=['y', 'x', 'other'],
531
+ name='test2',
532
+ )
533
+
534
+
535
+ @pytest.fixture(scope='module')
536
+ def ds1(da):
537
+ return xr.Dataset(dict(foo=da))
538
+
539
+
540
+ @pytest.fixture(scope='module')
541
+ def ds2(da, da2):
542
+ return xr.Dataset(dict(foo=da, bar=da2))
543
+
544
+
545
+ @pytest.mark.usefixtures('load_xarray_accessor')
546
+ class TestXarrayTitle:
547
+ def test_dataarray_2d_with_title(self, da, backend):
548
+ da_sel = da.sel(time=0, band=0)
549
+ plot = da_sel.hvplot() # Image plot
550
+ opts = Store.lookup_options(backend, plot, 'plot')
551
+ assert opts.kwargs['title'] == 'time = 0, band = 0'
552
+
553
+ def test_dataarray_1d_with_title(self, da, backend):
554
+ da_sel = da.sel(time=0, band=0, x=0)
555
+ plot = da_sel.hvplot() # Line plot
556
+ opts = Store.lookup_options(backend, plot, 'plot')
557
+ assert opts.kwargs['title'] == 'time = 0, x = 0, band = 0'
558
+
559
+ def test_dataarray_1d_and_by_with_title(self, da, backend):
560
+ da_sel = da.sel(time=0, band=0, x=[0, 1])
561
+ plot = da_sel.hvplot(by='x') # Line plot with hue/by
562
+ opts = Store.lookup_options(backend, plot, 'plot')
563
+ assert opts.kwargs['title'] == 'time = 0, band = 0'
564
+
565
+ def test_override_title(self, da, backend):
566
+ da_sel = da.sel(time=0, band=0)
567
+ plot = da_sel.hvplot(title='title') # Image plot
568
+ opts = Store.lookup_options(backend, plot, 'plot')
569
+ assert opts.kwargs['title'] == 'title'
570
+
571
+ def test_dataarray_4d_line_no_title(self, da, backend):
572
+ plot = da.hvplot.line(dynamic=False) # Line plot with widgets
573
+ opts = Store.lookup_options(backend, plot.last, 'plot')
574
+ assert 'title' not in opts.kwargs
575
+
576
+ def test_dataarray_3d_histogram_with_title(self, da, backend):
577
+ da_sel = da.sel(time=0)
578
+ plot = da_sel.hvplot() # Histogram and no widgets
579
+ opts = Store.lookup_options(backend, plot, 'plot')
580
+ assert opts.kwargs['title'] == 'time = 0'
581
+
582
+ def test_dataset_empty_raises(self, ds1, backend):
583
+ with pytest.raises(ValueError, match='empty xarray.Dataset'):
584
+ ds1.drop_vars('foo').hvplot()
585
+
586
+ def test_dataset_one_var_behaves_like_dataarray(self, ds1, backend):
587
+ ds_sel = ds1.sel(time=0, band=0)
588
+ plot = ds_sel.hvplot() # Image plot
589
+ opts = Store.lookup_options(backend, plot, 'plot')
590
+ assert opts.kwargs['title'] == 'time = 0, band = 0'
591
+
592
+ def test_dataset_scatter_with_title(self, ds2, backend):
593
+ ds_sel = ds2.sel(time=0, band=0, x=0, y=0)
594
+ plot = ds_sel.hvplot.scatter(x='foo', y='bar') # Image plot
595
+ opts = Store.lookup_options(backend, plot, 'plot')
596
+ assert opts.kwargs['title'] == 'time = 0, y = 0, x = 0, band = 0'
@@ -0,0 +1,74 @@
1
+ from collections import OrderedDict
2
+
3
+ import numpy as np
4
+ import pandas as pd
5
+ import xarray as xr
6
+
7
+ from hvplot.plotting import hvPlot, hvPlotTabular
8
+ from holoviews import Store, Scatter
9
+ from holoviews.element.comparison import ComparisonTestCase
10
+
11
+
12
+ class TestOverrides(ComparisonTestCase):
13
+ def setUp(self):
14
+ import hvplot.pandas # noqa
15
+
16
+ self.df = pd.DataFrame([[1, 2], [3, 4], [5, 6]], columns=['x', 'y'])
17
+
18
+ def test_define_default_options(self):
19
+ hvplot = hvPlotTabular(self.df, width=42, height=42)
20
+ curve = hvplot(y='y')
21
+ opts = Store.lookup_options('bokeh', curve, 'plot')
22
+ self.assertEqual(opts.options.get('width'), 42)
23
+ self.assertEqual(opts.options.get('height'), 42)
24
+
25
+ def test_define_custom_method(self):
26
+ hvplot = hvPlotTabular(self.df, {'custom_scatter': {'width': 42, 'height': 42}})
27
+ custom_scatter = hvplot.custom_scatter(y='y')
28
+ scatter = hvplot.scatter(y='y')
29
+ custom_opts = Store.lookup_options('bokeh', custom_scatter, 'plot')
30
+ opts = Store.lookup_options('bokeh', scatter, 'plot')
31
+ self.assertEqual(custom_opts.options.get('width'), 42)
32
+ self.assertEqual(custom_opts.options.get('height'), 42)
33
+ self.assertNotEqual(opts.options.get('width'), 42)
34
+ self.assertNotEqual(opts.options.get('height'), 42)
35
+
36
+ def test_define_customize_method(self):
37
+ hvplot = hvPlotTabular(self.df, {'scatter': {'width': 42, 'height': 42}})
38
+ custom_scatter = hvplot.scatter(y='y')
39
+ curve = hvplot.line(y='y')
40
+ custom_opts = Store.lookup_options('bokeh', custom_scatter, 'plot')
41
+ opts = Store.lookup_options('bokeh', curve, 'plot')
42
+ self.assertEqual(custom_opts.options.get('width'), 42)
43
+ self.assertEqual(custom_opts.options.get('height'), 42)
44
+ self.assertNotEqual(opts.options.get('width'), 42)
45
+ self.assertNotEqual(opts.options.get('height'), 42)
46
+
47
+ def test_attempt_to_override_kind_on_method(self):
48
+ hvplot = hvPlotTabular(self.df, {'scatter': {'kind': 'line'}})
49
+ self.assertIsInstance(hvplot.scatter(y='y'), Scatter)
50
+
51
+ def test_pandas_query_metadata(self):
52
+ hvplot = hvPlotTabular(self.df, query='x>2')
53
+ assert len(hvplot._data) == 2
54
+
55
+
56
+ class TestXArrayOverrides(ComparisonTestCase):
57
+ def setUp(self):
58
+ coords = OrderedDict([('time', [0, 1]), ('lat', [0, 1]), ('lon', [0, 1])])
59
+ self.da_img_by_time = xr.DataArray(
60
+ np.arange(8).reshape((2, 2, 2)), coords, ['time', 'lat', 'lon']
61
+ ).assign_coords(lat1=xr.DataArray([2, 3], dims=['lat']))
62
+
63
+ def test_xarray_isel_scalar_metadata(self):
64
+ hvplot = hvPlot(self.da_img_by_time, isel={'time': 1})
65
+ assert hvplot._data.ndim == 2
66
+
67
+ def test_xarray_isel_nonscalar_metadata(self):
68
+ hvplot = hvPlot(self.da_img_by_time, isel={'time': [1]})
69
+ assert hvplot._data.ndim == 3
70
+ assert len(hvplot._data.time) == 1
71
+
72
+ def test_xarray_sel_metadata(self):
73
+ hvplot = hvPlot(self.da_img_by_time, sel={'time': 1})
74
+ assert hvplot._data.ndim == 2