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:
ImportanceOfBeingErnest: Worth noting that my proposition contained two fixes; this PR only implements one of them. (Best test with and without "legend")

Also, `plot_point_collection` may exhibit a similar problem when it comes to norms, I did not look at it at all.
martinfleis: @ImportanceOfBeingErnest the second one fixing the behaviour of a legend is in #1089. I fixed it before I properly looked at your suggestions. 

Yes, it seems that point collections are affected as well, but it seems to be a bit more tricky. Will have a look later. Good catch.
codecov[bot]: # [Codecov](https://codecov.io/gh/geopandas/geopandas/pull/1091?src=pr&el=h1) Report
> Merging [#1091](https://codecov.io/gh/geopandas/geopandas/pull/1091?src=pr&el=desc) into [master](https://codecov.io/gh/geopandas/geopandas/commit/8c42164559173972e7a4bafe705bbb2987d15d47?src=pr&el=desc) will **decrease** coverage by `0.03%`.
> The diff coverage is `100%`.

[![Impacted file tree graph](https://codecov.io/gh/geopandas/geopandas/pull/1091/graphs/tree.svg?width=650&token=6TOPMcCBhB&height=150&src=pr)](https://codecov.io/gh/geopandas/geopandas/pull/1091?src=pr&el=tree)

```diff
@@            Coverage Diff             @@
##           master    #1091      +/-   ##
==========================================
- Coverage    90.2%   90.16%   -0.04%     
==========================================
  Files          19       20       +1     
  Lines        1837     1911      +74     
==========================================
+ Hits         1657     1723      +66     
- Misses        180      188       +8
```


| [Impacted Files](https://codecov.io/gh/geopandas/geopandas/pull/1091?src=pr&el=tree) | Coverage Δ | |
|---|---|---|
| [geopandas/plotting.py](https://codecov.io/gh/geopandas/geopandas/pull/1091/diff?src=pr&el=tree#diff-Z2VvcGFuZGFzL3Bsb3R0aW5nLnB5) | `93.33% <100%> (+0.05%)` | :arrow_up: |
| [geopandas/\_\_init\_\_.py](https://codecov.io/gh/geopandas/geopandas/pull/1091/diff?src=pr&el=tree#diff-Z2VvcGFuZGFzL19faW5pdF9fLnB5) | `100% <0%> (ø)` | :arrow_up: |
| [geopandas/tools/\_show\_versions.py](https://codecov.io/gh/geopandas/geopandas/pull/1091/diff?src=pr&el=tree#diff-Z2VvcGFuZGFzL3Rvb2xzL19zaG93X3ZlcnNpb25zLnB5) | `88.23% <0%> (ø)` | |

------

[Continue to review full report at Codecov](https://codecov.io/gh/geopandas/geopandas/pull/1091?src=pr&el=continue).
> **Legend** - [Click here to learn more](https://docs.codecov.io/docs/codecov-delta)
> `Δ = absolute <relative> (impact)`, `ø = not affected`, `? = missing data`
> Powered by [Codecov](https://codecov.io/gh/geopandas/geopandas/pull/1091?src=pr&el=footer). Last update [8c42164...fec1de4](https://codecov.io/gh/geopandas/geopandas/pull/1091?src=pr&el=lastupdated). Read the [comment docs](https://docs.codecov.io/docs/pull-request-comments).


Patch:
diff --git a/doc/source/contributing.rst b/doc/source/contributing.rst
index 18f75385..7cbbe410 100644
--- a/doc/source/contributing.rst
+++ b/doc/source/contributing.rst
@@ -32,21 +32,25 @@ In particular, when submitting a pull request:
 
 - Classes, methods, functions, etc. should have docstrings.  The first
   line of a docstring should be a standalone summary.  Parameters and
-  return values should be ducumented explicitly.
+  return values should be documented explicitly.
 
-- GeoPandas supports python 2 (2.6+) and python 3 (3.2+) with a single
+- GeoPandas supports python 2 (2.7+) and python 3 (3.5+) with a single
   code base.  Use modern python idioms when possible that are
-  compatibile with both major versions, and use the
+  compatible with both major versions, and use the
   `six <https://pythonhosted.org/six>`_ library where helpful to smooth
   over the differences.  Use ``from __future__ import`` statements where
   appropriate.  Test code locally in both python 2 and python 3 when
   possible (all supported versions will be automatically tested on
   Travis CI).
 
-- Follow PEP 8 when possible.
+- Follow PEP 8 when possible. We use `Black
+  <https://black.readthedocs.io/en/stable/>`_ and `Flake8
+  <http://flake8.pycqa.org/en/latest/>`_ to ensure a consistent code
+  format throughout the project. For more details see
+  :ref:`below <contributing_style>`.
 
 - Imports should be grouped with standard library imports first,
-  3rd-party libraries next, and geopandas imports third.  Within each
+  3rd-party libraries next, and GeoPandas imports third.  Within each
   grouping, imports should be alphabetized.  Always use absolute
   imports when possible, and explicit relative imports for local
   imports when necessary in tests.
@@ -55,12 +59,12 @@ In particular, when submitting a pull request:
 Seven Steps for Contributing
 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~
 
-There are seven basic steps to contributing to *geopandas*:
+There are seven basic steps to contributing to *GeoPandas*:
 
-1) Fork the *geopandas* git repository
+1) Fork the *GeoPandas* git repository
 2) Create a development environment
-3) Install *geopandas* dependencies
-4) Make a ``development`` build of *geopandas*
+3) Install *GeoPandas* dependencies
+4) Make a ``development`` build of *GeoPandas*
 5) Make changes to code and add tests
 6) Update the documentation
 7) Submit a Pull Request
@@ -68,10 +72,10 @@ There are seven basic steps to contributing to *geopandas*:
 Each of these 7 steps is detailed below.
 
 
-1) Forking the *geopandas* repository using Git
+1) Forking the *GeoPandas* repository using Git
 ------------------------------------------------
 
-To the new user, working with Git is one of the more daunting aspects of contributing to *geopandas**.
+To the new user, working with Git is one of the more daunting aspects of contributing to *GeoPandas**.
 It can very quickly become overwhelming, but sticking to the guidelines below will help keep the process
 straightforward and mostly trouble free.  As always, if you are having difficulties please
 feel free to ask for help.
@@ -89,7 +93,7 @@ Some great resources for learning Git:
 * Matthew Brett's `Pydagogue <http://matthew-brett.github.com/pydagogue/>`_.
 
 Getting started with Git
-~~~~~~~~~~~~~~~~~~~~~~~~~
+~~~~~~~~~~~~~~~~~~~~~~~~
 
 `GitHub has instructions <http://help.github.com/set-up-git-redirect>`__ for installing git,
 setting up your SSH key, and configuring git.  All these steps need to be completed before
@@ -98,9 +102,9 @@ you can work seamlessly between your local repository and GitHub.
 .. _contributing.forking:
 
 Forking
-~~~~~~~~
+~~~~~~~
 
-You will need your own fork to work on the code. Go to the `geopandas project
+You will need your own fork to work on the code. Go to the `GeoPandas project
 page <https://github.com/geopandas/geopandas>`_ and hit the ``Fork`` button. You will
 want to clone your fork to your machine::
 
@@ -109,7 +113,7 @@ want to clone your fork to your machine::
     git remote add upstream git://github.com/geopandas/geopandas.git
 
 This creates the directory `geopandas-yourname` and connects your repository to
-the upstream (main project) *geopandas* repository.
+the upstream (main project) *GeoPandas* repository.
 
 The testing suite will run automatically on Travis-CI once your pull request is
 submitted.  However, if you wish to run the test suite on a branch prior to
@@ -132,7 +136,7 @@ The above can be simplified to::
 
 This changes your working directory to the shiny-new-feature branch.  Keep any
 changes in this branch specific to one bug or feature so it is clear
-what the branch brings to *geopandas*. You can have many shiny-new-features
+what the branch brings to *GeoPandas*. You can have many shiny-new-features
 and switch in between them using the git checkout command.
 
 To update this branch, you need to retrieve the changes from the master branch::
@@ -140,7 +144,7 @@ To update this branch, you need to retrieve the changes from the master branch::
     git fetch upstream
     git rebase upstream/master
 
-This will replay your commits on top of the latest geopandas git master.  If this
+This will replay your commits on top of the latest GeoPandas git master.  If this
 leads to merge conflicts, you must resolve these before submitting your pull
 request.  If you have uncommitted changes, you will need to ``stash`` them prior
 to updating.  This will effectively store your changes and they can be reapplied
@@ -150,11 +154,11 @@ after updating.
 
 2) Creating a development environment
 ---------------------------------------
-A development environment is a virtual space where you can keep an independent installation of *geopandas*.
+A development environment is a virtual space where you can keep an independent installation of *GeoPandas*.
 This makes it easy to keep both a stable version of python in one place you use for work, and a development
 version (which you may break while playing with code) in another.
 
-An easy way to create a *geopandas* development environment is as follows:
+An easy way to create a *GeoPandas* development environment is as follows:
 
 - Install either `Anaconda <http://docs.continuum.io/anaconda/>`_ or
   `miniconda <http://conda.pydata.org/miniconda.html>`_
@@ -164,24 +168,18 @@ An easy way to create a *geopandas* development environment is as follows:
 Tell conda to create a new environment, named ``geopandas_dev``, or any other name you would like
 for this environment, by running::
 
-      conda create -n geopandas_dev
-
-For a python 3 environment::
-
-      conda create -n geopandas_dev python=3.4
+      conda create -n geopandas_dev python
 
 This will create the new environment, and not touch any of your existing environments,
 nor any existing python installation.
 
-To work in this environment, Windows users should ``activate`` it as follows::
-
-      activate geopandas_dev
+To work in this environment, you need to ``activate`` it. The instructions below
+should work for both Windows, Mac and Linux::
 
-Mac OSX and Linux users should use::
+      conda activate geopandas_dev
 
-      source activate geopandas_dev
-
-You will then see a confirmation message to indicate you are in the new development environment.
+Once your environment is activated, you will see a confirmation message to
+indicate you are in the new development environment.
 
 To view your environments::
 
@@ -189,7 +187,7 @@ To view your environments::
 
 To return to you home root environment::
 
-      deactivate
+      conda deactivate
 
 See the full conda docs `here <http://conda.pydata.org/docs>`__.
 
@@ -198,21 +196,20 @@ At this point you can easily do a *development* install, as detailed in the next
 3) Installing Dependencies
 --------------------------
 
-To run *geopandas* in an development environment, you must first install
-*geopandas*'s dependencies. We suggest doing so using the following commands
+To run *GeoPandas* in an development environment, you must first install
+*GeoPandas*'s dependencies. We suggest doing so using the following commands
 (executed after your development environment has been activated)::
 
-    conda install -c conda-forge fiona shapely pyproj rtree
-    conda install pandas
-
+    conda install -c conda-forge pandas fiona shapely pyproj rtree pytest
 
 This should install all necessary dependencies.
 
+
 4) Making a development build
 -----------------------------
 
 Once dependencies are in place, make an in-place build by navigating to the git
-clone of the *geopandas* repository and running::
+clone of the *GeoPandas* repository and running::
 
     python setup.py develop
 
@@ -220,7 +217,7 @@ clone of the *geopandas* repository and running::
 5) Making changes and writing tests
 -------------------------------------
 
-*geopandas* is serious about testing and strongly encourages contributors to embrace
+*GeoPandas* is serious about testing and strongly encourages contributors to embrace
 `test-driven development (TDD) <http://en.wikipedia.org/wiki/Test-driven_development>`_.
 This development process "relies on the repetition of a very short development cycle:
 first the developer writes an (initially failing) automated test case that defines a desired
@@ -229,10 +226,10 @@ So, before actually writing any code, you should write your tests.  Often the te
 taken from the original GitHub issue.  However, it is always worth considering additional
 use cases and writing corresponding tests.
 
-Adding tests is one of the most common requests after code is pushed to *geopandas*.  Therefore,
+Adding tests is one of the most common requests after code is pushed to *GeoPandas*.  Therefore,
 it is worth getting in the habit of writing tests ahead of time so this is never an issue.
 
-*geopandas* uses the `pytest testing system
+*GeoPandas* uses the `pytest testing system
 <http://doc.pytest.org/en/latest/>`_ and the convenient
 extensions in `numpy.testing
 <http://docs.scipy.org/doc/numpy/reference/routines.testing.html>`_.
@@ -253,16 +250,16 @@ Running the test suite
 ~~~~~~~~~~~~~~~~~~~~~~
 
 The tests can then be run directly inside your Git clone (without having to
-install *geopandas*) by typing::
+install *GeoPandas*) by typing::
 
     pytest
 
 6) Updating the Documentation
 -----------------------------
 
-*geopandas* documentation resides in the `doc` folder. Changes to the docs are
-make by modifying the appropriate file in the `source` folder within `doc`. 
-*geopandas* docs use reStructuredText syntax, `which is explained here <http://www.sphinx-doc.org/en/stable/rest.html#rst-primer>`_
+*GeoPandas* documentation resides in the `doc` folder. Changes to the docs are
+make by modifying the appropriate file in the `source` folder within `doc`.
+*GeoPandas* docs use reStructuredText syntax, `which is explained here <http://www.sphinx-doc.org/en/stable/rest.html#rst-primer>`_
 and the docstrings follow the `Numpy Docstring standard <https://github.com/numpy/numpy/blob/master/doc/HOWTO_DOCUMENT.rst.txt>`_.
 
 Once you have made your changes, you may try if they render correctly by
@@ -287,6 +284,41 @@ is usually quite straightforward.
 ------------------------------
 
 Once you've made changes and pushed them to your forked repository, you then
-submit a pull request to have them integrated into the *geopandas* code base.
+submit a pull request to have them integrated into the *GeoPandas* code base.
 
 You can find a pull request (or PR) tutorial in the `GitHub's Help Docs <https://help.github.com/articles/using-pull-requests/>`_.
+
+.. _contributing_style:
+
+Style Guide & Linting
+---------------------
+
+GeoPandas follows the `PEP8 <http://www.python.org/dev/peps/pep-0008/>`_ standard
+and uses `Black <https://black.readthedocs.io/en/stable/>`_ and
+`Flake8 <http://flake8.pycqa.org/en/latest/>`_ to ensure a consistent code
+format throughout the project.
+
+Continuous Integration (Travis CI) will run those tools and
+report any stylistic errors in your code. Therefore, it is helpful before
+submitting code to run the check yourself::
+
+   black geopandas
+   git diff upstream/master -u -- "*.py" | flake8 --diff
+
+to auto-format your code. Additionally, many editors have plugins that will
+apply ``black`` as you edit files.
+
+Optionally (but recommended), you can setup `pre-commit hooks <https://pre-commit.com/>`_
+to automatically run ``black`` and ``flake8`` when you make a git commit. This
+can be done by installing ``pre-commit``::
+
+   $ python -m pip install pre-commit
+
+From the root of the geopandas repository, you should then install the
+``pre-commit`` included in *GeoPandas*::
+
+   $ pre-commit install
+
+Then ``black`` and ``flake8`` will be run automatically
+each time you commit changes. You can skip these checks with
+``git commit --no-verify``.
diff --git a/geopandas/plotting.py b/geopandas/plotting.py
index 1d7b194f..476085cf 100644
--- 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
index 223a486b..ecb2d810 100644
--- a/geopandas/tests/test_plotting.py
+++ b/geopandas/tests/test_plotting.py
@@ -176,6 +176,19 @@ class TestPointPlotting:
         # 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 @@ class TestLineStringPlotting:
             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 @@ class TestPolygonPlotting:
         # 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):