Repository: geopandas/geopandas

Issue:
BUG: legend misplaced in subplots
I'm using v0.8.0. When I plot on multiple subplots and pass `legend_kwds` to `gdf.plot`, it draws all the subplot legends on the same subplot.

This works as expected:

```python
import geopandas as gpd
import matplotlib.pyplot as plt
gdf = gpd.read_file(gpd.datasets.get_path('naturalearth_lowres'))
fig, axes = plt.subplots(3, 2, figsize=(8,8))
for ax in axes.flat:
    gdf.plot(ax=ax, column='gdp_md_est', legend=True)
```
![1](https://user-images.githubusercontent.com/4977197/89090446-cccfb000-d357-11ea-8c9f-1505629b4f80.png)

But this draws the legends all on the same subplot:
```python
legend_kwds = {'orientation': 'horizontal'}
fig, axes = plt.subplots(3, 2, figsize=(8,8))
for ax in axes.flat:
    gdf.plot(ax=ax, column='gdp_md_est', legend=True, legend_kwds=legend_kwds)
```
![2](https://user-images.githubusercontent.com/4977197/89090447-ce997380-d357-11ea-9d86-7e5c6fb4edbf.png)

Is this user error or a bug?

Discussion:
jdmcbr: Yeah, a test of the colorbar getting onto the correct axis seemed like a very high effort to value ratio. That said, I suppose I could add a simple test that loops over axes like in #1555 and confirms that `legend_kwds` isn't updated, if that seems useful. 
martinfleis: > Yeah, a test of the colorbar getting onto the correct axis seemed like a very high effort to value ratio. That said, I suppose I could add a simple test that loops over axes like in #1555 and confirms that legend_kwds isn't updated, if that seems useful.

I am personally fine with a comment linking to the original issue.



Patch:
diff --git a/geopandas/plotting.py b/geopandas/plotting.py
index b827e781..e82c012f 100644
--- a/geopandas/plotting.py
+++ b/geopandas/plotting.py
@@ -313,14 +313,14 @@ def plot_series(
     figsize : pair of floats (default None)
         Size of the resulting matplotlib.figure.Figure. If the argument
         ax is given explicitly, figsize is ignored.
-    aspect : 'auto', 'equal' or float (default 'auto')
+    aspect : 'auto', 'equal', None or float (default 'auto')
         Set aspect of axis. If 'auto', the default aspect for map plots is 'equal'; if
         however data are not projected (coordinates are long/lat), the aspect is by
         default set to 1/cos(s_y * pi/180) with s_y the y coordinate of the middle of
         the GeoSeries (the mean of the y range of bounding box) so that a long/lat
         square appears square in the middle of the plot. This implies an
-        Equirectangular projection. It can also be set manually (float) as the ratio
-        of y-unit to x-unit.
+        Equirectangular projection. If None, the aspect of `ax` won't be changed. It can
+        also be set manually (float) as the ratio of y-unit to x-unit.
     **style_kwds : dict
         Color options to be passed on to the actual plot function, such
         as ``edgecolor``, ``facecolor``, ``linewidth``, ``markersize``,
@@ -366,7 +366,7 @@ def plot_series(
             # https://github.com/edzer/sp/blob/master/R/mapasp.R
         else:
             ax.set_aspect("equal")
-    else:
+    elif aspect is not None:
         ax.set_aspect(aspect)
 
     if s.empty:
@@ -535,14 +535,14 @@ def plot_dataframe(
         to be passed on to geometries with missing values in addition to
         or overwriting other style kwds. If None, geometries with missing
         values are not plotted.
-    aspect : 'auto', 'equal' or float (default 'auto')
+    aspect : 'auto', 'equal', None or float (default 'auto')
         Set aspect of axis. If 'auto', the default aspect for map plots is 'equal'; if
         however data are not projected (coordinates are long/lat), the aspect is by
         default set to 1/cos(df_y * pi/180) with df_y the y coordinate of the middle of
         the GeoDataFrame (the mean of the y range of bounding box) so that a long/lat
         square appears square in the middle of the plot. This implies an
-        Equirectangular projection. It can also be set manually (float) as the ratio
-        of y-unit to x-unit.
+        Equirectangular projection. If None, the aspect of `ax` won't be changed. It can
+        also be set manually (float) as the ratio of y-unit to x-unit.
 
     **style_kwds : dict
         Style options to be passed on to the actual plot function, such
@@ -597,9 +597,14 @@ def plot_dataframe(
             # https://github.com/edzer/sp/blob/master/R/mapasp.R
         else:
             ax.set_aspect("equal")
-    else:
+    elif aspect is not None:
         ax.set_aspect(aspect)
 
+    # GH 1555
+    # if legend_kwds set, copy so we don't update it in place
+    if legend_kwds is not None:
+        legend_kwds = legend_kwds.copy()
+
     if df.empty:
         warnings.warn(
             "The GeoDataFrame you are attempting to plot is "


Test patch:
diff --git a/geopandas/tests/test_plotting.py b/geopandas/tests/test_plotting.py
index 660693b6..096bc3de 100644
--- a/geopandas/tests/test_plotting.py
+++ b/geopandas/tests/test_plotting.py
@@ -877,22 +877,40 @@ class TestGeographicAspect:
     def test_manual(self):
         ax = self.north.geometry.plot(aspect="equal")
         assert ax.get_aspect() in ["equal", 1.0]
+        self.north.geometry.plot(ax=ax, aspect=None)
+        assert ax.get_aspect() in ["equal", 1.0]
         ax2 = self.north.geometry.plot(aspect=0.5)
         assert ax2.get_aspect() == 0.5
+        self.north.geometry.plot(ax=ax2, aspect=None)
+        assert ax2.get_aspect() == 0.5
         ax3 = self.north_proj.geometry.plot(aspect=0.5)
         assert ax3.get_aspect() == 0.5
+        self.north_proj.geometry.plot(ax=ax3, aspect=None)
+        assert ax3.get_aspect() == 0.5
         ax = self.north.plot(aspect="equal")
         assert ax.get_aspect() in ["equal", 1.0]
+        self.north.plot(ax=ax, aspect=None)
+        assert ax.get_aspect() in ["equal", 1.0]
         ax2 = self.north.plot(aspect=0.5)
         assert ax2.get_aspect() == 0.5
+        self.north.plot(ax=ax2, aspect=None)
+        assert ax2.get_aspect() == 0.5
         ax3 = self.north_proj.plot(aspect=0.5)
         assert ax3.get_aspect() == 0.5
+        self.north_proj.plot(ax=ax3, aspect=None)
+        assert ax3.get_aspect() == 0.5
         ax = self.north.plot("pop_est", aspect="equal")
         assert ax.get_aspect() in ["equal", 1.0]
+        self.north.plot("pop_est", ax=ax, aspect=None)
+        assert ax.get_aspect() in ["equal", 1.0]
         ax2 = self.north.plot("pop_est", aspect=0.5)
         assert ax2.get_aspect() == 0.5
+        self.north.plot("pop_est", ax=ax2, aspect=None)
+        assert ax2.get_aspect() == 0.5
         ax3 = self.north_proj.plot("pop_est", aspect=0.5)
         assert ax3.get_aspect() == 0.5
+        self.north_proj.plot("pop_est", ax=ax3, aspect=None)
+        assert ax3.get_aspect() == 0.5
 
 
 class TestMapclassifyPlotting: