Repository: holoviz/hvplot

Issue:
points is broken with holoviews 1.12.3 bokeh 1.2.0
```python
pd.DataFrame([[1,2], [3,4]]).hvplot.points()
```

```python-traceback
---------------------------------------------------------------------------
ValueError                                Traceback (most recent call last)
<ipython-input-32-c78e14955632> in <module>
----> 1 pd.DataFrame([[1,2], [3,4]]).hvplot.points()

~/scratch/examples/datashader_dashboard/envs/default/lib/python3.6/site-packages/hvplot/__init__.py in points(self, x, y, **kwds)
    643             The HoloViews representation of the plot.
    644         """
--> 645         return self(x, y, kind='points', **kwds)
    646 
    647     def polygons(self, x=None, y=None, c=None, **kwds):

~/scratch/examples/datashader_dashboard/envs/default/lib/python3.6/site-packages/hvplot/__init__.py in __call__(self, x, y, kind, **kwds)
    181         HoloViews object: Object representing the requested visualization
    182         """
--> 183         return self._get_converter(x, y, kind, **kwds)(kind, x, y)
    184 
    185     def _get_converter(self, x=None, y=None, kind=None, **kwds):

~/scratch/examples/datashader_dashboard/envs/default/lib/python3.6/site-packages/hvplot/converter.py in __call__(self, kind, x, y)
    717                 obj = DynamicMap(cbcallable, streams=[self.stream])
    718             else:
--> 719                 obj = method(x, y)
    720 
    721         if self.crs and self.project:

~/scratch/examples/datashader_dashboard/envs/default/lib/python3.6/site-packages/hvplot/converter.py in points(self, x, y, data)
   1277         vdims = vdims + self.hover_cols
   1278         params['vdims'] = vdims
-> 1279         return element(data, [x, y], **params).redim(**self._redim).redim.range(**ranges).opts(**opts)
   1280 
   1281     ##########################

~/scratch/examples/datashader_dashboard/envs/default/lib/python3.6/site-packages/holoviews/core/data/__init__.py in __init__(self, data, kdims, vdims, **kwargs)
    204             kwargs.update([(l, pvals[l]) for l in ['group', 'label']
    205                            if l in pvals and l not in kwargs])
--> 206         kwargs.update(process_dimensions(kdims, vdims))
    207         kdims, vdims = kwargs.get('kdims'), kwargs.get('vdims')
    208 

~/scratch/examples/datashader_dashboard/envs/default/lib/python3.6/site-packages/holoviews/core/dimension.py in process_dimensions(kdims, vdims)
    125                 raise ValueError('Dimensions must be defined as a tuple, '
    126                                  'string, dictionary or Dimension instance, '
--> 127                                  'found a %s type.' % type(dim).__name__)
    128         dimensions[group] = [asdim(d) for d in dims]
    129     return dimensions

ValueError: Dimensions must be defined as a tuple, string, dictionary or Dimension instance, found a NoneType type.
```


Discussion:
Turns out points requires x and y args. I am opening a PR to make that requirement raise a better error. 

Resolving patch:
diff --git a/hvplot/converter.py b/hvplot/converter.py
--- a/hvplot/converter.py
+++ b/hvplot/converter.py
@@ -1272,8 +1272,9 @@ def points(self, x=None, y=None, data=None):
         data = self.data if data is None else data
         params = dict(self._relabel)
 
-        x = x or self.x
-        y = y or self.y
+        x = x if x is not None else self.x
+        y = y if y is not None else self.y
+
         if hasattr(data, 'geom_type') and not (x and y):
             x, y = 'Longitude', 'Latitude'
 
@@ -1291,11 +1292,12 @@ def points(self, x=None, y=None, data=None):
         element = self._get_element('points')
         if self.geo: params['crs'] = self.crs
         vdims = [self.kwds['c']] if 'c' in self.kwds else []
+        kdims = [x, y] if x is not None and y is not None else None
         if 's' in self.kwds:
             vdims.append(self.kwds['s'])
         vdims = vdims + self.hover_cols
         params['vdims'] = vdims
-        return element(data, [x, y], **params).redim(**self._redim).redim.range(**ranges).opts(**opts)
+        return element(data, kdims, **params).redim(**self._redim).redim.range(**ranges).opts(**opts)
 
     ##########################
     #    Geometry plots      #


Test patch:
diff --git a/hvplot/tests/testcharts.py b/hvplot/tests/testcharts.py
--- a/hvplot/tests/testcharts.py
+++ b/hvplot/tests/testcharts.py
@@ -2,10 +2,35 @@
 from parameterized import parameterized
 
 from holoviews import NdOverlay, Store
-from holoviews.element import Curve, Area, Scatter
+from holoviews.element import Curve, Area, Scatter, Points
 from holoviews.element.comparison import ComparisonTestCase
 from hvplot import patch
 
+class TestChart2D(ComparisonTestCase):
+    def setUp(self):
+        try:
+            import pandas as pd
+        except:
+            raise SkipTest('Pandas not available')
+        patch('pandas')
+        self.df = pd.DataFrame([[1, 2], [3, 4], [5, 6]], columns=['x', 'y'])
+        self.cat_df = pd.DataFrame([[1, 2, 'A'], [3, 4, 'B'], [5, 6, 'C']],
+                                   columns=['x', 'y', 'category'])
+
+    @parameterized.expand([('points', Points)])
+    def test_tidy_chart_defaults(self, kind, element):
+        plot = self.df.hvplot(kind=kind)
+        self.assertEqual(plot, element(self.df))
+
+    @parameterized.expand([('points', Points)])
+    def test_tidy_chart(self, kind, element):
+        plot = self.df.hvplot(x='x', y='y', kind=kind)
+        self.assertEqual(plot, element(self.df, ['x', 'y']))
+
+    @parameterized.expand([('points', Points)])
+    def test_tidy_chart_index_and_c(self, kind, element):
+        plot = self.df.hvplot(x='index', y='y', c='x', kind=kind)
+        self.assertEqual(plot, element(self.df, ['index', 'y'], ['x']))
 
 class TestChart1D(ComparisonTestCase):