Repository: geopandas/geopandas

Issue:
cmap/norm not persisting when passed as arguments
Mentioned this briefly on gitter, but I'm having trouble with my color map and norm persisting across multiple calls to plot on version 0.4.0. xref:#730, #420. 

First I set up a cmap and norm:
```python
import matplotlib as mpl
cmap = mpl.cm.viridis_r
norm = mpl.colors.BoundaryNorm([4e7, 6e7, 8e7, 1e8, 2e8, 4e8, 1e9, 1.2e9], cmap.N)
```
I get the colors I expect when using the .plot method on the entire geodataframe:
```python
_ = geoAO.plot('AwardOutrightAdjusted', ax=ax, cmap=cmap, norm=norm)
```
![index](https://user-images.githubusercontent.com/1300499/49424026-5a17c700-f767-11e8-9086-ea4b95eff444.png)

But when I try to break the dataframe up using subplots or inset axes, the insets/subplots don't respect the cmap/norm I've set. [also tried explicitly setting the facecolor as a test and that didn't work either].
__Just Alaska__
![index5](https://user-images.githubusercontent.com/1300499/49424541-e4acf600-f768-11e8-9085-542e7f63545c.png)
```python
fig, ax = plt.subplots()
geoAO[geoAO['postal'].str.match('AK')].plot('AwardOutrightAdjusted', ax=ax, cmap=cmap, norm=norm)
```
__inset__
![indexinset](https://user-images.githubusercontent.com/1300499/49424216-f0e48380-f767-11e8-82c3-625f376a2cd6.png)
```
fig, ax = plt.subplots(figsize=(15,10))
im = geoAO[~geoAO['postal'].isin(['AK','HI'])].plot('AwardOutrightAdjusted', ax=ax, cmap=cmap, norm=norm)
                                                    
axa = ax.inset_axes([-127, 23, 10, 10], transform=ax.transData)
_ = geoAO[geoAO['postal'].str.match('AK')].plot('AwardOutrightAdjusted', ax=axa, cmap=cmap, norm=norm)

axh = ax.inset_axes([-75, 25, 9, 9], transform=ax.transData)
_ = geoAO[geoAO['postal'].str.match('HI')].plot('AwardOutrightAdjusted', ax=axh, cmap=cmap, norm=norm)
```
__gridspec__
![indexsub](https://user-images.githubusercontent.com/1300499/49424168-d0b4c480-f767-11e8-9d41-09bf1d6cc3f0.png)
```python
import matplotlib.gridspec as gridspec
gs = gridspec.GridSpec(2, 2, width_ratios=[2,1])
fig = plt.figure()
ax1 = fig.add_subplot(gs[:,0])
ax2 = fig.add_subplot(gs[0,1])
ax3 = fig.add_subplot(gs[1,1])

_ = geoAO[~geoAO['postal'].isin(['AK','HI'])].plot('AwardOutrightAdjusted', ax=ax1, cmap=cmap, norm=norm)
_ = geoAO[geoAO['postal'].str.match('AK')].plot('AwardOutrightAdjusted', ax=ax2, cmap=cmap, norm=norm)
_ = geoAO[geoAO['postal'].str.match('HI')].plot('AwardOutrightAdjusted', ax=ax3, cmap=cmap, norm=norm)
```


Discussion:
**Workaround**  
I found that this works fine if giving each `plot` call a new instance of the same norm, in the sense of 

```
norm1 = mpl.colors.BoundaryNorm([4e7, 6e7, 8e7, 1e8, 2e8, 4e8, 1e9, 1.2e9], cmap.N)
norm2 = mpl.colors.BoundaryNorm([4e7, 6e7, 8e7, 1e8, 2e8, 4e8, 1e9, 1.2e9], cmap.N)

mainland.plot(..., norm=norm1, ax=ax1, legend=False)
alaska.plot(..., norm=norm2, ax=ax2, legend=False)

# now create colorbar manually
fig.colorbar(ax1.collections[0], ax=ax1)
```

**To fix this:**

https://github.com/geopandas/geopandas/blob/8a61854a156434e0c5377f5eae3a352362f6c9a4/geopandas/plotting.py#L106-L109

needs to look like

    if values is not None:
        collection.set_array(np.asarray(values))
        collection.set_cmap(cmap)
        if not kwargs.get("norm", None):
            collection.set_clim(vmin, vmax)

same for other collections.

Also,

https://github.com/geopandas/geopandas/blob/8a61854a156434e0c5377f5eae3a352362f6c9a4/geopandas/plotting.py#L513

needs to look like

        norm = style_kwds.get("norm", None)
        if not norm:
            norm = Normalize(vmin=mn, vmax=mx)


With those fixes, the code can be simplified to

```
norm = mpl.colors.BoundaryNorm([4e7, 6e7, 8e7, 1e8, 2e8, 4e8, 1e9, 1.2e9], cmap.N)

mainland.plot(..., norm=norm, ax=ax1, legend=True)
alaska.plot(..., norm=norm, ax=ax2, legend=False)
```

Resolving patch:
diff --git a/geopandas/plotting.py b/geopandas/plotting.py
--- a/geopandas/plotting.py
+++ b/geopandas/plotting.py
@@ -115,7 +115,8 @@ def plot_polygon_collection(
     if values is not None:
         collection.set_array(np.asarray(values))
         collection.set_cmap(cmap)
-        collection.set_clim(vmin, vmax)
+        if "norm" not in kwargs:
+            collection.set_clim(vmin, vmax)
 
     ax.add_collection(collection, autolim=True)
     ax.autoscale_view()
@@ -173,7 +174,8 @@ def plot_linestring_collection(
     if values is not None:
         collection.set_array(np.asarray(values))
         collection.set_cmap(cmap)
-        collection.set_clim(vmin, vmax)
+        if "norm" not in kwargs:
+            collection.set_clim(vmin, vmax)
 
     ax.add_collection(collection, autolim=True)
     ax.autoscale_view()
@@ -233,9 +235,12 @@ def plot_point_collection(
         if pd.api.types.is_list_like(color):
             color = np.take(color, multiindex)
 
-    collection = ax.scatter(
-        x, y, color=color, vmin=vmin, vmax=vmax, cmap=cmap, marker=marker, **kwargs
-    )
+    if "norm" not in kwargs:
+        collection = ax.scatter(
+            x, y, color=color, vmin=vmin, vmax=vmax, cmap=cmap, marker=marker, **kwargs
+        )
+    else:
+        collection = ax.scatter(x, y, color=color, cmap=cmap, marker=marker, **kwargs)
 
     return collection
 


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
@@ -176,6 +176,19 @@ def test_legend(self):
         # last point == top of colorbar
         np.testing.assert_array_equal(point_colors[-1], cbar_colors[-1])
 
+    def test_subplots_norm(self):
+        # colors of subplots are the same as for plot (norm is applied)
+        cmap = matplotlib.cm.viridis_r
+        norm = matplotlib.colors.Normalize(vmin=0, vmax=20)
+        ax = self.df.plot(column="values", cmap=cmap, norm=norm)
+        actual_colors_orig = ax.collections[0].get_facecolors()
+        exp_colors = cmap(np.arange(10) / (20))
+        np.testing.assert_array_equal(exp_colors, actual_colors_orig)
+        fig, ax = plt.subplots()
+        self.df[1:].plot(column="values", ax=ax, norm=norm, cmap=cmap)
+        actual_colors_sub = ax.collections[0].get_facecolors()
+        np.testing.assert_array_equal(actual_colors_orig[1], actual_colors_sub[0])
+
     def test_empty_plot(self):
         s = GeoSeries([])
         with pytest.warns(UserWarning):
@@ -264,6 +277,19 @@ def test_style_kwargs(self):
             assert ls[0] == exp_ls[0]
             assert ls[1] == exp_ls[1]
 
+    def test_subplots_norm(self):
+        # colors of subplots are the same as for plot (norm is applied)
+        cmap = matplotlib.cm.viridis_r
+        norm = matplotlib.colors.Normalize(vmin=0, vmax=20)
+        ax = self.df.plot(column="values", cmap=cmap, norm=norm)
+        actual_colors_orig = ax.collections[0].get_edgecolors()
+        exp_colors = cmap(np.arange(10) / (20))
+        np.testing.assert_array_equal(exp_colors, actual_colors_orig)
+        fig, ax = plt.subplots()
+        self.df[1:].plot(column="values", ax=ax, norm=norm, cmap=cmap)
+        actual_colors_sub = ax.collections[0].get_edgecolors()
+        np.testing.assert_array_equal(actual_colors_orig[1], actual_colors_sub[0])
+
     def test_multilinestrings(self):
 
         # MultiLineStrings
@@ -411,6 +437,19 @@ def test_multipolygons(self):
         # colors are repeated for all components within a MultiPolygon
         _check_colors(4, ax.collections[0].get_facecolors(), ["r", "r", "b", "b"])
 
+    def test_subplots_norm(self):
+        # colors of subplots are the same as for plot (norm is applied)
+        cmap = matplotlib.cm.viridis_r
+        norm = matplotlib.colors.Normalize(vmin=0, vmax=10)
+        ax = self.df.plot(column="values", cmap=cmap, norm=norm)
+        actual_colors_orig = ax.collections[0].get_facecolors()
+        exp_colors = cmap(np.arange(2) / (10))
+        np.testing.assert_array_equal(exp_colors, actual_colors_orig)
+        fig, ax = plt.subplots()
+        self.df[1:].plot(column="values", ax=ax, norm=norm, cmap=cmap)
+        actual_colors_sub = ax.collections[0].get_facecolors()
+        np.testing.assert_array_equal(actual_colors_orig[1], actual_colors_sub[0])
+
 
 class TestPolygonZPlotting:
     def setup_method(self):