Repository: geopandas/geopandas

Issue:
Plot empty `GeoDataFrame`
If I do the following:

```python
import geopandas as gpd
db = gpd.read_file(gpd.datasets.get_path('nybb'))
db.loc[db.Shape_Area < 0, :].plot()
```

Is this behaviour expected (and desired?):

```python
In [12]: db.loc[db.Shape_Area < 0, :].plot()
/Users/dani/anaconda/envs/gds/lib/python3.5/site-packages/pandas/core/ops.py:798: FutureWarning: elementwise comparison failed; returning scalar instead, but in the future will perform elementwise comparison
  result = getattr(x, name)(y)
---------------------------------------------------------------------------
TypeError                                 Traceback (most recent call last)
<ipython-input-12-0f85e558ae7c> in <module>()
----> 1 db.loc[db.Shape_Area < 0, :].plot()

~/anaconda/envs/gds/lib/python3.5/site-packages/geopandas/geodataframe.py in plot(self, *args, **kwargs)
    467     def plot(self, *args, **kwargs):
    468
--> 469         return plot_dataframe(self, *args, **kwargs)
    470
    471     plot.__doc__ = plot_dataframe.__doc__

~/anaconda/envs/gds/lib/python3.5/site-packages/geopandas/plotting.py in plot_dataframe(df, column, cmap, color, ax, categorical, legend, scheme, k, vmin, vmax, figsize, **style_kwds)
    395     if column is None:
    396         return plot_series(df.geometry, cmap=cmap, color=color, ax=ax,
--> 397                            figsize=figsize, **style_kwds)
    398
    399     if df[column].dtype is np.dtype('O'):

~/anaconda/envs/gds/lib/python3.5/site-packages/geopandas/plotting.py in plot_series(s, cmap, color, ax, figsize, **style_kwds)
    271
    272     geom_types = s.geometry.type
--> 273     poly_idx = np.asarray((geom_types == 'Polygon')
    274                           | (geom_types == 'MultiPolygon'))
    275     line_idx = np.asarray((geom_types == 'LineString')

~/anaconda/envs/gds/lib/python3.5/site-packages/pandas/core/ops.py in wrapper(self, other, axis)
    859
    860             with np.errstate(all='ignore'):
--> 861                 res = na_op(values, other)
    862             if is_scalar(res):
    863                 raise TypeError('Could not compare %s type with Series' %

~/anaconda/envs/gds/lib/python3.5/site-packages/pandas/core/ops.py in na_op(x, y)
    798                     result = getattr(x, name)(y)
    799                 if result is NotImplemented:
--> 800                     raise TypeError("invalid type comparison")
    801             except AttributeError:
    802                 result = op(x, y)

TypeError: invalid type comparison

In [13]:
```

This is on 0.3.0. 


Discussion:
It should certainly give a better error message, but the question is whether we prefer an empty plot or an error message.

Looking at pandas and matplotlib as comparison:

```
In [118]: s = pd.Series([])

In [119]: s.plot()
...
TypeError: Empty 'DataFrame': no numeric data to plot

In [124]: plt.plot([])
Out[124]: [<matplotlib.lines.Line2D at 0x7f58154130f0>]  <-- empty plot
```

so they do it differently
From my usecases (certainly how I found out about it), I'd rather have a warning that prints an empty `GeoDataFrame` has been attempted to plot, but not fail. Some times (e.g. [LISA plots](http://nbviewer.jupyter.org/github/darribas/gds17/blob/master/content/labs/lab_05_ex.ipynb#Local-Spatial-autocorrelation)), when you plot multi-layered maps, it's not always the case that every layer will have observations, but you still want to try and, if there is nothing, the output map is still good. This of course can be worked around by checking `shape[0] > 0`, but allowing to pass with a warning would probably be easier. What other use cases do people have?
That is also an option, give empty plot but raise a warning.

Do you want to do a PR? I think we can just check in the beginning of the plot function that the passed data have a length > 0, and if not raise a warning and return the `ax` as is.

Resolving patch:
diff --git a/geopandas/plotting.py b/geopandas/plotting.py
--- a/geopandas/plotting.py
+++ b/geopandas/plotting.py
@@ -260,6 +260,11 @@ def plot_series(s, cmap=None, color=None, ax=None, figsize=None, **style_kwds):
         fig, ax = plt.subplots(figsize=figsize)
         ax.set_aspect('equal')
 
+    if s.empty:
+        warnings.warn("The GeoSeries you are attempting to plot is "
+                      "empty. Nothing has been displayed.", UserWarning)
+        return ax
+
     # if cmap is specified, create range of colors based on cmap
     values = None
     if cmap is not None:
@@ -396,6 +401,15 @@ def plot_dataframe(df, column=None, cmap=None, color=None, ax=None,
     import matplotlib
     import matplotlib.pyplot as plt
 
+    if ax is None:
+        fig, ax = plt.subplots(figsize=figsize)
+        ax.set_aspect('equal')
+
+    if df.empty:
+        warnings.warn("The GeoDataFrame you are attempting to plot is "
+                      "empty. Nothing has been displayed.", UserWarning)
+        return ax
+
     if column is None:
         return plot_series(df.geometry, cmap=cmap, color=color, ax=ax,
                            figsize=figsize, **style_kwds)
@@ -428,10 +442,6 @@ def plot_dataframe(df, column=None, cmap=None, color=None, ax=None,
                       for i in range(len(binedges)-1)]
         values = np.array(binning.yb)
 
-    if ax is None:
-        fig, ax = plt.subplots(figsize=figsize)
-        ax.set_aspect('equal')
-
     mn = values.min() if vmin is None else vmin
     mx = values.max() if vmax is None else vmax
 


Test patch:
diff --git a/geopandas/tests/test_plotting.py b/geopandas/tests/test_plotting.py
--- a/geopandas/tests/test_plotting.py
+++ b/geopandas/tests/test_plotting.py
@@ -146,6 +146,15 @@ def test_legend(self):
         # last point == top of colorbar
         np.testing.assert_array_equal(point_colors[-1], cbar_colors[-1])
 
+    def test_empty_plot(self):
+        s = GeoSeries([])
+        with pytest.warns(UserWarning):
+            ax = s.plot()
+        assert len(ax.collections) == 0
+        df = GeoDataFrame([])
+        with pytest.warns(UserWarning):
+            ax = df.plot()
+        assert len(ax.collections) == 0
 
 class TestPointZPlotting: