Repository: pandas-dev/pandas

Issue:
Raise more helpfull exception on s.plot, df.plot ... without numerical data
``` python
In [23]: df1 = pandas.DataFrame(list('abcd'))

In [24]: df1.plot()
---------------------------------------------------------------------------
AttributeError                            Traceback (most recent call last)
...
AttributeError: 'numpy.ndarray' object has no attribute 'find'
```



Discussion:
Also, passing an invalid value of `kind` gives a very cryptic error message.


Resolving patch:
diff --git a/pandas/tools/plotting.py b/pandas/tools/plotting.py
--- a/pandas/tools/plotting.py
+++ b/pandas/tools/plotting.py
@@ -1,6 +1,5 @@
 # being a bit too dynamic
 # pylint: disable=E1101
-from itertools import izip
 import datetime
 import warnings
 import re
@@ -701,10 +700,8 @@ class MPLPlot(object):
     """
     _default_rot = 0
 
-    _pop_attributes = ['label', 'style', 'logy', 'logx', 'loglog',
-                       'raise_on_error']
-    _attr_defaults = {'logy': False, 'logx': False, 'loglog': False,
-                      'raise_on_error': True}
+    _pop_attributes = ['label', 'style', 'logy', 'logx', 'loglog']
+    _attr_defaults = {'logy': False, 'logx': False, 'loglog': False}
 
     def __init__(self, data, kind=None, by=None, subplots=False, sharex=True,
                  sharey=False, use_index=True,
@@ -875,7 +872,27 @@ def _get_layout(self):
         return (len(self.data.columns), 1)
 
     def _compute_plot_data(self):
-        pass
+        try:
+            # might be a frame
+            numeric_data = self.data._get_numeric_data()
+        except AttributeError:
+            # a series, but no object dtypes allowed!
+            if self.data.dtype == np.object_:
+                raise TypeError('invalid dtype for plotting, please cast to a '
+                                'numeric dtype explicitly if you want to plot')
+
+            numeric_data = self.data
+
+        try:
+            is_empty = numeric_data.empty
+        except AttributeError:
+            is_empty = not len(numeric_data)
+
+        # no empty frames or series allowed
+        if is_empty:
+            raise TypeError('No numeric data to plot')
+
+        self.data = numeric_data
 
     def _make_plot(self):
         raise NotImplementedError
@@ -1184,27 +1201,17 @@ def _make_plot(self):
                 else:
                     args = (ax, x, y, style)
 
-                try:
-                    newline = plotf(*args, **kwds)[0]
-                    lines.append(newline)
-                    leg_label = label
-                    if self.mark_right and self.on_right(i):
-                        leg_label += ' (right)'
-                    labels.append(leg_label)
-                    ax.grid(self.grid)
-
-                    if self._is_datetype():
-                        left, right = _get_xlim(lines)
-                        ax.set_xlim(left, right)
-                except AttributeError as inst: # non-numeric
-                    msg = ('Unable to plot data %s vs index %s,\n'
-                           'error was: %s' % (str(y), str(x), str(inst)))
-                    if not self.raise_on_error:
-                        print msg
-                    else:
-                        msg = msg + ('\nConsider setting raise_on_error=False'
-                                     'to suppress')
-                        raise Exception(msg)
+                newline = plotf(*args, **kwds)[0]
+                lines.append(newline)
+                leg_label = label
+                if self.mark_right and self.on_right(i):
+                    leg_label += ' (right)'
+                labels.append(leg_label)
+                ax.grid(self.grid)
+
+                if self._is_datetype():
+                    left, right = _get_xlim(lines)
+                    ax.set_xlim(left, right)
 
             self._make_legend(lines, labels)
 
@@ -1223,22 +1230,12 @@ def to_leg_label(label, i):
             return label
 
         def _plot(data, col_num, ax, label, style, **kwds):
-            try:
-                newlines = tsplot(data, plotf, ax=ax, label=label,
-                                  style=style, **kwds)
-                ax.grid(self.grid)
-                lines.append(newlines[0])
-                leg_label = to_leg_label(label, col_num)
-                labels.append(leg_label)
-            except AttributeError as inst: #non-numeric
-                msg = ('Unable to plot %s,\n'
-                       'error was: %s' % (str(data), str(inst)))
-                if not self.raise_on_error:
-                    print msg
-                else:
-                    msg = msg + ('\nConsider setting raise_on_error=False'
-                                 'to suppress')
-                    raise Exception(msg)
+            newlines = tsplot(data, plotf, ax=ax, label=label,
+                                style=style, **kwds)
+            ax.grid(self.grid)
+            lines.append(newlines[0])
+            leg_label = to_leg_label(label, col_num)
+            labels.append(leg_label)
 
         if isinstance(data, Series):
             ax = self._get_ax(0)  # self.axes[0]
@@ -1610,8 +1607,8 @@ def plot_series(series, label=None, kind='line', use_index=True, rot=None,
         If not passed, uses gca()
     style : string, default matplotlib default
         matplotlib line style to use
-    grid : matplot grid
-    legend: matplot legende
+    grid : matplotlib grid
+    legend: matplotlib legend
     logx : boolean, default False
         For line plots, use log scaling on x axis
     logy : boolean, default False
@@ -1633,6 +1630,8 @@ def plot_series(series, label=None, kind='line', use_index=True, rot=None,
         klass = BarPlot
     elif kind == 'kde':
         klass = KdePlot
+    else:
+        raise ValueError('Invalid chart type given %s' % kind)
 
     """
     If no axis is specified, we check whether there are existing figures.


Test patch:
diff --git a/pandas/tests/test_graphics.py b/pandas/tests/test_graphics.py
--- a/pandas/tests/test_graphics.py
+++ b/pandas/tests/test_graphics.py
@@ -187,6 +187,27 @@ def test_bootstrap_plot(self):
         from pandas.tools.plotting import bootstrap_plot
         _check_plot_works(bootstrap_plot, self.ts, size=10)
 
+    @slow
+    def test_all_invalid_plot_data(self):
+        s = Series(list('abcd'))
+        kinds = 'line', 'bar', 'barh', 'kde', 'density'
+
+        for kind in kinds:
+            self.assertRaises(TypeError, s.plot, kind=kind)
+
+    @slow
+    def test_partially_invalid_plot_data(self):
+        s = Series(['a', 'b', 1.0, 2])
+        kinds = 'line', 'bar', 'barh', 'kde', 'density'
+
+        for kind in kinds:
+            self.assertRaises(TypeError, s.plot, kind=kind)
+
+    @slow
+    def test_invalid_kind(self):
+        s = Series([1, 2])
+        self.assertRaises(ValueError, s.plot, kind='aasdf')
+
 
 class TestDataFramePlots(unittest.TestCase):
 
@@ -249,11 +270,9 @@ def test_nonnumeric_exclude(self):
         plt.close('all')
 
         df = DataFrame({'A': ["x", "y", "z"], 'B': [1,2,3]})
-        ax = df.plot(raise_on_error=False) # it works
+        ax = df.plot()
         self.assert_(len(ax.get_lines()) == 1) #B was plotted
 
-        self.assertRaises(Exception, df.plot)
-
     @slow
     def test_label(self):
         import matplotlib.pyplot as plt
@@ -688,6 +707,26 @@ def test_unordered_ts(self):
         ydata = ax.lines[0].get_ydata()
         self.assert_(np.all(ydata == np.array([1.0, 2.0, 3.0])))
 
+    @slow
+    def test_all_invalid_plot_data(self):
+        kinds = 'line', 'bar', 'barh', 'kde', 'density'
+        df = DataFrame(list('abcd'))
+        for kind in kinds:
+            self.assertRaises(TypeError, df.plot, kind=kind)
+
+    @slow
+    def test_partially_invalid_plot_data(self):
+        kinds = 'line', 'bar', 'barh', 'kde', 'density'
+        df = DataFrame(np.random.randn(10, 2), dtype=object)
+        df[np.random.rand(df.shape[0]) > 0.5] = 'a'
+        for kind in kinds:
+            self.assertRaises(TypeError, df.plot, kind=kind)
+
+    @slow
+    def test_invalid_kind(self):
+        df = DataFrame(np.random.randn(10, 2))
+        self.assertRaises(ValueError, df.plot, kind='aasdf')
+
 class TestDataFrameGroupByPlots(unittest.TestCase):
 
     @classmethod
diff --git a/pandas/tseries/tests/test_plotting.py b/pandas/tseries/tests/test_plotting.py
--- a/pandas/tseries/tests/test_plotting.py
+++ b/pandas/tseries/tests/test_plotting.py
@@ -87,18 +87,14 @@ def test_nonnumeric_exclude(self):
 
         idx = date_range('1/1/1987', freq='A', periods=3)
         df = DataFrame({'A': ["x", "y", "z"], 'B': [1,2,3]}, idx)
-        self.assertRaises(Exception, df.plot)
 
         plt.close('all')
-        ax = df.plot(raise_on_error=False) # it works
+        ax = df.plot() # it works
         self.assert_(len(ax.get_lines()) == 1) #B was plotted
 
         plt.close('all')
-        self.assertRaises(Exception, df.A.plot)
 
-        plt.close('all')
-        ax = df['A'].plot(raise_on_error=False) # it works
-        self.assert_(len(ax.get_lines()) == 0)
+        self.assertRaises(TypeError, df['A'].plot)
 
     @slow
     def test_tsplot(self):