[seaborn] 08/10: New upstream version 0.8.0

Andreas Tille tille at debian.org
Mon Jul 24 10:43:38 UTC 2017


This is an automated email from the git hooks/post-receive script.

tille pushed a commit to branch debian
in repository seaborn.

commit c4aff36c0abfe3050ea7e7f783bbc79ee87fcd7a
Author: Andreas Tille <tille at debian.org>
Date:   Mon Jul 24 11:49:05 2017 +0200

    New upstream version 0.8.0
---
 .travis.yml                                        |   15 +-
 LICENSE                                            |    4 +-
 Makefile                                           |    4 +-
 README.md                                          |   44 +-
 doc/Makefile                                       |    2 +
 doc/_static/favicon.ico                            |  Bin 0 -> 270398 bytes
 doc/_static/style.css                              |   16 +-
 doc/api.rst                                        |   69 +-
 doc/conf.py                                        |   15 +-
 doc/index.rst                                      |   22 +-
 doc/installing.rst                                 |   62 +-
 doc/introduction.rst                               |   33 +-
 doc/releases/v0.6.0.txt                            |    3 +
 doc/releases/v0.7.0.txt                            |    3 +
 doc/releases/v0.7.1.txt                            |    3 +
 doc/releases/v0.8.0.txt                            |   39 +
 doc/sphinxext/plot_generator.py                    |   14 +-
 doc/tutorial.rst                                   |    2 +-
 doc/tutorial/aesthetics.ipynb                      |   24 +-
 doc/tutorial/axis_grids.ipynb                      |   27 +-
 doc/tutorial/categorical.ipynb                     |   23 +-
 doc/tutorial/color_palettes.ipynb                  |   28 +-
 doc/tutorial/distributions.ipynb                   |    6 +-
 doc/tutorial/regression.ipynb                      |    4 +-
 doc/tutorial/tools/nb_to_doc.py                    |   10 +-
 doc/whatsnew.rst                                   |    2 +-
 examples/heatmap_annotation.py                     |    4 +-
 examples/horizontal_boxplot.py                     |   22 +-
 examples/interactplot.py                           |   21 -
 examples/jitter_stripplot.py                       |   34 +
 examples/large_distributions.py                    |   13 +
 examples/many_facets.py                            |    3 +
 examples/many_pairwise_correlations.py             |    9 +-
 examples/marginal_ticks.py                         |    2 +-
 examples/multiple_joint_kde.py                     |    2 +-
 examples/multiple_regression.py                    |   14 +-
 examples/network_correlations.py                   |   26 -
 examples/paired_pointplots.py                      |    4 +-
 examples/scatterplot_matrix.py                     |    4 +-
 examples/structured_heatmap.py                     |   20 +-
 examples/tips.csv                                  |  245 ---
 seaborn/__init__.py                                |    8 +-
 seaborn/apionly.py                                 |    7 +
 seaborn/axisgrid.py                                |  465 +++++-
 seaborn/categorical.py                             |  531 ++++---
 seaborn/cm.py                                      | 1056 +++++++++++++
 seaborn/distributions.py                           |  285 +---
 seaborn/external/husl.py                           |    2 +-
 seaborn/external/six.py                            |  371 ++++-
 seaborn/linearmodels.py                            | 1634 +-------------------
 seaborn/matrix.py                                  |  295 ++--
 seaborn/miscplot.py                                |   22 +-
 seaborn/palettes.py                                |   30 +-
 seaborn/rcmod.py                                   |    7 +-
 seaborn/{linearmodels.py => regression.py}         |  439 +-----
 seaborn/tests/test_axisgrid.py                     |  153 +-
 seaborn/tests/test_categorical.py                  |  204 ++-
 seaborn/tests/test_distributions.py                |  115 +-
 seaborn/tests/test_matrix.py                       |  115 +-
 seaborn/tests/test_palettes.py                     |    2 +-
 seaborn/tests/test_rcmod.py                        |    5 +-
 .../{test_linearmodels.py => test_regression.py}   |   22 +-
 seaborn/tests/test_utils.py                        |   64 +-
 seaborn/timeseries.py                              |   42 +-
 seaborn/utils.py                                   |   84 +-
 seaborn/widgets.py                                 |   20 +-
 setup.py                                           |    6 +-
 67 files changed, 3257 insertions(+), 3624 deletions(-)

diff --git a/.travis.yml b/.travis.yml
index 8c8b7cf..0b4a8b1 100644
--- a/.travis.yml
+++ b/.travis.yml
@@ -4,21 +4,14 @@ env:
   - PYTHON=2.7 DEPS=modern
   - PYTHON=2.7 DEPS=minimal
   - PYTHON=3.4 DEPS=modern
-  #- PYTHON=3.5 DEPS=modern
+  - PYTHON=3.5 DEPS=modern
 
 install:
   - conda update conda --yes
   - conda create -n testenv --yes pip python=$PYTHON
   - conda update conda --yes
   - source activate testenv
-  - if [ ${PYTHON:0:1} == "2" ];
-    then conda install --yes imaging; else
-    pip install pillow;
-    fi
   - conda install --yes --file testing/deps_${DEPS}_${PYTHON}.txt
-  - conda install ipython-notebook=2 --yes
-  #- pip install sphinx numpydoc sphinx_bootstrap_theme runipy
-  #- sudo apt-get install pandoc
   - pip install pep8==1.5  # Later versions get stricter...
   - pip install https://github.com/dcramer/pyflakes/tarball/master
   - pip install .
@@ -42,12 +35,6 @@ before_script:
   - if [ ${PYTHON:0:1} == "2" ]; then
     make lint;
     fi
-  #- if [ ${TRAVIS_PYTHON_VERSION:0:1} == "2" ]; then
-  #  cd doc;
-  #  make notebooks html;
-  #  cd ..;
-  #  fi
-
 script:
   - if [ $DEPS == 'modern' ];
     then nosetests --with-doctest;
diff --git a/LICENSE b/LICENSE
index c6b4209..aff43d5 100644
--- a/LICENSE
+++ b/LICENSE
@@ -1,4 +1,4 @@
-Copyright (c) 2012-2013, Michael L. Waskom
+Copyright (c) 2012-2016, Michael L. Waskom
 All rights reserved.
 
 Redistribution and use in source and binary forms, with or without
@@ -11,7 +11,7 @@ modification, are permitted provided that the following conditions are met:
   this list of conditions and the following disclaimer in the documentation
   and/or other materials provided with the distribution.
 
-* Neither the name of the {organization} nor the names of its
+* Neither the name of the project nor the names of its
   contributors may be used to endorse or promote products derived from
   this software without specific prior written permission.
 
diff --git a/Makefile b/Makefile
index 1d71ae1..f9d5aa7 100644
--- a/Makefile
+++ b/Makefile
@@ -15,8 +15,8 @@ coverage:
 
 lint:
 
-	pyflakes -x W seaborn
-	pep8 --exclude external seaborn
+	pyflakes -x W -X seaborn/external/six.py seaborn
+	pep8 --exclude external,cm.py seaborn
 
 hexstrip:
 
diff --git a/README.md b/README.md
index d9b81f4..e6c7272 100644
--- a/README.md
+++ b/README.md
@@ -1,53 +1,54 @@
-Seaborn: statistical data visualization
+seaborn: statistical data visualization
 =======================================
 
 <div class="row">
-<a href=http://stanford.edu/~mwaskom/software/seaborn/examples/anscombes_quartet.html>
-<img src="http://stanford.edu/~mwaskom/software/seaborn/_static/anscombes_quartet_thumb.png" height="135" width="135">
+<a href=http://seaborn.pydata.org/examples/anscombes_quartet.html>
+<img src="http://seaborn.pydata.org/_static/anscombes_quartet_thumb.png" height="135" width="135">
 </a>
 
-<a href=http://stanford.edu/~mwaskom/software/seaborn/examples/timeseries_from_dataframe.html>
-<img src="http://stanford.edu/~mwaskom/software/seaborn/_static/timeseries_from_dataframe_thumb.png" height="135" width="135">
+<a href=http://seaborn.pydata.org/examples/many_pairwise_correlations.html>
+<img src="http://seaborn.pydata.org/_static/many_pairwise_correlations_thumb.png" height="135" width="135">
 </a>
 
-<a href=http://stanford.edu/~mwaskom/software/seaborn/examples/distplot_options.html>
-<img src="http://stanford.edu/~mwaskom/software/seaborn/_static/distplot_options_thumb.png" height="135" width="135">
-</a>    
+<a href=http://seaborn.pydata.org/examples/many_facets.html>
+<img src="http://seaborn.pydata.org/_static/many_facets_thumb.png" height="135" width="135">
+</a>
+
+<a href=http://seaborn.pydata.org/examples/scatterplot_matrix.html>
+<img src="http://seaborn.pydata.org/_static/scatterplot_matrix_thumb.png" height="135" width="135">
+</a>
 
-<a href=http://stanford.edu/~mwaskom/software/seaborn/examples/regression_marginals.html>
-<img src="http://stanford.edu/~mwaskom/software/seaborn/_static/regression_marginals_thumb.png" height="135" width="135">
+<a href=http://seaborn.pydata.org/examples/hexbin_marginals.html>
+<img src="http://seaborn.pydata.org/_static/hexbin_marginals_thumb.png" height="135" width="135">
 </a>
 
-<a href=http://stanford.edu/~mwaskom/software/seaborn/examples/grouped_violinplots.html>
-<img src="http://stanford.edu/~mwaskom/software/seaborn/_static/grouped_violinplots_thumb.png" height="135" width="135">
+<a href=http://seaborn.pydata.org/examples/scatterplot_categorical.html>
+<img src="http://seaborn.pydata.org/_static/scatterplot_categorical_thumb.png" height="135" width="135">
 </a>
 
 </div>
 
 Seaborn is a Python visualization library based on matplotlib. It provides a high-level interface for drawing attractive statistical graphics.
 
-
 Documentation
 -------------
 
-Online documentation is available [here](http://stanford.edu/~mwaskom/software/seaborn/). It includes a high-level tutorial, detailed API documentation, and other useful info.
-
-There are docs for the development version [here](http://stanford.edu/~mwaskom/software/seaborn-dev/). These should more or less correspond with the github master branch, but they're not built automatically and thus may fall out of sync at times.
+Online documentation is available [here](http://seaborn.pydata.org/). It includes a high-level tutorial, detailed API documentation, and other useful info.
 
 Examples
 --------
 
-The documentation has an [example gallery](http://stanford.edu/~mwaskom/software/seaborn/examples/index.html) with short scripts showing how to use different parts of the package.
+The documentation has an [example gallery](http://seaborn.pydata.org/examples/index.html) with short scripts showing how to use different parts of the package.
 
 Citing
 ------
 
-Seaborn can be cited using a DOI provided through Zenodo: [![DOI](https://zenodo.org/badge/doi/10.5281/zenodo.45133.svg)](http://dx.doi.org/10.5281/zenodo.45133)
+Seaborn can be cited using a DOI provided through Zenodo: [![DOI](https://zenodo.org/badge/DOI/10.5281/zenodo.54844.svg)](https://doi.org/10.5281/zenodo.54844)
 
 Dependencies
 ------------
 
-- Python 2.7 or 3.3+
+- Python 2.7 or 3.4+
 
 ### Mandatory
 
@@ -55,7 +56,7 @@ Dependencies
 
 - [scipy](http://www.scipy.org/)
 
-- [matplotlib](http://matplotlib.sourceforge.net)
+- [matplotlib](http://matplotlib.org/)
 
 - [pandas](http://pandas.pydata.org/)
 
@@ -73,7 +74,7 @@ To install the released version, just do
 
 You may instead want to use the development version from Github, by running
 
-    pip install git+git://github.com/mwaskom/seaborn.git#egg=seaborn
+    pip install git+https://github.com/mwaskom/seaborn.git#egg=seaborn
 
 
 Testing
@@ -84,6 +85,7 @@ Testing
 To test seaborn, run `make test` in the source directory. This will run the
 unit-test and doctest suite (using `nose`).
 
+ 
 Development
 -----------
 
diff --git a/doc/Makefile b/doc/Makefile
index 9d1e410..e10872b 100644
--- a/doc/Makefile
+++ b/doc/Makefile
@@ -18,7 +18,9 @@ I18NSPHINXOPTS  = $(PAPEROPT_$(PAPER)) $(SPHINXOPTS) .
 
 help:
 	@echo "Please use \`make <target>' where <target> is one of"
+	@echo "  clean      to remove genrated output"
 	@echo "  html       to make standalone HTML files"
+	@echo "  notebooks   to make the Jupyter notebook-based tutorials"
 	@echo "  dirhtml    to make HTML files named index.html in directories"
 	@echo "  singlehtml to make a single large HTML file"
 	@echo "  pickle     to make pickle files"
diff --git a/doc/_static/favicon.ico b/doc/_static/favicon.ico
new file mode 100644
index 0000000..1145b96
Binary files /dev/null and b/doc/_static/favicon.ico differ
diff --git a/doc/_static/style.css b/doc/_static/style.css
index 2cb8474..6777c04 100644
--- a/doc/_static/style.css
+++ b/doc/_static/style.css
@@ -1,3 +1,17 @@
+h1 { font-size: 40px !important; }
+h2 { font-size: 32px !important; }
+h3 { font-size: 24px !important; }
+h4 { font-size: 18px !important; }
+h5 { font-size: 14px !important; }
+h6 { font-size: 10px !important; }
+
+footer a{
+
+    color: #4c72b0 !important;
+}
+a.reference {
+    color: #4c72b0 !important;
+}
 
 blockquote p {
     font-size: 14px !important;
@@ -9,7 +23,7 @@ blockquote {
 
 code {
     color: #49759c !important;
-    background-color: #f3f5f9 !important;
+    background-color: #ffffff !important;
 }
 
 .alert-info {
diff --git a/doc/api.rst b/doc/api.rst
index 1945900..7745bd6 100644
--- a/doc/api.rst
+++ b/doc/api.rst
@@ -5,6 +5,39 @@
 API reference
 =============
 
+.. _grid_api:
+
+Axis grids
+----------
+
+.. autosummary::
+   :toctree: generated/
+
+    FacetGrid
+    factorplot
+    lmplot
+    PairGrid
+    pairplot
+    JointGrid
+    jointplot
+
+.. _categorical_api:
+
+Categorical plots
+-----------------
+
+.. autosummary::
+    :toctree: generated/
+
+    stripplot
+    swarmplot
+    boxplot
+    violinplot
+    lvplot
+    pointplot
+    barplot
+    countplot
+
 .. _distribution_api:
 
 Distribution plots
@@ -13,8 +46,6 @@ Distribution plots
 .. autosummary::
     :toctree: generated/
 
-    jointplot
-    pairplot
     distplot
     kdeplot
     rugplot
@@ -27,28 +58,8 @@ Regression plots
 .. autosummary::
     :toctree: generated/
 
-    lmplot
     regplot
     residplot
-    interactplot
-    coefplot
-
-.. _categorical_api:
-
-Categorical plots
------------------
-
-.. autosummary::
-    :toctree: generated/
-
-    factorplot
-    boxplot
-    violinplot
-    stripplot
-    swarmplot
-    pointplot
-    barplot
-    countplot
 
 .. _matrix_api:
 
@@ -77,18 +88,6 @@ Miscellaneous plots
 
     palplot
 
-.. _grid_api:
-
-Axis grids
-----------
-
-.. autosummary::
-   :toctree: generated/
-
-    FacetGrid
-    PairGrid
-    JointGrid
-
 .. _style_api:
 
 Style frontend
@@ -150,5 +149,3 @@ Utility functions
     desaturate
     saturate
     set_hls_values
-    ci_to_errsize
-    axlabel
diff --git a/doc/conf.py b/doc/conf.py
index 96351fe..8a6785e 100644
--- a/doc/conf.py
+++ b/doc/conf.py
@@ -65,7 +65,8 @@ master_doc = 'index'
 
 # General information about the project.
 project = u'seaborn'
-copyright = u'2012-2015, Michael Waskom'
+import time
+copyright = u'2012-{}, Michael Waskom'.format(time.strftime("%Y"))
 
 # The version info for the project you're documenting, acts as replacement for
 # |version| and |release|, also used in various other places throughout the
@@ -124,12 +125,14 @@ html_theme = 'bootstrap'
 # documentation.
 html_theme_options = {
     'source_link_position': "footer",
-    'bootswatch_theme': "flatly",
+    'bootswatch_theme': "paper",
     'navbar_sidebarrel': False,
     'bootstrap_version': "3",
-    'navbar_links': [("API", "api"),
+    'navbar_links': [
+                     ("Gallery", "examples/index"),
                      ("Tutorial", "tutorial"),
-                     ("Gallery", "examples/index")],
+                     ("API", "api"),
+                     ],
 
     }
 
@@ -150,7 +153,7 @@ html_theme_path = sphinx_bootstrap_theme.get_html_theme_path()
 # The name of an image file (within the static path) to use as favicon of the
 # docs.  This file should be a Windows icon file (.ico) being 16x16 or 32x32
 # pixels large.
-#html_favicon = None
+html_favicon = "_static/favicon.ico"
 
 # Add any paths that contain custom static files (such as style sheets) here,
 # relative to this directory. They are copied after the builtin static files,
@@ -182,7 +185,7 @@ html_static_path = ['_static', 'example_thumbs']
 #html_split_index = False
 
 # If true, links to the reST sources are added to the pages.
-#html_show_sourcelink = True
+html_show_sourcelink = False
 
 # If true, "Created using Sphinx" is shown in the HTML footer. Default is True.
 #html_show_sphinx = True
diff --git a/doc/index.rst b/doc/index.rst
index a3e0f7b..a8437ac 100644
--- a/doc/index.rst
+++ b/doc/index.rst
@@ -19,7 +19,7 @@
 
     </style>
 
-Seaborn: statistical data visualization
+seaborn: statistical data visualization
 =======================================
 
 .. raw:: html
@@ -33,9 +33,9 @@ Seaborn: statistical data visualization
             <img src="_static/anscombes_quartet_thumb.png">
           </div>
         </a>
-        <a href="examples/many_pairwise_correlations.html">
+        <a href="examples/multiple_regression.html">
           <div class="col-md-2 thumbnail">
-            <img src="_static/many_pairwise_correlations_thumb.png">
+            <img src="_static/multiple_regression_thumb.png">
           </div>
         </a>
         <a href="examples/many_facets.html">
@@ -43,19 +43,19 @@ Seaborn: statistical data visualization
             <img src="_static/many_facets_thumb.png">
           </div>
         </a>
-        <a href="examples/scatterplot_matrix.html">
+        <a href="examples/structured_heatmap.html">
           <div class="col-md-2 thumbnail">
-            <img src="_static/scatterplot_matrix_thumb.png">
+            <img src="_static/structured_heatmap_thumb.png">
           </div>
         </a>
-        <a href="examples/hexbin_marginals.html">
+        <a href="examples/scatterplot_matrix.html">
           <div class="col-md-2 thumbnail">
-            <img src="_static/hexbin_marginals_thumb.png">
+            <img src="_static/scatterplot_matrix_thumb.png">
           </div>
         </a>
-        <a href="examples/scatterplot_categorical.html">
+        <a href="examples/horizontal_boxplot.html">
           <div class="col-md-2 thumbnail">
-            <img src="_static/scatterplot_categorical_thumb.png">
+            <img src="_static/horizontal_boxplot_thumb.png">
           </div>
         </a>
       </div>
@@ -92,8 +92,8 @@ To see the code or report a bug, please visit the `github repository
    whatsnew
    installing
    examples/index
-   api
    tutorial
+   api
 
 .. raw:: html
 
@@ -104,8 +104,8 @@ To see the code or report a bug, please visit the `github repository
 * Style functions: :ref:`API <style_api>` | :ref:`Tutorial <aesthetics_tutorial>`
 * Color palettes: :ref:`API <palette_api>` | :ref:`Tutorial <palette_tutorial>`
 * Distribution plots: :ref:`API <distribution_api>` | :ref:`Tutorial <distribution_tutorial>`
-* Regression plots: :ref:`API <regression_api>` | :ref:`Tutorial <regression_tutorial>`
 * Categorical plots: :ref:`API <categorical_api>` | :ref:`Tutorial <categorical_tutorial>`
+* Regression plots: :ref:`API <regression_api>` | :ref:`Tutorial <regression_tutorial>`
 * Axis grid objects: :ref:`API <grid_api>` | :ref:`Tutorial <grid_tutorial>`
  
 .. raw:: html
diff --git a/doc/installing.rst b/doc/installing.rst
index 0127a38..74819f3 100644
--- a/doc/installing.rst
+++ b/doc/installing.rst
@@ -6,25 +6,19 @@ Installing and getting started
 To install the released version of seaborn, you can use ``pip`` (i.e. ``pip
 install seaborn``). It's also possible to install the released version using
 ``conda`` (i.e. ``conda install seaborn``), although this may lag behind the
-version availible from PyPI.
+version available from PyPI.
 
 Alternatively, you can use ``pip`` to install the development version, with the
-command ``pip install git+git://github.com/mwaskom/seaborn.git#egg=seaborn``.
+command ``pip install git+https://github.com/mwaskom/seaborn.git``.
 Another option would be to to clone the `github repository
 <https://github.com/mwaskom/seaborn>`_ and install with ``pip install .`` from
 the source directory. Seaborn itself is pure Python, so installation should be
 reasonably straightforward.
 
-When using the development version, you may want to refer to the `development
-docs <http://stanford.edu/~mwaskom/software/seaborn-dev/>`_. Note that these
-are not built automatically and may at times fall out of sync with the actual
-master branch on github.
-
-
-Dependencies 
+Dependencies
 ~~~~~~~~~~~~
 
--  Python 2.7 or 3.3+
+-  Python 2.7 or 3.4+
 
 Mandatory dependencies
 ^^^^^^^^^^^^^^^^^^^^^^
@@ -33,7 +27,7 @@ Mandatory dependencies
 
 -  `scipy <http://www.scipy.org/>`__
 
--  `matplotlib <matplotlib.sourceforge.net>`__
+-  `matplotlib <http://matplotlib.org>`__
 
 -  `pandas <http://pandas.pydata.org/>`__
 
@@ -42,48 +36,26 @@ Recommended dependencies
 
 -  `statsmodels <http://statsmodels.sourceforge.net/>`__
 
-The `pip` installation script will attempt to download the mandatory
-dependencies if they do not exist at install-time.
-
-I recommend using seaborn with the `Anaconda distribution
-<https://store.continuum.io/cshop/anaconda/>`_, as this makes it easy to manage
-the main dependencies, which otherwise can be difficult to install. 
+The ``pip`` installation script will attempt to download the mandatory
+dependencies only if they do not exist at install-time.
 
-I attempt to keep seaborn importable and generally functional on the versions
-available through the stable Debian channels.  There may be cases where some
-more advanced features only work with newer versions of these dependencies,
-although these should be relatively rare.
+Unit tests aim to keep seaborn importable and generally functional on the
+versions available through the stable Debian channels.  There may be cases
+where some more advanced features only work with newer versions of these
+libraries, although these should be relatively rare.
 
 There are also some known bugs on older versions of matplotlib, so you should
 in general try to use a modern version. For many use cases, though, older
 matplotlibs will work fine.
 
-Seaborn is tested on the most recent versions offered through ``conda``.
-
-
-Importing seaborn
-~~~~~~~~~~~~~~~~~
-
-Seaborn will apply its default style parameters to the global matplotlib style
-dictionary when you import it. This will change the look of all plots,
-including those created by using matplotlib functions directly. To avoid this
-behavior and use the default matplotlib aesthetics (along with any
-customization in your ``matplotlibrc``), you can import the ``seaborn.apionly``
-namespace.
-
-Seaborn has several other pre-packaged styles along with high-level :ref:`tools
-<aesthetics_tutorial>` for managing them, so you should not limit yourself to the
-default aesthetics.
-
-By convention, ``seaborn`` is abbreviated to ``sns`` on import.
-
+Seaborn is also tested on the most recent versions offered through ``conda``.
 
 Testing
 ~~~~~~~
 
 To test seaborn, run ``make test`` in the root directory of the source
 distribution. This runs the unit test suite (which can also be exercised
-separately by running ``nosetests``). It also runs the code in the example 
+separately by running ``nosetests``). It also runs the code in the example
 notebooks to smoke-test a broader and more realistic range of example usage.
 
 The full set of tests requires an internet connection to download the example
@@ -105,14 +77,8 @@ report.
 Known issues
 ~~~~~~~~~~~~
 
-There is a `bug <https://github.com/matplotlib/matplotlib/issues/2654>`_ in the
-matplotlib OSX backend that causes unavoidable problems with some of the
-seaborn functions (particularly those that draw multi-panel figures). If you
-encounter this, you will want to try a `different backend
-<http://matplotlib.org/api/matplotlib_configuration_api.html>`_. In particular, this bug affects any multi-panel figure that internally calls the matplotlib ``tight_layout`` function.
-
 An unfortunate consequence of how the matplotlib marker styles work is that
 line-art markers (e.g. ``"+"``) or markers with ``facecolor`` set to ``"none"``
 will be invisible when the default seaborn style is in effect. This can be
 changed by using a different ``markeredgewidth`` (aliased to ``mew``) either in
-the function call or globally in the `rcParams`.
+the function call or globally in the ``rcParams``.
diff --git a/doc/introduction.rst b/doc/introduction.rst
index 761c5d2..2fec204 100644
--- a/doc/introduction.rst
+++ b/doc/introduction.rst
@@ -13,7 +13,7 @@ support for `numpy <http://www.numpy.org/>`_ and `pandas
 
 Some of the features that seaborn offers are
 
-- Several :ref:`built-in themes <aesthetics_tutorial>` that improve on the default matplotlib aesthetics
+- Several :ref:`built-in themes <aesthetics_tutorial>` for styling matplotlib graphics
 - Tools for choosing :ref:`color palettes <palette_tutorial>` to make beautiful plots that reveal patterns in your data
 - Functions for visualizing :ref:`univariate <distplot_options>` and :ref:`bivariate <joint_kde>` distributions or for :ref:`comparing <grouped_violinplots>` them between subsets of data
 - Tools that fit and visualize :ref:`linear regression <anscombes_quartet>` models for different kinds of :ref:`independent <pointplot_anova>` and :ref:`dependent <logistic_regression>` variables
@@ -33,24 +33,23 @@ set of arguments, and they expose a number of customizable options through
 additional parameters. Some of the functions plot directly into a matplotlib
 axes object, while others operate on an entire figure and produce plots with
 several panels. In the latter case, the plot is drawn using a Grid object that
-links the structure of the figure to the structure of the dataset in an
-abstract way.
-
-Because seaborn uses matplotlib, the graphics can be further tweaked using
-matplotlib tools and rendered with any of the matplotlib backends to generate
-publication-quality figures. Seaborn can also be used to target web-based
-graphics through the `mpld3 <http://mpld3.github.io/>`_ and `Bokeh
-<http://bokeh.pydata.org/>`_ libraries.
+links the structure of the figure to the structure of the dataset.
 
 Seaborn should be thought of as a complement to matplotlib, not a replacement
 for it. When using seaborn, it is likely that you will often invoke matplotlib
 functions directly to draw simpler plots already available through the
-``pyplot`` namespace. Further, while the seaborn functions aim to make plots
-that are reasonably "production ready" (including extracting semantic
-information from Pandas objects to add informative labels), full customization
-of the figures will require a sophisticated understanding of matplotlib objects.
-
-For more detailed information and copious examples of the syntax and resulting
-plots, you can check out the :ref:`example gallery <example_gallery>`,
-:ref:`tutorial <tutorial>` or :ref:`API reference <api_ref>`.
+``pyplot`` namespace. Further, the seaborn functions aim to make plots that are
+reasonably "production ready" (including extracting semantic information from
+Pandas objects to add informative labels), but full customization will reqiure
+changing attributes on the matplotlib objects directly. The combination of
+seaborn's high-level interface and matplotlib's customizability and wide range
+of backends makes it easy to generate publication-quality figures.
+
+The documentation is divided into three separate domains. The breadth of
+functionality offered by the package is demonstrated in a set of short scripts
+and rendered in the :ref:`example gallery <example_gallery>`. Some motivation
+behind the kind of plots that seaborn can help to make is explained in the
+:ref:`tutorial <tutorial>`. Authoritative documentation on the options afforded
+by each function and class can be found by consulting the :ref:`API reference
+<api_ref>`.
 
diff --git a/doc/releases/v0.6.0.txt b/doc/releases/v0.6.0.txt
index 0cfce7b..7bbd7ae 100644
--- a/doc/releases/v0.6.0.txt
+++ b/doc/releases/v0.6.0.txt
@@ -2,6 +2,9 @@
 v0.6.0 (June 2015)
 ------------------
 
+.. image:: https://zenodo.org/badge/DOI/10.5281/zenodo.19108.svg
+   :target: https://doi.org/10.5281/zenodo.19108
+
 This is a major release from 0.5. The main objective of this release was to unify the API for categorical plots, which means that there are some relatively large API changes in some of the older functions. See below for details of those changes, which may break code written for older versions of seaborn. There are also some new functions (:func:`stripplot`,  and :func:`countplot`), numerous enhancements to existing functions, and bug fixes.
 
 Additionally, the documentation has been completely revamped and expanded for the 0.6 release. Now, the API docs page for each function has multiple examples with embedded plots showing how to use the various options. These pages should be considered the most comprehensive resource for examples, and the tutorial pages are now streamlined and oriented towards a higher-level overview of the various features.
diff --git a/doc/releases/v0.7.0.txt b/doc/releases/v0.7.0.txt
index d809c10..0a6abbe 100644
--- a/doc/releases/v0.7.0.txt
+++ b/doc/releases/v0.7.0.txt
@@ -2,6 +2,9 @@
 v0.7.0 (January 2016)
 ---------------------
 
+.. image:: https://zenodo.org/badge/DOI/10.5281/zenodo.45133.svg
+   :target: https://doi.org/10.5281/zenodo.45133
+
 This is a major release from 0.6. The main new feature is :func:`swarmplot` which implements the beeswarm approach for drawing categorical scatterplots. There are also some performance improvements, bug fixes, and updates for compatibility with new versions of dependencies.
 
 - Added the :func:`swarmplot` function, which draws beeswarm plots. These are categorical scatterplots, similar to those produced by :func:`stripplot`, but position of the points on the categorical axis is chosen to avoid overlapping points. See the :ref:`categorical plot tutorial <categorical_tutorial>` for more information.
diff --git a/doc/releases/v0.7.1.txt b/doc/releases/v0.7.1.txt
index 3aacbf6..27dc99b 100644
--- a/doc/releases/v0.7.1.txt
+++ b/doc/releases/v0.7.1.txt
@@ -2,6 +2,9 @@
 v0.7.1 (June 2016)
 -------------------
 
+.. image:: https://zenodo.org/badge/DOI/10.5281/zenodo.54844.svg
+   :target: https://doi.org/10.5281/zenodo.54844
+
 - Added the ability to put "caps" on the error bars that are drawn by :func:`barplot` or :func:`pointplot` (and, by extension, :func:`factorplot`). Additionally, the line width of the error bars can now be controlled. These changes involve the new parameters ``capsize`` and ``errwidth``. See the `github pull request <https://github.com/mwaskom/seaborn/pull/898>`_ for examples of usage.
 
 - Improved the row and column colors display in :func:`clustermap`. It is now possible to pass Pandas objects for these elements and, when possible, the semantic information in the Pandas objects will be used to add labels to the plot. When Pandas objects are used, the color data is matched against the main heatmap based on the index, not on position. This is more accurate, but it may lead to different results if current code assumed positional matching.
diff --git a/doc/releases/v0.8.0.txt b/doc/releases/v0.8.0.txt
new file mode 100644
index 0000000..b99989b
--- /dev/null
+++ b/doc/releases/v0.8.0.txt
@@ -0,0 +1,39 @@
+
+v0.8.0 (July 2017)
+------------------
+
+- The default style is no longer applied when seaborn is imported. It is now necessary to explicitly call :func:`set` or one or more of :func:`set_style`, :func:`set_context`, and :func:`set_palette`. Correspondingly, the ``seaborn.apionly`` module has been deprecated.
+
+- Changed the behavior of :func:`heatmap` (and by extension :func:`clustermap`) when plotting divergent dataesets (i.e. when the ``center`` parameter is used). Instead of extending the lower and upper limits of the colormap to be symettrical around the ``center`` value, the colormap is modified so that its middle color corresponds to ``center``. This means that the full range of the colormap will not be used (unless the data or specified ``vmin`` and ``vmax`` are symettric), but the uppe [...]
+
+- Removed automatic detection of diverging data in :func:`heatmap` (and by extension :func:`clustermap`). If you want the colormap to be treated as diverging (see above), it is now necessary to specify the ``center`` value. When no colormap is specified, specifying ``center`` will still change the default to be one that is more appropriate for displaying diverging data.
+
+- Added four new colormaps, created using `viscm <https://github.com/matplotlib/viscm>`_ for perceptual uniformity. The new colormaps include two sequential colormaps ("rocket" and "mako") and two diverging colormaps ("icefire" and "vlag"). These colormaps are registered with matplotlib on seaborn input and the colormap objects can be accessed in the ``seaborn.cm`` namespace.
+
+- Changed the default :func:`heatmap` colormaps to be "rocket" (in the case of sequential data) or "icefire" (in the case of diverging data). Note that this change reverses the direction of the luminance ramp from the previous defaults. While potentially confusing and disruptive, this change better aligns the seaborn defaults with the new matplotlib default colormap ("viridis") and arguably better aligns the semantics of a "heat" map with the appearance of the colormap.
+
+- Added ``"auto"`` as a (default) option for tick labels in :func:`heatmap` and :func:`clustermap`. This will try to estimate how many ticks can be labeled without the text objects overlapping, which should improve performance for larger matrices.
+
+- Added the ``dodge`` parameter to :func:`boxplot`, :func:`violinplot`, and :func:`barplot` to allow use of ``hue`` without changing the position or width of the plot elements, as when the ``hue`` varible is not nested within the main categorical variable.
+
+- Correspondingly, the ``split`` parameter for :func:`stripplot` and :func:`swarmplot` has been renamed to ``dodge`` for consistency with the other categorical functions (and for differentiation from the meaning of ``split`` in :func:`violinplot`).
+
+- Added the ability to draw a colorbar for a bivariate :func:`kdeplot` with the ``cbar`` parameter (and related ``cbar_ax`` and ``cbar_kws`` parameters).
+
+- Added the ability to use error bars to show standard deviations rather than bootstrap confidence intervals in most statistical functions by putting ``ci="sd"``.
+
+- Allow side-specific offsets in :func:`despine`.
+
+- Figure size is no longer part of the seaborn plotting context parameters.
+
+- Put a cap on the number of bins used in :func:`jointplot` for ``type=="hex"`` to avoid hanging when the reference rule prescribes too many.
+
+- Turn off dendrogram axes in :func:`clustermap` rather than setting the background color to white.
+
+- New matplotlib qualitative palettes (e.g. "tab10") are now handled correctly.
+
+- Some modules and functions have been internally reorganized; there should be no effect on code that uses the ``seaborn`` namespace.
+
+- Added a deprecation warning to :func:`tsplot` function to indicate that it will be removed or replaced with a substantially altered version in a future release.
+
+- The ``interactplot`` and ``coefplot`` functions are officially deprecated and will be removed in a future release.
diff --git a/doc/sphinxext/plot_generator.py b/doc/sphinxext/plot_generator.py
index 46fbdf0..b5c056c 100644
--- a/doc/sphinxext/plot_generator.py
+++ b/doc/sphinxext/plot_generator.py
@@ -12,7 +12,8 @@ import glob
 import token
 import tokenize
 import shutil
-import json
+
+from seaborn.external import six
 
 import matplotlib
 matplotlib.use('Agg')
@@ -20,6 +21,12 @@ import matplotlib.pyplot as plt
 
 from matplotlib import image
 
+if six.PY3:
+    # Python 3 has no execfile
+    def execfile(filename, globals=None, locals=None):
+        with open(filename, "rb") as fp:
+            six.exec_(compile(fp.read(), filename, 'exec'), globals, locals)
+
 
 RST_TEMPLATE = """
 .. _{sphinx_tag}:
@@ -117,7 +124,7 @@ Example gallery
 
 
 def create_thumbnail(infile, thumbfile,
-                     width=300, height=300,
+                     width=275, height=275,
                      cx=0.5, cy=0.5, border=4):
     baseout, extout = op.splitext(thumbfile)
 
@@ -235,7 +242,8 @@ class ExampleGenerator(object):
 
         docstring = ''
         first_par = ''
-        tokens = tokenize.generate_tokens(lines.__iter__().next)
+        line_iter = lines.__iter__()
+        tokens = tokenize.generate_tokens(lambda: next(line_iter))
         for tok_type, tok_content, _, (erow, _), _ in tokens:
             tok_type = token.tok_name[tok_type]
             if tok_type in ('NEWLINE', 'COMMENT', 'NL', 'INDENT', 'DEDENT'):
diff --git a/doc/tutorial.rst b/doc/tutorial.rst
index 1967b87..03c2a39 100644
--- a/doc/tutorial.rst
+++ b/doc/tutorial.rst
@@ -19,8 +19,8 @@ Plotting functions
    :maxdepth: 2
 
    tutorial/distributions
-   tutorial/regression
    tutorial/categorical
+   tutorial/regression
 
 Structured grids
 ----------------
diff --git a/doc/tutorial/aesthetics.ipynb b/doc/tutorial/aesthetics.ipynb
index 49c7a2a..dd65a76 100644
--- a/doc/tutorial/aesthetics.ipynb
+++ b/doc/tutorial/aesthetics.ipynb
@@ -47,6 +47,7 @@
     "import numpy as np\n",
     "import matplotlib as mpl\n",
     "import matplotlib.pyplot as plt\n",
+    "import seaborn as sns\n",
     "np.random.seed(sum(map(ord, \"aesthetics\")))"
    ]
   },
@@ -93,7 +94,7 @@
    "cell_type": "raw",
    "metadata": {},
    "source": [
-    "To switch to seaborn defaults, simply import the package."
+    "To switch to seaborn defaults, simply call the :func:`set` function."
    ]
   },
   {
@@ -104,7 +105,7 @@
    },
    "outputs": [],
    "source": [
-    "import seaborn as sns\n",
+    "sns.set()\n",
     "sinplot()"
    ]
   },
@@ -112,7 +113,7 @@
    "cell_type": "raw",
    "metadata": {},
    "source": [
-    "The seaborn defaults break from the MATLAB inspired aesthetic of matplotlib to plot in more muted colors over a light gray background with white grid lines. We find that the grid aids in the use of figures for conveying quantitative information – in almost all cases, figures should be preferred to tables. The white-on-gray grid that is used by default avoids being obtrusive. The grid is particularly useful in giving structure to figures with multiple facets, which is central to some [...]
+    "(Note that in versions of seaborn prior to 0.8, :func:`set` was called on import. On later versions, it must be explicitly invoked).\n",
     "\n",
     "Seaborn splits matplotlib parameters into two independent groups. The first group sets the aesthetic style of the plot, and the second scales various elements of the figure so that it can be easily incorporated into different contexts.\n",
     "\n",
@@ -120,8 +121,8 @@
     "\n",
     ".. _axes_style:\n",
     "\n",
-    "Styling figures with :func:`axes_style` and :func:`set_style`\n",
-    "-------------------------------------------------------------\n",
+    "Seaborn figure styles\n",
+    "---------------------\n",
     "\n",
     "There are five preset seaborn themes: ``darkgrid``, ``whitegrid``, ``dark``, ``white``, and ``ticks``. They are each suited to different applications and personal preferences. The default theme is ``darkgrid``. As mentioned above, the grid helps the plot serve as a lookup table for quantitative information, and the white-on grey helps to keep the grid from competing with lines that represent data. The ``whitegrid`` theme is similar, but it is better suited to plots with heavy data e [...]
    ]
@@ -215,8 +216,8 @@
    "source": [
     ".. _remove_spines:\n",
     "\n",
-    "Removing spines with :func:`despine`\n",
-    "------------------------------------\n",
+    "Removing axes spines\n",
+    "--------------------\n",
     "\n",
     "Both the ``white`` and ``ticks`` styles can benefit from removing the top and right axes spines, which are not needed. It's impossible to do this through the matplotlib parameters, but you can call the seaborn function :func:`despine` to remove them:"
    ]
@@ -346,8 +347,8 @@
    "source": [
     ".. _plotting_context:\n",
     "\n",
-    "Scaling plot elements with :func:`plotting_context` and :func:`set_context`\n",
-    "---------------------------------------------------------------------------\n",
+    "Scaling plot elements\n",
+    "---------------------\n",
     "\n",
     "A separate set of parameters control the scale of plot elements, which should let you use the same code to make plots that are suited for use in settings where larger or smaller plots are appropriate.\n",
     "\n",
@@ -381,7 +382,6 @@
    "outputs": [],
    "source": [
     "sns.set_context(\"paper\")\n",
-    "plt.figure(figsize=(8, 6))\n",
     "sinplot()"
    ]
   },
@@ -394,7 +394,6 @@
    "outputs": [],
    "source": [
     "sns.set_context(\"talk\")\n",
-    "plt.figure(figsize=(8, 6))\n",
     "sinplot()"
    ]
   },
@@ -407,7 +406,6 @@
    "outputs": [],
    "source": [
     "sns.set_context(\"poster\")\n",
-    "plt.figure(figsize=(8, 6))\n",
     "sinplot()"
    ]
   },
@@ -460,7 +458,7 @@
    "name": "python",
    "nbconvert_exporter": "python",
    "pygments_lexer": "ipython2",
-   "version": "2.7.11"
+   "version": "2.7.12"
   }
  },
  "nbformat": 4,
diff --git a/doc/tutorial/axis_grids.ipynb b/doc/tutorial/axis_grids.ipynb
index 2f2cb04..7c51db9 100644
--- a/doc/tutorial/axis_grids.ipynb
+++ b/doc/tutorial/axis_grids.ipynb
@@ -20,11 +20,11 @@
    "cell_type": "raw",
    "metadata": {},
    "source": [
-    "When exploring medium-dimensional data, a useful approach is to draw multiple instances of the same plot on different subsets of your dataset. This technique is sometimes called either \"lattice\", or `\"trellis\" <http://netlib.bell-labs.com/cm/ms/departments/sia/project/trellis>`_ plotting, and it is related to the idea of `\"small multiples\" <http://en.wikipedia.org/wiki/Small_multiple>`_. It allows a viewer to quickly extract a large amount of information about complex data. Ma [...]
+    "When exploring medium-dimensional data, a useful approach is to draw multiple instances of the same plot on different subsets of your dataset. This technique is sometimes called either \"lattice\", or \"trellis\" plotting, and it is related to the idea of `\"small multiples\" <http://en.wikipedia.org/wiki/Small_multiple>`_. It allows a viewer to quickly extract a large amount of information about complex data. Matplotlib offers good support for making figures with multiple axes; sea [...]
     "\n",
     "To use these features, your data has to be in a Pandas DataFrame and it must take the form of what Hadley Whickam calls `\"tidy\" data <http://vita.had.co.nz/papers/tidy-data.pdf>`_. In brief, that means your dataframe should be structured such that each column is a variable and each row is an observation.\n",
     "\n",
-    "For advanced use, you can use the objects discussed in this part of the tutorial directly, which will provide maximum flexibility. Some seaborn functions (such as :func:`lmplot`, :func:`factorplot`, and :func:`pairplot`) also use them behind the scenes. Unlike other seaborn functions that are \"Axes-level\" and draw onto specific (possibly already-existing) matplotlib ``Axes`` without otherwise manipulating the figure, these higher-level functions create a figure when called and are [...]
+    "For advanced use, you can use the objects discussed in this part of the tutorial directly, which will provide maximum flexibility. Some seaborn functions (such as :func:`lmplot`, :func:`factorplot`, and :func:`pairplot`) also use them behind the scenes. Unlike other seaborn functions that are \"Axes-level\" and draw onto specific (possibly already-existing) matplotlib ``Axes`` without otherwise manipulating the figure, these higher-level functions create a figure when called and are [...]
    ]
   },
   {
@@ -72,8 +72,8 @@
    "source": [
     ".. _facet_grid:\n",
     "\n",
-    "Subsetting data with :class:`FacetGrid`\n",
-    "---------------------------------------\n",
+    "Plotting small multiples of data subsets\n",
+    "----------------------------------------\n",
     "\n",
     "The :class:`FacetGrid` class is useful when you want to visualize the distribution of a variable or the relationship between multiple variables separately within subsets of your dataset. A :class:`FacetGrid` can be drawn with up to three dimensions: ``row``, ``col``, and ``hue``. The first two have obvious correspondence with the resulting array of axes; think of the hue variable as a third dimension along a depth axis, where different levels are plotted with different colors.\n",
     "\n",
@@ -201,7 +201,7 @@
    "outputs": [],
    "source": [
     "titanic = sns.load_dataset(\"titanic\")\n",
-    "titanic = titanic.assign(deck=titanic.deck.astype(object)).sort(\"deck\")\n",
+    "titanic = titanic.assign(deck=titanic.deck.astype(object)).sort_values(\"deck\")\n",
     "g = sns.FacetGrid(titanic, col=\"class\", sharex=False,\n",
     "                  gridspec_kws={\"width_ratios\": [5, 3, 3]})\n",
     "g.map(sns.boxplot, \"deck\", \"age\");"
@@ -463,8 +463,8 @@
    "source": [
     ".. _pair_grid:\n",
     "\n",
-    "Plotting pairwise relationships with :class:`PairGrid` and :func:`pairplot`\n",
-    "---------------------------------------------------------------------------\n",
+    "Plotting pairwise relationships in a dataset\n",
+    "--------------------------------------------\n",
     "\n",
     ":class:`PairGrid` also allows you to quickly draw a grid of small subplots using the same plot type to visualize data in each. In a :class:`PairGrid`, each row and column is assigned to a different variable, so the resulting plot shows each pairwise relationship in the dataset. This style of plot is sometimes called a \"scatterplot matrix\", as this is the most common way to show each relationship, but :class:`PairGrid` is not limited to scatterplots.\n",
     "\n",
@@ -642,6 +642,15 @@
    "source": [
     "g = sns.pairplot(iris, hue=\"species\", palette=\"Set2\", diag_kind=\"kde\", size=2.5)"
    ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "metadata": {
+    "collapsed": true
+   },
+   "outputs": [],
+   "source": []
   }
  ],
  "metadata": {
@@ -660,9 +669,9 @@
    "name": "python",
    "nbconvert_exporter": "python",
    "pygments_lexer": "ipython2",
-   "version": "2.7.10"
+   "version": "2.7.12"
   }
  },
  "nbformat": 4,
  "nbformat_minor": 0
-}
\ No newline at end of file
+}
diff --git a/doc/tutorial/categorical.ipynb b/doc/tutorial/categorical.ipynb
index 82bb9e6..0f8661c 100644
--- a/doc/tutorial/categorical.ipynb
+++ b/doc/tutorial/categorical.ipynb
@@ -231,6 +231,25 @@
    "cell_type": "raw",
    "metadata": {},
    "source": [
+    "For boxplots, the assumption when using a ``hue`` variable is that it is nested within the ``x`` or ``y`` variable. This means that by default, the boxes for different levels of ``hue`` will be offset, as you can see above. If your ``hue`` variable is not nested, you can set the ``dodge`` parameter to disable offsetting:"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "metadata": {
+    "collapsed": false
+   },
+   "outputs": [],
+   "source": [
+    "tips[\"weekend\"] = tips[\"day\"].isin([\"Sat\", \"Sun\"])\n",
+    "sns.boxplot(x=\"day\", y=\"total_bill\", hue=\"weekend\", data=tips, dodge=False);"
+   ]
+  },
+  {
+   "cell_type": "raw",
+   "metadata": {},
+   "source": [
     "Violinplots\n",
     "^^^^^^^^^^^\n",
     "\n",
@@ -493,7 +512,7 @@
     "Drawing multi-panel categorical plots\n",
     "-------------------------------------\n",
     "\n",
-    "As we mentioned above, there are two ways to draw categorical plots in seaborn. Similar to the duality in the regression plots, you can either use the functions introduced above, or the higher-level function :func:`factorplot`, which combines these functions with a :func:`FacetGrid` to add the ability to examine additional categories through the larger structure of the figure. By default, :func:`factorplot` produces a :func:`pairplot`:"
+    "As we mentioned above, there are two ways to draw categorical plots in seaborn. Similar to the duality in the regression plots, you can either use the functions introduced above, or the higher-level function :func:`factorplot`, which combines these functions with a :func:`FacetGrid` to add the ability to examine additional categories through the larger structure of the figure. By default, :func:`factorplot` produces a :func:`pointplot`:"
    ]
   },
   {
@@ -613,7 +632,7 @@
    "name": "python",
    "nbconvert_exporter": "python",
    "pygments_lexer": "ipython2",
-   "version": "2.7.11"
+   "version": "2.7.12"
   }
  },
  "nbformat": 4,
diff --git a/doc/tutorial/color_palettes.ipynb b/doc/tutorial/color_palettes.ipynb
index 8f6cacb..a39d3c4 100644
--- a/doc/tutorial/color_palettes.ipynb
+++ b/doc/tutorial/color_palettes.ipynb
@@ -71,8 +71,8 @@
     "raw_mimetype": "text/restructuredtext"
    },
    "source": [
-    "Building color palettes with :func:`color_palette`\n",
-    "--------------------------------------------------\n",
+    "Building color palettes\n",
+    "-----------------------\n",
     "\n",
     "The most important function for working with discrete color palettes is :func:`color_palette`. This function provides an interface to many (though not all) of the possible ways you can generate colors in seaborn, and it's used internally by any function that has a ``palette`` argument (and in some cases for a ``color`` argument when multiple colors are needed).\n",
     "\n",
@@ -262,7 +262,7 @@
    "cell_type": "raw",
    "metadata": {},
    "source": [
-    "If you want to spend some time picking colors, this `interactive visualization <http://www.luminoso.com/colors/>`_ may be useful. In addition to pulling out single colors from the ``xkcd_rgb`` dictionary, you can also pass a list of names to the :func:`xkcd_palette` function."
+    "In addition to pulling out single colors from the ``xkcd_rgb`` dictionary, you can also pass a list of names to the :func:`xkcd_palette` function."
    ]
   },
   {
@@ -357,8 +357,8 @@
    "source": [
     ".. _cubehelix_palettes:\n",
     "\n",
-    "Sequential palettes with :func:`cubehelix_palette`\n",
-    "~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n",
+    "Sequential \"cubehelix\" palettes\n",
+    "~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n",
     "\n",
     "The `cubehelix <http://www.mrao.cam.ac.uk/~dag/CUBEHELIX/>`_ color palette system makes sequential palettes with a linear increase or decrease in brightness and some variation in hue. This means that the information in your colormap will be preserved when converted to black and white (for printing) or when viewed by a colorblind individual.\n",
     "\n",
@@ -463,8 +463,8 @@
    "cell_type": "raw",
    "metadata": {},
    "source": [
-    "Custom sequential palettes with :func:`light_palette` and :func:`dark_palette`\n",
-    "~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n",
+    "Custom sequential palettes\n",
+    "~~~~~~~~~~~~~~~~~~~~~~~~~~\n",
     "\n",
     "For a simpler interface to custom sequential palettes, you can use :func:`light_palette` or :func:`dark_palette`, which are both seeded with a single color and produce a palette that ramps either from light or dark desaturated values to that color. These functions are also accompanied by the :func:`choose_light_palette` and :func:`choose_dark_palette` functions that launch interactive widgets to create these palettes."
    ]
@@ -626,10 +626,10 @@
    "cell_type": "raw",
    "metadata": {},
    "source": [
-    "Custom diverging palettes with :func:`diverging_palette`\n",
-    "~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n",
+    "Custom diverging palettes\n",
+    "~~~~~~~~~~~~~~~~~~~~~~~~~\n",
     "\n",
-    "You can also use the seaborn function :func:`diverging_palette` to create a custom colormap for diverging data. (Naturally there is also a companion interactive widget, :func:`choose_diverging_palette`). This function makes diverging palettes using the ``husl`` color system. You pass it two hues (in degreees) and, optionally, the lightness and saturation values for the extremes. Using ``husl`` means that the extreme values, and the resulting ramps to the midpoint, will be well-balanced"
+    "You can also use the seaborn function :func:`diverging_palette` to create a custom colormap for diverging data. (Naturally there is also a companion interactive widget, :func:`choose_diverging_palette`). This function makes diverging palettes using the ``husl`` color system. You pass it two hues (in degrees) and, optionally, the lightness and saturation values for the extremes. Using ``husl`` means that the extreme values, and the resulting ramps to the midpoint, will be well-balanced"
    ]
   },
   {
@@ -696,8 +696,8 @@
    "source": [
     ".. _palette_contexts:\n",
     "\n",
-    "Changing default palettes with :func:`set_palette`\n",
-    "--------------------------------------------------\n",
+    "Setting the default color palette\n",
+    "---------------------------------\n",
     "\n",
     "The :func:`color_palette` function has a companion called :func:`set_palette`. The relationship between them is similar to the pairs covered in the :ref:`aesthetics tutorial <aesthetics_tutorial>`. :func:`set_palette` accepts the same arguments as :func:`color_palette`, but it changes the default matplotlib parameters so that the palette is used for all plots."
    ]
@@ -773,9 +773,9 @@
    "name": "python",
    "nbconvert_exporter": "python",
    "pygments_lexer": "ipython2",
-   "version": "2.7.9"
+   "version": "2.7.12"
   }
  },
  "nbformat": 4,
  "nbformat_minor": 0
-}
\ No newline at end of file
+}
diff --git a/doc/tutorial/distributions.ipynb b/doc/tutorial/distributions.ipynb
index 524430e..ae0eb94 100644
--- a/doc/tutorial/distributions.ipynb
+++ b/doc/tutorial/distributions.ipynb
@@ -20,7 +20,7 @@
    "cell_type": "raw",
    "metadata": {},
    "source": [
-    "When dealing with a set of data, often the first thing you'll want to do is get a sense for how the variables are distributed. This chapter of the tutorial will give a brief introduction to some of the tools in seborn for examining univariate and bivariate distributions. You may also want to look at the :ref:`categorical plots <categorical_tutorial>` chapter for examples of functions that make it easy to compare the distribution of a variable across levels of other variables."
+    "When dealing with a set of data, often the first thing you'll want to do is get a sense for how the variables are distributed. This chapter of the tutorial will give a brief introduction to some of the tools in seaborn for examining univariate and bivariate distributions. You may also want to look at the :ref:`categorical plots <categorical_tutorial>` chapter for examples of functions that make it easy to compare the distribution of a variable across levels of other variables."
    ]
   },
   {
@@ -291,7 +291,7 @@
     "Plotting bivariate distributions\n",
     "--------------------------------\n",
     "\n",
-    "It can also be useful to visualize a bivariate distribution of two variables. The easiest way to do this in seaborn is to just the :func:`jointplot` function, which creates a multi-panel figure that shows both the bivariate (or joint) relationship between two variables along with the univariate (or marginal) distribution of each on separate axes."
+    "It can also be useful to visualize a bivariate distribution of two variables. The easiest way to do this in seaborn is to just use the :func:`jointplot` function, which creates a multi-panel figure that shows both the bivariate (or joint) relationship between two variables along with the univariate (or marginal) distribution of each on separate axes."
    ]
   },
   {
@@ -335,7 +335,7 @@
     "Hexbin plots\n",
     "^^^^^^^^^^^^\n",
     "\n",
-    "The bivariate analogue of a histogram is known as a \"hexbin\" plot, because it shows the counts of observations that fall within hexagonal bins. This plot works best with relatively large datasets. It's availible through the matplotlib ``plt.hexbin`` function and as a style in :func:`jointplot`. It looks best with a white background:"
+    "The bivariate analogue of a histogram is known as a \"hexbin\" plot, because it shows the counts of observations that fall within hexagonal bins. This plot works best with relatively large datasets. It's available through the matplotlib ``plt.hexbin`` function and as a style in :func:`jointplot`. It looks best with a white background:"
    ]
   },
   {
diff --git a/doc/tutorial/regression.ipynb b/doc/tutorial/regression.ipynb
index 5eeb278..8763255 100644
--- a/doc/tutorial/regression.ipynb
+++ b/doc/tutorial/regression.ipynb
@@ -390,7 +390,7 @@
     "Conditioning on other variables\n",
     "-------------------------------\n",
     "\n",
-    "The plots above show many ways to explore the relationship between a pair of variables. Often, however, a more interesting question is \"how does the relationship between these two variables change as a function of a third variable?\" This is where the difference  between :func:`regplot` and :func:`lmplot` appears. While :func:`regplot` always shows a single relationsihp, :func:`lmplot` combines :func:`regplot` with :class:`FacetGrid` to provide an easy interface to show a linear re [...]
+    "The plots above show many ways to explore the relationship between a pair of variables. Often, however, a more interesting question is \"how does the relationship between these two variables change as a function of a third variable?\" This is where the difference  between :func:`regplot` and :func:`lmplot` appears. While :func:`regplot` always shows a single relationship, :func:`lmplot` combines :func:`regplot` with :class:`FacetGrid` to provide an easy interface to show a linear re [...]
     "\n",
     "The best way to separate out a relationship is to plot both levels on the same axes and to use color to distinguish them:"
    ]
@@ -462,7 +462,7 @@
     "Controlling the size and shape of the plot\n",
     "------------------------------------------\n",
     "\n",
-    "Before we noted that the default plots made by :func:`regplot` and :func:`lmplot` look the same but on axes that have a different size and shape. This is because func:`regplot` is an \"axes-level\" function draws onto a specific axes. This means that you can make mutli-panel figures yourself and control exactly where the the regression plot goes. If no axes is provided, it simply uses the \"currently active\" axes, which is why the default plot has the same size and shape as most ot [...]
+    "Before we noted that the default plots made by :func:`regplot` and :func:`lmplot` look the same but on axes that have a different size and shape. This is because :func:`regplot` is an \"axes-level\" function draws onto a specific axes. This means that you can make multi-panel figures yourself and control exactly where the regression plot goes. If no axes object is explictly provided, it simply uses the \"currently active\" axes, which is why the default plot has the same size and sh [...]
    ]
   },
   {
diff --git a/doc/tutorial/tools/nb_to_doc.py b/doc/tutorial/tools/nb_to_doc.py
index 47c3a73..c0a2cba 100755
--- a/doc/tutorial/tools/nb_to_doc.py
+++ b/doc/tutorial/tools/nb_to_doc.py
@@ -10,15 +10,15 @@ from subprocess import check_call as sh
 def convert_nb(nbname):
 
     # Execute the notebook
-    sh(["ipython", "nbconvert", "--to", "notebook",
-        "--execute", "--inplace", nbname + ".ipynb"])
+    sh(["jupyter", "nbconvert", "--to", "notebook",
+        "--execute", "--inplace", nbname])
 
     # Convert to .rst for Sphinx
-    sh(["ipython", "nbconvert", "--to", "rst", nbname + ".ipynb"])
+    sh(["jupyter", "nbconvert", "--to", "rst", nbname])
     
     # Clear notebook output
-    sh(["ipython", "nbconvert", "--to", "notebook", "--inplace",
-        "--ClearOutputPreprocessor.enabled=True", nbname + ".ipynb"])
+    sh(["jupyter", "nbconvert", "--to", "notebook", "--inplace",
+        "--ClearOutputPreprocessor.enabled=True", nbname])
 
 
 if __name__ == "__main__":
diff --git a/doc/whatsnew.rst b/doc/whatsnew.rst
index 902d861..4dfb93c 100644
--- a/doc/whatsnew.rst
+++ b/doc/whatsnew.rst
@@ -5,7 +5,7 @@
 What's new in the package
 =========================
 
-A catalog of new features, improvements, and bug-fixes in each release.
+.. include:: releases/v0.8.0.txt
 
 .. include:: releases/v0.7.1.txt
 
diff --git a/examples/heatmap_annotation.py b/examples/heatmap_annotation.py
index 33de576..7512dd3 100644
--- a/examples/heatmap_annotation.py
+++ b/examples/heatmap_annotation.py
@@ -3,6 +3,7 @@ Annotated heatmaps
 ==================
 
 """
+import matplotlib.pyplot as plt
 import seaborn as sns
 sns.set()
 
@@ -11,4 +12,5 @@ flights_long = sns.load_dataset("flights")
 flights = flights_long.pivot("month", "year", "passengers")
 
 # Draw a heatmap with the numeric values in each cell
-sns.heatmap(flights, annot=True, fmt="d", linewidths=.5)
+f, ax = plt.subplots(figsize=(9, 6))
+sns.heatmap(flights, annot=True, fmt="d", linewidths=.5, ax=ax)
diff --git a/examples/horizontal_boxplot.py b/examples/horizontal_boxplot.py
index 44995dd..84cf4bf 100644
--- a/examples/horizontal_boxplot.py
+++ b/examples/horizontal_boxplot.py
@@ -2,24 +2,30 @@
 Horizontal boxplot with observations
 ====================================
 
-_thumb: .7, .45
+_thumb: .7, .37
 """
 import numpy as np
 import seaborn as sns
-sns.set(style="ticks", palette="muted", color_codes=True)
+import matplotlib.pyplot as plt
+sns.set(style="ticks")
+
+# Initialize the figure
+f, ax = plt.subplots(figsize=(7, 6))
+ax.set_xscale("log")
 
 # Load the example planets dataset
 planets = sns.load_dataset("planets")
 
 # Plot the orbital period with horizontal boxes
-ax = sns.boxplot(x="distance", y="method", data=planets,
-                 whis=np.inf, color="c")
+sns.boxplot(x="distance", y="method", data=planets,
+            whis=np.inf, palette="vlag")
 
 # Add in points to show each observation
-sns.stripplot(x="distance", y="method", data=planets,
-              jitter=True, size=3, color=".3", linewidth=0)
+sns.swarmplot(x="distance", y="method", data=planets,
+              size=2, color=".3", linewidth=0)
 
 
 # Make the quantitative axis logarithmic
-ax.set_xscale("log")
-sns.despine(trim=True)
+ax.xaxis.grid(True)
+ax.set(ylabel="")
+sns.despine(trim=True, left=True)
diff --git a/examples/interactplot.py b/examples/interactplot.py
deleted file mode 100644
index 28ae928..0000000
--- a/examples/interactplot.py
+++ /dev/null
@@ -1,21 +0,0 @@
-"""
-Continuous interactions
-=======================
-
-"""
-import numpy as np
-import pandas as pd
-import seaborn as sns
-sns.set(style="darkgrid")
-
-# Generate a random dataset with strong simple effects and an interaction
-n = 80
-rs = np.random.RandomState(11)
-x1 = rs.randn(n)
-x2 = x1 / 5 + rs.randn(n)
-b0, b1, b2, b3 = .5, .25, -1, 2
-y = b0  + b1 * x1 + b2 * x2 + b3 * x1 * x2 + rs.randn(n)
-df = pd.DataFrame(np.c_[x1, x2, y], columns=["x1", "x2", "y"])
-
-# Show a scatterplot of the predictors with the estimated model surface
-sns.interactplot("x1", "x2", "y", df)
diff --git a/examples/jitter_stripplot.py b/examples/jitter_stripplot.py
new file mode 100644
index 0000000..f990ff0
--- /dev/null
+++ b/examples/jitter_stripplot.py
@@ -0,0 +1,34 @@
+"""
+Conditional means with observations
+===================================
+
+"""
+import pandas as pd
+import seaborn as sns
+import matplotlib.pyplot as plt
+
+sns.set(style="whitegrid")
+iris = sns.load_dataset("iris")
+
+# "Melt" the dataset to "long-form" or "tidy" representation
+iris = pd.melt(iris, "species", var_name="measurement")
+
+# Initialize the figure
+f, ax = plt.subplots()
+sns.despine(bottom=True, left=True)
+
+# Show each observation with a scatterplot
+sns.stripplot(x="value", y="measurement", hue="species",
+              data=iris, dodge=True, jitter=True,
+              alpha=.25, zorder=1)
+
+# Show the conditional means
+sns.pointplot(x="value", y="measurement", hue="species",
+              data=iris, dodge=.532, join=False, palette="dark",
+              markers="d", scale=.75, ci=None)
+
+# Improve the legend 
+handles, labels = ax.get_legend_handles_labels()
+ax.legend(handles[3:], labels[3:], title="species",
+          handletextpad=0, columnspacing=1,
+          loc="lower right", ncol=3, frameon=True)
diff --git a/examples/large_distributions.py b/examples/large_distributions.py
new file mode 100644
index 0000000..f8e4b14
--- /dev/null
+++ b/examples/large_distributions.py
@@ -0,0 +1,13 @@
+"""
+Plotting large distributions
+============================
+
+"""
+import seaborn as sns
+sns.set(style="whitegrid")
+
+networks = sns.load_dataset("brain_networks", index_col=0, header=[0, 1, 2])
+networks = networks.T.groupby(level="network").mean().T
+order = networks.std().sort_values().index
+
+sns.lvplot(data=networks, order=order, scale="linear", palette="mako")
diff --git a/examples/many_facets.py b/examples/many_facets.py
index 05cca4d..c4f23ea 100644
--- a/examples/many_facets.py
+++ b/examples/many_facets.py
@@ -2,11 +2,14 @@
 Plotting on a large number of facets
 ====================================
 
+_thumb: .35, .35
+
 """
 import numpy as np
 import pandas as pd
 import seaborn as sns
 import matplotlib.pyplot as plt
+
 sns.set(style="ticks")
 
 # Create a dataset with many short random walks
diff --git a/examples/many_pairwise_correlations.py b/examples/many_pairwise_correlations.py
index f43fc08..e414e76 100644
--- a/examples/many_pairwise_correlations.py
+++ b/examples/many_pairwise_correlations.py
@@ -4,7 +4,7 @@ Plotting a diagonal correlation matrix
 
 _thumb: .3, .6
 """
-from string import letters
+from string import ascii_letters
 import numpy as np
 import pandas as pd
 import seaborn as sns
@@ -15,7 +15,7 @@ sns.set(style="white")
 # Generate a large random dataset
 rs = np.random.RandomState(33)
 d = pd.DataFrame(data=rs.normal(size=(100, 26)),
-                 columns=list(letters[:26]))
+                 columns=list(ascii_letters[26:]))
 
 # Compute the correlation matrix
 corr = d.corr()
@@ -31,6 +31,5 @@ f, ax = plt.subplots(figsize=(11, 9))
 cmap = sns.diverging_palette(220, 10, as_cmap=True)
 
 # Draw the heatmap with the mask and correct aspect ratio
-sns.heatmap(corr, mask=mask, cmap=cmap, vmax=.3,
-            square=True, xticklabels=5, yticklabels=5,
-            linewidths=.5, cbar_kws={"shrink": .5}, ax=ax)
+sns.heatmap(corr, mask=mask, cmap=cmap, vmax=.3, center=0,
+            square=True, linewidths=.5, cbar_kws={"shrink": .5})
diff --git a/examples/marginal_ticks.py b/examples/marginal_ticks.py
index 17938e1..aa3aad7 100644
--- a/examples/marginal_ticks.py
+++ b/examples/marginal_ticks.py
@@ -2,7 +2,7 @@
 Scatterplot with marginal ticks
 ===============================
 
-_thumb: .65, .35
+_thumb: .68, .32
 """
 import numpy as np
 import seaborn as sns
diff --git a/examples/multiple_joint_kde.py b/examples/multiple_joint_kde.py
index 7877d6b..521144d 100644
--- a/examples/multiple_joint_kde.py
+++ b/examples/multiple_joint_kde.py
@@ -2,7 +2,7 @@
 Multiple bivariate KDE plots
 ============================
 
-_thumb: .6, .4
+_thumb: .6, .45
 """
 import seaborn as sns
 import matplotlib.pyplot as plt
diff --git a/examples/multiple_regression.py b/examples/multiple_regression.py
index e5e65ab..5af8667 100644
--- a/examples/multiple_regression.py
+++ b/examples/multiple_regression.py
@@ -2,19 +2,17 @@
 Multiple linear regression
 ==========================
 
+_thumb: .45, .45
 """
 import seaborn as sns
-sns.set(style="ticks", context="talk")
+sns.set()
 
 # Load the example tips dataset
-tips = sns.load_dataset("tips")
-
-# Make a custom sequential palette using the cubehelix system
-pal = sns.cubehelix_palette(4, 1.5, .75, light=.6, dark=.2)
+iris = sns.load_dataset("iris")
 
 # Plot tip as a function of toal bill across days
-g = sns.lmplot(x="total_bill", y="tip", hue="day", data=tips,
-               palette=pal, size=7)
+g = sns.lmplot(x="sepal_length", y="sepal_width", hue="species",
+               truncate=True, size=5, data=iris)
 
 # Use more informative axis labels than are provided by default
-g.set_axis_labels("Total bill ($)", "Tip ($)")
+g.set_axis_labels("Sepal length (mm)", "Sepal width (mm)")
diff --git a/examples/network_correlations.py b/examples/network_correlations.py
deleted file mode 100644
index c2f6daf..0000000
--- a/examples/network_correlations.py
+++ /dev/null
@@ -1,26 +0,0 @@
-"""
-Correlation matrix heatmap
-==========================
-
-"""
-import seaborn as sns
-import matplotlib.pyplot as plt
-sns.set(context="paper", font="monospace")
-
-# Load the datset of correlations between cortical brain networks
-df = sns.load_dataset("brain_networks", header=[0, 1, 2], index_col=0)
-corrmat = df.corr()
-
-# Set up the matplotlib figure
-f, ax = plt.subplots(figsize=(12, 9))
-
-# Draw the heatmap using seaborn
-sns.heatmap(corrmat, vmax=.8, square=True)
-
-# Use matplotlib directly to emphasize known networks
-networks = corrmat.columns.get_level_values("network")
-for i, network in enumerate(networks):
-    if i and network != networks[i - 1]:
-        ax.axhline(len(networks) - i, c="w")
-        ax.axvline(i, c="w")
-f.tight_layout()
diff --git a/examples/paired_pointplots.py b/examples/paired_pointplots.py
index 9b558fb..39b7643 100644
--- a/examples/paired_pointplots.py
+++ b/examples/paired_pointplots.py
@@ -1,6 +1,6 @@
 """
-Paired discrete plots
-=====================
+Paired categorical plots
+========================
 
 """
 import seaborn as sns
diff --git a/examples/scatterplot_matrix.py b/examples/scatterplot_matrix.py
index ebafe56..399072f 100644
--- a/examples/scatterplot_matrix.py
+++ b/examples/scatterplot_matrix.py
@@ -2,10 +2,10 @@
 Scatterplot Matrix
 ==================
 
-_thumb: .5, .4
+_thumb: .5, .43
 """
 import seaborn as sns
-sns.set()
+sns.set(style="ticks")
 
 df = sns.load_dataset("iris")
 sns.pairplot(df, hue="species")
diff --git a/examples/structured_heatmap.py b/examples/structured_heatmap.py
index 4f1d9ac..7986eae 100644
--- a/examples/structured_heatmap.py
+++ b/examples/structured_heatmap.py
@@ -2,35 +2,31 @@
 Discovering structure in heatmap data
 =====================================
 
-_thumb: .4, .2
+_thumb: .4, .25
 """
 import pandas as pd
 import seaborn as sns
-sns.set(font="monospace")
+sns.set()
 
 # Load the brain networks example dataset
 df = sns.load_dataset("brain_networks", header=[0, 1, 2], index_col=0)
 
 # Select a subset of the networks
-used_networks = [1, 5, 6, 7, 8, 11, 12, 13, 16, 17]
+used_networks = [1, 5, 6, 7, 8, 12, 13, 17]
 used_columns = (df.columns.get_level_values("network")
                           .astype(int)
                           .isin(used_networks))
 df = df.loc[:, used_columns]
 
-# Create a custom palette to identify the networks
-network_pal = sns.cubehelix_palette(len(used_networks),
-                                    light=.9, dark=.1, reverse=True,
-                                    start=1, rot=-2)
+# Create a categorical palette to identify the networks
+network_pal = sns.husl_palette(8, s=.45)
 network_lut = dict(zip(map(str, used_networks), network_pal))
 
 # Convert the palette to vectors that will be drawn on the side of the matrix
 networks = df.columns.get_level_values("network")
 network_colors = pd.Series(networks, index=df.columns).map(network_lut)
 
-# Create a custom colormap for the heatmap values
-cmap = sns.diverging_palette(h_neg=210, h_pos=350, s=90, l=30, as_cmap=True)
-
 # Draw the full plot
-sns.clustermap(df.corr(), row_colors=network_colors, linewidths=.5,
-               col_colors=network_colors, figsize=(13, 13), cmap=cmap)
+sns.clustermap(df.corr(), center=0, cmap="vlag",
+               row_colors=network_colors, col_colors=network_colors,
+               linewidths=.75, figsize=(13, 13))
diff --git a/examples/tips.csv b/examples/tips.csv
deleted file mode 100644
index 1280a10..0000000
--- a/examples/tips.csv
+++ /dev/null
@@ -1,245 +0,0 @@
-"total_bill","tip","sex","smoker","day","time","size"
-16.99,1.01,"Female","No","Sun","Dinner",2
-10.34,1.66,"Male","No","Sun","Dinner",3
-21.01,3.5,"Male","No","Sun","Dinner",3
-23.68,3.31,"Male","No","Sun","Dinner",2
-24.59,3.61,"Female","No","Sun","Dinner",4
-25.29,4.71,"Male","No","Sun","Dinner",4
-8.77,2,"Male","No","Sun","Dinner",2
-26.88,3.12,"Male","No","Sun","Dinner",4
-15.04,1.96,"Male","No","Sun","Dinner",2
-14.78,3.23,"Male","No","Sun","Dinner",2
-10.27,1.71,"Male","No","Sun","Dinner",2
-35.26,5,"Female","No","Sun","Dinner",4
-15.42,1.57,"Male","No","Sun","Dinner",2
-18.43,3,"Male","No","Sun","Dinner",4
-14.83,3.02,"Female","No","Sun","Dinner",2
-21.58,3.92,"Male","No","Sun","Dinner",2
-10.33,1.67,"Female","No","Sun","Dinner",3
-16.29,3.71,"Male","No","Sun","Dinner",3
-16.97,3.5,"Female","No","Sun","Dinner",3
-20.65,3.35,"Male","No","Sat","Dinner",3
-17.92,4.08,"Male","No","Sat","Dinner",2
-20.29,2.75,"Female","No","Sat","Dinner",2
-15.77,2.23,"Female","No","Sat","Dinner",2
-39.42,7.58,"Male","No","Sat","Dinner",4
-19.82,3.18,"Male","No","Sat","Dinner",2
-17.81,2.34,"Male","No","Sat","Dinner",4
-13.37,2,"Male","No","Sat","Dinner",2
-12.69,2,"Male","No","Sat","Dinner",2
-21.7,4.3,"Male","No","Sat","Dinner",2
-19.65,3,"Female","No","Sat","Dinner",2
-9.55,1.45,"Male","No","Sat","Dinner",2
-18.35,2.5,"Male","No","Sat","Dinner",4
-15.06,3,"Female","No","Sat","Dinner",2
-20.69,2.45,"Female","No","Sat","Dinner",4
-17.78,3.27,"Male","No","Sat","Dinner",2
-24.06,3.6,"Male","No","Sat","Dinner",3
-16.31,2,"Male","No","Sat","Dinner",3
-16.93,3.07,"Female","No","Sat","Dinner",3
-18.69,2.31,"Male","No","Sat","Dinner",3
-31.27,5,"Male","No","Sat","Dinner",3
-16.04,2.24,"Male","No","Sat","Dinner",3
-17.46,2.54,"Male","No","Sun","Dinner",2
-13.94,3.06,"Male","No","Sun","Dinner",2
-9.68,1.32,"Male","No","Sun","Dinner",2
-30.4,5.6,"Male","No","Sun","Dinner",4
-18.29,3,"Male","No","Sun","Dinner",2
-22.23,5,"Male","No","Sun","Dinner",2
-32.4,6,"Male","No","Sun","Dinner",4
-28.55,2.05,"Male","No","Sun","Dinner",3
-18.04,3,"Male","No","Sun","Dinner",2
-12.54,2.5,"Male","No","Sun","Dinner",2
-10.29,2.6,"Female","No","Sun","Dinner",2
-34.81,5.2,"Female","No","Sun","Dinner",4
-9.94,1.56,"Male","No","Sun","Dinner",2
-25.56,4.34,"Male","No","Sun","Dinner",4
-19.49,3.51,"Male","No","Sun","Dinner",2
-38.01,3,"Male","Yes","Sat","Dinner",4
-26.41,1.5,"Female","No","Sat","Dinner",2
-11.24,1.76,"Male","Yes","Sat","Dinner",2
-48.27,6.73,"Male","No","Sat","Dinner",4
-20.29,3.21,"Male","Yes","Sat","Dinner",2
-13.81,2,"Male","Yes","Sat","Dinner",2
-11.02,1.98,"Male","Yes","Sat","Dinner",2
-18.29,3.76,"Male","Yes","Sat","Dinner",4
-17.59,2.64,"Male","No","Sat","Dinner",3
-20.08,3.15,"Male","No","Sat","Dinner",3
-16.45,2.47,"Female","No","Sat","Dinner",2
-3.07,1,"Female","Yes","Sat","Dinner",1
-20.23,2.01,"Male","No","Sat","Dinner",2
-15.01,2.09,"Male","Yes","Sat","Dinner",2
-12.02,1.97,"Male","No","Sat","Dinner",2
-17.07,3,"Female","No","Sat","Dinner",3
-26.86,3.14,"Female","Yes","Sat","Dinner",2
-25.28,5,"Female","Yes","Sat","Dinner",2
-14.73,2.2,"Female","No","Sat","Dinner",2
-10.51,1.25,"Male","No","Sat","Dinner",2
-17.92,3.08,"Male","Yes","Sat","Dinner",2
-27.2,4,"Male","No","Thur","Lunch",4
-22.76,3,"Male","No","Thur","Lunch",2
-17.29,2.71,"Male","No","Thur","Lunch",2
-19.44,3,"Male","Yes","Thur","Lunch",2
-16.66,3.4,"Male","No","Thur","Lunch",2
-10.07,1.83,"Female","No","Thur","Lunch",1
-32.68,5,"Male","Yes","Thur","Lunch",2
-15.98,2.03,"Male","No","Thur","Lunch",2
-34.83,5.17,"Female","No","Thur","Lunch",4
-13.03,2,"Male","No","Thur","Lunch",2
-18.28,4,"Male","No","Thur","Lunch",2
-24.71,5.85,"Male","No","Thur","Lunch",2
-21.16,3,"Male","No","Thur","Lunch",2
-28.97,3,"Male","Yes","Fri","Dinner",2
-22.49,3.5,"Male","No","Fri","Dinner",2
-5.75,1,"Female","Yes","Fri","Dinner",2
-16.32,4.3,"Female","Yes","Fri","Dinner",2
-22.75,3.25,"Female","No","Fri","Dinner",2
-40.17,4.73,"Male","Yes","Fri","Dinner",4
-27.28,4,"Male","Yes","Fri","Dinner",2
-12.03,1.5,"Male","Yes","Fri","Dinner",2
-21.01,3,"Male","Yes","Fri","Dinner",2
-12.46,1.5,"Male","No","Fri","Dinner",2
-11.35,2.5,"Female","Yes","Fri","Dinner",2
-15.38,3,"Female","Yes","Fri","Dinner",2
-44.3,2.5,"Female","Yes","Sat","Dinner",3
-22.42,3.48,"Female","Yes","Sat","Dinner",2
-20.92,4.08,"Female","No","Sat","Dinner",2
-15.36,1.64,"Male","Yes","Sat","Dinner",2
-20.49,4.06,"Male","Yes","Sat","Dinner",2
-25.21,4.29,"Male","Yes","Sat","Dinner",2
-18.24,3.76,"Male","No","Sat","Dinner",2
-14.31,4,"Female","Yes","Sat","Dinner",2
-14,3,"Male","No","Sat","Dinner",2
-7.25,1,"Female","No","Sat","Dinner",1
-38.07,4,"Male","No","Sun","Dinner",3
-23.95,2.55,"Male","No","Sun","Dinner",2
-25.71,4,"Female","No","Sun","Dinner",3
-17.31,3.5,"Female","No","Sun","Dinner",2
-29.93,5.07,"Male","No","Sun","Dinner",4
-10.65,1.5,"Female","No","Thur","Lunch",2
-12.43,1.8,"Female","No","Thur","Lunch",2
-24.08,2.92,"Female","No","Thur","Lunch",4
-11.69,2.31,"Male","No","Thur","Lunch",2
-13.42,1.68,"Female","No","Thur","Lunch",2
-14.26,2.5,"Male","No","Thur","Lunch",2
-15.95,2,"Male","No","Thur","Lunch",2
-12.48,2.52,"Female","No","Thur","Lunch",2
-29.8,4.2,"Female","No","Thur","Lunch",6
-8.52,1.48,"Male","No","Thur","Lunch",2
-14.52,2,"Female","No","Thur","Lunch",2
-11.38,2,"Female","No","Thur","Lunch",2
-22.82,2.18,"Male","No","Thur","Lunch",3
-19.08,1.5,"Male","No","Thur","Lunch",2
-20.27,2.83,"Female","No","Thur","Lunch",2
-11.17,1.5,"Female","No","Thur","Lunch",2
-12.26,2,"Female","No","Thur","Lunch",2
-18.26,3.25,"Female","No","Thur","Lunch",2
-8.51,1.25,"Female","No","Thur","Lunch",2
-10.33,2,"Female","No","Thur","Lunch",2
-14.15,2,"Female","No","Thur","Lunch",2
-16,2,"Male","Yes","Thur","Lunch",2
-13.16,2.75,"Female","No","Thur","Lunch",2
-17.47,3.5,"Female","No","Thur","Lunch",2
-34.3,6.7,"Male","No","Thur","Lunch",6
-41.19,5,"Male","No","Thur","Lunch",5
-27.05,5,"Female","No","Thur","Lunch",6
-16.43,2.3,"Female","No","Thur","Lunch",2
-8.35,1.5,"Female","No","Thur","Lunch",2
-18.64,1.36,"Female","No","Thur","Lunch",3
-11.87,1.63,"Female","No","Thur","Lunch",2
-9.78,1.73,"Male","No","Thur","Lunch",2
-7.51,2,"Male","No","Thur","Lunch",2
-14.07,2.5,"Male","No","Sun","Dinner",2
-13.13,2,"Male","No","Sun","Dinner",2
-17.26,2.74,"Male","No","Sun","Dinner",3
-24.55,2,"Male","No","Sun","Dinner",4
-19.77,2,"Male","No","Sun","Dinner",4
-29.85,5.14,"Female","No","Sun","Dinner",5
-48.17,5,"Male","No","Sun","Dinner",6
-25,3.75,"Female","No","Sun","Dinner",4
-13.39,2.61,"Female","No","Sun","Dinner",2
-16.49,2,"Male","No","Sun","Dinner",4
-21.5,3.5,"Male","No","Sun","Dinner",4
-12.66,2.5,"Male","No","Sun","Dinner",2
-16.21,2,"Female","No","Sun","Dinner",3
-13.81,2,"Male","No","Sun","Dinner",2
-17.51,3,"Female","Yes","Sun","Dinner",2
-24.52,3.48,"Male","No","Sun","Dinner",3
-20.76,2.24,"Male","No","Sun","Dinner",2
-31.71,4.5,"Male","No","Sun","Dinner",4
-10.59,1.61,"Female","Yes","Sat","Dinner",2
-10.63,2,"Female","Yes","Sat","Dinner",2
-50.81,10,"Male","Yes","Sat","Dinner",3
-15.81,3.16,"Male","Yes","Sat","Dinner",2
-7.25,5.15,"Male","Yes","Sun","Dinner",2
-31.85,3.18,"Male","Yes","Sun","Dinner",2
-16.82,4,"Male","Yes","Sun","Dinner",2
-32.9,3.11,"Male","Yes","Sun","Dinner",2
-17.89,2,"Male","Yes","Sun","Dinner",2
-14.48,2,"Male","Yes","Sun","Dinner",2
-9.6,4,"Female","Yes","Sun","Dinner",2
-34.63,3.55,"Male","Yes","Sun","Dinner",2
-34.65,3.68,"Male","Yes","Sun","Dinner",4
-23.33,5.65,"Male","Yes","Sun","Dinner",2
-45.35,3.5,"Male","Yes","Sun","Dinner",3
-23.17,6.5,"Male","Yes","Sun","Dinner",4
-40.55,3,"Male","Yes","Sun","Dinner",2
-20.69,5,"Male","No","Sun","Dinner",5
-20.9,3.5,"Female","Yes","Sun","Dinner",3
-30.46,2,"Male","Yes","Sun","Dinner",5
-18.15,3.5,"Female","Yes","Sun","Dinner",3
-23.1,4,"Male","Yes","Sun","Dinner",3
-15.69,1.5,"Male","Yes","Sun","Dinner",2
-19.81,4.19,"Female","Yes","Thur","Lunch",2
-28.44,2.56,"Male","Yes","Thur","Lunch",2
-15.48,2.02,"Male","Yes","Thur","Lunch",2
-16.58,4,"Male","Yes","Thur","Lunch",2
-7.56,1.44,"Male","No","Thur","Lunch",2
-10.34,2,"Male","Yes","Thur","Lunch",2
-43.11,5,"Female","Yes","Thur","Lunch",4
-13,2,"Female","Yes","Thur","Lunch",2
-13.51,2,"Male","Yes","Thur","Lunch",2
-18.71,4,"Male","Yes","Thur","Lunch",3
-12.74,2.01,"Female","Yes","Thur","Lunch",2
-13,2,"Female","Yes","Thur","Lunch",2
-16.4,2.5,"Female","Yes","Thur","Lunch",2
-20.53,4,"Male","Yes","Thur","Lunch",4
-16.47,3.23,"Female","Yes","Thur","Lunch",3
-26.59,3.41,"Male","Yes","Sat","Dinner",3
-38.73,3,"Male","Yes","Sat","Dinner",4
-24.27,2.03,"Male","Yes","Sat","Dinner",2
-12.76,2.23,"Female","Yes","Sat","Dinner",2
-30.06,2,"Male","Yes","Sat","Dinner",3
-25.89,5.16,"Male","Yes","Sat","Dinner",4
-48.33,9,"Male","No","Sat","Dinner",4
-13.27,2.5,"Female","Yes","Sat","Dinner",2
-28.17,6.5,"Female","Yes","Sat","Dinner",3
-12.9,1.1,"Female","Yes","Sat","Dinner",2
-28.15,3,"Male","Yes","Sat","Dinner",5
-11.59,1.5,"Male","Yes","Sat","Dinner",2
-7.74,1.44,"Male","Yes","Sat","Dinner",2
-30.14,3.09,"Female","Yes","Sat","Dinner",4
-12.16,2.2,"Male","Yes","Fri","Lunch",2
-13.42,3.48,"Female","Yes","Fri","Lunch",2
-8.58,1.92,"Male","Yes","Fri","Lunch",1
-15.98,3,"Female","No","Fri","Lunch",3
-13.42,1.58,"Male","Yes","Fri","Lunch",2
-16.27,2.5,"Female","Yes","Fri","Lunch",2
-10.09,2,"Female","Yes","Fri","Lunch",2
-20.45,3,"Male","No","Sat","Dinner",4
-13.28,2.72,"Male","No","Sat","Dinner",2
-22.12,2.88,"Female","Yes","Sat","Dinner",2
-24.01,2,"Male","Yes","Sat","Dinner",4
-15.69,3,"Male","Yes","Sat","Dinner",3
-11.61,3.39,"Male","No","Sat","Dinner",2
-10.77,1.47,"Male","No","Sat","Dinner",2
-15.53,3,"Male","Yes","Sat","Dinner",2
-10.07,1.25,"Male","No","Sat","Dinner",2
-12.6,1,"Male","Yes","Sat","Dinner",2
-32.83,1.17,"Male","Yes","Sat","Dinner",2
-35.83,4.67,"Female","No","Sat","Dinner",3
-29.03,5.92,"Male","No","Sat","Dinner",3
-27.18,2,"Female","Yes","Sat","Dinner",2
-22.67,2,"Male","Yes","Sat","Dinner",2
-17.82,1.75,"Male","No","Sat","Dinner",2
-18.78,3,"Female","No","Thur","Dinner",2
diff --git a/seaborn/__init__.py b/seaborn/__init__.py
index 49657f1..2227514 100644
--- a/seaborn/__init__.py
+++ b/seaborn/__init__.py
@@ -6,7 +6,7 @@ _orig_rc_params = mpl.rcParams.copy()
 from .rcmod import *
 from .utils import *
 from .palettes import *
-from .linearmodels import *
+from .regression import *
 from .categorical import *
 from .distributions import *
 from .timeseries import *
@@ -16,8 +16,6 @@ from .axisgrid import *
 from .widgets import *
 from .xkcd_rgb import xkcd_rgb
 from .crayons import crayons
+from . import cm
 
-# Set default aesthetics
-set()
-
-__version__ = "0.7.1"
+__version__ = "0.8.0"
diff --git a/seaborn/apionly.py b/seaborn/apionly.py
index 03679a5..686e477 100644
--- a/seaborn/apionly.py
+++ b/seaborn/apionly.py
@@ -1,2 +1,9 @@
+import warnings
+msg = (
+    "As seaborn no longer sets a default style on import, the seaborn.apionly "
+    "module is deprecated. It will be removed in a future version."
+)
+warnings.warn(msg, UserWarning)
+
 from seaborn import *
 reset_orig()
diff --git a/seaborn/axisgrid.py b/seaborn/axisgrid.py
index 749bb68..a1c9483 100644
--- a/seaborn/axisgrid.py
+++ b/seaborn/axisgrid.py
@@ -6,14 +6,17 @@ from textwrap import dedent
 
 import numpy as np
 import pandas as pd
+from scipy import stats
 import matplotlib as mpl
 import matplotlib.pyplot as plt
 
 from . import utils
-from .palettes import color_palette
+from .palettes import color_palette, blend_palette
+from .external.six import string_types
+from .distributions import distplot, kdeplot,  _freedman_diaconis_bins
 
 
-__all__ = ["FacetGrid", "PairGrid", "JointGrid"]
+__all__ = ["FacetGrid", "PairGrid", "JointGrid", "pairplot", "jointplot"]
 
 
 class Grid(object):
@@ -64,7 +67,7 @@ class Grid(object):
             if self.hue_names is None:
                 label_order = np.sort(list(legend_data.keys()))
             else:
-                label_order = list(map(str, self.hue_names))
+                label_order = list(map(utils.to_utf8, self.hue_names))
 
         blank_handle = mpl.patches.Patch(alpha=0, linewidth=0)
         handles = [legend_data.get(l, blank_handle) for l in label_order]
@@ -711,7 +714,7 @@ class FacetGrid(Grid):
 
             # Insert a label in the keyword arguments for the legend
             if self._hue_var is not None:
-                kwargs["label"] = str(self.hue_names[hue_k])
+                kwargs["label"] = utils.to_utf8(self.hue_names[hue_k])
 
             # Get the actual data we are going to plot with
             plot_data = data_ijk[list(args)]
@@ -1325,6 +1328,7 @@ class PairGrid(Grid):
             self.diag_axes = np.array(diag_axes, np.object)
 
         # Plot on each of the diagonal axes
+        color = kwargs.pop('color', None)
         for i, var in enumerate(self.x_vars):
             ax = self.diag_axes[i]
             hue_grouped = self.data[var].groupby(self.hue_vals)
@@ -1340,11 +1344,13 @@ class PairGrid(Grid):
                     except KeyError:
                         vals.append(np.array([]))
 
+                if color is None:
+                    color = self.palette
                 # check and see if histtype override was provided in kwargs
                 if 'histtype' in kwargs:
-                    func(vals, color=self.palette, **kwargs)
+                    func(vals, color=color, **kwargs)
                 else:
-                    func(vals, color=self.palette, histtype="barstacked",
+                    func(vals, color=color, histtype="barstacked",
                          **kwargs)
             else:
                 for k, label_k in enumerate(self.hue_names):
@@ -1354,8 +1360,10 @@ class PairGrid(Grid):
                     except KeyError:
                         data_k = np.array([])
                     plt.sca(ax)
+                    if color is None:
+                        color = self.palette[k]
                     func(data_k, label=label_k,
-                         color=self.palette[k], **kwargs)
+                         color=color, **kwargs)
 
             self._clean_axis(ax)
 
@@ -1649,10 +1657,13 @@ class JointGrid(object):
 
         # Possibly extract the variables from a DataFrame
         if data is not None:
-            if x in data:
-                x = data[x]
-            if y in data:
-                y = data[y]
+            x = data.get(x, x)
+            y = data.get(y, y)
+
+        for var in [x, y]:
+            if isinstance(var, string_types):
+                err = "Could not interpret input '{}'".format(var)
+                raise ValueError(err)
 
         # Possibly drop NA
         if dropna:
@@ -1841,3 +1852,435 @@ class JointGrid(object):
         """Wrap figure.savefig defaulting to tight bounding box."""
         kwargs.setdefault("bbox_inches", "tight")
         self.fig.savefig(*args, **kwargs)
+
+
+def pairplot(data, hue=None, hue_order=None, palette=None,
+             vars=None, x_vars=None, y_vars=None,
+             kind="scatter", diag_kind="hist", markers=None,
+             size=2.5, aspect=1, dropna=True,
+             plot_kws=None, diag_kws=None, grid_kws=None):
+    """Plot pairwise relationships in a dataset.
+
+    By default, this function will create a grid of Axes such that each
+    variable in ``data`` will by shared in the y-axis across a single row and
+    in the x-axis across a single column. The diagonal Axes are treated
+    differently, drawing a plot to show the univariate distribution of the data
+    for the variable in that column.
+
+    It is also possible to show a subset of variables or plot different
+    variables on the rows and columns.
+
+    This is a high-level interface for :class:`PairGrid` that is intended to
+    make it easy to draw a few common styles. You should use :class`PairGrid`
+    directly if you need more flexibility.
+
+    Parameters
+    ----------
+    data : DataFrame
+        Tidy (long-form) dataframe where each column is a variable and
+        each row is an observation.
+    hue : string (variable name), optional
+        Variable in ``data`` to map plot aspects to different colors.
+    hue_order : list of strings
+        Order for the levels of the hue variable in the palette
+    palette : dict or seaborn color palette
+        Set of colors for mapping the ``hue`` variable. If a dict, keys
+        should be values  in the ``hue`` variable.
+    vars : list of variable names, optional
+        Variables within ``data`` to use, otherwise use every column with
+        a numeric datatype.
+    {x, y}_vars : lists of variable names, optional
+        Variables within ``data`` to use separately for the rows and
+        columns of the figure; i.e. to make a non-square plot.
+    kind : {'scatter', 'reg'}, optional
+        Kind of plot for the non-identity relationships.
+    diag_kind : {'hist', 'kde'}, optional
+        Kind of plot for the diagonal subplots.
+    markers : single matplotlib marker code or list, optional
+        Either the marker to use for all datapoints or a list of markers with
+        a length the same as the number of levels in the hue variable so that
+        differently colored points will also have different scatterplot
+        markers.
+    size : scalar, optional
+        Height (in inches) of each facet.
+    aspect : scalar, optional
+        Aspect * size gives the width (in inches) of each facet.
+    dropna : boolean, optional
+        Drop missing values from the data before plotting.
+    {plot, diag, grid}_kws : dicts, optional
+        Dictionaries of keyword arguments.
+
+    Returns
+    -------
+    grid : PairGrid
+        Returns the underlying ``PairGrid`` instance for further tweaking.
+
+    See Also
+    --------
+    PairGrid : Subplot grid for more flexible plotting of pairwise
+               relationships.
+
+    Examples
+    --------
+
+    Draw scatterplots for joint relationships and histograms for univariate
+    distributions:
+
+    .. plot::
+        :context: close-figs
+
+        >>> import seaborn as sns; sns.set(style="ticks", color_codes=True)
+        >>> iris = sns.load_dataset("iris")
+        >>> g = sns.pairplot(iris)
+
+    Show different levels of a categorical variable by the color of plot
+    elements:
+
+    .. plot::
+        :context: close-figs
+
+        >>> g = sns.pairplot(iris, hue="species")
+
+    Use a different color palette:
+
+    .. plot::
+        :context: close-figs
+
+        >>> g = sns.pairplot(iris, hue="species", palette="husl")
+
+    Use different markers for each level of the hue variable:
+
+    .. plot::
+        :context: close-figs
+
+        >>> g = sns.pairplot(iris, hue="species", markers=["o", "s", "D"])
+
+    Plot a subset of variables:
+
+    .. plot::
+        :context: close-figs
+
+        >>> g = sns.pairplot(iris, vars=["sepal_width", "sepal_length"])
+
+    Draw larger plots:
+
+    .. plot::
+        :context: close-figs
+
+        >>> g = sns.pairplot(iris, size=3,
+        ...                  vars=["sepal_width", "sepal_length"])
+
+    Plot different variables in the rows and columns:
+
+    .. plot::
+        :context: close-figs
+
+        >>> g = sns.pairplot(iris,
+        ...                  x_vars=["sepal_width", "sepal_length"],
+        ...                  y_vars=["petal_width", "petal_length"])
+
+    Use kernel density estimates for univariate plots:
+
+    .. plot::
+        :context: close-figs
+
+        >>> g = sns.pairplot(iris, diag_kind="kde")
+
+    Fit linear regression models to the scatter plots:
+
+    .. plot::
+        :context: close-figs
+
+        >>> g = sns.pairplot(iris, kind="reg")
+
+    Pass keyword arguments down to the underlying functions (it may be easier
+    to use :class:`PairGrid` directly):
+
+    .. plot::
+        :context: close-figs
+
+        >>> g = sns.pairplot(iris, diag_kind="kde", markers="+",
+        ...                  plot_kws=dict(s=50, edgecolor="b", linewidth=1),
+        ...                  diag_kws=dict(shade=True))
+
+    """
+    if plot_kws is None:
+        plot_kws = {}
+    if diag_kws is None:
+        diag_kws = {}
+    if grid_kws is None:
+        grid_kws = {}
+
+    # Set up the PairGrid
+    diag_sharey = diag_kind == "hist"
+    grid = PairGrid(data, vars=vars, x_vars=x_vars, y_vars=y_vars, hue=hue,
+                    hue_order=hue_order, palette=palette,
+                    diag_sharey=diag_sharey,
+                    size=size, aspect=aspect, dropna=dropna, **grid_kws)
+
+    # Add the markers here as PairGrid has figured out how many levels of the
+    # hue variable are needed and we don't want to duplicate that process
+    if markers is not None:
+        if grid.hue_names is None:
+            n_markers = 1
+        else:
+            n_markers = len(grid.hue_names)
+        if not isinstance(markers, list):
+            markers = [markers] * n_markers
+        if len(markers) != n_markers:
+            raise ValueError(("markers must be a singeton or a list of markers"
+                              " for each level of the hue variable"))
+        grid.hue_kws = {"marker": markers}
+
+    # Maybe plot on the diagonal
+    if grid.square_grid:
+        if diag_kind == "hist":
+            grid.map_diag(plt.hist, **diag_kws)
+        elif diag_kind == "kde":
+            diag_kws["legend"] = False
+            grid.map_diag(kdeplot, **diag_kws)
+
+    # Maybe plot on the off-diagonals
+    if grid.square_grid and diag_kind is not None:
+        plotter = grid.map_offdiag
+    else:
+        plotter = grid.map
+
+    if kind == "scatter":
+        plot_kws.setdefault("edgecolor", "white")
+        plotter(plt.scatter, **plot_kws)
+    elif kind == "reg":
+        from .regression import regplot  # Avoid circular import
+        plotter(regplot, **plot_kws)
+
+    # Add a legend
+    if hue is not None:
+        grid.add_legend()
+
+    return grid
+
+
+def jointplot(x, y, data=None, kind="scatter", stat_func=stats.pearsonr,
+              color=None, size=6, ratio=5, space=.2,
+              dropna=True, xlim=None, ylim=None,
+              joint_kws=None, marginal_kws=None, annot_kws=None, **kwargs):
+    """Draw a plot of two variables with bivariate and univariate graphs.
+
+    This function provides a convenient interface to the :class:`JointGrid`
+    class, with several canned plot kinds. This is intended to be a fairly
+    lightweight wrapper; if you need more flexibility, you should use
+    :class:`JointGrid` directly.
+
+    Parameters
+    ----------
+    x, y : strings or vectors
+        Data or names of variables in ``data``.
+    data : DataFrame, optional
+        DataFrame when ``x`` and ``y`` are variable names.
+    kind : { "scatter" | "reg" | "resid" | "kde" | "hex" }, optional
+        Kind of plot to draw.
+    stat_func : callable or None, optional
+        Function used to calculate a statistic about the relationship and
+        annotate the plot. Should map `x` and `y` either to a single value
+        or to a (value, p) tuple. Set to ``None`` if you don't want to
+        annotate the plot.
+    color : matplotlib color, optional
+        Color used for the plot elements.
+    size : numeric, optional
+        Size of the figure (it will be square).
+    ratio : numeric, optional
+        Ratio of joint axes size to marginal axes height.
+    space : numeric, optional
+        Space between the joint and marginal axes
+    dropna : bool, optional
+        If True, remove observations that are missing from ``x`` and ``y``.
+    {x, y}lim : two-tuples, optional
+        Axis limits to set before plotting.
+    {joint, marginal, annot}_kws : dicts, optional
+        Additional keyword arguments for the plot components.
+    kwargs : key, value pairings
+        Additional keyword arguments are passed to the function used to
+        draw the plot on the joint Axes, superseding items in the
+        ``joint_kws`` dictionary.
+
+    Returns
+    -------
+    grid : :class:`JointGrid`
+        :class:`JointGrid` object with the plot on it.
+
+    See Also
+    --------
+    JointGrid : The Grid class used for drawing this plot. Use it directly if
+                you need more flexibility.
+
+    Examples
+    --------
+
+    Draw a scatterplot with marginal histograms:
+
+    .. plot::
+        :context: close-figs
+
+        >>> import numpy as np, pandas as pd; np.random.seed(0)
+        >>> import seaborn as sns; sns.set(style="white", color_codes=True)
+        >>> tips = sns.load_dataset("tips")
+        >>> g = sns.jointplot(x="total_bill", y="tip", data=tips)
+
+    Add regression and kernel density fits:
+
+    .. plot::
+        :context: close-figs
+
+        >>> g = sns.jointplot("total_bill", "tip", data=tips, kind="reg")
+
+    Replace the scatterplot with a joint histogram using hexagonal bins:
+
+    .. plot::
+        :context: close-figs
+
+        >>> g = sns.jointplot("total_bill", "tip", data=tips, kind="hex")
+
+    Replace the scatterplots and histograms with density estimates and align
+    the marginal Axes tightly with the joint Axes:
+
+    .. plot::
+        :context: close-figs
+
+        >>> iris = sns.load_dataset("iris")
+        >>> g = sns.jointplot("sepal_width", "petal_length", data=iris,
+        ...                   kind="kde", space=0, color="g")
+
+    Use a different statistic for the annotation:
+
+    .. plot::
+        :context: close-figs
+
+        >>> from scipy.stats import spearmanr
+        >>> g = sns.jointplot("size", "total_bill", data=tips,
+        ...                   stat_func=spearmanr, color="m")
+
+    Draw a scatterplot, then add a joint density estimate:
+
+    .. plot::
+        :context: close-figs
+
+        >>> g = (sns.jointplot("sepal_length", "sepal_width",
+        ...                    data=iris, color="k")
+        ...         .plot_joint(sns.kdeplot, zorder=0, n_levels=6))
+
+    Pass vectors in directly without using Pandas, then name the axes:
+
+    .. plot::
+        :context: close-figs
+
+        >>> x, y = np.random.randn(2, 300)
+        >>> g = (sns.jointplot(x, y, kind="hex", stat_func=None)
+        ...         .set_axis_labels("x", "y"))
+
+    Draw a smaller figure with more space devoted to the marginal plots:
+
+    .. plot::
+        :context: close-figs
+
+        >>> g = sns.jointplot("total_bill", "tip", data=tips,
+        ...                   size=5, ratio=3, color="g")
+
+    Pass keyword arguments down to the underlying plots:
+
+    .. plot::
+        :context: close-figs
+
+        >>> g = sns.jointplot("petal_length", "sepal_length", data=iris,
+        ...                   marginal_kws=dict(bins=15, rug=True),
+        ...                   annot_kws=dict(stat="r"),
+        ...                   s=40, edgecolor="w", linewidth=1)
+
+    """
+    # Set up empty default kwarg dicts
+    if joint_kws is None:
+        joint_kws = {}
+    joint_kws.update(kwargs)
+    if marginal_kws is None:
+        marginal_kws = {}
+    if annot_kws is None:
+        annot_kws = {}
+
+    # Make a colormap based off the plot color
+    if color is None:
+        color = color_palette()[0]
+    color_rgb = mpl.colors.colorConverter.to_rgb(color)
+    colors = [utils.set_hls_values(color_rgb, l=l)
+              for l in np.linspace(1, 0, 12)]
+    cmap = blend_palette(colors, as_cmap=True)
+
+    # Initialize the JointGrid object
+    grid = JointGrid(x, y, data, dropna=dropna,
+                     size=size, ratio=ratio, space=space,
+                     xlim=xlim, ylim=ylim)
+
+    # Plot the data using the grid
+    if kind == "scatter":
+
+        joint_kws.setdefault("color", color)
+        grid.plot_joint(plt.scatter, **joint_kws)
+
+        marginal_kws.setdefault("kde", False)
+        marginal_kws.setdefault("color", color)
+        grid.plot_marginals(distplot, **marginal_kws)
+
+    elif kind.startswith("hex"):
+
+        x_bins = min(_freedman_diaconis_bins(grid.x), 50)
+        y_bins = min(_freedman_diaconis_bins(grid.y), 50)
+        gridsize = int(np.mean([x_bins, y_bins]))
+
+        joint_kws.setdefault("gridsize", gridsize)
+        joint_kws.setdefault("cmap", cmap)
+        grid.plot_joint(plt.hexbin, **joint_kws)
+
+        marginal_kws.setdefault("kde", False)
+        marginal_kws.setdefault("color", color)
+        grid.plot_marginals(distplot, **marginal_kws)
+
+    elif kind.startswith("kde"):
+
+        joint_kws.setdefault("shade", True)
+        joint_kws.setdefault("cmap", cmap)
+        grid.plot_joint(kdeplot, **joint_kws)
+
+        marginal_kws.setdefault("shade", True)
+        marginal_kws.setdefault("color", color)
+        grid.plot_marginals(kdeplot, **marginal_kws)
+
+    elif kind.startswith("reg"):
+
+        from .regression import regplot
+
+        marginal_kws.setdefault("color", color)
+        grid.plot_marginals(distplot, **marginal_kws)
+
+        joint_kws.setdefault("color", color)
+        grid.plot_joint(regplot, **joint_kws)
+
+    elif kind.startswith("resid"):
+
+        from .regression import residplot
+
+        joint_kws.setdefault("color", color)
+        grid.plot_joint(residplot, **joint_kws)
+
+        x, y = grid.ax_joint.collections[0].get_offsets().T
+        marginal_kws.setdefault("color", color)
+        marginal_kws.setdefault("kde", False)
+        distplot(x, ax=grid.ax_marg_x, **marginal_kws)
+        distplot(y, vertical=True, fit=stats.norm, ax=grid.ax_marg_y,
+                 **marginal_kws)
+        stat_func = None
+    else:
+        msg = "kind must be either 'scatter', 'reg', 'resid', 'kde', or 'hex'"
+        raise ValueError(msg)
+
+    if stat_func is not None:
+        grid.annotate(stat_func, **annot_kws)
+
+    return grid
diff --git a/seaborn/categorical.py b/seaborn/categorical.py
index 7229e93..16bd6a1 100644
--- a/seaborn/categorical.py
+++ b/seaborn/categorical.py
@@ -356,16 +356,23 @@ class _CategoricalPlotter(object):
     def hue_offsets(self):
         """A list of center positions for plots when hue nesting is used."""
         n_levels = len(self.hue_names)
-        each_width = self.width / n_levels
-        offsets = np.linspace(0, self.width - each_width, n_levels)
-        offsets -= offsets.mean()
+        if self.dodge:
+            each_width = self.width / n_levels
+            offsets = np.linspace(0, self.width - each_width, n_levels)
+            offsets -= offsets.mean()
+        else:
+            offsets = np.zeros(n_levels)
 
         return offsets
 
     @property
     def nested_width(self):
         """A float with the width of plot elements when hue nesting is used."""
-        return self.width / len(self.hue_names) * .98
+        if self.dodge:
+            width = self.width / len(self.hue_names) * .98
+        else:
+            width = self.width
+        return width
 
     def annotate_axes(self, ax):
         """Add descriptive labels to an Axes object."""
@@ -421,11 +428,12 @@ class _BoxPlotter(_CategoricalPlotter):
 
     def __init__(self, x, y, hue, data, order, hue_order,
                  orient, color, palette, saturation,
-                 width, fliersize, linewidth):
+                 width, dodge, fliersize, linewidth):
 
         self.establish_variables(x, y, hue, data, orient, order, hue_order)
         self.establish_colors(color, palette, saturation)
 
+        self.dodge = dodge
         self.width = width
         self.fliersize = fliersize
 
@@ -535,7 +543,7 @@ class _ViolinPlotter(_CategoricalPlotter):
 
     def __init__(self, x, y, hue, data, order, hue_order,
                  bw, cut, scale, scale_hue, gridsize,
-                 width, inner, split, orient, linewidth,
+                 width, inner, split, dodge, orient, linewidth,
                  color, palette, saturation):
 
         self.establish_variables(x, y, hue, data, orient, order, hue_order)
@@ -544,6 +552,7 @@ class _ViolinPlotter(_CategoricalPlotter):
 
         self.gridsize = gridsize
         self.width = width
+        self.dodge = dodge
 
         if inner is not None:
             if not any([inner.startswith("quart"),
@@ -555,7 +564,8 @@ class _ViolinPlotter(_CategoricalPlotter):
         self.inner = inner
 
         if split and self.hue_names is not None and len(self.hue_names) != 2:
-            raise ValueError("Cannot use `split` with more than 2 hue levels.")
+            msg = "There must be exactly two hue levels to use `split`.'"
+            raise ValueError(msg)
         self.split = split
 
         if linewidth is None:
@@ -768,7 +778,7 @@ class _ViolinPlotter(_CategoricalPlotter):
     @property
     def dwidth(self):
 
-        if self.hue_names is None:
+        if self.hue_names is None or not self.dodge:
             return self.width / 2
         elif self.split:
             return self.width / 2
@@ -839,7 +849,7 @@ class _ViolinPlotter(_CategoricalPlotter):
                 for j, hue_level in enumerate(self.hue_names):
 
                     support, density = self.support[i][j], self.density[i][j]
-                    kws["color"] = self.colors[j]
+                    kws["facecolor"] = self.colors[j]
 
                     # Add legend data, but just for one set of violins
                     if not i:
@@ -1107,20 +1117,20 @@ class _CategoricalScatterPlotter(_CategoricalPlotter):
 class _StripPlotter(_CategoricalScatterPlotter):
     """1-d scatterplot with categorical organization."""
     def __init__(self, x, y, hue, data, order, hue_order,
-                 jitter, split, orient, color, palette):
+                 jitter, dodge, orient, color, palette):
         """Initialize the plotter."""
         self.establish_variables(x, y, hue, data, orient, order, hue_order)
         self.establish_colors(color, palette, 1)
 
         # Set object attributes
-        self.split = split
+        self.dodge = dodge
         self.width = .8
 
         if jitter == 1:  # Use a good default for `jitter = True`
             jlim = 0.1
         else:
             jlim = float(jitter)
-        if self.hue_names is not None and split:
+        if self.hue_names is not None and dodge:
             jlim /= len(self.hue_names)
         self.jitterer = stats.uniform(-jlim, jlim * 2).rvs
 
@@ -1129,7 +1139,7 @@ class _StripPlotter(_CategoricalScatterPlotter):
         # Set the default zorder to 2.1, so that the points
         # will be drawn on top of line elements (like in a boxplot)
         for i, group_data in enumerate(self.plot_data):
-            if self.plot_hues is None or not self.split:
+            if self.plot_hues is None or not self.dodge:
 
                 if self.hue_names is None:
                     hue_mask = np.ones(group_data.size, np.bool)
@@ -1178,21 +1188,15 @@ class _StripPlotter(_CategoricalScatterPlotter):
 class _SwarmPlotter(_CategoricalScatterPlotter):
 
     def __init__(self, x, y, hue, data, order, hue_order,
-                 split, orient, color, palette):
+                 dodge, orient, color, palette):
         """Initialize the plotter."""
         self.establish_variables(x, y, hue, data, orient, order, hue_order)
         self.establish_colors(color, palette, 1)
 
         # Set object attributes
-        self.split = split
+        self.dodge = dodge
         self.width = .8
 
-    def overlap(self, xy_i, xy_j, d):
-        """Return True if two circles with the same diameter will overlap."""
-        x_i, y_i = xy_i
-        x_j, y_j = xy_j
-        return ((x_i - x_j) ** 2 + (y_i - y_j) ** 2) < (d ** 2)
-
     def could_overlap(self, xy_i, swarm, d):
         """Return a list of all swarm points that could overlap with target.
 
@@ -1206,7 +1210,7 @@ class _SwarmPlotter(_CategoricalScatterPlotter):
                 neighbors.append(xy_j)
             else:
                 break
-        return list(reversed(neighbors))
+        return np.array(list(reversed(neighbors)))
 
     def position_candidates(self, xy_i, neighbors, d):
         """Return a list of (x, y) coordinates that might be valid."""
@@ -1223,19 +1227,41 @@ class _SwarmPlotter(_CategoricalScatterPlotter):
                 new_candidates = [cr, cl]
             candidates.extend(new_candidates)
             left_first = not left_first
-        return candidates
+        return np.array(candidates)
 
-    def prune_candidates(self, candidates, neighbors, d):
+    def first_non_overlapping_candidate(self, candidates, neighbors, d):
         """Remove candidates from the list if they overlap with the swarm."""
-        good_candidates = []
+
+        # IF we have no neighbours, all candidates are good.
+        if len(neighbors) == 0:
+            return candidates[0]
+
+        neighbors_x = neighbors[:, 0]
+        neighbors_y = neighbors[:, 1]
+
+        d_square = d ** 2
+
         for xy_i in candidates:
-            good_candidate = True
-            for xy_j in neighbors:
-                if self.overlap(xy_i, xy_j, d):
-                    good_candidate = False
+            x_i, y_i = xy_i
+
+            dx = neighbors_x - x_i
+            dy = neighbors_y - y_i
+
+            sq_distances = np.power(dx, 2.0) + np.power(dy, 2.0)
+
+            # good candidate does not overlap any of neighbors
+            # which means that squared distance between candidate
+            # and any of the neighbours has to be at least
+            # square of the diameter
+            good_candidate = np.all(sq_distances >= d_square)
+
             if good_candidate:
-                good_candidates.append(xy_i)
-        return np.array(good_candidates)
+                return xy_i
+
+        # If `position_candidates` works well
+        # this should never happen
+        raise Exception('No non-overlapping candidates found. '
+                        'This should not happen.')
 
     def beeswarm(self, orig_xy, d):
         """Adjust x position of points to avoid overlaps."""
@@ -1257,14 +1283,15 @@ class _SwarmPlotter(_CategoricalScatterPlotter):
             # with respect to each of the swarm neighbors
             candidates = self.position_candidates(xy_i, neighbors, d)
 
-            # Remove the positions that overlap with any of the
-            # other neighbors
-            candidates = self.prune_candidates(candidates, neighbors, d)
-
-            # Find the most central of the remaining positions
+            # Sort candidates by their centrality
             offsets = np.abs(candidates[:, 0] - midline)
-            best_index = np.argmin(offsets)
-            new_xy_i = candidates[best_index]
+            candidates = candidates[np.argsort(offsets)]
+
+            # Find the first candidate that doesn't overlap any neighbours
+            new_xy_i = self.first_non_overlapping_candidate(candidates,
+                                                            neighbors, d)
+
+            # Place it into the swarm
             swarm.append(new_xy_i)
 
         return np.array(swarm)
@@ -1287,7 +1314,8 @@ class _SwarmPlotter(_CategoricalScatterPlotter):
         # Convert from point size (area) to diameter
         default_lw = mpl.rcParams["patch.linewidth"]
         lw = kws.get("linewidth", kws.get("lw", default_lw))
-        d = np.sqrt(s) + lw
+        dpi = ax.figure.dpi
+        d = (np.sqrt(s) + lw) * (dpi / 72)
 
         # Transform the data coordinates to point coordinates.
         # We'll figure out the swarm positions in the latter
@@ -1331,7 +1359,7 @@ class _SwarmPlotter(_CategoricalScatterPlotter):
         # Plot each swarm
         for i, group_data in enumerate(self.plot_data):
 
-            if self.plot_hues is None or not self.split:
+            if self.plot_hues is None or not self.dodge:
 
                 width = self.width
 
@@ -1406,7 +1434,11 @@ class _CategoricalStatPlotter(_CategoricalPlotter):
     @property
     def nested_width(self):
         """A float with the width of plot elements when hue nesting is used."""
-        return self.width / len(self.hue_names)
+        if self.dodge:
+            width = self.width / len(self.hue_names)
+        else:
+            width = self.width
+        return width
 
     def estimate_statistic(self, estimator, ci, n_boot):
 
@@ -1446,10 +1478,18 @@ class _CategoricalStatPlotter(_CategoricalPlotter):
                         confint.append([np.nan, np.nan])
                         continue
 
-                    boots = bootstrap(stat_data, func=estimator,
-                                      n_boot=n_boot,
-                                      units=unit_data)
-                    confint.append(utils.ci(boots, ci))
+                    if ci == "sd":
+
+                        estimate = estimator(stat_data)
+                        sd = np.std(stat_data)
+                        confint.append((estimate - sd, estimate + sd))
+
+                    else:
+
+                        boots = bootstrap(stat_data, func=estimator,
+                                          n_boot=n_boot,
+                                          units=unit_data)
+                        confint.append(utils.ci(boots, ci))
 
             # Option 2: we are grouping by a hue layer
             # ----------------------------------------
@@ -1488,20 +1528,23 @@ class _CategoricalStatPlotter(_CategoricalPlotter):
                             confint[i].append([np.nan, np.nan])
                             continue
 
-                        boots = bootstrap(stat_data, func=estimator,
-                                          n_boot=n_boot,
-                                          units=unit_data)
-                        confint[i].append(utils.ci(boots, ci))
+                        if ci == "sd":
+
+                            estimate = estimator(stat_data)
+                            sd = np.std(stat_data)
+                            confint[i].append((estimate - sd, estimate + sd))
+
+                        else:
+
+                            boots = bootstrap(stat_data, func=estimator,
+                                              n_boot=n_boot,
+                                              units=unit_data)
+                            confint[i].append(utils.ci(boots, ci))
 
         # Save the resulting values for plotting
         self.statistic = np.array(statistic)
         self.confint = np.array(confint)
 
-        # Rename the value label to reflect the estimation
-        if self.value_label is not None:
-            self.value_label = "{}({})".format(estimator.__name__,
-                                               self.value_label)
-
     def draw_confints(self, ax, at_group, confint, colors,
                       errwidth=None, capsize=None, **kws):
 
@@ -1536,14 +1579,16 @@ class _BarPlotter(_CategoricalStatPlotter):
 
     def __init__(self, x, y, hue, data, order, hue_order,
                  estimator, ci, n_boot, units,
-                 orient, color, palette, saturation, errcolor, errwidth=None,
-                 capsize=None):
+                 orient, color, palette, saturation, errcolor,
+                 errwidth, capsize, dodge):
         """Initialize the plotter."""
         self.establish_variables(x, y, hue, data, orient,
                                  order, hue_order, units)
         self.establish_colors(color, palette, saturation)
         self.estimate_statistic(estimator, ci, n_boot)
 
+        self.dodge = dodge
+
         self.errcolor = errcolor
         self.errwidth = errwidth
         self.capsize = capsize
@@ -1642,8 +1687,11 @@ class _PointPlotter(_CategoricalStatPlotter):
     @property
     def hue_offsets(self):
         """Offsets relative to the center position for each hue level."""
-        offset = np.linspace(0, self.dodge, len(self.hue_names))
-        offset -= offset.mean()
+        if self.dodge:
+            offset = np.linspace(0, self.dodge, len(self.hue_names))
+            offset -= offset.mean()
+        else:
+            offset = np.zeros(len(self.hue_names))
         return offset
 
     def draw_points(self, ax):
@@ -1739,12 +1787,15 @@ class _LVPlotter(_CategoricalPlotter):
 
     def __init__(self, x, y, hue, data, order, hue_order,
                  orient, color, palette, saturation,
-                 width, k_depth, linewidth, scale, outlier_prop):
+                 width, dodge, k_depth, linewidth, scale, outlier_prop):
 
+        # TODO assigning variables for None is unceccesary
         if width is None:
             width = .8
         self.width = width
 
+        self.dodge = dodge
+
         if saturation is None:
             saturation = .75
         self.saturation = saturation
@@ -2026,10 +2077,11 @@ _categorical_docs = dict(
     stat_api_params=dedent("""\
     estimator : callable that maps vector -> scalar, optional
         Statistical function to estimate within each categorical bin.
-    ci : float or None, optional
-        Size of confidence intervals to draw around estimated values. If
-        ``None``, no bootstrapping will be performed, and error bars will
-        not be drawn.
+    ci : float or "sd" or None, optional
+        Size of confidence intervals to draw around estimated values.  If
+        "sd", skip bootstrapping and draw the standard deviation of the
+        observerations. If ``None``, no bootstrapping will be performed, and
+        error bars will not be drawn.
     n_boot : int, optional
         Number of bootstrap iterations to use when computing confidence
         intervals.
@@ -2075,6 +2127,11 @@ _categorical_docs = dict(
         Width of a full element when not using hue nesting, or width of all the
         elements for one level of the major grouping variable.\
     """),
+    dodge=dedent("""\
+    dodge : bool, optional
+        When hue nesting is used, whether elements should be shifted along the
+        categorical axis.\
+    """),
     linewidth=dedent("""\
     linewidth : float, optional
         Width of the gray lines that frame the plot elements.\
@@ -2127,52 +2184,12 @@ _categorical_docs.update(_facet_docs)
 
 def boxplot(x=None, y=None, hue=None, data=None, order=None, hue_order=None,
             orient=None, color=None, palette=None, saturation=.75,
-            width=.8, fliersize=5, linewidth=None, whis=1.5, notch=False,
-            ax=None, **kwargs):
-
-    # Try to handle broken backwards-compatability
-    # This should help with the lack of a smooth deprecation,
-    # but won't catch everything
-    warn = False
-    if isinstance(x, pd.DataFrame):
-        data = x
-        x = None
-        warn = True
-
-    if "vals" in kwargs:
-        x = kwargs.pop("vals")
-        warn = True
-
-    if "groupby" in kwargs:
-        y = x
-        x = kwargs.pop("groupby")
-        warn = True
-
-    if "vert" in kwargs:
-        vert = kwargs.pop("vert", True)
-        if not vert:
-            x, y = y, x
-        orient = "v" if vert else "h"
-        warn = True
-
-    if "names" in kwargs:
-        kwargs.pop("names")
-        warn = True
-
-    if "join_rm" in kwargs:
-        kwargs.pop("join_rm")
-        warn = True
-
-    msg = ("The boxplot API has been changed. Attempting to adjust your "
-           "arguments for the new API (which might not work). Please update "
-           "your code. See the version 0.6 release notes for more info.")
-
-    if warn:
-        warnings.warn(msg, UserWarning)
+            width=.8, dodge=True, fliersize=5, linewidth=None,
+            whis=1.5, notch=False, ax=None, **kwargs):
 
     plotter = _BoxPlotter(x, y, hue, data, order, hue_order,
                           orient, color, palette, saturation,
-                          width, fliersize, linewidth)
+                          width, dodge, fliersize, linewidth)
 
     if ax is None:
         ax = plt.gca()
@@ -2203,6 +2220,7 @@ boxplot.__doc__ = dedent("""\
     {palette}
     {saturation}
     {width}
+    {dodge}
     fliersize : float, optional
         Size of the markers used to indicate outlier observations.
     {linewidth}
@@ -2282,6 +2300,15 @@ boxplot.__doc__ = dedent("""\
         >>> iris = sns.load_dataset("iris")
         >>> ax = sns.boxplot(data=iris, orient="h", palette="Set2")
 
+    Use ``hue`` without changing box position or width:
+
+    .. plot::
+        :context: close-figs
+
+        >>> tips["weekend"] = tips["day"].isin(["Sat", "Sun"])
+        >>> ax = sns.boxplot(x="day", y="total_bill", hue="weekend",
+        ...                  data=tips, dodge=False)
+
     Use :func:`swarmplot` to show the datapoints on top of the boxes:
 
     .. plot::
@@ -2290,60 +2317,31 @@ boxplot.__doc__ = dedent("""\
         >>> ax = sns.boxplot(x="day", y="total_bill", data=tips)
         >>> ax = sns.swarmplot(x="day", y="total_bill", data=tips, color=".25")
 
-    Draw a box plot on to a :class:`FacetGrid` to group within an additional
-    categorical variable:
+    Use :func:`factorplot` to combine a :func:`boxplot` and a
+    :class:`FacetGrid`. This allows grouping within additional categorical
+    variables. Using :func:`factorplot` is safer than using :class:`FacetGrid`
+    directly, as it ensures synchronization of variable order across facets:
 
     .. plot::
         :context: close-figs
 
-        >>> g = sns.FacetGrid(tips, col="time", size=4, aspect=.7)
-        >>> (g.map(sns.boxplot, "sex", "total_bill", "smoker")
-        ...   .despine(left=True)
-        ...   .add_legend(title="smoker"))  #doctest: +ELLIPSIS
-        <seaborn.axisgrid.FacetGrid object at 0x...>
+        >>> g = sns.factorplot(x="sex", y="total_bill",
+        ...                    hue="smoker", col="time",
+        ...                    data=tips, kind="box",
+        ...                    size=4, aspect=.7);
 
     """).format(**_categorical_docs)
 
 
 def violinplot(x=None, y=None, hue=None, data=None, order=None, hue_order=None,
                bw="scott", cut=2, scale="area", scale_hue=True, gridsize=100,
-               width=.8, inner="box", split=False, orient=None, linewidth=None,
-               color=None, palette=None, saturation=.75, ax=None, **kwargs):
-
-    # Try to handle broken backwards-compatability
-    # This should help with the lack of a smooth deprecation,
-    # but won't catch everything
-    warn = False
-    if isinstance(x, pd.DataFrame):
-        data = x
-        x = None
-        warn = True
-
-    if "vals" in kwargs:
-        x = kwargs.pop("vals")
-        warn = True
-
-    if "groupby" in kwargs:
-        y = x
-        x = kwargs.pop("groupby")
-        warn = True
-
-    if "vert" in kwargs:
-        vert = kwargs.pop("vert", True)
-        if not vert:
-            x, y = y, x
-        orient = "v" if vert else "h"
-        warn = True
-
-    msg = ("The violinplot API has been changed. Attempting to adjust your "
-           "arguments for the new API (which might not work). Please update "
-           "your code. See the version 0.6 release notes for more info.")
-    if warn:
-        warnings.warn(msg, UserWarning)
+               width=.8, inner="box", split=False, dodge=True, orient=None,
+               linewidth=None, color=None, palette=None, saturation=.75,
+               ax=None, **kwargs):
 
     plotter = _ViolinPlotter(x, y, hue, data, order, hue_order,
                              bw, cut, scale, scale_hue, gridsize,
-                             width, inner, split, orient, linewidth,
+                             width, inner, split, dodge, orient, linewidth,
                              color, palette, saturation)
 
     if ax is None:
@@ -2407,6 +2405,7 @@ violinplot.__doc__ = dedent("""\
         When using hue nesting with a variable that takes two levels, setting
         ``split`` to True will draw half of a violin for each level. This can
         make it easier to directly compare the distributions.
+    {dodge}
     {orient}
     {linewidth}
     {color}
@@ -2524,27 +2523,51 @@ violinplot.__doc__ = dedent("""\
         ...                     data=planets[planets.orbital_period < 1000],
         ...                     scale="width", palette="Set3")
 
-    Draw a violin plot on to a :class:`FacetGrid` to group within an additional
-    categorical variable:
+    Don't let density extend past extreme values in the data:
 
     .. plot::
         :context: close-figs
 
-        >>> g = sns.FacetGrid(tips, col="time", size=4, aspect=.7)
-        >>> (g.map(sns.violinplot, "sex", "total_bill", "smoker", split=True)
-        ...   .despine(left=True)
-        ...   .add_legend(title="smoker"))  # doctest: +ELLIPSIS
-        <seaborn.axisgrid.FacetGrid object at 0x...>
+        >>> ax = sns.violinplot(x="orbital_period", y="method",
+        ...                     data=planets[planets.orbital_period < 1000],
+        ...                     cut=0, scale="width", palette="Set3")
+
+    Use ``hue`` without changing violin position or width:
+
+    .. plot::
+        :context: close-figs
+
+        >>> tips["weekend"] = tips["day"].isin(["Sat", "Sun"])
+        >>> ax = sns.violinplot(x="day", y="total_bill", hue="weekend",
+        ...                     data=tips, dodge=False)
+
+    Use :func:`factorplot` to combine a :func:`violinplot` and a
+    :class:`FacetGrid`. This allows grouping within additional categorical
+    variables. Using :func:`factorplot` is safer than using :class:`FacetGrid`
+    directly, as it ensures synchronization of variable order across facets:
+
+    .. plot::
+        :context: close-figs
+
+        >>> g = sns.factorplot(x="sex", y="total_bill",
+        ...                    hue="smoker", col="time",
+        ...                    data=tips, kind="violin", split=True,
+        ...                    size=4, aspect=.7);
 
     """).format(**_categorical_docs)
 
 
 def stripplot(x=None, y=None, hue=None, data=None, order=None, hue_order=None,
-              jitter=False, split=False, orient=None, color=None, palette=None,
+              jitter=False, dodge=False, orient=None, color=None, palette=None,
               size=5, edgecolor="gray", linewidth=0, ax=None, **kwargs):
 
+    if "split" in kwargs:
+        dodge = kwargs.pop("split")
+        msg = "The `split` parameter has been renamed to `dodge`."
+        warnings.warn(msg, UserWarning)
+
     plotter = _StripPlotter(x, y, hue, data, order, hue_order,
-                            jitter, split, orient, color, palette)
+                            jitter, dodge, orient, color, palette)
     if ax is None:
         ax = plt.gca()
 
@@ -2677,7 +2700,7 @@ stripplot.__doc__ = dedent("""\
 
         >>> ax = sns.stripplot(x="day", y="total_bill", hue="smoker",
         ...                    data=tips, jitter=True,
-        ...                    palette="Set2", split=True)
+        ...                    palette="Set2", dodge=True)
 
     Control strip order by passing an explicit order:
 
@@ -2714,15 +2737,34 @@ stripplot.__doc__ = dedent("""\
         ...                     inner=None, color=".8")
         >>> ax = sns.stripplot(x="day", y="total_bill", data=tips, jitter=True)
 
+    Use :func:`factorplot` to combine a :func:`stripplot` and a
+    :class:`FacetGrid`. This allows grouping within additional categorical
+    variables. Using :func:`factorplot` is safer than using :class:`FacetGrid`
+    directly, as it ensures synchronization of variable order across facets:
+
+    .. plot::
+        :context: close-figs
+
+        >>> g = sns.factorplot(x="sex", y="total_bill",
+        ...                    hue="smoker", col="time",
+        ...                    data=tips, kind="strip",
+        ...                    jitter=True,
+        ...                    size=4, aspect=.7);
+
     """).format(**_categorical_docs)
 
 
 def swarmplot(x=None, y=None, hue=None, data=None, order=None, hue_order=None,
-              split=False, orient=None, color=None, palette=None,
+              dodge=False, orient=None, color=None, palette=None,
               size=5, edgecolor="gray", linewidth=0, ax=None, **kwargs):
 
+    if "split" in kwargs:
+        dodge = kwargs.pop("split")
+        msg = "The `split` parameter has been renamed to `dodge`."
+        warnings.warn(msg, UserWarning)
+
     plotter = _SwarmPlotter(x, y, hue, data, order, hue_order,
-                            split, orient, color, palette)
+                            dodge, orient, color, palette)
     if ax is None:
         ax = plt.gca()
 
@@ -2836,7 +2878,7 @@ swarmplot.__doc__ = dedent("""\
         :context: close-figs
 
         >>> ax = sns.swarmplot(x="day", y="total_bill", hue="smoker",
-        ...                    data=tips, palette="Set2", split=True)
+        ...                    data=tips, palette="Set2", dodge=True)
 
     Control swarm order by passing an explicit order:
 
@@ -2853,14 +2895,13 @@ swarmplot.__doc__ = dedent("""\
 
         >>> ax = sns.swarmplot(x="time", y="tip", data=tips, size=6)
 
-
     Draw swarms of observations on top of a box plot:
 
     .. plot::
         :context: close-figs
 
         >>> ax = sns.boxplot(x="tip", y="day", data=tips, whis=np.inf)
-        >>> ax = sns.swarmplot(x="tip", y="day", data=tips)
+        >>> ax = sns.swarmplot(x="tip", y="day", data=tips, color=".2")
 
     Draw swarms of observations on top of a violin plot:
 
@@ -2871,32 +2912,32 @@ swarmplot.__doc__ = dedent("""\
         >>> ax = sns.swarmplot(x="day", y="total_bill", data=tips,
         ...                    color="white", edgecolor="gray")
 
+    Use :func:`factorplot` to combine a :func:`swarmplot` and a
+    :class:`FacetGrid`. This allows grouping within additional categorical
+    variables. Using :func:`factorplot` is safer than using :class:`FacetGrid`
+    directly, as it ensures synchronization of variable order across facets:
+
+    .. plot::
+        :context: close-figs
+
+        >>> g = sns.factorplot(x="sex", y="total_bill",
+        ...                    hue="smoker", col="time",
+        ...                    data=tips, kind="swarm",
+        ...                    size=4, aspect=.7);
+
     """).format(**_categorical_docs)
 
 
 def barplot(x=None, y=None, hue=None, data=None, order=None, hue_order=None,
             estimator=np.mean, ci=95, n_boot=1000, units=None,
             orient=None, color=None, palette=None, saturation=.75,
-            errcolor=".26", errwidth=None, capsize=None, ax=None, **kwargs):
-
-    # Handle some deprecated arguments
-    if "hline" in kwargs:
-        kwargs.pop("hline")
-        warnings.warn("The `hline` parameter has been removed", UserWarning)
-
-    if "dropna" in kwargs:
-        kwargs.pop("dropna")
-        warnings.warn("The `dropna` parameter has been removed", UserWarning)
-
-    if "x_order" in kwargs:
-        order = kwargs.pop("x_order")
-        warnings.warn("The `x_order` parameter has been renamed `order`",
-                      UserWarning)
+            errcolor=".26", errwidth=None, capsize=None, dodge=True,
+            ax=None, **kwargs):
 
     plotter = _BarPlotter(x, y, hue, data, order, hue_order,
                           estimator, ci, n_boot, units,
                           orient, color, palette, saturation,
-                          errcolor, errwidth, capsize)
+                          errcolor, errwidth, capsize, dodge)
 
     if ax is None:
         ax = plt.gca()
@@ -2942,6 +2983,7 @@ barplot.__doc__ = dedent("""\
     {ax_in}
     {errwidth}
     {capsize}
+    {dodge}
     kwargs : key, value mappings
         Other keyword arguments are passed through to ``plt.bar`` at draw
         time.
@@ -3006,6 +3048,13 @@ barplot.__doc__ = dedent("""\
 
         >>> ax = sns.barplot(x="day", y="tip", data=tips, ci=68)
 
+    Show standard deviation of observations instead of a confidence interval:
+
+    .. plot::
+        :context: close-figs
+
+        >>> ax = sns.barplot(x="day", y="tip", data=tips, ci="sd")
+
     Add "caps" to the error bars:
 
     .. plot::
@@ -3021,6 +3070,15 @@ barplot.__doc__ = dedent("""\
         >>> ax = sns.barplot("size", y="total_bill", data=tips,
         ...                  palette="Blues_d")
 
+    Use ``hue`` without changing bar position or width:
+
+    .. plot::
+        :context: close-figs
+
+        >>> tips["weekend"] = tips["day"].isin(["Sat", "Sun"])
+        >>> ax = sns.barplot(x="day", y="total_bill", hue="weekend",
+        ...                  data=tips, dodge=False)
+
     Plot all bars in a single color:
 
     .. plot::
@@ -3038,28 +3096,27 @@ barplot.__doc__ = dedent("""\
         ...                  linewidth=2.5, facecolor=(1, 1, 1, 0),
         ...                  errcolor=".2", edgecolor=".2")
 
+    Use :func:`factorplot` to combine a :func:`barplot` and a
+    :class:`FacetGrid`. This allows grouping within additional categorical
+    variables. Using :func:`factorplot` is safer than using :class:`FacetGrid`
+    directly, as it ensures synchronization of variable order across facets:
+
+    .. plot::
+        :context: close-figs
+
+        >>> g = sns.factorplot(x="sex", y="total_bill",
+        ...                    hue="smoker", col="time",
+        ...                    data=tips, kind="bar",
+        ...                    size=4, aspect=.7);
+
     """).format(**_categorical_docs)
 
 
 def pointplot(x=None, y=None, hue=None, data=None, order=None, hue_order=None,
               estimator=np.mean, ci=95, n_boot=1000, units=None,
               markers="o", linestyles="-", dodge=False, join=True, scale=1,
-              orient=None, color=None, palette=None, ax=None, errwidth=None,
-              capsize=None, **kwargs):
-
-    # Handle some deprecated arguments
-    if "hline" in kwargs:
-        kwargs.pop("hline")
-        warnings.warn("The `hline` parameter has been removed", UserWarning)
-
-    if "dropna" in kwargs:
-        kwargs.pop("dropna")
-        warnings.warn("The `dropna` parameter has been removed", UserWarning)
-
-    if "x_order" in kwargs:
-        order = kwargs.pop("x_order")
-        warnings.warn("The `x_order` parameter has been renamed `order`",
-                      UserWarning)
+              orient=None, color=None, palette=None, errwidth=None,
+              capsize=None, ax=None, **kwargs):
 
     plotter = _PointPlotter(x, y, hue, data, order, hue_order,
                             estimator, ci, n_boot, units,
@@ -3118,6 +3175,8 @@ pointplot.__doc__ = dedent("""\
     {orient}
     {color}
     {palette}
+    {errwidth}
+    {capsize}
     {ax_in}
 
     Returns
@@ -3221,6 +3280,13 @@ pointplot.__doc__ = dedent("""\
 
         >>> ax = sns.pointplot(x="day", y="tip", data=tips, ci=68)
 
+    Show standard deviation of observations instead of a confidence interval:
+
+    .. plot::
+        :context: close-figs
+
+        >>> ax = sns.pointplot(x="day", y="tip", data=tips, ci="sd")
+
     Add "caps" to the error bars:
 
     .. plot::
@@ -3228,18 +3294,34 @@ pointplot.__doc__ = dedent("""\
 
         >>> ax = sns.pointplot(x="day", y="tip", data=tips, capsize=.2)
 
+    Use :func:`factorplot` to combine a :func:`barplot` and a
+    :class:`FacetGrid`. This allows grouping within additional categorical
+    variables. Using :func:`factorplot` is safer than using :class:`FacetGrid`
+    directly, as it ensures synchronization of variable order across facets:
+
+    .. plot::
+        :context: close-figs
+
+        >>> g = sns.factorplot(x="sex", y="total_bill",
+        ...                    hue="smoker", col="time",
+        ...                    data=tips, kind="point",
+        ...                    dodge=True,
+        ...                    size=4, aspect=.7);
+
     """).format(**_categorical_docs)
 
 
 def countplot(x=None, y=None, hue=None, data=None, order=None, hue_order=None,
               orient=None, color=None, palette=None, saturation=.75,
-              ax=None, **kwargs):
+              dodge=True, ax=None, **kwargs):
 
     estimator = len
     ci = None
     n_boot = 0
     units = None
     errcolor = None
+    errwidth = None
+    capsize = None
 
     if x is None and y is not None:
         orient = "h"
@@ -3255,7 +3337,7 @@ def countplot(x=None, y=None, hue=None, data=None, order=None, hue_order=None,
     plotter = _BarPlotter(x, y, hue, data, order, hue_order,
                           estimator, ci, n_boot, units,
                           orient, color, palette, saturation,
-                          errcolor)
+                          errcolor, errwidth, capsize, dodge)
 
     plotter.value_label = "count"
 
@@ -3284,6 +3366,7 @@ countplot.__doc__ = dedent("""\
     {color}
     {palette}
     {saturation}
+    {dodge}
     {ax_in}
     kwargs : key, value mappings
         Other keyword arguments are passed to ``plt.bar``.
@@ -3341,6 +3424,18 @@ countplot.__doc__ = dedent("""\
         ...                    linewidth=5,
         ...                    edgecolor=sns.color_palette("dark", 3))
 
+    Use :func:`factorplot` to combine a :func:`countplot` and a
+    :class:`FacetGrid`. This allows grouping within additional categorical
+    variables. Using :func:`factorplot` is safer than using :class:`FacetGrid`
+    directly, as it ensures synchronization of variable order across facets:
+
+    .. plot::
+        :context: close-figs
+
+        >>> g = sns.factorplot(x="class", hue="who", col="survived",
+        ...                    data=titanic, kind="count",
+        ...                    size=4, aspect=.7);
+
     """).format(**_categorical_docs)
 
 
@@ -3352,20 +3447,6 @@ def factorplot(x=None, y=None, hue=None, data=None, row=None, col=None,
                legend=True, legend_out=True, sharex=True, sharey=True,
                margin_titles=False, facet_kws=None, **kwargs):
 
-    # Handle some deprecated arguments
-    if "hline" in kwargs:
-        kwargs.pop("hline")
-        warnings.warn("The `hline` parameter has been removed", UserWarning)
-
-    if "dropna" in kwargs:
-        kwargs.pop("dropna")
-        warnings.warn("The `dropna` parameter has been removed", UserWarning)
-
-    if "x_order" in kwargs:
-        order = kwargs.pop("x_order")
-        warnings.warn("The `x_order` parameter has been renamed `order`",
-                      UserWarning)
-
     # Determine the plotting function
     try:
         plot_func = globals()[kind + "plot"]
@@ -3437,7 +3518,7 @@ def factorplot(x=None, y=None, hue=None, data=None, row=None, col=None,
             g.set_axis_labels(y_var="count")
 
     if legend and (hue is not None) and (hue not in [x, row, col]):
-        hue_order = list(map(str, hue_order))
+        hue_order = list(map(utils.to_utf8, hue_order))
         g.add_legend(title=hue, label_order=hue_order)
 
     return g
@@ -3566,7 +3647,7 @@ factorplot.__doc__ = dedent("""\
         ...                    hue="sex", row="class",
         ...                    data=titanic[titanic.embark_town.notnull()],
         ...                    orient="h", size=2, aspect=3.5, palette="Set3",
-        ...                    kind="violin", split=True, cut=0, bw=.2)
+        ...                    kind="violin", dodge=True, cut=0, bw=.2)
 
     Use methods on the returned :class:`FacetGrid` to tweak the presentation:
 
@@ -3588,12 +3669,12 @@ factorplot.__doc__ = dedent("""\
 
 def lvplot(x=None, y=None, hue=None, data=None, order=None, hue_order=None,
            orient=None, color=None, palette=None, saturation=.75,
-           width=.8, k_depth='proportion', linewidth=None, scale='exponential',
-           outlier_prop=None, ax=None, **kwargs):
+           width=.8, dodge=True, k_depth='proportion', linewidth=None,
+           scale='exponential', outlier_prop=None, ax=None, **kwargs):
 
     plotter = _LVPlotter(x, y, hue, data, order, hue_order,
                          orient, color, palette, saturation,
-                         width, k_depth, linewidth, scale, outlier_prop)
+                         width, dodge, k_depth, linewidth, scale, outlier_prop)
 
     if ax is None:
         ax = plt.gca()
@@ -3602,7 +3683,7 @@ def lvplot(x=None, y=None, hue=None, data=None, order=None, hue_order=None,
     return ax
 
 lvplot.__doc__ = dedent("""\
-    Create a letter value plot
+    Draw a letter value plot to show distributions of large datasets.
 
     Letter value (LV) plots are non-parametric estimates of the distribution of
     a dataset, similar to boxplots. LV plots are also similar to violin plots
@@ -3626,6 +3707,7 @@ lvplot.__doc__ = dedent("""\
     {palette}
     {saturation}
     {width}
+    {dodge}
     k_depth : "proportion" | "tukey" | "trustworthy", optional
         The number of boxes, and by extension number of percentiles, to draw.
         All methods are detailed in Wickham's paper. Each makes different
@@ -3714,18 +3796,19 @@ lvplot.__doc__ = dedent("""\
 
         >>> ax = sns.lvplot(x="day", y="total_bill", data=tips)
         >>> ax = sns.stripplot(x="day", y="total_bill", data=tips,
-        ...                    size=4, jitter=True, edgecolor="gray")
+        ...                    size=4, jitter=True, color="gray")
 
-    Draw a letter value plot on to a :class:`FacetGrid` to group within an
-    additional categorical variable:
+    Use :func:`factorplot` to combine a :func:`lvplot` and a
+    :class:`FacetGrid`. This allows grouping within additional categorical
+    variables. Using :func:`factorplot` is safer than using :class:`FacetGrid`
+    directly, as it ensures synchronization of variable order across facets:
 
     .. plot::
         :context: close-figs
 
-        >>> g = sns.FacetGrid(tips, col="time", size=4, aspect=.7)
-        >>> (g.map(sns.lvplot, "sex", "total_bill", "smoker")
-        ...   .despine(left=True)
-        ...   .add_legend(title="smoker"))  #doctest: +ELLIPSIS
-        <seaborn.axisgrid.FacetGrid object at 0x...>
+        >>> g = sns.factorplot(x="sex", y="total_bill",
+        ...                    hue="smoker", col="time",
+        ...                    data=tips, kind="lv",
+        ...                    size=4, aspect=.7);
 
     """).format(**_categorical_docs)
diff --git a/seaborn/cm.py b/seaborn/cm.py
new file mode 100644
index 0000000..c250163
--- /dev/null
+++ b/seaborn/cm.py
@@ -0,0 +1,1056 @@
+from matplotlib import colors, cm as mpl_cm
+
+
+_rocket_lut = [
+    [ 0.01060815, 0.01808215, 0.10018654],
+    [ 0.01428972, 0.02048237, 0.10374486],
+    [ 0.01831941, 0.0229766 , 0.10738511],
+    [ 0.02275049, 0.02554464, 0.11108639],
+    [ 0.02759119, 0.02818316, 0.11483751],
+    [ 0.03285175, 0.03088792, 0.11863035],
+    [ 0.03853466, 0.03365771, 0.12245873],
+    [ 0.04447016, 0.03648425, 0.12631831],
+    [ 0.05032105, 0.03936808, 0.13020508],
+    [ 0.05611171, 0.04224835, 0.13411624],
+    [ 0.0618531 , 0.04504866, 0.13804929],
+    [ 0.06755457, 0.04778179, 0.14200206],
+    [ 0.0732236 , 0.05045047, 0.14597263],
+    [ 0.0788708 , 0.05305461, 0.14995981],
+    [ 0.08450105, 0.05559631, 0.15396203],
+    [ 0.09011319, 0.05808059, 0.15797687],
+    [ 0.09572396, 0.06050127, 0.16200507],
+    [ 0.10132312, 0.06286782, 0.16604287],
+    [ 0.10692823, 0.06517224, 0.17009175],
+    [ 0.1125315 , 0.06742194, 0.17414848],
+    [ 0.11813947, 0.06961499, 0.17821272],
+    [ 0.12375803, 0.07174938, 0.18228425],
+    [ 0.12938228, 0.07383015, 0.18636053],
+    [ 0.13501631, 0.07585609, 0.19044109],
+    [ 0.14066867, 0.0778224 , 0.19452676],
+    [ 0.14633406, 0.07973393, 0.1986151 ],
+    [ 0.15201338, 0.08159108, 0.20270523],
+    [ 0.15770877, 0.08339312, 0.20679668],
+    [ 0.16342174, 0.0851396 , 0.21088893],
+    [ 0.16915387, 0.08682996, 0.21498104],
+    [ 0.17489524, 0.08848235, 0.2190294 ],
+    [ 0.18065495, 0.09009031, 0.22303512],
+    [ 0.18643324, 0.09165431, 0.22699705],
+    [ 0.19223028, 0.09317479, 0.23091409],
+    [ 0.19804623, 0.09465217, 0.23478512],
+    [ 0.20388117, 0.09608689, 0.23860907],
+    [ 0.20973515, 0.09747934, 0.24238489],
+    [ 0.21560818, 0.09882993, 0.24611154],
+    [ 0.22150014, 0.10013944, 0.2497868 ],
+    [ 0.22741085, 0.10140876, 0.25340813],
+    [ 0.23334047, 0.10263737, 0.25697736],
+    [ 0.23928891, 0.10382562, 0.2604936 ],
+    [ 0.24525608, 0.10497384, 0.26395596],
+    [ 0.25124182, 0.10608236, 0.26736359],
+    [ 0.25724602, 0.10715148, 0.27071569],
+    [ 0.26326851, 0.1081815 , 0.27401148],
+    [ 0.26930915, 0.1091727 , 0.2772502 ],
+    [ 0.27536766, 0.11012568, 0.28043021],
+    [ 0.28144375, 0.11104133, 0.2835489 ],
+    [ 0.2875374 , 0.11191896, 0.28660853],
+    [ 0.29364846, 0.11275876, 0.2896085 ],
+    [ 0.29977678, 0.11356089, 0.29254823],
+    [ 0.30592213, 0.11432553, 0.29542718],
+    [ 0.31208435, 0.11505284, 0.29824485],
+    [ 0.31826327, 0.1157429 , 0.30100076],
+    [ 0.32445869, 0.11639585, 0.30369448],
+    [ 0.33067031, 0.11701189, 0.30632563],
+    [ 0.33689808, 0.11759095, 0.3088938 ],
+    [ 0.34314168, 0.11813362, 0.31139721],
+    [ 0.34940101, 0.11863987, 0.3138355 ],
+    [ 0.355676  , 0.11910909, 0.31620996],
+    [ 0.36196644, 0.1195413 , 0.31852037],
+    [ 0.36827206, 0.11993653, 0.32076656],
+    [ 0.37459292, 0.12029443, 0.32294825],
+    [ 0.38092887, 0.12061482, 0.32506528],
+    [ 0.38727975, 0.12089756, 0.3271175 ],
+    [ 0.39364518, 0.12114272, 0.32910494],
+    [ 0.40002537, 0.12134964, 0.33102734],
+    [ 0.40642019, 0.12151801, 0.33288464],
+    [ 0.41282936, 0.12164769, 0.33467689],
+    [ 0.41925278, 0.12173833, 0.33640407],
+    [ 0.42569057, 0.12178916, 0.33806605],
+    [ 0.43214263, 0.12179973, 0.33966284],
+    [ 0.43860848, 0.12177004, 0.34119475],
+    [ 0.44508855, 0.12169883, 0.34266151],
+    [ 0.45158266, 0.12158557, 0.34406324],
+    [ 0.45809049, 0.12142996, 0.34540024],
+    [ 0.46461238, 0.12123063, 0.34667231],
+    [ 0.47114798, 0.12098721, 0.34787978],
+    [ 0.47769736, 0.12069864, 0.34902273],
+    [ 0.48426077, 0.12036349, 0.35010104],
+    [ 0.49083761, 0.11998161, 0.35111537],
+    [ 0.49742847, 0.11955087, 0.35206533],
+    [ 0.50403286, 0.11907081, 0.35295152],
+    [ 0.51065109, 0.11853959, 0.35377385],
+    [ 0.51728314, 0.1179558 , 0.35453252],
+    [ 0.52392883, 0.11731817, 0.35522789],
+    [ 0.53058853, 0.11662445, 0.35585982],
+    [ 0.53726173, 0.11587369, 0.35642903],
+    [ 0.54394898, 0.11506307, 0.35693521],
+    [ 0.5506426 , 0.11420757, 0.35737863],
+    [ 0.55734473, 0.11330456, 0.35775059],
+    [ 0.56405586, 0.11235265, 0.35804813],
+    [ 0.57077365, 0.11135597, 0.35827146],
+    [ 0.5774991 , 0.11031233, 0.35841679],
+    [ 0.58422945, 0.10922707, 0.35848469],
+    [ 0.59096382, 0.10810205, 0.35847347],
+    [ 0.59770215, 0.10693774, 0.35838029],
+    [ 0.60444226, 0.10573912, 0.35820487],
+    [ 0.61118304, 0.10450943, 0.35794557],
+    [ 0.61792306, 0.10325288, 0.35760108],
+    [ 0.62466162, 0.10197244, 0.35716891],
+    [ 0.63139686, 0.10067417, 0.35664819],
+    [ 0.63812122, 0.09938212, 0.35603757],
+    [ 0.64483795, 0.0980891 , 0.35533555],
+    [ 0.65154562, 0.09680192, 0.35454107],
+    [ 0.65824241, 0.09552918, 0.3536529 ],
+    [ 0.66492652, 0.09428017, 0.3526697 ],
+    [ 0.67159578, 0.09306598, 0.35159077],
+    [ 0.67824099, 0.09192342, 0.3504148 ],
+    [ 0.684863  , 0.09085633, 0.34914061],
+    [ 0.69146268, 0.0898675 , 0.34776864],
+    [ 0.69803757, 0.08897226, 0.3462986 ],
+    [ 0.70457834, 0.0882129 , 0.34473046],
+    [ 0.71108138, 0.08761223, 0.3430635 ],
+    [ 0.7175507 , 0.08716212, 0.34129974],
+    [ 0.72398193, 0.08688725, 0.33943958],
+    [ 0.73035829, 0.0868623 , 0.33748452],
+    [ 0.73669146, 0.08704683, 0.33543669],
+    [ 0.74297501, 0.08747196, 0.33329799],
+    [ 0.74919318, 0.08820542, 0.33107204],
+    [ 0.75535825, 0.08919792, 0.32876184],
+    [ 0.76145589, 0.09050716, 0.32637117],
+    [ 0.76748424, 0.09213602, 0.32390525],
+    [ 0.77344838, 0.09405684, 0.32136808],
+    [ 0.77932641, 0.09634794, 0.31876642],
+    [ 0.78513609, 0.09892473, 0.31610488],
+    [ 0.79085854, 0.10184672, 0.313391  ],
+    [ 0.7965014 , 0.10506637, 0.31063031],
+    [ 0.80205987, 0.10858333, 0.30783   ],
+    [ 0.80752799, 0.11239964, 0.30499738],
+    [ 0.81291606, 0.11645784, 0.30213802],
+    [ 0.81820481, 0.12080606, 0.29926105],
+    [ 0.82341472, 0.12535343, 0.2963705 ],
+    [ 0.82852822, 0.13014118, 0.29347474],
+    [ 0.83355779, 0.13511035, 0.29057852],
+    [ 0.83850183, 0.14025098, 0.2876878 ],
+    [ 0.84335441, 0.14556683, 0.28480819],
+    [ 0.84813096, 0.15099892, 0.281943  ],
+    [ 0.85281737, 0.15657772, 0.27909826],
+    [ 0.85742602, 0.1622583 , 0.27627462],
+    [ 0.86196552, 0.16801239, 0.27346473],
+    [ 0.86641628, 0.17387796, 0.27070818],
+    [ 0.87079129, 0.17982114, 0.26797378],
+    [ 0.87507281, 0.18587368, 0.26529697],
+    [ 0.87925878, 0.19203259, 0.26268136],
+    [ 0.8833417 , 0.19830556, 0.26014181],
+    [ 0.88731387, 0.20469941, 0.25769539],
+    [ 0.89116859, 0.21121788, 0.2553592 ],
+    [ 0.89490337, 0.21785614, 0.25314362],
+    [ 0.8985026 , 0.22463251, 0.25108745],
+    [ 0.90197527, 0.23152063, 0.24918223],
+    [ 0.90530097, 0.23854541, 0.24748098],
+    [ 0.90848638, 0.24568473, 0.24598324],
+    [ 0.911533  , 0.25292623, 0.24470258],
+    [ 0.9144225 , 0.26028902, 0.24369359],
+    [ 0.91717106, 0.26773821, 0.24294137],
+    [ 0.91978131, 0.27526191, 0.24245973],
+    [ 0.92223947, 0.28287251, 0.24229568],
+    [ 0.92456587, 0.29053388, 0.24242622],
+    [ 0.92676657, 0.29823282, 0.24285536],
+    [ 0.92882964, 0.30598085, 0.24362274],
+    [ 0.93078135, 0.31373977, 0.24468803],
+    [ 0.93262051, 0.3215093 , 0.24606461],
+    [ 0.93435067, 0.32928362, 0.24775328],
+    [ 0.93599076, 0.33703942, 0.24972157],
+    [ 0.93752831, 0.34479177, 0.25199928],
+    [ 0.93899289, 0.35250734, 0.25452808],
+    [ 0.94036561, 0.36020899, 0.25734661],
+    [ 0.94167588, 0.36786594, 0.2603949 ],
+    [ 0.94291042, 0.37549479, 0.26369821],
+    [ 0.94408513, 0.3830811 , 0.26722004],
+    [ 0.94520419, 0.39062329, 0.27094924],
+    [ 0.94625977, 0.39813168, 0.27489742],
+    [ 0.94727016, 0.4055909 , 0.27902322],
+    [ 0.94823505, 0.41300424, 0.28332283],
+    [ 0.94914549, 0.42038251, 0.28780969],
+    [ 0.95001704, 0.42771398, 0.29244728],
+    [ 0.95085121, 0.43500005, 0.29722817],
+    [ 0.95165009, 0.44224144, 0.30214494],
+    [ 0.9524044 , 0.44944853, 0.3072105 ],
+    [ 0.95312556, 0.45661389, 0.31239776],
+    [ 0.95381595, 0.46373781, 0.31769923],
+    [ 0.95447591, 0.47082238, 0.32310953],
+    [ 0.95510255, 0.47787236, 0.32862553],
+    [ 0.95569679, 0.48489115, 0.33421404],
+    [ 0.95626788, 0.49187351, 0.33985601],
+    [ 0.95681685, 0.49882008, 0.34555431],
+    [ 0.9573439 , 0.50573243, 0.35130912],
+    [ 0.95784842, 0.51261283, 0.35711942],
+    [ 0.95833051, 0.51946267, 0.36298589],
+    [ 0.95879054, 0.52628305, 0.36890904],
+    [ 0.95922872, 0.53307513, 0.3748895 ],
+    [ 0.95964538, 0.53983991, 0.38092784],
+    [ 0.96004345, 0.54657593, 0.3870292 ],
+    [ 0.96042097, 0.55328624, 0.39319057],
+    [ 0.96077819, 0.55997184, 0.39941173],
+    [ 0.9611152 , 0.5666337 , 0.40569343],
+    [ 0.96143273, 0.57327231, 0.41203603],
+    [ 0.96173392, 0.57988594, 0.41844491],
+    [ 0.96201757, 0.58647675, 0.42491751],
+    [ 0.96228344, 0.59304598, 0.43145271],
+    [ 0.96253168, 0.5995944 , 0.43805131],
+    [ 0.96276513, 0.60612062, 0.44471698],
+    [ 0.96298491, 0.6126247 , 0.45145074],
+    [ 0.96318967, 0.61910879, 0.45824902],
+    [ 0.96337949, 0.6255736 , 0.46511271],
+    [ 0.96355923, 0.63201624, 0.47204746],
+    [ 0.96372785, 0.63843852, 0.47905028],
+    [ 0.96388426, 0.64484214, 0.4861196 ],
+    [ 0.96403203, 0.65122535, 0.4932578 ],
+    [ 0.96417332, 0.65758729, 0.50046894],
+    [ 0.9643063 , 0.66393045, 0.5077467 ],
+    [ 0.96443322, 0.67025402, 0.51509334],
+    [ 0.96455845, 0.67655564, 0.52251447],
+    [ 0.96467922, 0.68283846, 0.53000231],
+    [ 0.96479861, 0.68910113, 0.53756026],
+    [ 0.96492035, 0.69534192, 0.5451917 ],
+    [ 0.96504223, 0.7015636 , 0.5528892 ],
+    [ 0.96516917, 0.70776351, 0.5606593 ],
+    [ 0.96530224, 0.71394212, 0.56849894],
+    [ 0.96544032, 0.72010124, 0.57640375],
+    [ 0.96559206, 0.72623592, 0.58438387],
+    [ 0.96575293, 0.73235058, 0.59242739],
+    [ 0.96592829, 0.73844258, 0.60053991],
+    [ 0.96612013, 0.74451182, 0.60871954],
+    [ 0.96632832, 0.75055966, 0.61696136],
+    [ 0.96656022, 0.75658231, 0.62527295],
+    [ 0.96681185, 0.76258381, 0.63364277],
+    [ 0.96709183, 0.76855969, 0.64207921],
+    [ 0.96739773, 0.77451297, 0.65057302],
+    [ 0.96773482, 0.78044149, 0.65912731],
+    [ 0.96810471, 0.78634563, 0.66773889],
+    [ 0.96850919, 0.79222565, 0.6764046 ],
+    [ 0.96893132, 0.79809112, 0.68512266],
+    [ 0.96935926, 0.80395415, 0.69383201],
+    [ 0.9698028 , 0.80981139, 0.70252255],
+    [ 0.97025511, 0.81566605, 0.71120296],
+    [ 0.97071849, 0.82151775, 0.71987163],
+    [ 0.97120159, 0.82736371, 0.72851999],
+    [ 0.97169389, 0.83320847, 0.73716071],
+    [ 0.97220061, 0.83905052, 0.74578903],
+    [ 0.97272597, 0.84488881, 0.75440141],
+    [ 0.97327085, 0.85072354, 0.76299805],
+    [ 0.97383206, 0.85655639, 0.77158353],
+    [ 0.97441222, 0.86238689, 0.78015619],
+    [ 0.97501782, 0.86821321, 0.78871034],
+    [ 0.97564391, 0.87403763, 0.79725261],
+    [ 0.97628674, 0.87986189, 0.8057883 ],
+    [ 0.97696114, 0.88568129, 0.81430324],
+    [ 0.97765722, 0.89149971, 0.82280948],
+    [ 0.97837585, 0.89731727, 0.83130786],
+    [ 0.97912374, 0.90313207, 0.83979337],
+    [ 0.979891  , 0.90894778, 0.84827858],
+    [ 0.98067764, 0.91476465, 0.85676611],
+    [ 0.98137749, 0.92061729, 0.86536915]
+]
+
+
+_mako_lut = [
+    [ 0.04503935, 0.01482344, 0.02092227],
+    [ 0.04933018, 0.01709292, 0.02535719],
+    [ 0.05356262, 0.01950702, 0.03018802],
+    [ 0.05774337, 0.02205989, 0.03545515],
+    [ 0.06188095, 0.02474764, 0.04115287],
+    [ 0.06598247, 0.0275665 , 0.04691409],
+    [ 0.07005374, 0.03051278, 0.05264306],
+    [ 0.07409947, 0.03358324, 0.05834631],
+    [ 0.07812339, 0.03677446, 0.06403249],
+    [ 0.08212852, 0.0400833 , 0.06970862],
+    [ 0.08611731, 0.04339148, 0.07538208],
+    [ 0.09009161, 0.04664706, 0.08105568],
+    [ 0.09405308, 0.04985685, 0.08673591],
+    [ 0.09800301, 0.05302279, 0.09242646],
+    [ 0.10194255, 0.05614641, 0.09813162],
+    [ 0.10587261, 0.05922941, 0.103854  ],
+    [ 0.1097942 , 0.06227277, 0.10959847],
+    [ 0.11370826, 0.06527747, 0.11536893],
+    [ 0.11761516, 0.06824548, 0.12116393],
+    [ 0.12151575, 0.07117741, 0.12698763],
+    [ 0.12541095, 0.07407363, 0.1328442 ],
+    [ 0.12930083, 0.07693611, 0.13873064],
+    [ 0.13317849, 0.07976988, 0.14465095],
+    [ 0.13701138, 0.08259683, 0.15060265],
+    [ 0.14079223, 0.08542126, 0.15659379],
+    [ 0.14452486, 0.08824175, 0.16262484],
+    [ 0.14820351, 0.09106304, 0.16869476],
+    [ 0.15183185, 0.09388372, 0.17480366],
+    [ 0.15540398, 0.09670855, 0.18094993],
+    [ 0.15892417, 0.09953561, 0.18713384],
+    [ 0.16238588, 0.10236998, 0.19335329],
+    [ 0.16579435, 0.10520905, 0.19960847],
+    [ 0.16914226, 0.10805832, 0.20589698],
+    [ 0.17243586, 0.11091443, 0.21221911],
+    [ 0.17566717, 0.11378321, 0.21857219],
+    [ 0.17884322, 0.11666074, 0.2249565 ],
+    [ 0.18195582, 0.11955283, 0.23136943],
+    [ 0.18501213, 0.12245547, 0.23781116],
+    [ 0.18800459, 0.12537395, 0.24427914],
+    [ 0.19093944, 0.1283047 , 0.25077369],
+    [ 0.19381092, 0.13125179, 0.25729255],
+    [ 0.19662307, 0.13421303, 0.26383543],
+    [ 0.19937337, 0.13719028, 0.27040111],
+    [ 0.20206187, 0.14018372, 0.27698891],
+    [ 0.20469116, 0.14319196, 0.28359861],
+    [ 0.20725547, 0.14621882, 0.29022775],
+    [ 0.20976258, 0.14925954, 0.29687795],
+    [ 0.21220409, 0.15231929, 0.30354703],
+    [ 0.21458611, 0.15539445, 0.31023563],
+    [ 0.21690827, 0.15848519, 0.31694355],
+    [ 0.21916481, 0.16159489, 0.32366939],
+    [ 0.2213631 , 0.16471913, 0.33041431],
+    [ 0.22349947, 0.1678599 , 0.33717781],
+    [ 0.2255714 , 0.1710185 , 0.34395925],
+    [ 0.22758415, 0.17419169, 0.35075983],
+    [ 0.22953569, 0.17738041, 0.35757941],
+    [ 0.23142077, 0.18058733, 0.3644173 ],
+    [ 0.2332454 , 0.18380872, 0.37127514],
+    [ 0.2350092 , 0.18704459, 0.3781528 ],
+    [ 0.23670785, 0.190297  , 0.38504973],
+    [ 0.23834119, 0.19356547, 0.39196711],
+    [ 0.23991189, 0.19684817, 0.39890581],
+    [ 0.24141903, 0.20014508, 0.4058667 ],
+    [ 0.24286214, 0.20345642, 0.4128484 ],
+    [ 0.24423453, 0.20678459, 0.41985299],
+    [ 0.24554109, 0.21012669, 0.42688124],
+    [ 0.2467815 , 0.21348266, 0.43393244],
+    [ 0.24795393, 0.21685249, 0.4410088 ],
+    [ 0.24905614, 0.22023618, 0.448113  ],
+    [ 0.25007383, 0.22365053, 0.45519562],
+    [ 0.25098926, 0.22710664, 0.46223892],
+    [ 0.25179696, 0.23060342, 0.46925447],
+    [ 0.25249346, 0.23414353, 0.47623196],
+    [ 0.25307401, 0.23772973, 0.48316271],
+    [ 0.25353152, 0.24136961, 0.49001976],
+    [ 0.25386167, 0.24506548, 0.49679407],
+    [ 0.25406082, 0.2488164 , 0.50348932],
+    [ 0.25412435, 0.25262843, 0.51007843],
+    [ 0.25404842, 0.25650743, 0.51653282],
+    [ 0.25383134, 0.26044852, 0.52286845],
+    [ 0.2534705 , 0.26446165, 0.52903422],
+    [ 0.25296722, 0.2685428 , 0.53503572],
+    [ 0.2523226 , 0.27269346, 0.54085315],
+    [ 0.25153974, 0.27691629, 0.54645752],
+    [ 0.25062402, 0.28120467, 0.55185939],
+    [ 0.24958205, 0.28556371, 0.55701246],
+    [ 0.24842386, 0.28998148, 0.56194601],
+    [ 0.24715928, 0.29446327, 0.56660884],
+    [ 0.24580099, 0.29899398, 0.57104399],
+    [ 0.24436202, 0.30357852, 0.57519929],
+    [ 0.24285591, 0.30819938, 0.57913247],
+    [ 0.24129828, 0.31286235, 0.58278615],
+    [ 0.23970131, 0.3175495 , 0.5862272 ],
+    [ 0.23807973, 0.32226344, 0.58941872],
+    [ 0.23644557, 0.32699241, 0.59240198],
+    [ 0.2348113 , 0.33173196, 0.59518282],
+    [ 0.23318874, 0.33648036, 0.59775543],
+    [ 0.2315855 , 0.34122763, 0.60016456],
+    [ 0.23001121, 0.34597357, 0.60240251],
+    [ 0.2284748 , 0.35071512, 0.6044784 ],
+    [ 0.22698081, 0.35544612, 0.60642528],
+    [ 0.22553305, 0.36016515, 0.60825252],
+    [ 0.22413977, 0.36487341, 0.60994938],
+    [ 0.22280246, 0.36956728, 0.61154118],
+    [ 0.22152555, 0.37424409, 0.61304472],
+    [ 0.22030752, 0.37890437, 0.61446646],
+    [ 0.2191538 , 0.38354668, 0.61581561],
+    [ 0.21806257, 0.38817169, 0.61709794],
+    [ 0.21703799, 0.39277882, 0.61831922],
+    [ 0.21607792, 0.39736958, 0.61948028],
+    [ 0.21518463, 0.40194196, 0.62059763],
+    [ 0.21435467, 0.40649717, 0.62167507],
+    [ 0.21358663, 0.41103579, 0.62271724],
+    [ 0.21288172, 0.41555771, 0.62373011],
+    [ 0.21223835, 0.42006355, 0.62471794],
+    [ 0.21165312, 0.42455441, 0.62568371],
+    [ 0.21112526, 0.42903064, 0.6266318 ],
+    [ 0.21065161, 0.43349321, 0.62756504],
+    [ 0.21023306, 0.43794288, 0.62848279],
+    [ 0.20985996, 0.44238227, 0.62938329],
+    [ 0.20951045, 0.44680966, 0.63030696],
+    [ 0.20916709, 0.45122981, 0.63124483],
+    [ 0.20882976, 0.45564335, 0.63219599],
+    [ 0.20849798, 0.46005094, 0.63315928],
+    [ 0.20817199, 0.46445309, 0.63413391],
+    [ 0.20785149, 0.46885041, 0.63511876],
+    [ 0.20753716, 0.47324327, 0.63611321],
+    [ 0.20722876, 0.47763224, 0.63711608],
+    [ 0.20692679, 0.48201774, 0.63812656],
+    [ 0.20663156, 0.48640018, 0.63914367],
+    [ 0.20634336, 0.49078002, 0.64016638],
+    [ 0.20606303, 0.49515755, 0.6411939 ],
+    [ 0.20578999, 0.49953341, 0.64222457],
+    [ 0.20552612, 0.50390766, 0.64325811],
+    [ 0.20527189, 0.50828072, 0.64429331],
+    [ 0.20502868, 0.51265277, 0.64532947],
+    [ 0.20479718, 0.51702417, 0.64636539],
+    [ 0.20457804, 0.52139527, 0.64739979],
+    [ 0.20437304, 0.52576622, 0.64843198],
+    [ 0.20418396, 0.53013715, 0.64946117],
+    [ 0.20401238, 0.53450825, 0.65048638],
+    [ 0.20385896, 0.53887991, 0.65150606],
+    [ 0.20372653, 0.54325208, 0.65251978],
+    [ 0.20361709, 0.5476249 , 0.6535266 ],
+    [ 0.20353258, 0.55199854, 0.65452542],
+    [ 0.20347472, 0.55637318, 0.655515  ],
+    [ 0.20344718, 0.56074869, 0.65649508],
+    [ 0.20345161, 0.56512531, 0.65746419],
+    [ 0.20349089, 0.56950304, 0.65842151],
+    [ 0.20356842, 0.57388184, 0.65936642],
+    [ 0.20368663, 0.57826181, 0.66029768],
+    [ 0.20384884, 0.58264293, 0.6612145 ],
+    [ 0.20405904, 0.58702506, 0.66211645],
+    [ 0.20431921, 0.59140842, 0.66300179],
+    [ 0.20463464, 0.59579264, 0.66387079],
+    [ 0.20500731, 0.60017798, 0.66472159],
+    [ 0.20544449, 0.60456387, 0.66555409],
+    [ 0.20596097, 0.60894927, 0.66636568],
+    [ 0.20654832, 0.61333521, 0.66715744],
+    [ 0.20721003, 0.61772167, 0.66792838],
+    [ 0.20795035, 0.62210845, 0.66867802],
+    [ 0.20877302, 0.62649546, 0.66940555],
+    [ 0.20968223, 0.63088252, 0.6701105 ],
+    [ 0.21068163, 0.63526951, 0.67079211],
+    [ 0.21177544, 0.63965621, 0.67145005],
+    [ 0.21298582, 0.64404072, 0.67208182],
+    [ 0.21430361, 0.64842404, 0.67268861],
+    [ 0.21572716, 0.65280655, 0.67326978],
+    [ 0.21726052, 0.65718791, 0.6738255 ],
+    [ 0.21890636, 0.66156803, 0.67435491],
+    [ 0.220668  , 0.66594665, 0.67485792],
+    [ 0.22255447, 0.67032297, 0.67533374],
+    [ 0.22458372, 0.67469531, 0.67578061],
+    [ 0.22673713, 0.67906542, 0.67620044],
+    [ 0.22901625, 0.6834332 , 0.67659251],
+    [ 0.23142316, 0.68779836, 0.67695703],
+    [ 0.23395924, 0.69216072, 0.67729378],
+    [ 0.23663857, 0.69651881, 0.67760151],
+    [ 0.23946645, 0.70087194, 0.67788018],
+    [ 0.24242624, 0.70522162, 0.67813088],
+    [ 0.24549008, 0.70957083, 0.67835215],
+    [ 0.24863372, 0.71392166, 0.67854868],
+    [ 0.25187832, 0.71827158, 0.67872193],
+    [ 0.25524083, 0.72261873, 0.67887024],
+    [ 0.25870947, 0.72696469, 0.67898912],
+    [ 0.26229238, 0.73130855, 0.67907645],
+    [ 0.26604085, 0.73564353, 0.67914062],
+    [ 0.26993099, 0.73997282, 0.67917264],
+    [ 0.27397488, 0.74429484, 0.67917096],
+    [ 0.27822463, 0.74860229, 0.67914468],
+    [ 0.28264201, 0.75290034, 0.67907959],
+    [ 0.2873016 , 0.75717817, 0.67899164],
+    [ 0.29215894, 0.76144162, 0.67886578],
+    [ 0.29729823, 0.76567816, 0.67871894],
+    [ 0.30268199, 0.76989232, 0.67853896],
+    [ 0.30835665, 0.77407636, 0.67833512],
+    [ 0.31435139, 0.77822478, 0.67811118],
+    [ 0.3206671 , 0.78233575, 0.67786729],
+    [ 0.32733158, 0.78640315, 0.67761027],
+    [ 0.33437168, 0.79042043, 0.67734882],
+    [ 0.34182112, 0.79437948, 0.67709394],
+    [ 0.34968889, 0.79827511, 0.67685638],
+    [ 0.35799244, 0.80210037, 0.67664969],
+    [ 0.36675371, 0.80584651, 0.67649539],
+    [ 0.3759816 , 0.80950627, 0.67641393],
+    [ 0.38566792, 0.81307432, 0.67642947],
+    [ 0.39579804, 0.81654592, 0.67656899],
+    [ 0.40634556, 0.81991799, 0.67686215],
+    [ 0.41730243, 0.82318339, 0.67735255],
+    [ 0.4285828 , 0.82635051, 0.6780564 ],
+    [ 0.44012728, 0.82942353, 0.67900049],
+    [ 0.45189421, 0.83240398, 0.68021733],
+    [ 0.46378379, 0.83530763, 0.6817062 ],
+    [ 0.47573199, 0.83814472, 0.68347352],
+    [ 0.48769865, 0.84092197, 0.68552698],
+    [ 0.49962354, 0.84365379, 0.68783929],
+    [ 0.5114027 , 0.8463718 , 0.69029789],
+    [ 0.52301693, 0.84908401, 0.69288545],
+    [ 0.53447549, 0.85179048, 0.69561066],
+    [ 0.54578602, 0.8544913 , 0.69848331],
+    [ 0.55695565, 0.85718723, 0.70150427],
+    [ 0.56798832, 0.85987893, 0.70468261],
+    [ 0.57888639, 0.86256715, 0.70802931],
+    [ 0.5896541 , 0.8652532 , 0.71154204],
+    [ 0.60028928, 0.86793835, 0.71523675],
+    [ 0.61079441, 0.87062438, 0.71910895],
+    [ 0.62116633, 0.87331311, 0.72317003],
+    [ 0.63140509, 0.87600675, 0.72741689],
+    [ 0.64150735, 0.87870746, 0.73185717],
+    [ 0.65147219, 0.8814179 , 0.73648495],
+    [ 0.66129632, 0.8841403 , 0.74130658],
+    [ 0.67097934, 0.88687758, 0.74631123],
+    [ 0.68051833, 0.88963189, 0.75150483],
+    [ 0.68991419, 0.89240612, 0.75687187],
+    [ 0.69916533, 0.89520211, 0.76241714],
+    [ 0.70827373, 0.89802257, 0.76812286],
+    [ 0.71723995, 0.90086891, 0.77399039],
+    [ 0.72606665, 0.90374337, 0.7800041 ],
+    [ 0.73475675, 0.90664718, 0.78615802],
+    [ 0.74331358, 0.90958151, 0.79244474],
+    [ 0.75174143, 0.91254787, 0.79884925],
+    [ 0.76004473, 0.91554656, 0.80536823],
+    [ 0.76827704, 0.91856549, 0.81196513],
+    [ 0.77647029, 0.921603  , 0.81855729],
+    [ 0.78462009, 0.92466151, 0.82514119],
+    [ 0.79273542, 0.92773848, 0.83172131],
+    [ 0.8008109 , 0.93083672, 0.83829355],
+    [ 0.80885107, 0.93395528, 0.84485982],
+    [ 0.81685878, 0.9370938 , 0.85142101],
+    [ 0.82483206, 0.94025378, 0.8579751 ],
+    [ 0.83277661, 0.94343371, 0.86452477],
+    [ 0.84069127, 0.94663473, 0.87106853],
+    [ 0.84857662, 0.9498573 , 0.8776059 ],
+    [ 0.8564431 , 0.95309792, 0.88414253],
+    [ 0.86429066, 0.95635719, 0.89067759],
+    [ 0.87218969, 0.95960708, 0.89725384]
+]
+
+
+_vlag_lut = [
+    [ 0.13850039, 0.41331206, 0.74052025],
+    [ 0.15077609, 0.41762684, 0.73970427],
+    [ 0.16235219, 0.4219191 , 0.7389667 ],
+    [ 0.1733322 , 0.42619024, 0.73832537],
+    [ 0.18382538, 0.43044226, 0.73776764],
+    [ 0.19394034, 0.4346772 , 0.73725867],
+    [ 0.20367115, 0.43889576, 0.73685314],
+    [ 0.21313625, 0.44310003, 0.73648045],
+    [ 0.22231173, 0.44729079, 0.73619681],
+    [ 0.23125148, 0.45146945, 0.73597803],
+    [ 0.23998101, 0.45563715, 0.7358223 ],
+    [ 0.24853358, 0.45979489, 0.73571524],
+    [ 0.25691416, 0.4639437 , 0.73566943],
+    [ 0.26513894, 0.46808455, 0.73568319],
+    [ 0.27322194, 0.47221835, 0.73575497],
+    [ 0.28117543, 0.47634598, 0.73588332],
+    [ 0.28901021, 0.48046826, 0.73606686],
+    [ 0.2967358 , 0.48458597, 0.73630433],
+    [ 0.30436071, 0.48869986, 0.73659451],
+    [ 0.3118955 , 0.49281055, 0.73693255],
+    [ 0.31935389, 0.49691847, 0.73730851],
+    [ 0.32672701, 0.5010247 , 0.73774013],
+    [ 0.33402607, 0.50512971, 0.73821941],
+    [ 0.34125337, 0.50923419, 0.73874905],
+    [ 0.34840921, 0.51333892, 0.73933402],
+    [ 0.35551826, 0.51744353, 0.73994642],
+    [ 0.3625676 , 0.52154929, 0.74060763],
+    [ 0.36956356, 0.52565656, 0.74131327],
+    [ 0.37649902, 0.52976642, 0.74207698],
+    [ 0.38340273, 0.53387791, 0.74286286],
+    [ 0.39025859, 0.53799253, 0.7436962 ],
+    [ 0.39706821, 0.54211081, 0.744578  ],
+    [ 0.40384046, 0.54623277, 0.74549872],
+    [ 0.41058241, 0.55035849, 0.74645094],
+    [ 0.41728385, 0.55448919, 0.74745174],
+    [ 0.42395178, 0.55862494, 0.74849357],
+    [ 0.4305964 , 0.56276546, 0.74956387],
+    [ 0.4372044 , 0.56691228, 0.75068412],
+    [ 0.4437909 , 0.57106468, 0.75183427],
+    [ 0.45035117, 0.5752235 , 0.75302312],
+    [ 0.45687824, 0.57938983, 0.75426297],
+    [ 0.46339713, 0.58356191, 0.75551816],
+    [ 0.46988778, 0.58774195, 0.75682037],
+    [ 0.47635605, 0.59192986, 0.75816245],
+    [ 0.48281101, 0.5961252 , 0.75953212],
+    [ 0.4892374 , 0.60032986, 0.76095418],
+    [ 0.49566225, 0.60454154, 0.76238852],
+    [ 0.50206137, 0.60876307, 0.76387371],
+    [ 0.50845128, 0.61299312, 0.76538551],
+    [ 0.5148258 , 0.61723272, 0.76693475],
+    [ 0.52118385, 0.62148236, 0.76852436],
+    [ 0.52753571, 0.62574126, 0.77013939],
+    [ 0.53386831, 0.63001125, 0.77180152],
+    [ 0.54020159, 0.63429038, 0.7734803 ],
+    [ 0.54651272, 0.63858165, 0.77521306],
+    [ 0.55282975, 0.64288207, 0.77695608],
+    [ 0.55912585, 0.64719519, 0.77875327],
+    [ 0.56542599, 0.65151828, 0.78056551],
+    [ 0.57170924, 0.65585426, 0.78242747],
+    [ 0.57799572, 0.6602009 , 0.78430751],
+    [ 0.58426817, 0.66456073, 0.78623458],
+    [ 0.590544  , 0.66893178, 0.78818117],
+    [ 0.59680758, 0.67331643, 0.79017369],
+    [ 0.60307553, 0.67771273, 0.79218572],
+    [ 0.60934065, 0.68212194, 0.79422987],
+    [ 0.61559495, 0.68654548, 0.7963202 ],
+    [ 0.62185554, 0.69098125, 0.79842918],
+    [ 0.62810662, 0.69543176, 0.80058381],
+    [ 0.63436425, 0.69989499, 0.80275812],
+    [ 0.64061445, 0.70437326, 0.80497621],
+    [ 0.6468706 , 0.70886488, 0.80721641],
+    [ 0.65312213, 0.7133717 , 0.80949719],
+    [ 0.65937818, 0.71789261, 0.81180392],
+    [ 0.66563334, 0.72242871, 0.81414642],
+    [ 0.67189155, 0.72697967, 0.81651872],
+    [ 0.67815314, 0.73154569, 0.81892097],
+    [ 0.68441395, 0.73612771, 0.82136094],
+    [ 0.69068321, 0.74072452, 0.82382353],
+    [ 0.69694776, 0.7453385 , 0.82633199],
+    [ 0.70322431, 0.74996721, 0.8288583 ],
+    [ 0.70949595, 0.75461368, 0.83143221],
+    [ 0.7157774 , 0.75927574, 0.83402904],
+    [ 0.72206299, 0.76395461, 0.83665922],
+    [ 0.72835227, 0.76865061, 0.8393242 ],
+    [ 0.73465238, 0.7733628 , 0.84201224],
+    [ 0.74094862, 0.77809393, 0.84474951],
+    [ 0.74725683, 0.78284158, 0.84750915],
+    [ 0.75357103, 0.78760701, 0.85030217],
+    [ 0.75988961, 0.79239077, 0.85313207],
+    [ 0.76621987, 0.79719185, 0.85598668],
+    [ 0.77255045, 0.8020125 , 0.85888658],
+    [ 0.77889241, 0.80685102, 0.86181298],
+    [ 0.78524572, 0.81170768, 0.86476656],
+    [ 0.79159841, 0.81658489, 0.86776906],
+    [ 0.79796459, 0.82148036, 0.8707962 ],
+    [ 0.80434168, 0.82639479, 0.87385315],
+    [ 0.8107221 , 0.83132983, 0.87695392],
+    [ 0.81711301, 0.8362844 , 0.88008641],
+    [ 0.82351479, 0.84125863, 0.88325045],
+    [ 0.82992772, 0.84625263, 0.88644594],
+    [ 0.83634359, 0.85126806, 0.8896878 ],
+    [ 0.84277295, 0.85630293, 0.89295721],
+    [ 0.84921192, 0.86135782, 0.89626076],
+    [ 0.85566206, 0.866432  , 0.89959467],
+    [ 0.86211514, 0.87152627, 0.90297183],
+    [ 0.86857483, 0.87663856, 0.90638248],
+    [ 0.87504231, 0.88176648, 0.90981938],
+    [ 0.88151194, 0.88690782, 0.91328493],
+    [ 0.88797938, 0.89205857, 0.91677544],
+    [ 0.89443865, 0.89721298, 0.9202854 ],
+    [ 0.90088204, 0.90236294, 0.92380601],
+    [ 0.90729768, 0.90749778, 0.92732797],
+    [ 0.91367037, 0.91260329, 0.93083814],
+    [ 0.91998105, 0.91766106, 0.93431861],
+    [ 0.92620596, 0.92264789, 0.93774647],
+    [ 0.93231683, 0.9275351 , 0.94109192],
+    [ 0.93827772, 0.9322888 , 0.94432312],
+    [ 0.94404755, 0.93686925, 0.94740137],
+    [ 0.94958284, 0.94123072, 0.95027696],
+    [ 0.95482682, 0.9453245 , 0.95291103],
+    [ 0.9597248 , 0.94909728, 0.95525103],
+    [ 0.96422552, 0.95249273, 0.95723271],
+    [ 0.96826161, 0.95545812, 0.95882188],
+    [ 0.97178458, 0.95793984, 0.95995705],
+    [ 0.97474105, 0.95989142, 0.96059997],
+    [ 0.97708604, 0.96127366, 0.96071853],
+    [ 0.97877855, 0.96205832, 0.96030095],
+    [ 0.97978484, 0.96222949, 0.95935496],
+    [ 0.9805997 , 0.96155216, 0.95813083],
+    [ 0.98152619, 0.95993719, 0.95639322],
+    [ 0.9819726 , 0.95766608, 0.95399269],
+    [ 0.98191855, 0.9547873 , 0.95098107],
+    [ 0.98138514, 0.95134771, 0.94740644],
+    [ 0.98040845, 0.94739906, 0.94332125],
+    [ 0.97902107, 0.94300131, 0.93878672],
+    [ 0.97729348, 0.93820409, 0.93385135],
+    [ 0.9752533 , 0.933073  , 0.92858252],
+    [ 0.97297834, 0.92765261, 0.92302309],
+    [ 0.97049104, 0.92200317, 0.91723505],
+    [ 0.96784372, 0.91616744, 0.91126063],
+    [ 0.96507281, 0.91018664, 0.90514124],
+    [ 0.96222034, 0.90409203, 0.89890756],
+    [ 0.9593079 , 0.89791478, 0.89259122],
+    [ 0.95635626, 0.89167908, 0.88621654],
+    [ 0.95338303, 0.88540373, 0.87980238],
+    [ 0.95040174, 0.87910333, 0.87336339],
+    [ 0.94742246, 0.87278899, 0.86691076],
+    [ 0.94445249, 0.86646893, 0.86045277],
+    [ 0.94150476, 0.86014606, 0.85399191],
+    [ 0.93857394, 0.85382798, 0.84753642],
+    [ 0.93566206, 0.84751766, 0.84108935],
+    [ 0.93277194, 0.8412164 , 0.83465197],
+    [ 0.92990106, 0.83492672, 0.82822708],
+    [ 0.92704736, 0.82865028, 0.82181656],
+    [ 0.92422703, 0.82238092, 0.81541333],
+    [ 0.92142581, 0.81612448, 0.80902415],
+    [ 0.91864501, 0.80988032, 0.80264838],
+    [ 0.91587578, 0.80365187, 0.79629001],
+    [ 0.9131367 , 0.79743115, 0.78994   ],
+    [ 0.91041602, 0.79122265, 0.78360361],
+    [ 0.90771071, 0.78502727, 0.77728196],
+    [ 0.90501581, 0.77884674, 0.7709771 ],
+    [ 0.90235365, 0.77267117, 0.76467793],
+    [ 0.8997019 , 0.76650962, 0.75839484],
+    [ 0.89705346, 0.76036481, 0.752131  ],
+    [ 0.89444021, 0.75422253, 0.74587047],
+    [ 0.89183355, 0.74809474, 0.73962689],
+    [ 0.88923216, 0.74198168, 0.73340061],
+    [ 0.88665892, 0.73587283, 0.72717995],
+    [ 0.88408839, 0.72977904, 0.72097718],
+    [ 0.88153537, 0.72369332, 0.71478461],
+    [ 0.87899389, 0.7176179 , 0.70860487],
+    [ 0.87645157, 0.71155805, 0.7024439 ],
+    [ 0.8739399 , 0.70549893, 0.6962854 ],
+    [ 0.87142626, 0.6994551 , 0.69014561],
+    [ 0.8689268 , 0.69341868, 0.68401597],
+    [ 0.86643562, 0.687392  , 0.67789917],
+    [ 0.86394434, 0.68137863, 0.67179927],
+    [ 0.86147586, 0.67536728, 0.665704  ],
+    [ 0.85899928, 0.66937226, 0.6596292 ],
+    [ 0.85654668, 0.66337773, 0.6535577 ],
+    [ 0.85408818, 0.65739772, 0.64750494],
+    [ 0.85164413, 0.65142189, 0.64145983],
+    [ 0.84920091, 0.6454565 , 0.63542932],
+    [ 0.84676427, 0.63949827, 0.62941   ],
+    [ 0.84433231, 0.63354773, 0.62340261],
+    [ 0.84190106, 0.62760645, 0.61740899],
+    [ 0.83947935, 0.62166951, 0.61142404],
+    [ 0.8370538 , 0.61574332, 0.60545478],
+    [ 0.83463975, 0.60981951, 0.59949247],
+    [ 0.83221877, 0.60390724, 0.593547  ],
+    [ 0.82980985, 0.59799607, 0.58760751],
+    [ 0.82740268, 0.59209095, 0.58167944],
+    [ 0.82498638, 0.5861973 , 0.57576866],
+    [ 0.82258181, 0.5803034 , 0.56986307],
+    [ 0.82016611, 0.57442123, 0.56397539],
+    [ 0.81776305, 0.56853725, 0.55809173],
+    [ 0.81534551, 0.56266602, 0.55222741],
+    [ 0.81294293, 0.55679056, 0.5463651 ],
+    [ 0.81052113, 0.55092973, 0.54052443],
+    [ 0.80811509, 0.54506305, 0.53468464],
+    [ 0.80568952, 0.53921036, 0.52886622],
+    [ 0.80327506, 0.53335335, 0.52305077],
+    [ 0.80084727, 0.52750583, 0.51725256],
+    [ 0.79842217, 0.5216578 , 0.51146173],
+    [ 0.79599382, 0.51581223, 0.50568155],
+    [ 0.79355781, 0.50997127, 0.49991444],
+    [ 0.79112596, 0.50412707, 0.49415289],
+    [ 0.78867442, 0.49829386, 0.48841129],
+    [ 0.7862306 , 0.49245398, 0.48267247],
+    [ 0.7837687 , 0.48662309, 0.47695216],
+    [ 0.78130809, 0.4807883 , 0.47123805],
+    [ 0.77884467, 0.47495151, 0.46553236],
+    [ 0.77636283, 0.46912235, 0.45984473],
+    [ 0.77388383, 0.46328617, 0.45416141],
+    [ 0.77138912, 0.45745466, 0.44849398],
+    [ 0.76888874, 0.45162042, 0.44283573],
+    [ 0.76638802, 0.44577901, 0.43718292],
+    [ 0.76386116, 0.43994762, 0.43155211],
+    [ 0.76133542, 0.43410655, 0.42592523],
+    [ 0.75880631, 0.42825801, 0.42030488],
+    [ 0.75624913, 0.42241905, 0.41470727],
+    [ 0.7536919 , 0.41656866, 0.40911347],
+    [ 0.75112748, 0.41071104, 0.40352792],
+    [ 0.74854331, 0.40485474, 0.3979589 ],
+    [ 0.74594723, 0.39899309, 0.39240088],
+    [ 0.74334332, 0.39312199, 0.38685075],
+    [ 0.74073277, 0.38723941, 0.3813074 ],
+    [ 0.73809409, 0.38136133, 0.37578553],
+    [ 0.73544692, 0.37547129, 0.37027123],
+    [ 0.73278943, 0.36956954, 0.36476549],
+    [ 0.73011829, 0.36365761, 0.35927038],
+    [ 0.72743485, 0.35773314, 0.35378465],
+    [ 0.72472722, 0.35180504, 0.34831662],
+    [ 0.72200473, 0.34586421, 0.34285937],
+    [ 0.71927052, 0.33990649, 0.33741033],
+    [ 0.71652049, 0.33393396, 0.33197219],
+    [ 0.71375362, 0.32794602, 0.32654545],
+    [ 0.71096951, 0.32194148, 0.32113016],
+    [ 0.70816772, 0.31591904, 0.31572637],
+    [ 0.70534784, 0.30987734, 0.31033414],
+    [ 0.70250944, 0.30381489, 0.30495353],
+    [ 0.69965211, 0.2977301 , 0.2995846 ],
+    [ 0.6967754 , 0.29162126, 0.29422741],
+    [ 0.69388446, 0.28548074, 0.28887769],
+    [ 0.69097561, 0.2793096 , 0.28353795],
+    [ 0.68803513, 0.27311993, 0.27821876],
+    [ 0.6850794 , 0.26689144, 0.27290694],
+    [ 0.682108  , 0.26062114, 0.26760246],
+    [ 0.67911013, 0.2543177 , 0.26231367],
+    [ 0.67609393, 0.24796818, 0.25703372],
+    [ 0.67305921, 0.24156846, 0.25176238],
+    [ 0.67000176, 0.23511902, 0.24650278],
+    [ 0.66693423, 0.22859879, 0.24124404],
+    [ 0.6638441 , 0.22201742, 0.2359961 ],
+    [ 0.66080672, 0.21526712, 0.23069468]
+]
+
+
+_icefire_lut = [
+    [ 0.73936227, 0.90443867, 0.85757238],
+    [ 0.72888063, 0.89639109, 0.85488394],
+    [ 0.71834255, 0.88842162, 0.8521605 ],
+    [ 0.70773866, 0.88052939, 0.849422  ],
+    [ 0.69706215, 0.87271313, 0.84668315],
+    [ 0.68629021, 0.86497329, 0.84398721],
+    [ 0.67543654, 0.85730617, 0.84130969],
+    [ 0.66448539, 0.84971123, 0.83868005],
+    [ 0.65342679, 0.84218728, 0.83611512],
+    [ 0.64231804, 0.83471867, 0.83358584],
+    [ 0.63117745, 0.827294  , 0.83113431],
+    [ 0.62000484, 0.81991069, 0.82876741],
+    [ 0.60879435, 0.81256797, 0.82648905],
+    [ 0.59754118, 0.80526458, 0.82430414],
+    [ 0.58624247, 0.79799884, 0.82221573],
+    [ 0.57489525, 0.7907688 , 0.82022901],
+    [ 0.56349779, 0.78357215, 0.81834861],
+    [ 0.55204294, 0.77640827, 0.81657563],
+    [ 0.54052516, 0.76927562, 0.81491462],
+    [ 0.52894085, 0.76217215, 0.81336913],
+    [ 0.51728854, 0.75509528, 0.81194156],
+    [ 0.50555676, 0.74804469, 0.81063503],
+    [ 0.49373871, 0.7410187 , 0.80945242],
+    [ 0.48183174, 0.73401449, 0.80839675],
+    [ 0.46982587, 0.72703075, 0.80747097],
+    [ 0.45770893, 0.72006648, 0.80667756],
+    [ 0.44547249, 0.71311941, 0.80601991],
+    [ 0.43318643, 0.70617126, 0.80549278],
+    [ 0.42110294, 0.69916972, 0.80506683],
+    [ 0.40925101, 0.69211059, 0.80473246],
+    [ 0.3976693 , 0.68498786, 0.80448272],
+    [ 0.38632002, 0.67781125, 0.80431024],
+    [ 0.37523981, 0.67057537, 0.80420832],
+    [ 0.36442578, 0.66328229, 0.80417474],
+    [ 0.35385939, 0.65593699, 0.80420591],
+    [ 0.34358916, 0.64853177, 0.8043    ],
+    [ 0.33355526, 0.64107876, 0.80445484],
+    [ 0.32383062, 0.63356578, 0.80467091],
+    [ 0.31434372, 0.62600624, 0.8049475 ],
+    [ 0.30516161, 0.618389  , 0.80528692],
+    [ 0.29623491, 0.61072284, 0.80569021],
+    [ 0.28759072, 0.60300319, 0.80616055],
+    [ 0.27923924, 0.59522877, 0.80669803],
+    [ 0.27114651, 0.5874047 , 0.80730545],
+    [ 0.26337153, 0.57952055, 0.80799113],
+    [ 0.25588696, 0.57157984, 0.80875922],
+    [ 0.248686  , 0.56358255, 0.80961366],
+    [ 0.24180668, 0.55552289, 0.81055123],
+    [ 0.23526251, 0.54739477, 0.8115939 ],
+    [ 0.22921445, 0.53918506, 0.81267292],
+    [ 0.22397687, 0.53086094, 0.8137141 ],
+    [ 0.21977058, 0.52241482, 0.81457651],
+    [ 0.21658989, 0.51384321, 0.81528511],
+    [ 0.21452772, 0.50514155, 0.81577278],
+    [ 0.21372783, 0.49630865, 0.81589566],
+    [ 0.21409503, 0.48734861, 0.81566163],
+    [ 0.2157176 , 0.47827123, 0.81487615],
+    [ 0.21842857, 0.46909168, 0.81351614],
+    [ 0.22211705, 0.45983212, 0.81146983],
+    [ 0.22665681, 0.45052233, 0.80860217],
+    [ 0.23176013, 0.44119137, 0.80494325],
+    [ 0.23727775, 0.43187704, 0.80038017],
+    [ 0.24298285, 0.42261123, 0.79493267],
+    [ 0.24865068, 0.41341842, 0.78869164],
+    [ 0.25423116, 0.40433127, 0.78155831],
+    [ 0.25950239, 0.39535521, 0.77376848],
+    [ 0.2644736 , 0.38651212, 0.76524809],
+    [ 0.26901584, 0.37779582, 0.75621942],
+    [ 0.27318141, 0.36922056, 0.746605  ],
+    [ 0.27690355, 0.3607736 , 0.73659374],
+    [ 0.28023585, 0.35244234, 0.72622103],
+    [ 0.28306009, 0.34438449, 0.71500731],
+    [ 0.28535896, 0.33660243, 0.70303975],
+    [ 0.28708711, 0.32912157, 0.69034504],
+    [ 0.28816354, 0.32200604, 0.67684067],
+    [ 0.28862749, 0.31519824, 0.66278813],
+    [ 0.28847904, 0.30869064, 0.6482815 ],
+    [ 0.28770912, 0.30250126, 0.63331265],
+    [ 0.28640325, 0.29655509, 0.61811374],
+    [ 0.28458943, 0.29082155, 0.60280913],
+    [ 0.28233561, 0.28527482, 0.58742866],
+    [ 0.27967038, 0.2798938 , 0.57204225],
+    [ 0.27665361, 0.27465357, 0.55667809],
+    [ 0.27332564, 0.2695165 , 0.54145387],
+    [ 0.26973851, 0.26447054, 0.52634916],
+    [ 0.2659204 , 0.25949691, 0.511417  ],
+    [ 0.26190145, 0.25458123, 0.49668768],
+    [ 0.2577151 , 0.24971691, 0.48214874],
+    [ 0.25337618, 0.24490494, 0.46778758],
+    [ 0.24890842, 0.24013332, 0.45363816],
+    [ 0.24433654, 0.23539226, 0.4397245 ],
+    [ 0.23967922, 0.23067729, 0.4260591 ],
+    [ 0.23495608, 0.22598894, 0.41262952],
+    [ 0.23018113, 0.22132414, 0.39945577],
+    [ 0.22534609, 0.21670847, 0.38645794],
+    [ 0.22048761, 0.21211723, 0.37372555],
+    [ 0.2156198 , 0.20755389, 0.36125301],
+    [ 0.21074637, 0.20302717, 0.34903192],
+    [ 0.20586893, 0.19855368, 0.33701661],
+    [ 0.20101757, 0.19411573, 0.32529173],
+    [ 0.19619947, 0.18972425, 0.31383846],
+    [ 0.19140726, 0.18540157, 0.30260777],
+    [ 0.1866769 , 0.1811332 , 0.29166583],
+    [ 0.18201285, 0.17694992, 0.28088776],
+    [ 0.17745228, 0.17282141, 0.27044211],
+    [ 0.17300684, 0.16876921, 0.26024893],
+    [ 0.16868273, 0.16479861, 0.25034479],
+    [ 0.16448691, 0.16091728, 0.24075373],
+    [ 0.16043195, 0.15714351, 0.23141745],
+    [ 0.15652427, 0.15348248, 0.22238175],
+    [ 0.15277065, 0.14994111, 0.21368395],
+    [ 0.14918274, 0.14653431, 0.20529486],
+    [ 0.14577095, 0.14327403, 0.19720829],
+    [ 0.14254381, 0.14016944, 0.18944326],
+    [ 0.13951035, 0.13723063, 0.18201072],
+    [ 0.13667798, 0.13446606, 0.17493774],
+    [ 0.13405762, 0.13188822, 0.16820842],
+    [ 0.13165767, 0.12950667, 0.16183275],
+    [ 0.12948748, 0.12733187, 0.15580631],
+    [ 0.12755435, 0.1253723 , 0.15014098],
+    [ 0.12586516, 0.12363617, 0.1448459 ],
+    [ 0.12442647, 0.12213143, 0.13992571],
+    [ 0.12324241, 0.12086419, 0.13539995],
+    [ 0.12232067, 0.11984278, 0.13124644],
+    [ 0.12166209, 0.11907077, 0.12749671],
+    [ 0.12126982, 0.11855309, 0.12415079],
+    [ 0.12114244, 0.11829179, 0.1212385 ],
+    [ 0.12127766, 0.11828837, 0.11878534],
+    [ 0.12284806, 0.1179729 , 0.11772022],
+    [ 0.12619498, 0.11721796, 0.11770203],
+    [ 0.129968  , 0.11663788, 0.11792377],
+    [ 0.13410011, 0.11625146, 0.11839138],
+    [ 0.13855459, 0.11606618, 0.11910584],
+    [ 0.14333775, 0.11607038, 0.1200606 ],
+    [ 0.148417  , 0.11626929, 0.12125453],
+    [ 0.15377389, 0.11666192, 0.12268364],
+    [ 0.15941427, 0.11723486, 0.12433911],
+    [ 0.16533376, 0.11797856, 0.12621303],
+    [ 0.17152547, 0.11888403, 0.12829735],
+    [ 0.17797765, 0.11994436, 0.13058435],
+    [ 0.18468769, 0.12114722, 0.13306426],
+    [ 0.19165663, 0.12247737, 0.13572616],
+    [ 0.19884415, 0.12394381, 0.1385669 ],
+    [ 0.20627181, 0.12551883, 0.14157124],
+    [ 0.21394877, 0.12718055, 0.14472604],
+    [ 0.22184572, 0.12893119, 0.14802579],
+    [ 0.22994394, 0.13076731, 0.15146314],
+    [ 0.23823937, 0.13267611, 0.15502793],
+    [ 0.24676041, 0.13462172, 0.15870321],
+    [ 0.25546457, 0.13661751, 0.16248722],
+    [ 0.26433628, 0.13865956, 0.16637301],
+    [ 0.27341345, 0.14070412, 0.17034221],
+    [ 0.28264773, 0.14277192, 0.1743957 ],
+    [ 0.29202272, 0.14486161, 0.17852793],
+    [ 0.30159648, 0.14691224, 0.1827169 ],
+    [ 0.31129002, 0.14897583, 0.18695213],
+    [ 0.32111555, 0.15103351, 0.19119629],
+    [ 0.33107961, 0.1530674 , 0.19543758],
+    [ 0.34119892, 0.15504762, 0.1996803 ],
+    [ 0.35142388, 0.15701131, 0.20389086],
+    [ 0.36178937, 0.1589124 , 0.20807639],
+    [ 0.37229381, 0.16073993, 0.21223189],
+    [ 0.38288348, 0.16254006, 0.2163249 ],
+    [ 0.39359592, 0.16426336, 0.22036577],
+    [ 0.40444332, 0.16588767, 0.22434027],
+    [ 0.41537995, 0.16745325, 0.2282297 ],
+    [ 0.42640867, 0.16894939, 0.23202755],
+    [ 0.43754706, 0.17034847, 0.23572899],
+    [ 0.44878564, 0.1716535 , 0.23932344],
+    [ 0.4601126 , 0.17287365, 0.24278607],
+    [ 0.47151732, 0.17401641, 0.24610337],
+    [ 0.48300689, 0.17506676, 0.2492737 ],
+    [ 0.49458302, 0.17601892, 0.25227688],
+    [ 0.50623876, 0.17687777, 0.255096  ],
+    [ 0.5179623 , 0.17765528, 0.2577162 ],
+    [ 0.52975234, 0.17835232, 0.2601134 ],
+    [ 0.54159776, 0.17898292, 0.26226847],
+    [ 0.55348804, 0.17956232, 0.26416003],
+    [ 0.56541729, 0.18010175, 0.26575971],
+    [ 0.57736669, 0.180631  , 0.26704888],
+    [ 0.58932081, 0.18117827, 0.26800409],
+    [ 0.60127582, 0.18175888, 0.26858488],
+    [ 0.61319563, 0.1824336 , 0.2687872 ],
+    [ 0.62506376, 0.18324015, 0.26858301],
+    [ 0.63681202, 0.18430173, 0.26795276],
+    [ 0.64842603, 0.18565472, 0.26689463],
+    [ 0.65988195, 0.18734638, 0.26543435],
+    [ 0.67111966, 0.18948885, 0.26357955],
+    [ 0.68209194, 0.19216636, 0.26137175],
+    [ 0.69281185, 0.19535326, 0.25887063],
+    [ 0.70335022, 0.19891271, 0.25617971],
+    [ 0.71375229, 0.20276438, 0.25331365],
+    [ 0.72401436, 0.20691287, 0.25027366],
+    [ 0.73407638, 0.21145051, 0.24710661],
+    [ 0.74396983, 0.21631913, 0.24380715],
+    [ 0.75361506, 0.22163653, 0.24043996],
+    [ 0.7630579 , 0.22731637, 0.23700095],
+    [ 0.77222228, 0.23346231, 0.23356628],
+    [ 0.78115441, 0.23998404, 0.23013825],
+    [ 0.78979746, 0.24694858, 0.22678822],
+    [ 0.79819286, 0.25427223, 0.22352658],
+    [ 0.80630444, 0.26198807, 0.22040877],
+    [ 0.81417437, 0.27001406, 0.21744645],
+    [ 0.82177364, 0.27837336, 0.21468316],
+    [ 0.82915955, 0.28696963, 0.21210766],
+    [ 0.83628628, 0.2958499 , 0.20977813],
+    [ 0.84322168, 0.30491136, 0.20766435],
+    [ 0.84995458, 0.31415945, 0.2057863 ],
+    [ 0.85648867, 0.32358058, 0.20415327],
+    [ 0.86286243, 0.33312058, 0.20274969],
+    [ 0.86908321, 0.34276705, 0.20157271],
+    [ 0.87512876, 0.3525416 , 0.20064949],
+    [ 0.88100349, 0.36243385, 0.19999078],
+    [ 0.8866469 , 0.37249496, 0.1997976 ],
+    [ 0.89203964, 0.38273475, 0.20013431],
+    [ 0.89713496, 0.39318156, 0.20121514],
+    [ 0.90195099, 0.40380687, 0.20301555],
+    [ 0.90648379, 0.41460191, 0.20558847],
+    [ 0.9106967 , 0.42557857, 0.20918529],
+    [ 0.91463791, 0.43668557, 0.21367954],
+    [ 0.91830723, 0.44790913, 0.21916352],
+    [ 0.92171507, 0.45922856, 0.22568002],
+    [ 0.92491786, 0.4705936 , 0.23308207],
+    [ 0.92790792, 0.48200153, 0.24145932],
+    [ 0.93073701, 0.49341219, 0.25065486],
+    [ 0.93343918, 0.5048017 , 0.26056148],
+    [ 0.93602064, 0.51616486, 0.27118485],
+    [ 0.93850535, 0.52748892, 0.28242464],
+    [ 0.94092933, 0.53875462, 0.29416042],
+    [ 0.94330011, 0.5499628 , 0.30634189],
+    [ 0.94563159, 0.56110987, 0.31891624],
+    [ 0.94792955, 0.57219822, 0.33184256],
+    [ 0.95020929, 0.5832232 , 0.34508419],
+    [ 0.95247324, 0.59419035, 0.35859866],
+    [ 0.95471709, 0.60510869, 0.37236035],
+    [ 0.95698411, 0.61595766, 0.38629631],
+    [ 0.95923863, 0.62676473, 0.40043317],
+    [ 0.9615041 , 0.6375203 , 0.41474106],
+    [ 0.96371553, 0.64826619, 0.42928335],
+    [ 0.96591497, 0.65899621, 0.44380444],
+    [ 0.96809871, 0.66971662, 0.45830232],
+    [ 0.9702495 , 0.6804394 , 0.47280492],
+    [ 0.9723881 , 0.69115622, 0.48729272],
+    [ 0.97450723, 0.70187358, 0.50178034],
+    [ 0.9766108 , 0.712592  , 0.51626837],
+    [ 0.97871716, 0.72330511, 0.53074053],
+    [ 0.98082222, 0.73401769, 0.54520694],
+    [ 0.9829001 , 0.74474445, 0.5597019 ],
+    [ 0.98497466, 0.75547635, 0.57420239],
+    [ 0.98705581, 0.76621129, 0.58870185],
+    [ 0.98913325, 0.77695637, 0.60321626],
+    [ 0.99119918, 0.78771716, 0.61775821],
+    [ 0.9932672 , 0.79848979, 0.63231691],
+    [ 0.99535958, 0.80926704, 0.64687278],
+    [ 0.99740544, 0.82008078, 0.66150571],
+    [ 0.9992197 , 0.83100723, 0.6764127 ]
+]
+
+
+_luts = [_rocket_lut, _mako_lut, _vlag_lut, _icefire_lut]
+_names = ["rocket", "mako", "vlag", "icefire"]
+
+for _lut, _name in zip(_luts, _names):
+
+    _cmap = colors.ListedColormap(_lut, _name) 
+    locals()[_name] = _cmap
+
+    _cmap_r = colors.ListedColormap(_lut[::-1], _name + "_r")  
+    locals()[_name + "_r"] = _cmap_r
+
+    mpl_cm.register_cmap(_name, _cmap)
+    mpl_cm.register_cmap(_name + "_r", _cmap_r)
diff --git a/seaborn/distributions.py b/seaborn/distributions.py
index 94e4f53..c3ae5b9 100644
--- a/seaborn/distributions.py
+++ b/seaborn/distributions.py
@@ -15,12 +15,11 @@ try:
 except ImportError:
     _has_statsmodels = False
 
-from .utils import set_hls_values, iqr, _kde_support
+from .utils import iqr, _kde_support
 from .palettes import color_palette, blend_palette
-from .axisgrid import JointGrid
 
 
-__all__ = ["distplot", "kdeplot", "rugplot", "jointplot"]
+__all__ = ["distplot", "kdeplot", "rugplot"]
 
 
 def _freedman_diaconis_bins(a):
@@ -103,7 +102,7 @@ def distplot(a, bins=None, hist=True, kde=True, rug=False, fit=None,
         :context: close-figs
 
         >>> import seaborn as sns, numpy as np
-        >>> sns.set(rc={"figure.figsize": (8, 4)}); np.random.seed(0)
+        >>> sns.set(); np.random.seed(0)
         >>> x = np.random.randn(100)
         >>> ax = sns.distplot(x)
 
@@ -309,9 +308,15 @@ def _univariate_kdeplot(data, shade, vertical, kernel, bw, gridsize, cut,
     alpha = kwargs.get("alpha", 0.25)
     if shade:
         if vertical:
-            ax.fill_betweenx(y, 1e-12, x, facecolor=color, alpha=alpha)
+            ax.fill_betweenx(y, 0, x, facecolor=color, alpha=alpha)
         else:
-            ax.fill_between(x, 1e-12, y, facecolor=color, alpha=alpha)
+            ax.fill_between(x, 0, y, facecolor=color, alpha=alpha)
+
+    # Set the density axis minimum to 0
+    if vertical:
+        ax.set_xlim(0, None)
+    else:
+        ax.set_ylim(0, None)
 
     # Draw the legend here
     if legend:
@@ -353,7 +358,7 @@ def _scipy_univariate_kde(data, bw, gridsize, cut, clip):
 
 def _bivariate_kdeplot(x, y, filled, fill_lowest,
                        kernel, bw, gridsize, cut, clip,
-                       axlabel, ax, **kwargs):
+                       axlabel, cbar, cbar_ax, cbar_kws, ax, **kwargs):
     """Plot a joint KDE estimate as a bivariate contour plot."""
     # Determine the clipping
     if clip is None:
@@ -385,6 +390,10 @@ def _bivariate_kdeplot(x, y, filled, fill_lowest,
         cset.collections[0].set_alpha(0)
     kwargs["n_levels"] = n_levels
 
+    if cbar:
+        cbar_kws = {} if cbar_kws is None else cbar_kws
+        ax.figure.colorbar(cset, cbar_ax, ax, **cbar_kws)
+
     # Label the axes
     if hasattr(x, "name") and axlabel:
         ax.set_xlabel(x.name)
@@ -441,7 +450,8 @@ def _scipy_bivariate_kde(x, y, bw, gridsize, cut, clip):
 
 def kdeplot(data, data2=None, shade=False, vertical=False, kernel="gau",
             bw="scott", gridsize=100, cut=3, clip=None, legend=True,
-            cumulative=False, shade_lowest=True, ax=None, **kwargs):
+            cumulative=False, shade_lowest=True, cbar=False, cbar_ax=None,
+            cbar_kws=None, ax=None, **kwargs):
     """Fit and plot a univariate or bivariate kernel density estimate.
 
     Parameters
@@ -477,8 +487,15 @@ def kdeplot(data, data2=None, shade=False, vertical=False, kernel="gau",
         relevant when drawing a univariate plot or when ``shade=False``.
         Setting this to ``False`` can be useful when you want multiple
         densities on the same Axes.
-    ax : matplotlib axis, optional
-        Axis to plot on, otherwise uses current axis.
+    cbar : bool, optional
+        If True and drawing a bivariate KDE plot, add a colorbar.
+    cbar_ax : matplotlib axes, optional
+        Existing axes to draw the colorbar onto, otherwise space is taken
+        from the main axes.
+    cbar_kws : dict, optional
+        Keyword arguments for ``fig.colorbar()``.
+    ax : matplotlib axes, optional
+        Axes to plot on, otherwise uses current axes.
     kwargs : key, value pairings
         Other keyword arguments are passed to ``plt.plot()`` or
         ``plt.contour{f}`` depending on whether a univariate or bivariate
@@ -557,6 +574,13 @@ def kdeplot(data, data2=None, shade=False, vertical=False, kernel="gau",
 
         >>> ax = sns.kdeplot(x, cut=0)
 
+    Add a colorbar for the contours:
+
+    .. plot::
+        :context: close-figs
+
+        >>> ax = sns.kdeplot(x, y, cbar=True)
+
     Plot two shaded bivariate densities:
 
     .. plot::
@@ -574,15 +598,23 @@ def kdeplot(data, data2=None, shade=False, vertical=False, kernel="gau",
     if ax is None:
         ax = plt.gca()
 
+    if isinstance(data, list):
+        data = np.asarray(data)
+
     data = data.astype(np.float64)
     if data2 is not None:
+        if isinstance(data2, list):
+            data2 = np.asarray(data2)
         data2 = data2.astype(np.float64)
 
+    warn = False
     bivariate = False
     if isinstance(data, np.ndarray) and np.ndim(data) > 1:
+        warn = True
         bivariate = True
         x, y = data.T
     elif isinstance(data, pd.DataFrame) and np.ndim(data) > 1:
+        warn = True
         bivariate = True
         x = data.iloc[:, 0].values
         y = data.iloc[:, 1].values
@@ -591,13 +623,19 @@ def kdeplot(data, data2=None, shade=False, vertical=False, kernel="gau",
         x = data
         y = data2
 
+    if warn:
+        warn_msg = ("Passing a 2D dataset for a bivariate plot is deprecated "
+                    "in favor of kdeplot(x, y), and it will cause an error in "
+                    "future versions. Please update your code.")
+        warnings.warn(warn_msg, UserWarning)
+
     if bivariate and cumulative:
         raise TypeError("Cumulative distribution plots are not"
                         "supported for bivariate distributions.")
     if bivariate:
         ax = _bivariate_kdeplot(x, y, shade, shade_lowest,
                                 kernel, bw, gridsize, cut, clip, legend,
-                                ax, **kwargs)
+                                cbar, cbar_ax, cbar_kws, ax, **kwargs)
     else:
         ax = _univariate_kdeplot(data, shade, vertical, kernel, bw,
                                  gridsize, cut, clip, legend, ax,
@@ -638,228 +676,3 @@ def rugplot(a, height=.05, axis="x", ax=None, **kwargs):
         func(pt, 0, height, **kwargs)
 
     return ax
-
-
-def jointplot(x, y, data=None, kind="scatter", stat_func=stats.pearsonr,
-              color=None, size=6, ratio=5, space=.2,
-              dropna=True, xlim=None, ylim=None,
-              joint_kws=None, marginal_kws=None, annot_kws=None, **kwargs):
-    """Draw a plot of two variables with bivariate and univariate graphs.
-
-    This function provides a convenient interface to the :class:`JointGrid`
-    class, with several canned plot kinds. This is intended to be a fairly
-    lightweight wrapper; if you need more flexibility, you should use
-    :class:`JointGrid` directly.
-
-    Parameters
-    ----------
-    x, y : strings or vectors
-        Data or names of variables in ``data``.
-    data : DataFrame, optional
-        DataFrame when ``x`` and ``y`` are variable names.
-    kind : { "scatter" | "reg" | "resid" | "kde" | "hex" }, optional
-        Kind of plot to draw.
-    stat_func : callable or None, optional
-        Function used to calculate a statistic about the relationship and
-        annotate the plot. Should map `x` and `y` either to a single value
-        or to a (value, p) tuple. Set to ``None`` if you don't want to
-        annotate the plot.
-    color : matplotlib color, optional
-        Color used for the plot elements.
-    size : numeric, optional
-        Size of the figure (it will be square).
-    ratio : numeric, optional
-        Ratio of joint axes size to marginal axes height.
-    space : numeric, optional
-        Space between the joint and marginal axes
-    dropna : bool, optional
-        If True, remove observations that are missing from ``x`` and ``y``.
-    {x, y}lim : two-tuples, optional
-        Axis limits to set before plotting.
-    {joint, marginal, annot}_kws : dicts, optional
-        Additional keyword arguments for the plot components.
-    kwargs : key, value pairings
-        Additional keyword arguments are passed to the function used to
-        draw the plot on the joint Axes, superseding items in the
-        ``joint_kws`` dictionary.
-
-    Returns
-    -------
-    grid : :class:`JointGrid`
-        :class:`JointGrid` object with the plot on it.
-
-    See Also
-    --------
-    JointGrid : The Grid class used for drawing this plot. Use it directly if
-                you need more flexibility.
-
-    Examples
-    --------
-
-    Draw a scatterplot with marginal histograms:
-
-    .. plot::
-        :context: close-figs
-
-        >>> import numpy as np, pandas as pd; np.random.seed(0)
-        >>> import seaborn as sns; sns.set(style="white", color_codes=True)
-        >>> tips = sns.load_dataset("tips")
-        >>> g = sns.jointplot(x="total_bill", y="tip", data=tips)
-
-    Add regression and kernel density fits:
-
-    .. plot::
-        :context: close-figs
-
-        >>> g = sns.jointplot("total_bill", "tip", data=tips, kind="reg")
-
-    Replace the scatterplot with a joint histogram using hexagonal bins:
-
-    .. plot::
-        :context: close-figs
-
-        >>> g = sns.jointplot("total_bill", "tip", data=tips, kind="hex")
-
-    Replace the scatterplots and histograms with density estimates and align
-    the marginal Axes tightly with the joint Axes:
-
-    .. plot::
-        :context: close-figs
-
-        >>> iris = sns.load_dataset("iris")
-        >>> g = sns.jointplot("sepal_width", "petal_length", data=iris,
-        ...                   kind="kde", space=0, color="g")
-
-    Use a different statistic for the annotation:
-
-    .. plot::
-        :context: close-figs
-
-        >>> from scipy.stats import spearmanr
-        >>> g = sns.jointplot("size", "total_bill", data=tips,
-        ...                   stat_func=spearmanr, color="m")
-
-    Draw a scatterplot, then add a joint density estimate:
-
-    .. plot::
-        :context: close-figs
-
-        >>> g = (sns.jointplot("sepal_length", "sepal_width",
-        ...                    data=iris, color="k")
-        ...         .plot_joint(sns.kdeplot, zorder=0, n_levels=6))
-
-    Pass vectors in directly without using Pandas, then name the axes:
-
-    .. plot::
-        :context: close-figs
-
-        >>> x, y = np.random.randn(2, 300)
-        >>> g = (sns.jointplot(x, y, kind="hex", stat_func=None)
-        ...         .set_axis_labels("x", "y"))
-
-    Draw a smaller figure with more space devoted to the marginal plots:
-
-    .. plot::
-        :context: close-figs
-
-        >>> g = sns.jointplot("total_bill", "tip", data=tips,
-        ...                   size=5, ratio=3, color="g")
-
-    Pass keyword arguments down to the underlying plots:
-
-    .. plot::
-        :context: close-figs
-
-        >>> g = sns.jointplot("petal_length", "sepal_length", data=iris,
-        ...                   marginal_kws=dict(bins=15, rug=True),
-        ...                   annot_kws=dict(stat="r"),
-        ...                   s=40, edgecolor="w", linewidth=1)
-
-    """
-    # Set up empty default kwarg dicts
-    if joint_kws is None:
-        joint_kws = {}
-    joint_kws.update(kwargs)
-    if marginal_kws is None:
-        marginal_kws = {}
-    if annot_kws is None:
-        annot_kws = {}
-
-    # Make a colormap based off the plot color
-    if color is None:
-        color = color_palette()[0]
-    color_rgb = mpl.colors.colorConverter.to_rgb(color)
-    colors = [set_hls_values(color_rgb, l=l) for l in np.linspace(1, 0, 12)]
-    cmap = blend_palette(colors, as_cmap=True)
-
-    # Initialize the JointGrid object
-    grid = JointGrid(x, y, data, dropna=dropna,
-                     size=size, ratio=ratio, space=space,
-                     xlim=xlim, ylim=ylim)
-
-    # Plot the data using the grid
-    if kind == "scatter":
-
-        joint_kws.setdefault("color", color)
-        grid.plot_joint(plt.scatter, **joint_kws)
-
-        marginal_kws.setdefault("kde", False)
-        marginal_kws.setdefault("color", color)
-        grid.plot_marginals(distplot, **marginal_kws)
-
-    elif kind.startswith("hex"):
-
-        x_bins = _freedman_diaconis_bins(grid.x)
-        y_bins = _freedman_diaconis_bins(grid.y)
-        gridsize = int(np.mean([x_bins, y_bins]))
-
-        joint_kws.setdefault("gridsize", gridsize)
-        joint_kws.setdefault("cmap", cmap)
-        grid.plot_joint(plt.hexbin, **joint_kws)
-
-        marginal_kws.setdefault("kde", False)
-        marginal_kws.setdefault("color", color)
-        grid.plot_marginals(distplot, **marginal_kws)
-
-    elif kind.startswith("kde"):
-
-        joint_kws.setdefault("shade", True)
-        joint_kws.setdefault("cmap", cmap)
-        grid.plot_joint(kdeplot, **joint_kws)
-
-        marginal_kws.setdefault("shade", True)
-        marginal_kws.setdefault("color", color)
-        grid.plot_marginals(kdeplot, **marginal_kws)
-
-    elif kind.startswith("reg"):
-
-        from .linearmodels import regplot
-
-        marginal_kws.setdefault("color", color)
-        grid.plot_marginals(distplot, **marginal_kws)
-
-        joint_kws.setdefault("color", color)
-        grid.plot_joint(regplot, **joint_kws)
-
-    elif kind.startswith("resid"):
-
-        from .linearmodels import residplot
-
-        joint_kws.setdefault("color", color)
-        grid.plot_joint(residplot, **joint_kws)
-
-        x, y = grid.ax_joint.collections[0].get_offsets().T
-        marginal_kws.setdefault("color", color)
-        marginal_kws.setdefault("kde", False)
-        distplot(x, ax=grid.ax_marg_x, **marginal_kws)
-        distplot(y, vertical=True, fit=stats.norm, ax=grid.ax_marg_y,
-                 **marginal_kws)
-        stat_func = None
-    else:
-        msg = "kind must be either 'scatter', 'reg', 'resid', 'kde', or 'hex'"
-        raise ValueError(msg)
-
-    if stat_func is not None:
-        grid.annotate(stat_func, **annot_kws)
-
-    return grid
diff --git a/seaborn/external/husl.py b/seaborn/external/husl.py
index 37f0a38..5ba2d2c 100644
--- a/seaborn/external/husl.py
+++ b/seaborn/external/husl.py
@@ -170,7 +170,7 @@ def rgb_prepare(triple):
         # instead of Python 2 which is rounded to 5.0 which caused
         # a couple off by one errors in the tests. Tests now all pass
         # in Python 2 and Python 3
-        ret.append(round(ch * 255 + 0.001, 0))
+        ret.append(int(round(ch * 255 + 0.001, 0)))
 
     return ret
 
diff --git a/seaborn/external/six.py b/seaborn/external/six.py
index 7ec7f1b..c374474 100644
--- a/seaborn/external/six.py
+++ b/seaborn/external/six.py
@@ -1,6 +1,6 @@
 """Utilities for writing code that runs on Python 2 and 3"""
 
-# Copyright (c) 2010-2014 Benjamin Peterson
+# Copyright (c) 2010-2015 Benjamin Peterson
 #
 # Permission is hereby granted, free of charge, to any person obtaining a copy
 # of this software and associated documentation files (the "Software"), to deal
@@ -20,17 +20,22 @@
 # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
 # SOFTWARE.
 
+from __future__ import absolute_import
+
+import functools
+import itertools
 import operator
 import sys
 import types
 
 __author__ = "Benjamin Peterson <benjamin at python.org>"
-__version__ = "1.5.2"
+__version__ = "1.10.0"
 
 
 # Useful for very coarse version differentiation.
 PY2 = sys.version_info[0] == 2
 PY3 = sys.version_info[0] == 3
+PY34 = sys.version_info[0:2] >= (3, 4)
 
 if PY3:
     string_types = str,
@@ -53,6 +58,7 @@ else:
     else:
         # It's possible to have sizeof(long) != sizeof(Py_ssize_t).
         class X(object):
+
             def __len__(self):
                 return 1 << 31
         try:
@@ -84,9 +90,13 @@ class _LazyDescr(object):
 
     def __get__(self, obj, tp):
         result = self._resolve()
-        setattr(obj, self.name, result) # Invokes __set__.
-        # This is a bit ugly, but it avoids running this again.
-        delattr(obj.__class__, self.name)
+        setattr(obj, self.name, result)  # Invokes __set__.
+        try:
+            # This is a bit ugly, but it avoids running this again by
+            # removing this descriptor.
+            delattr(obj.__class__, self.name)
+        except AttributeError:
+            pass
         return result
 
 
@@ -105,14 +115,6 @@ class MovedModule(_LazyDescr):
         return _import_module(self.mod)
 
     def __getattr__(self, attr):
-        # Hack around the Django autoreloader. The reloader tries to get
-        # __file__ or __name__ of every module in sys.modules. This doesn't work
-        # well if this MovedModule is for an module that is unavailable on this
-        # machine (like winreg on Unix systems). Thus, we pretend __file__ and
-        # __name__ don't exist if the module hasn't been loaded yet. See issues
-        # #51 and #53.
-        if attr in ("__file__", "__name__") and self.mod not in sys.modules:
-            raise AttributeError
         _module = self._resolve()
         value = getattr(_module, attr)
         setattr(self, attr, value)
@@ -159,9 +161,75 @@ class MovedAttribute(_LazyDescr):
         return getattr(module, self.attr)
 
 
+class _SixMetaPathImporter(object):
+
+    """
+    A meta path importer to import six.moves and its submodules.
+
+    This class implements a PEP302 finder and loader. It should be compatible
+    with Python 2.5 and all existing versions of Python3
+    """
+
+    def __init__(self, six_module_name):
+        self.name = six_module_name
+        self.known_modules = {}
+
+    def _add_module(self, mod, *fullnames):
+        for fullname in fullnames:
+            self.known_modules[self.name + "." + fullname] = mod
+
+    def _get_module(self, fullname):
+        return self.known_modules[self.name + "." + fullname]
+
+    def find_module(self, fullname, path=None):
+        if fullname in self.known_modules:
+            return self
+        return None
+
+    def __get_module(self, fullname):
+        try:
+            return self.known_modules[fullname]
+        except KeyError:
+            raise ImportError("This loader does not know module " + fullname)
+
+    def load_module(self, fullname):
+        try:
+            # in case of a reload
+            return sys.modules[fullname]
+        except KeyError:
+            pass
+        mod = self.__get_module(fullname)
+        if isinstance(mod, MovedModule):
+            mod = mod._resolve()
+        else:
+            mod.__loader__ = self
+        sys.modules[fullname] = mod
+        return mod
+
+    def is_package(self, fullname):
+        """
+        Return true, if the named module is a package.
+
+        We need this method to get correct spec objects with
+        Python 3.4 (see PEP451)
+        """
+        return hasattr(self.__get_module(fullname), "__path__")
+
+    def get_code(self, fullname):
+        """Return None
+
+        Required, if is_package is implemented"""
+        self.__get_module(fullname)  # eventually raises ImportError
+        return None
+    get_source = get_code  # same as get_code
+
+_importer = _SixMetaPathImporter(__name__)
+
 
 class _MovedItems(_LazyModule):
+
     """Lazy loading of moved objects"""
+    __path__ = []  # mark as package
 
 
 _moved_attributes = [
@@ -169,26 +237,33 @@ _moved_attributes = [
     MovedAttribute("filter", "itertools", "builtins", "ifilter", "filter"),
     MovedAttribute("filterfalse", "itertools", "itertools", "ifilterfalse", "filterfalse"),
     MovedAttribute("input", "__builtin__", "builtins", "raw_input", "input"),
+    MovedAttribute("intern", "__builtin__", "sys"),
     MovedAttribute("map", "itertools", "builtins", "imap", "map"),
+    MovedAttribute("getcwd", "os", "os", "getcwdu", "getcwd"),
+    MovedAttribute("getcwdb", "os", "os", "getcwd", "getcwdb"),
     MovedAttribute("range", "__builtin__", "builtins", "xrange", "range"),
-    MovedAttribute("reload_module", "__builtin__", "imp", "reload"),
+    MovedAttribute("reload_module", "__builtin__", "importlib" if PY34 else "imp", "reload"),
     MovedAttribute("reduce", "__builtin__", "functools"),
+    MovedAttribute("shlex_quote", "pipes", "shlex", "quote"),
     MovedAttribute("StringIO", "StringIO", "io"),
+    MovedAttribute("UserDict", "UserDict", "collections"),
+    MovedAttribute("UserList", "UserList", "collections"),
     MovedAttribute("UserString", "UserString", "collections"),
     MovedAttribute("xrange", "__builtin__", "builtins", "xrange", "range"),
     MovedAttribute("zip", "itertools", "builtins", "izip", "zip"),
     MovedAttribute("zip_longest", "itertools", "itertools", "izip_longest", "zip_longest"),
-
     MovedModule("builtins", "__builtin__"),
     MovedModule("configparser", "ConfigParser"),
     MovedModule("copyreg", "copy_reg"),
     MovedModule("dbm_gnu", "gdbm", "dbm.gnu"),
+    MovedModule("_dummy_thread", "dummy_thread", "_dummy_thread"),
     MovedModule("http_cookiejar", "cookielib", "http.cookiejar"),
     MovedModule("http_cookies", "Cookie", "http.cookies"),
     MovedModule("html_entities", "htmlentitydefs", "html.entities"),
     MovedModule("html_parser", "HTMLParser", "html.parser"),
     MovedModule("http_client", "httplib", "http.client"),
     MovedModule("email_mime_multipart", "email.MIMEMultipart", "email.mime.multipart"),
+    MovedModule("email_mime_nonmultipart", "email.MIMENonMultipart", "email.mime.nonmultipart"),
     MovedModule("email_mime_text", "email.MIMEText", "email.mime.text"),
     MovedModule("email_mime_base", "email.MIMEBase", "email.mime.base"),
     MovedModule("BaseHTTPServer", "BaseHTTPServer", "http.server"),
@@ -222,25 +297,34 @@ _moved_attributes = [
     MovedModule("urllib", __name__ + ".moves.urllib", __name__ + ".moves.urllib"),
     MovedModule("urllib_robotparser", "robotparser", "urllib.robotparser"),
     MovedModule("xmlrpc_client", "xmlrpclib", "xmlrpc.client"),
-    MovedModule("winreg", "_winreg"),
+    MovedModule("xmlrpc_server", "SimpleXMLRPCServer", "xmlrpc.server"),
 ]
+# Add windows specific modules.
+if sys.platform == "win32":
+    _moved_attributes += [
+        MovedModule("winreg", "_winreg"),
+    ]
+
 for attr in _moved_attributes:
     setattr(_MovedItems, attr.name, attr)
     if isinstance(attr, MovedModule):
-        sys.modules[__name__ + ".moves." + attr.name] = attr
+        _importer._add_module(attr, "moves." + attr.name)
 del attr
 
 _MovedItems._moved_attributes = _moved_attributes
 
-moves = sys.modules[__name__ + ".moves"] = _MovedItems(__name__ + ".moves")
+moves = _MovedItems(__name__ + ".moves")
+_importer._add_module(moves, "moves")
 
 
 class Module_six_moves_urllib_parse(_LazyModule):
+
     """Lazy loading of moved objects in six.moves.urllib_parse"""
 
 
 _urllib_parse_moved_attributes = [
     MovedAttribute("ParseResult", "urlparse", "urllib.parse"),
+    MovedAttribute("SplitResult", "urlparse", "urllib.parse"),
     MovedAttribute("parse_qs", "urlparse", "urllib.parse"),
     MovedAttribute("parse_qsl", "urlparse", "urllib.parse"),
     MovedAttribute("urldefrag", "urlparse", "urllib.parse"),
@@ -254,6 +338,14 @@ _urllib_parse_moved_attributes = [
     MovedAttribute("unquote", "urllib", "urllib.parse"),
     MovedAttribute("unquote_plus", "urllib", "urllib.parse"),
     MovedAttribute("urlencode", "urllib", "urllib.parse"),
+    MovedAttribute("splitquery", "urllib", "urllib.parse"),
+    MovedAttribute("splittag", "urllib", "urllib.parse"),
+    MovedAttribute("splituser", "urllib", "urllib.parse"),
+    MovedAttribute("uses_fragment", "urlparse", "urllib.parse"),
+    MovedAttribute("uses_netloc", "urlparse", "urllib.parse"),
+    MovedAttribute("uses_params", "urlparse", "urllib.parse"),
+    MovedAttribute("uses_query", "urlparse", "urllib.parse"),
+    MovedAttribute("uses_relative", "urlparse", "urllib.parse"),
 ]
 for attr in _urllib_parse_moved_attributes:
     setattr(Module_six_moves_urllib_parse, attr.name, attr)
@@ -261,10 +353,12 @@ del attr
 
 Module_six_moves_urllib_parse._moved_attributes = _urllib_parse_moved_attributes
 
-sys.modules[__name__ + ".moves.urllib_parse"] = sys.modules[__name__ + ".moves.urllib.parse"] = Module_six_moves_urllib_parse(__name__ + ".moves.urllib_parse")
+_importer._add_module(Module_six_moves_urllib_parse(__name__ + ".moves.urllib_parse"),
+                      "moves.urllib_parse", "moves.urllib.parse")
 
 
 class Module_six_moves_urllib_error(_LazyModule):
+
     """Lazy loading of moved objects in six.moves.urllib_error"""
 
 
@@ -279,10 +373,12 @@ del attr
 
 Module_six_moves_urllib_error._moved_attributes = _urllib_error_moved_attributes
 
-sys.modules[__name__ + ".moves.urllib_error"] = sys.modules[__name__ + ".moves.urllib.error"] = Module_six_moves_urllib_error(__name__ + ".moves.urllib.error")
+_importer._add_module(Module_six_moves_urllib_error(__name__ + ".moves.urllib.error"),
+                      "moves.urllib_error", "moves.urllib.error")
 
 
 class Module_six_moves_urllib_request(_LazyModule):
+
     """Lazy loading of moved objects in six.moves.urllib_request"""
 
 
@@ -327,10 +423,12 @@ del attr
 
 Module_six_moves_urllib_request._moved_attributes = _urllib_request_moved_attributes
 
-sys.modules[__name__ + ".moves.urllib_request"] = sys.modules[__name__ + ".moves.urllib.request"] = Module_six_moves_urllib_request(__name__ + ".moves.urllib.request")
+_importer._add_module(Module_six_moves_urllib_request(__name__ + ".moves.urllib.request"),
+                      "moves.urllib_request", "moves.urllib.request")
 
 
 class Module_six_moves_urllib_response(_LazyModule):
+
     """Lazy loading of moved objects in six.moves.urllib_response"""
 
 
@@ -346,10 +444,12 @@ del attr
 
 Module_six_moves_urllib_response._moved_attributes = _urllib_response_moved_attributes
 
-sys.modules[__name__ + ".moves.urllib_response"] = sys.modules[__name__ + ".moves.urllib.response"] = Module_six_moves_urllib_response(__name__ + ".moves.urllib.response")
+_importer._add_module(Module_six_moves_urllib_response(__name__ + ".moves.urllib.response"),
+                      "moves.urllib_response", "moves.urllib.response")
 
 
 class Module_six_moves_urllib_robotparser(_LazyModule):
+
     """Lazy loading of moved objects in six.moves.urllib_robotparser"""
 
 
@@ -362,22 +462,25 @@ del attr
 
 Module_six_moves_urllib_robotparser._moved_attributes = _urllib_robotparser_moved_attributes
 
-sys.modules[__name__ + ".moves.urllib_robotparser"] = sys.modules[__name__ + ".moves.urllib.robotparser"] = Module_six_moves_urllib_robotparser(__name__ + ".moves.urllib.robotparser")
+_importer._add_module(Module_six_moves_urllib_robotparser(__name__ + ".moves.urllib.robotparser"),
+                      "moves.urllib_robotparser", "moves.urllib.robotparser")
 
 
 class Module_six_moves_urllib(types.ModuleType):
+
     """Create a six.moves.urllib namespace that resembles the Python 3 namespace"""
-    parse = sys.modules[__name__ + ".moves.urllib_parse"]
-    error = sys.modules[__name__ + ".moves.urllib_error"]
-    request = sys.modules[__name__ + ".moves.urllib_request"]
-    response = sys.modules[__name__ + ".moves.urllib_response"]
-    robotparser = sys.modules[__name__ + ".moves.urllib_robotparser"]
+    __path__ = []  # mark as package
+    parse = _importer._get_module("moves.urllib_parse")
+    error = _importer._get_module("moves.urllib_error")
+    request = _importer._get_module("moves.urllib_request")
+    response = _importer._get_module("moves.urllib_response")
+    robotparser = _importer._get_module("moves.urllib_robotparser")
 
     def __dir__(self):
         return ['parse', 'error', 'request', 'response', 'robotparser']
 
-
-sys.modules[__name__ + ".moves.urllib"] = Module_six_moves_urllib(__name__ + ".moves.urllib")
+_importer._add_module(Module_six_moves_urllib(__name__ + ".moves.urllib"),
+                      "moves.urllib")
 
 
 def add_move(move):
@@ -404,11 +507,6 @@ if PY3:
     _func_code = "__code__"
     _func_defaults = "__defaults__"
     _func_globals = "__globals__"
-
-    _iterkeys = "keys"
-    _itervalues = "values"
-    _iteritems = "items"
-    _iterlists = "lists"
 else:
     _meth_func = "im_func"
     _meth_self = "im_self"
@@ -418,11 +516,6 @@ else:
     _func_defaults = "func_defaults"
     _func_globals = "func_globals"
 
-    _iterkeys = "iterkeys"
-    _itervalues = "itervalues"
-    _iteritems = "iteritems"
-    _iterlists = "iterlists"
-
 
 try:
     advance_iterator = next
@@ -445,6 +538,9 @@ if PY3:
 
     create_bound_method = types.MethodType
 
+    def create_unbound_method(func, cls):
+        return func
+
     Iterator = object
 else:
     def get_unbound_function(unbound):
@@ -453,6 +549,9 @@ else:
     def create_bound_method(func, obj):
         return types.MethodType(func, obj, obj.__class__)
 
+    def create_unbound_method(func, cls):
+        return types.MethodType(func, None, cls)
+
     class Iterator(object):
 
         def next(self):
@@ -471,66 +570,117 @@ get_function_defaults = operator.attrgetter(_func_defaults)
 get_function_globals = operator.attrgetter(_func_globals)
 
 
-def iterkeys(d, **kw):
-    """Return an iterator over the keys of a dictionary."""
-    return iter(getattr(d, _iterkeys)(**kw))
+if PY3:
+    def iterkeys(d, **kw):
+        return iter(d.keys(**kw))
+
+    def itervalues(d, **kw):
+        return iter(d.values(**kw))
+
+    def iteritems(d, **kw):
+        return iter(d.items(**kw))
+
+    def iterlists(d, **kw):
+        return iter(d.lists(**kw))
+
+    viewkeys = operator.methodcaller("keys")
 
-def itervalues(d, **kw):
-    """Return an iterator over the values of a dictionary."""
-    return iter(getattr(d, _itervalues)(**kw))
+    viewvalues = operator.methodcaller("values")
+
+    viewitems = operator.methodcaller("items")
+else:
+    def iterkeys(d, **kw):
+        return d.iterkeys(**kw)
 
-def iteritems(d, **kw):
-    """Return an iterator over the (key, value) pairs of a dictionary."""
-    return iter(getattr(d, _iteritems)(**kw))
+    def itervalues(d, **kw):
+        return d.itervalues(**kw)
 
-def iterlists(d, **kw):
-    """Return an iterator over the (key, [values]) pairs of a dictionary."""
-    return iter(getattr(d, _iterlists)(**kw))
+    def iteritems(d, **kw):
+        return d.iteritems(**kw)
+
+    def iterlists(d, **kw):
+        return d.iterlists(**kw)
+
+    viewkeys = operator.methodcaller("viewkeys")
+
+    viewvalues = operator.methodcaller("viewvalues")
+
+    viewitems = operator.methodcaller("viewitems")
+
+_add_doc(iterkeys, "Return an iterator over the keys of a dictionary.")
+_add_doc(itervalues, "Return an iterator over the values of a dictionary.")
+_add_doc(iteritems,
+         "Return an iterator over the (key, value) pairs of a dictionary.")
+_add_doc(iterlists,
+         "Return an iterator over the (key, [values]) pairs of a dictionary.")
 
 
 if PY3:
     def b(s):
         return s.encode("latin-1")
+
     def u(s):
         return s
     unichr = chr
-    if sys.version_info[1] <= 1:
-        def int2byte(i):
-            return bytes((i,))
-    else:
-        # This is about 2x faster than the implementation above on 3.2+
-        int2byte = operator.methodcaller("to_bytes", 1, "big")
+    import struct
+    int2byte = struct.Struct(">B").pack
+    del struct
     byte2int = operator.itemgetter(0)
     indexbytes = operator.getitem
     iterbytes = iter
     import io
     StringIO = io.StringIO
     BytesIO = io.BytesIO
+    _assertCountEqual = "assertCountEqual"
+    if sys.version_info[1] <= 1:
+        _assertRaisesRegex = "assertRaisesRegexp"
+        _assertRegex = "assertRegexpMatches"
+    else:
+        _assertRaisesRegex = "assertRaisesRegex"
+        _assertRegex = "assertRegex"
 else:
     def b(s):
         return s
     # Workaround for standalone backslash
+
     def u(s):
         return unicode(s.replace(r'\\', r'\\\\'), "unicode_escape")
     unichr = unichr
     int2byte = chr
+
     def byte2int(bs):
         return ord(bs[0])
+
     def indexbytes(buf, i):
         return ord(buf[i])
-    def iterbytes(buf):
-        return (ord(byte) for byte in buf)
+    iterbytes = functools.partial(itertools.imap, ord)
     import StringIO
     StringIO = BytesIO = StringIO.StringIO
+    _assertCountEqual = "assertItemsEqual"
+    _assertRaisesRegex = "assertRaisesRegexp"
+    _assertRegex = "assertRegexpMatches"
 _add_doc(b, """Byte literal""")
 _add_doc(u, """Text literal""")
 
 
+def assertCountEqual(self, *args, **kwargs):
+    return getattr(self, _assertCountEqual)(*args, **kwargs)
+
+
+def assertRaisesRegex(self, *args, **kwargs):
+    return getattr(self, _assertRaisesRegex)(*args, **kwargs)
+
+
+def assertRegex(self, *args, **kwargs):
+    return getattr(self, _assertRegex)(*args, **kwargs)
+
+
 if PY3:
     exec_ = getattr(moves.builtins, "exec")
 
-
     def reraise(tp, value, tb=None):
+        if value is None:
+            value = tp()
         if value.__traceback__ is not tb:
             raise value.with_traceback(tb)
         raise value
@@ -548,12 +698,26 @@ else:
             _locs_ = _globs_
         exec("""exec _code_ in _globs_, _locs_""")
 
-
     exec_("""def reraise(tp, value, tb=None):
     raise tp, value, tb
 """)
 
 
+if sys.version_info[:2] == (3, 2):
+    exec_("""def raise_from(value, from_value):
+    if from_value is None:
+        raise value
+    raise value from from_value
+""")
+elif sys.version_info[:2] > (3, 2):
+    exec_("""def raise_from(value, from_value):
+    raise value from from_value
+""")
+else:
+    def raise_from(value, from_value):
+        raise value
+
+
 print_ = getattr(moves.builtins, "print", None)
 if print_ is None:
     def print_(*args, **kwargs):
@@ -561,13 +725,14 @@ if print_ is None:
         fp = kwargs.pop("file", sys.stdout)
         if fp is None:
             return
+
         def write(data):
             if not isinstance(data, basestring):
                 data = str(data)
             # If the file has an encoding, encode unicode with it.
             if (isinstance(fp, file) and
-                isinstance(data, unicode) and
-                fp.encoding is not None):
+                    isinstance(data, unicode) and
+                    fp.encoding is not None):
                 errors = getattr(fp, "errors", None)
                 if errors is None:
                     errors = "strict"
@@ -608,25 +773,97 @@ if print_ is None:
                 write(sep)
             write(arg)
         write(end)
+if sys.version_info[:2] < (3, 3):
+    _print = print_
+
+    def print_(*args, **kwargs):
+        fp = kwargs.get("file", sys.stdout)
+        flush = kwargs.pop("flush", False)
+        _print(*args, **kwargs)
+        if flush and fp is not None:
+            fp.flush()
 
 _add_doc(reraise, """Reraise an exception.""")
 
+if sys.version_info[0:2] < (3, 4):
+    def wraps(wrapped, assigned=functools.WRAPPER_ASSIGNMENTS,
+              updated=functools.WRAPPER_UPDATES):
+        def wrapper(f):
+            f = functools.wraps(wrapped, assigned, updated)(f)
+            f.__wrapped__ = wrapped
+            return f
+        return wrapper
+else:
+    wraps = functools.wraps
+
 
 def with_metaclass(meta, *bases):
     """Create a base class with a metaclass."""
-    return meta("NewBase", bases, {})
+    # This requires a bit of explanation: the basic idea is to make a dummy
+    # metaclass for one level of class instantiation that replaces itself with
+    # the actual metaclass.
+    class metaclass(meta):
+
+        def __new__(cls, name, this_bases, d):
+            return meta(name, bases, d)
+    return type.__new__(metaclass, 'temporary_class', (), {})
+
 
 def add_metaclass(metaclass):
     """Class decorator for creating a class with a metaclass."""
     def wrapper(cls):
         orig_vars = cls.__dict__.copy()
-        orig_vars.pop('__dict__', None)
-        orig_vars.pop('__weakref__', None)
         slots = orig_vars.get('__slots__')
         if slots is not None:
             if isinstance(slots, str):
                 slots = [slots]
             for slots_var in slots:
                 orig_vars.pop(slots_var)
+        orig_vars.pop('__dict__', None)
+        orig_vars.pop('__weakref__', None)
         return metaclass(cls.__name__, cls.__bases__, orig_vars)
     return wrapper
+
+
+def python_2_unicode_compatible(klass):
+    """
+    A decorator that defines __unicode__ and __str__ methods under Python 2.
+    Under Python 3 it does nothing.
+
+    To support Python 2 and 3 with a single code base, define a __str__ method
+    returning text and apply this decorator to the class.
+    """
+    if PY2:
+        if '__str__' not in klass.__dict__:
+            raise ValueError("@python_2_unicode_compatible cannot be applied "
+                             "to %s because it doesn't define __str__()." %
+                             klass.__name__)
+        klass.__unicode__ = klass.__str__
+        klass.__str__ = lambda self: self.__unicode__().encode('utf-8')
+    return klass
+
+
+# Complete the moves implementation.
+# This code is at the end of this module to speed up module loading.
+# Turn this module into a package.
+__path__ = []  # required for PEP 302 and PEP 451
+__package__ = __name__  # see PEP 366 @ReservedAssignment
+if globals().get("__spec__") is not None:
+    __spec__.submodule_search_locations = []  # PEP 451 @UndefinedVariable
+# Remove other six meta path importers, since they cause problems. This can
+# happen if six is removed from sys.modules and then reloaded. (Setuptools does
+# this for some reason.)
+if sys.meta_path:
+    for i, importer in enumerate(sys.meta_path):
+        # Here's some real nastiness: Another "instance" of the six module might
+        # be floating around. Therefore, we can't use isinstance() to check for
+        # the six meta path importer, since the other six instance will have
+        # inserted an importer with different class.
+        if (type(importer).__name__ == "_SixMetaPathImporter" and
+                importer.name == __name__):
+            del sys.meta_path[i]
+            break
+    del i, importer
+# Finally, add the importer to the meta path import hook.
+sys.meta_path.append(_importer)
+
diff --git a/seaborn/linearmodels.py b/seaborn/linearmodels.py
index 2c90617..4b04935 100644
--- a/seaborn/linearmodels.py
+++ b/seaborn/linearmodels.py
@@ -1,1630 +1,6 @@
-"""Plotting functions for linear models (broadly construed)."""
-from __future__ import division
-import copy
-import itertools
-from textwrap import dedent
-import numpy as np
-import pandas as pd
-from scipy.spatial import distance
-import matplotlib as mpl
-import matplotlib.pyplot as plt
-
 import warnings
-
-try:
-    import statsmodels
-    assert statsmodels
-    _has_statsmodels = True
-except ImportError:
-    _has_statsmodels = False
-
-from .external.six import string_types
-from .external.six.moves import range
-
-from . import utils
-from . import algorithms as algo
-from .palettes import color_palette
-from .axisgrid import FacetGrid, PairGrid, _facet_docs
-from .distributions import kdeplot
-
-
-__all__ = ["lmplot", "regplot", "residplot",
-           "coefplot", "interactplot",
-           "pairplot"]
-
-
-class _LinearPlotter(object):
-    """Base class for plotting relational data in tidy format.
-
-    To get anything useful done you'll have to inherit from this, but setup
-    code that can be abstracted out should be put here.
-
-    """
-    def establish_variables(self, data, **kws):
-        """Extract variables from data or use directly."""
-        self.data = data
-
-        # Validate the inputs
-        any_strings = any([isinstance(v, string_types) for v in kws.values()])
-        if any_strings and data is None:
-            raise ValueError("Must pass `data` if using named variables.")
-
-        # Set the variables
-        for var, val in kws.items():
-            if isinstance(val, string_types):
-                setattr(self, var, data[val])
-            else:
-                setattr(self, var, val)
-
-    def dropna(self, *vars):
-        """Remove observations with missing data."""
-        vals = [getattr(self, var) for var in vars]
-        vals = [v for v in vals if v is not None]
-        not_na = np.all(np.column_stack([pd.notnull(v) for v in vals]), axis=1)
-        for var in vars:
-            val = getattr(self, var)
-            if val is not None:
-                setattr(self, var, val[not_na])
-
-    def plot(self, ax):
-        raise NotImplementedError
-
-
-class _RegressionPlotter(_LinearPlotter):
-    """Plotter for numeric independent variables with regression model.
-
-    This does the computations and drawing for the `regplot` function, and
-    is thus also used indirectly by `lmplot`.
-    """
-    def __init__(self, x, y, data=None, x_estimator=None, x_bins=None,
-                 x_ci="ci", scatter=True, fit_reg=True, ci=95, n_boot=1000,
-                 units=None, order=1, logistic=False, lowess=False,
-                 robust=False, logx=False, x_partial=None, y_partial=None,
-                 truncate=False, dropna=True, x_jitter=None, y_jitter=None,
-                 color=None, label=None):
-
-        # Set member attributes
-        self.x_estimator = x_estimator
-        self.ci = ci
-        self.x_ci = ci if x_ci == "ci" else x_ci
-        self.n_boot = n_boot
-        self.scatter = scatter
-        self.fit_reg = fit_reg
-        self.order = order
-        self.logistic = logistic
-        self.lowess = lowess
-        self.robust = robust
-        self.logx = logx
-        self.truncate = truncate
-        self.x_jitter = x_jitter
-        self.y_jitter = y_jitter
-        self.color = color
-        self.label = label
-
-        # Validate the regression options:
-        if sum((order > 1, logistic, robust, lowess, logx)) > 1:
-            raise ValueError("Mutually exclusive regression options.")
-
-        # Extract the data vals from the arguments or passed dataframe
-        self.establish_variables(data, x=x, y=y, units=units,
-                                 x_partial=x_partial, y_partial=y_partial)
-
-        # Drop null observations
-        if dropna:
-            self.dropna("x", "y", "units", "x_partial", "y_partial")
-
-        # Regress nuisance variables out of the data
-        if self.x_partial is not None:
-            self.x = self.regress_out(self.x, self.x_partial)
-        if self.y_partial is not None:
-            self.y = self.regress_out(self.y, self.y_partial)
-
-        # Possibly bin the predictor variable, which implies a point estimate
-        if x_bins is not None:
-            self.x_estimator = np.mean if x_estimator is None else x_estimator
-            x_discrete, x_bins = self.bin_predictor(x_bins)
-            self.x_discrete = x_discrete
-        else:
-            self.x_discrete = self.x
-
-        # Save the range of the x variable for the grid later
-        self.x_range = self.x.min(), self.x.max()
-
-    @property
-    def scatter_data(self):
-        """Data where each observation is a point."""
-        x_j = self.x_jitter
-        if x_j is None:
-            x = self.x
-        else:
-            x = self.x + np.random.uniform(-x_j, x_j, len(self.x))
-
-        y_j = self.y_jitter
-        if y_j is None:
-            y = self.y
-        else:
-            y = self.y + np.random.uniform(-y_j, y_j, len(self.y))
-
-        return x, y
-
-    @property
-    def estimate_data(self):
-        """Data with a point estimate and CI for each discrete x value."""
-        x, y = self.x_discrete, self.y
-        vals = sorted(np.unique(x))
-        points, cis = [], []
-
-        for val in vals:
-
-            # Get the point estimate of the y variable
-            _y = y[x == val]
-            est = self.x_estimator(_y)
-            points.append(est)
-
-            # Compute the confidence interval for this estimate
-            if self.x_ci is None:
-                cis.append(None)
-            else:
-                units = None
-                if self.units is not None:
-                    units = self.units[x == val]
-                boots = algo.bootstrap(_y, func=self.x_estimator,
-                                       n_boot=self.n_boot, units=units)
-                _ci = utils.ci(boots, self.x_ci)
-                cis.append(_ci)
-
-        return vals, points, cis
-
-    def fit_regression(self, ax=None, x_range=None, grid=None):
-        """Fit the regression model."""
-        # Create the grid for the regression
-        if grid is None:
-            if self.truncate:
-                x_min, x_max = self.x_range
-            else:
-                if ax is None:
-                    x_min, x_max = x_range
-                else:
-                    x_min, x_max = ax.get_xlim()
-            grid = np.linspace(x_min, x_max, 100)
-        ci = self.ci
-
-        # Fit the regression
-        if self.order > 1:
-            yhat, yhat_boots = self.fit_poly(grid, self.order)
-        elif self.logistic:
-            from statsmodels.genmod.generalized_linear_model import GLM
-            from statsmodels.genmod.families import Binomial
-            yhat, yhat_boots = self.fit_statsmodels(grid, GLM,
-                                                    family=Binomial())
-        elif self.lowess:
-            ci = None
-            grid, yhat = self.fit_lowess()
-        elif self.robust:
-            from statsmodels.robust.robust_linear_model import RLM
-            yhat, yhat_boots = self.fit_statsmodels(grid, RLM)
-        elif self.logx:
-            yhat, yhat_boots = self.fit_logx(grid)
-        else:
-            yhat, yhat_boots = self.fit_fast(grid)
-
-        # Compute the confidence interval at each grid point
-        if ci is None:
-            err_bands = None
-        else:
-            err_bands = utils.ci(yhat_boots, ci, axis=0)
-
-        return grid, yhat, err_bands
-
-    def fit_fast(self, grid):
-        """Low-level regression and prediction using linear algebra."""
-        X, y = np.c_[np.ones(len(self.x)), self.x], self.y
-        grid = np.c_[np.ones(len(grid)), grid]
-        reg_func = lambda _x, _y: np.linalg.pinv(_x).dot(_y)
-        yhat = grid.dot(reg_func(X, y))
-        if self.ci is None:
-            return yhat, None
-
-        beta_boots = algo.bootstrap(X, y, func=reg_func,
-                                    n_boot=self.n_boot, units=self.units).T
-        yhat_boots = grid.dot(beta_boots).T
-        return yhat, yhat_boots
-
-    def fit_poly(self, grid, order):
-        """Regression using numpy polyfit for higher-order trends."""
-        x, y = self.x, self.y
-        reg_func = lambda _x, _y: np.polyval(np.polyfit(_x, _y, order), grid)
-        yhat = reg_func(x, y)
-        if self.ci is None:
-            return yhat, None
-
-        yhat_boots = algo.bootstrap(x, y, func=reg_func,
-                                    n_boot=self.n_boot, units=self.units)
-        return yhat, yhat_boots
-
-    def fit_statsmodels(self, grid, model, **kwargs):
-        """More general regression function using statsmodels objects."""
-        X, y = np.c_[np.ones(len(self.x)), self.x], self.y
-        grid = np.c_[np.ones(len(grid)), grid]
-        reg_func = lambda _x, _y: model(_y, _x, **kwargs).fit().predict(grid)
-        yhat = reg_func(X, y)
-        if self.ci is None:
-            return yhat, None
-
-        yhat_boots = algo.bootstrap(X, y, func=reg_func,
-                                    n_boot=self.n_boot, units=self.units)
-        return yhat, yhat_boots
-
-    def fit_lowess(self):
-        """Fit a locally-weighted regression, which returns its own grid."""
-        from statsmodels.nonparametric.smoothers_lowess import lowess
-        grid, yhat = lowess(self.y, self.x).T
-        return grid, yhat
-
-    def fit_logx(self, grid):
-        """Fit the model in log-space."""
-        X, y = np.c_[np.ones(len(self.x)), self.x], self.y
-        grid = np.c_[np.ones(len(grid)), np.log(grid)]
-
-        def reg_func(_x, _y):
-            _x = np.c_[_x[:, 0], np.log(_x[:, 1])]
-            return np.linalg.pinv(_x).dot(_y)
-
-        yhat = grid.dot(reg_func(X, y))
-        if self.ci is None:
-            return yhat, None
-
-        beta_boots = algo.bootstrap(X, y, func=reg_func,
-                                    n_boot=self.n_boot, units=self.units).T
-        yhat_boots = grid.dot(beta_boots).T
-        return yhat, yhat_boots
-
-    def bin_predictor(self, bins):
-        """Discretize a predictor by assigning value to closest bin."""
-        x = self.x
-        if np.isscalar(bins):
-            percentiles = np.linspace(0, 100, bins + 2)[1:-1]
-            bins = np.c_[utils.percentiles(x, percentiles)]
-        else:
-            bins = np.c_[np.ravel(bins)]
-
-        dist = distance.cdist(np.c_[x], bins)
-        x_binned = bins[np.argmin(dist, axis=1)].ravel()
-
-        return x_binned, bins.ravel()
-
-    def regress_out(self, a, b):
-        """Regress b from a keeping a's original mean."""
-        a_mean = a.mean()
-        a = a - a_mean
-        b = b - b.mean()
-        b = np.c_[b]
-        a_prime = a - b.dot(np.linalg.pinv(b).dot(a))
-        return (a_prime + a_mean).reshape(a.shape)
-
-    def plot(self, ax, scatter_kws, line_kws):
-        """Draw the full plot."""
-        # Insert the plot label into the correct set of keyword arguments
-        if self.scatter:
-            scatter_kws["label"] = self.label
-        else:
-            line_kws["label"] = self.label
-
-        # Use the current color cycle state as a default
-        if self.color is None:
-            lines, = plt.plot(self.x.mean(), self.y.mean())
-            color = lines.get_color()
-            lines.remove()
-        else:
-            color = self.color
-
-        # Ensure that color is hex to avoid matplotlib weidness
-        color = mpl.colors.rgb2hex(mpl.colors.colorConverter.to_rgb(color))
-
-        # Let color in keyword arguments override overall plot color
-        scatter_kws.setdefault("color", color)
-        line_kws.setdefault("color", color)
-
-        # Draw the constituent plots
-        if self.scatter:
-            self.scatterplot(ax, scatter_kws)
-        if self.fit_reg:
-            self.lineplot(ax, line_kws)
-
-        # Label the axes
-        if hasattr(self.x, "name"):
-            ax.set_xlabel(self.x.name)
-        if hasattr(self.y, "name"):
-            ax.set_ylabel(self.y.name)
-
-    def scatterplot(self, ax, kws):
-        """Draw the data."""
-        # Treat the line-based markers specially, explicitly setting larger
-        # linewidth than is provided by the seaborn style defaults.
-        # This would ideally be handled better in matplotlib (i.e., distinguish
-        # between edgewidth for solid glyphs and linewidth for line glyphs
-        # but this should do for now.
-        line_markers = ["1", "2", "3", "4", "+", "x", "|", "_"]
-        if self.x_estimator is None:
-            if "marker" in kws and kws["marker"] in line_markers:
-                lw = mpl.rcParams["lines.linewidth"]
-            else:
-                lw = mpl.rcParams["lines.markeredgewidth"]
-            kws.setdefault("linewidths", lw)
-
-            if not hasattr(kws['color'], 'shape') or kws['color'].shape[1] < 4:
-                kws.setdefault("alpha", .8)
-
-            x, y = self.scatter_data
-            ax.scatter(x, y, **kws)
-        else:
-            # TODO abstraction
-            ci_kws = {"color": kws["color"]}
-            ci_kws["linewidth"] = mpl.rcParams["lines.linewidth"] * 1.75
-            kws.setdefault("s", 50)
-
-            xs, ys, cis = self.estimate_data
-            if [ci for ci in cis if ci is not None]:
-                for x, ci in zip(xs, cis):
-                    ax.plot([x, x], ci, **ci_kws)
-            ax.scatter(xs, ys, **kws)
-
-    def lineplot(self, ax, kws):
-        """Draw the model."""
-        xlim = ax.get_xlim()
-
-        # Fit the regression model
-        grid, yhat, err_bands = self.fit_regression(ax)
-
-        # Get set default aesthetics
-        fill_color = kws["color"]
-        lw = kws.pop("lw", mpl.rcParams["lines.linewidth"] * 1.5)
-        kws.setdefault("linewidth", lw)
-
-        # Draw the regression line and confidence interval
-        ax.plot(grid, yhat, **kws)
-        if err_bands is not None:
-            ax.fill_between(grid, *err_bands, facecolor=fill_color, alpha=.15)
-        ax.set_xlim(*xlim)
-
-
-_regression_docs = dict(
-
-    model_api=dedent("""\
-    There are a number of mutually exclusive options for estimating the
-    regression model: ``order``, ``logistic``, ``lowess``, ``robust``, and
-    ``logx``. See the parameter docs for more information on these options.\
-    """),
-
-    regplot_vs_lmplot=dedent("""\
-    Understanding the difference between :func:`regplot` and :func:`lmplot` can
-    be a bit tricky. In fact, they are closely related, as :func:`lmplot` uses
-    :func:`regplot` internally and takes most of its parameters. However,
-    :func:`regplot` is an axes-level function, so it draws directly onto an
-    axes (either the currently active axes or the one provided by the ``ax``
-    parameter), while :func:`lmplot` is a figure-level function and creates its
-    own figure, which is managed through a :class:`FacetGrid`. This has a few
-    consequences, namely that :func:`regplot` can happily coexist in a figure
-    with other kinds of plots and will follow the global matplotlib color
-    cycle. In contrast, :func:`lmplot` needs to occupy an entire figure, and
-    the size and color cycle are controlled through function parameters,
-    ignoring the global defaults.\
-    """),
-
-    x_estimator=dedent("""\
-    x_estimator : callable that maps vector -> scalar, optional
-        Apply this function to each unique value of ``x`` and plot the
-        resulting estimate. This is useful when ``x`` is a discrete variable.
-        If ``x_ci`` is not ``None``, this estimate will be bootstrapped and a
-        confidence interval will be drawn.\
-    """),
-    x_bins=dedent("""\
-    x_bins : int or vector, optional
-        Bin the ``x`` variable into discrete bins and then estimate the central
-        tendency and a confidence interval. This binning only influences how
-        the scatterplot is drawn; the regression is still fit to the original
-        data.  This parameter is interpreted either as the number of
-        evenly-sized (not necessary spaced) bins or the positions of the bin
-        centers. When this parameter is used, it implies that the default of
-        ``x_estimator`` is ``numpy.mean``.\
-    """),
-    x_ci=dedent("""\
-    x_ci : "ci", int in [0, 100] or None, optional
-        Size of the confidence interval used when plotting a central tendency
-        for discrete values of ``x``. If "ci", defer to the value of the``ci``
-        parameter.\
-    """),
-    scatter=dedent("""\
-    scatter : bool, optional
-        If ``True``, draw a scatterplot with the underlying observations (or
-        the ``x_estimator`` values).\
-    """),
-    fit_reg=dedent("""\
-    fit_reg : bool, optional
-        If ``True``, estimate and plot a regression model relating the ``x``
-        and ``y`` variables.\
-    """),
-    ci=dedent("""\
-    ci : int in [0, 100] or None, optional
-        Size of the confidence interval for the regression estimate. This will
-        be drawn using translucent bands around the regression line. The
-        confidence interval is estimated using a bootstrap; for large
-        datasets, it may be advisable to avoid that computation by setting
-        this parameter to None.\
-    """),
-    n_boot=dedent("""\
-    n_boot : int, optional
-        Number of bootstrap resamples used to estimate the ``ci``. The default
-        value attempts to balance time and stability; you may want to increase
-        this value for "final" versions of plots.\
-    """),
-    units=dedent("""\
-    units : variable name in ``data``, optional
-        If the ``x`` and ``y`` observations are nested within sampling units,
-        those can be specified here. This will be taken into account when
-        computing the confidence intervals by performing a multilevel bootstrap
-        that resamples both units and observations (within unit). This does not
-        otherwise influence how the regression is estimated or drawn.\
-    """),
-    order=dedent("""\
-    order : int, optional
-        If ``order`` is greater than 1, use ``numpy.polyfit`` to estimate a
-        polynomial regression.\
-    """),
-    logistic=dedent("""\
-    logistic : bool, optional
-        If ``True``, assume that ``y`` is a binary variable and use
-        ``statsmodels`` to estimate a logistic regression model. Note that this
-        is substantially more computationally intensive than linear regression,
-        so you may wish to decrease the number of bootstrap resamples
-        (``n_boot``) or set ``ci`` to None.\
-    """),
-    lowess=dedent("""\
-    lowess : bool, optional
-        If ``True``, use ``statsmodels`` to estimate a nonparametric lowess
-        model (locally weighted linear regression). Note that confidence
-        intervals cannot currently be drawn for this kind of model.\
-    """),
-    robust=dedent("""\
-    robust : bool, optional
-        If ``True``, use ``statsmodels`` to estimate a robust regression. This
-        will de-weight outliers. Note that this is substantially more
-        computationally intensive than standard linear regression, so you may
-        wish to decrease the number of bootstrap resamples (``n_boot``) or set
-        ``ci`` to None.\
-    """),
-    logx=dedent("""\
-    logx : bool, optional
-        If ``True``, estimate a linear regression of the form y ~ log(x), but
-        plot the scatterplot and regression model in the input space. Note that
-        ``x`` must be positive for this to work.\
-    """),
-    xy_partial=dedent("""\
-    {x,y}_partial : strings in ``data`` or matrices
-        Confounding variables to regress out of the ``x`` or ``y`` variables
-        before plotting.\
-    """),
-    truncate=dedent("""\
-    truncate : bool, optional
-        By default, the regression line is drawn to fill the x axis limits
-        after the scatterplot is drawn. If ``truncate`` is ``True``, it will
-        instead by bounded by the data limits.\
-    """),
-    xy_jitter=dedent("""\
-    {x,y}_jitter : floats, optional
-        Add uniform random noise of this size to either the ``x`` or ``y``
-        variables. The noise is added to a copy of the data after fitting the
-        regression, and only influences the look of the scatterplot. This can
-        be helpful when plotting variables that take discrete values.\
-    """),
-    scatter_line_kws=dedent("""\
-    {scatter,line}_kws : dictionaries
-        Additional keyword arguments to pass to ``plt.scatter`` and
-        ``plt.plot``.\
-    """),
-    )
-_regression_docs.update(_facet_docs)
-
-
-def lmplot(x, y, data, hue=None, col=None, row=None, palette=None,
-           col_wrap=None, size=5, aspect=1, markers="o", sharex=True,
-           sharey=True, hue_order=None, col_order=None, row_order=None,
-           legend=True, legend_out=True, x_estimator=None, x_bins=None,
-           x_ci="ci", scatter=True, fit_reg=True, ci=95, n_boot=1000,
-           units=None, order=1, logistic=False, lowess=False, robust=False,
-           logx=False, x_partial=None, y_partial=None, truncate=False,
-           x_jitter=None, y_jitter=None, scatter_kws=None, line_kws=None):
-
-    # Reduce the dataframe to only needed columns
-    need_cols = [x, y, hue, col, row, units, x_partial, y_partial]
-    cols = np.unique([a for a in need_cols if a is not None]).tolist()
-    data = data[cols]
-
-    # Initialize the grid
-    facets = FacetGrid(data, row, col, hue, palette=palette,
-                       row_order=row_order, col_order=col_order,
-                       hue_order=hue_order, size=size, aspect=aspect,
-                       col_wrap=col_wrap, sharex=sharex, sharey=sharey,
-                       legend_out=legend_out)
-
-    # Add the markers here as FacetGrid has figured out how many levels of the
-    # hue variable are needed and we don't want to duplicate that process
-    if facets.hue_names is None:
-        n_markers = 1
-    else:
-        n_markers = len(facets.hue_names)
-    if not isinstance(markers, list):
-        markers = [markers] * n_markers
-    if len(markers) != n_markers:
-        raise ValueError(("markers must be a singeton or a list of markers "
-                          "for each level of the hue variable"))
-    facets.hue_kws = {"marker": markers}
-
-    # Hack to set the x limits properly, which needs to happen here
-    # because the extent of the regression estimate is determined
-    # by the limits of the plot
-    if sharex:
-        for ax in facets.axes.flat:
-            ax.scatter(data[x], np.ones(len(data)) * data[y].mean()).remove()
-
-    # Draw the regression plot on each facet
-    regplot_kws = dict(
-        x_estimator=x_estimator, x_bins=x_bins, x_ci=x_ci,
-        scatter=scatter, fit_reg=fit_reg, ci=ci, n_boot=n_boot, units=units,
-        order=order, logistic=logistic, lowess=lowess, robust=robust,
-        logx=logx, x_partial=x_partial, y_partial=y_partial, truncate=truncate,
-        x_jitter=x_jitter, y_jitter=y_jitter,
-        scatter_kws=scatter_kws, line_kws=line_kws,
-        )
-    facets.map_dataframe(regplot, x, y, **regplot_kws)
-
-    # Add a legend
-    if legend and (hue is not None) and (hue not in [col, row]):
-        facets.add_legend()
-    return facets
-
-
-lmplot.__doc__ = dedent("""\
-    Plot data and regression model fits across a FacetGrid.
-
-    This function combines :func:`regplot` and :class:`FacetGrid`. It is
-    intended as a convenient interface to fit regression models across
-    conditional subsets of a dataset.
-
-    When thinking about how to assign variables to different facets, a general
-    rule is that it makes sense to use ``hue`` for the most important
-    comparison, followed by ``col`` and ``row``. However, always think about
-    your particular dataset and the goals of the visualization you are
-    creating.
-
-    {model_api}
-
-    The parameters to this function span most of the options in
-    :class:`FacetGrid`, although there may be occasional cases where you will
-    want to use that class and :func:`regplot` directly.
-
-    Parameters
-    ----------
-    x, y : strings, optional
-        Input variables; these should be column names in ``data``.
-    {data}
-    hue, col, row : strings
-        Variables that define subsets of the data, which will be drawn on
-        separate facets in the grid. See the ``*_order`` parameters to control
-        the order of levels of this variable.
-    {palette}
-    {col_wrap}
-    {size}
-    {aspect}
-    markers : matplotlib marker code or list of marker codes, optional
-        Markers for the scatterplot. If a list, each marker in the list will be
-        used for each level of the ``hue`` variable.
-    {share_xy}
-    {{hue,col,row}}_order : lists, optional
-        Order for the levels of the faceting variables. By default, this will
-        be the order that the levels appear in ``data`` or, if the variables
-        are pandas categoricals, the category order.
-    legend : bool, optional
-        If ``True`` and there is a ``hue`` variable, add a legend.
-    {legend_out}
-    {x_estimator}
-    {x_bins}
-    {x_ci}
-    {scatter}
-    {fit_reg}
-    {ci}
-    {n_boot}
-    {units}
-    {order}
-    {logistic}
-    {lowess}
-    {robust}
-    {logx}
-    {xy_partial}
-    {truncate}
-    {xy_jitter}
-    {scatter_line_kws}
-
-    See Also
-    --------
-    regplot : Plot data and a conditional model fit.
-    FacetGrid : Subplot grid for plotting conditional relationships.
-    pairplot : Combine :func:`regplot` and :class:`PairGrid` (when used with
-               ``kind="reg"``).
-
-    Notes
-    -----
-
-    {regplot_vs_lmplot}
-
-    Examples
-    --------
-
-    These examples focus on basic regression model plots to exhibit the
-    various faceting options; see the :func:`regplot` docs for demonstrations
-    of the other options for plotting the data and models. There are also
-    other examples for how to manipulate plot using the returned object on
-    the :class:`FacetGrid` docs.
-
-    Plot a simple linear relationship between two variables:
-
-    .. plot::
-        :context: close-figs
-
-        >>> import seaborn as sns; sns.set(color_codes=True)
-        >>> tips = sns.load_dataset("tips")
-        >>> g = sns.lmplot(x="total_bill", y="tip", data=tips)
-
-    Condition on a third variable and plot the levels in different colors:
-
-    .. plot::
-        :context: close-figs
-
-        >>> g = sns.lmplot(x="total_bill", y="tip", hue="smoker", data=tips)
-
-    Use different markers as well as colors so the plot will reproduce to
-    black-and-white more easily:
-
-    .. plot::
-        :context: close-figs
-
-        >>> g = sns.lmplot(x="total_bill", y="tip", hue="smoker", data=tips,
-        ...                markers=["o", "x"])
-
-    Use a different color palette:
-
-    .. plot::
-        :context: close-figs
-
-        >>> g = sns.lmplot(x="total_bill", y="tip", hue="smoker", data=tips,
-        ...                palette="Set1")
-
-    Map ``hue`` levels to colors with a dictionary:
-
-    .. plot::
-        :context: close-figs
-
-        >>> g = sns.lmplot(x="total_bill", y="tip", hue="smoker", data=tips,
-        ...                palette=dict(Yes="g", No="m"))
-
-    Plot the levels of the third variable across different columns:
-
-    .. plot::
-        :context: close-figs
-
-        >>> g = sns.lmplot(x="total_bill", y="tip", col="smoker", data=tips)
-
-    Change the size and aspect ratio of the facets:
-
-    .. plot::
-        :context: close-figs
-
-        >>> g = sns.lmplot(x="size", y="total_bill", hue="day", col="day",
-        ...                data=tips, aspect=.4, x_jitter=.1)
-
-    Wrap the levels of the column variable into multiple rows:
-
-    .. plot::
-        :context: close-figs
-
-        >>> g = sns.lmplot(x="total_bill", y="tip", col="day", hue="day",
-        ...                data=tips, col_wrap=2, size=3)
-
-    Condition on two variables to make a full grid:
-
-    .. plot::
-        :context: close-figs
-
-        >>> g = sns.lmplot(x="total_bill", y="tip", row="sex", col="time",
-        ...                data=tips, size=3)
-
-    Use methods on the returned :class:`FacetGrid` instance to further tweak
-    the plot:
-
-    .. plot::
-        :context: close-figs
-
-        >>> g = sns.lmplot(x="total_bill", y="tip", row="sex", col="time",
-        ...                data=tips, size=3)
-        >>> g = (g.set_axis_labels("Total bill (US Dollars)", "Tip")
-        ...       .set(xlim=(0, 60), ylim=(0, 12),
-        ...            xticks=[10, 30, 50], yticks=[2, 6, 10])
-        ...       .fig.subplots_adjust(wspace=.02))
-
-
-
-    """).format(**_regression_docs)
-
-
-def regplot(x, y, data=None, x_estimator=None, x_bins=None, x_ci="ci",
-            scatter=True, fit_reg=True, ci=95, n_boot=1000, units=None,
-            order=1, logistic=False, lowess=False, robust=False,
-            logx=False, x_partial=None, y_partial=None,
-            truncate=False, dropna=True, x_jitter=None, y_jitter=None,
-            label=None, color=None, marker="o",
-            scatter_kws=None, line_kws=None, ax=None):
-
-    plotter = _RegressionPlotter(x, y, data, x_estimator, x_bins, x_ci,
-                                 scatter, fit_reg, ci, n_boot, units,
-                                 order, logistic, lowess, robust, logx,
-                                 x_partial, y_partial, truncate, dropna,
-                                 x_jitter, y_jitter, color, label)
-
-    if ax is None:
-        ax = plt.gca()
-
-    scatter_kws = {} if scatter_kws is None else copy.copy(scatter_kws)
-    scatter_kws["marker"] = marker
-    line_kws = {} if line_kws is None else copy.copy(line_kws)
-    plotter.plot(ax, scatter_kws, line_kws)
-    return ax
-
-regplot.__doc__ = dedent("""\
-    Plot data and a linear regression model fit.
-
-    {model_api}
-
-    Parameters
-    ----------
-    x, y: string, series, or vector array
-        Input variables. If strings, these should correspond with column names
-        in ``data``. When pandas objects are used, axes will be labeled with
-        the series name.
-    {data}
-    {x_estimator}
-    {x_bins}
-    {x_ci}
-    {scatter}
-    {fit_reg}
-    {ci}
-    {n_boot}
-    {units}
-    {order}
-    {logistic}
-    {lowess}
-    {robust}
-    {logx}
-    {xy_partial}
-    {truncate}
-    {xy_jitter}
-    label : string
-        Label to apply to ether the scatterplot or regression line (if
-        ``scatter`` is ``False``) for use in a legend.
-    color : matplotlib color
-        Color to apply to all plot elements; will be superseded by colors
-        passed in ``scatter_kws`` or ``line_kws``.
-    marker : matplotlib marker code
-        Marker to use for the scatterplot glyphs.
-    {scatter_line_kws}
-    ax : matplotlib Axes, optional
-        Axes object to draw the plot onto, otherwise uses the current Axes.
-
-    Returns
-    -------
-    ax : matplotlib Axes
-        The Axes object containing the plot.
-
-    See Also
-    --------
-    lmplot : Combine :func:`regplot` and :class:`FacetGrid` to plot multiple
-             linear relationships in a dataset.
-    jointplot : Combine :func:`regplot` and :class:`JointGrid` (when used with
-                ``kind="reg"``).
-    pairplot : Combine :func:`regplot` and :class:`PairGrid` (when used with
-               ``kind="reg"``).
-    residplot : Plot the residuals of a linear regression model.
-    interactplot : Plot a two-way interaction between continuous variables
-
-    Notes
-    -----
-
-    {regplot_vs_lmplot}
-
-
-    It's also easy to combine combine :func:`regplot` and :class:`JointGrid` or
-    :class:`PairGrid` through the :func:`jointplot` and :func:`pairplot`
-    functions, although these do not directly accept all of :func:`regplot`'s
-    parameters.
-
-    Examples
-    --------
-
-    Plot the relationship between two variables in a DataFrame:
-
-    .. plot::
-        :context: close-figs
-
-        >>> import seaborn as sns; sns.set(color_codes=True)
-        >>> tips = sns.load_dataset("tips")
-        >>> ax = sns.regplot(x="total_bill", y="tip", data=tips)
-
-    Plot with two variables defined as numpy arrays; use a different color:
-
-    .. plot::
-        :context: close-figs
-
-        >>> import numpy as np; np.random.seed(8)
-        >>> mean, cov = [4, 6], [(1.5, .7), (.7, 1)]
-        >>> x, y = np.random.multivariate_normal(mean, cov, 80).T
-        >>> ax = sns.regplot(x=x, y=y, color="g")
-
-    Plot with two variables defined as pandas Series; use a different marker:
-
-    .. plot::
-        :context: close-figs
-
-        >>> import pandas as pd
-        >>> x, y = pd.Series(x, name="x_var"), pd.Series(y, name="y_var")
-        >>> ax = sns.regplot(x=x, y=y, marker="+")
-
-    Use a 68% confidence interval, which corresponds with the standard error
-    of the estimate:
-
-    .. plot::
-        :context: close-figs
-
-        >>> ax = sns.regplot(x=x, y=y, ci=68)
-
-    Plot with a discrete ``x`` variable and add some jitter:
-
-    .. plot::
-        :context: close-figs
-
-        >>> ax = sns.regplot(x="size", y="total_bill", data=tips, x_jitter=.1)
-
-    Plot with a discrete ``x`` variable showing means and confidence intervals
-    for unique values:
-
-    .. plot::
-        :context: close-figs
-
-        >>> ax = sns.regplot(x="size", y="total_bill", data=tips,
-        ...                  x_estimator=np.mean)
-
-    Plot with a continuous variable divided into discrete bins:
-
-    .. plot::
-        :context: close-figs
-
-        >>> ax = sns.regplot(x=x, y=y, x_bins=4)
-
-    Fit a higher-order polynomial regression and truncate the model prediction:
-
-    .. plot::
-        :context: close-figs
-
-        >>> ans = sns.load_dataset("anscombe")
-        >>> ax = sns.regplot(x="x", y="y", data=ans.loc[ans.dataset == "II"],
-        ...                  scatter_kws={{"s": 80}},
-        ...                  order=2, ci=None, truncate=True)
-
-    Fit a robust regression and don't plot a confidence interval:
-
-    .. plot::
-        :context: close-figs
-
-        >>> ax = sns.regplot(x="x", y="y", data=ans.loc[ans.dataset == "III"],
-        ...                  scatter_kws={{"s": 80}},
-        ...                  robust=True, ci=None)
-
-    Fit a logistic regression; jitter the y variable and use fewer bootstrap
-    iterations:
-
-    .. plot::
-        :context: close-figs
-
-        >>> tips["big_tip"] = (tips.tip / tips.total_bill) > .175
-        >>> ax = sns.regplot(x="total_bill", y="big_tip", data=tips,
-        ...                  logistic=True, n_boot=500, y_jitter=.03)
-
-    Fit the regression model using log(x) and truncate the model prediction:
-
-    .. plot::
-        :context: close-figs
-
-        >>> ax = sns.regplot(x="size", y="total_bill", data=tips,
-        ...                  x_estimator=np.mean, logx=True, truncate=True)
-
-    """).format(**_regression_docs)
-
-
-def residplot(x, y, data=None, lowess=False, x_partial=None, y_partial=None,
-              order=1, robust=False, dropna=True, label=None, color=None,
-              scatter_kws=None, line_kws=None, ax=None):
-    """Plot the residuals of a linear regression.
-
-    This function will regress y on x (possibly as a robust or polynomial
-    regression) and then draw a scatterplot of the residuals. You can
-    optionally fit a lowess smoother to the residual plot, which can
-    help in determining if there is structure to the residuals.
-
-    Parameters
-    ----------
-    x : vector or string
-        Data or column name in `data` for the predictor variable.
-    y : vector or string
-        Data or column name in `data` for the response variable.
-    data : DataFrame, optional
-        DataFrame to use if `x` and `y` are column names.
-    lowess : boolean, optional
-        Fit a lowess smoother to the residual scatterplot.
-    {x, y}_partial : matrix or string(s) , optional
-        Matrix with same first dimension as `x`, or column name(s) in `data`.
-        These variables are treated as confounding and are removed from
-        the `x` or `y` variables before plotting.
-    order : int, optional
-        Order of the polynomial to fit when calculating the residuals.
-    robust : boolean, optional
-        Fit a robust linear regression when calculating the residuals.
-    dropna : boolean, optional
-        If True, ignore observations with missing data when fitting and
-        plotting.
-    label : string, optional
-        Label that will be used in any plot legends.
-    color : matplotlib color, optional
-        Color to use for all elements of the plot.
-    {scatter, line}_kws : dictionaries, optional
-        Additional keyword arguments passed to scatter() and plot() for drawing
-        the components of the plot.
-    ax : matplotlib axis, optional
-        Plot into this axis, otherwise grab the current axis or make a new
-        one if not existing.
-
-    Returns
-    -------
-    ax: matplotlib axes
-        Axes with the regression plot.
-
-    See Also
-    --------
-    regplot : Plot a simple linear regression model.
-    jointplot (with kind="resid"): Draw a residplot with univariate
-                                   marginal distrbutions.
-
-    """
-    plotter = _RegressionPlotter(x, y, data, ci=None,
-                                 order=order, robust=robust,
-                                 x_partial=x_partial, y_partial=y_partial,
-                                 dropna=dropna, color=color, label=label)
-
-    if ax is None:
-        ax = plt.gca()
-
-    # Calculate the residual from a linear regression
-    _, yhat, _ = plotter.fit_regression(grid=plotter.x)
-    plotter.y = plotter.y - yhat
-
-    # Set the regression option on the plotter
-    if lowess:
-        plotter.lowess = True
-    else:
-        plotter.fit_reg = False
-
-    # Plot a horizontal line at 0
-    ax.axhline(0, ls=":", c=".2")
-
-    # Draw the scatterplot
-    scatter_kws = {} if scatter_kws is None else scatter_kws
-    line_kws = {} if line_kws is None else line_kws
-    plotter.plot(ax, scatter_kws, line_kws)
-    return ax
-
-
-def coefplot(formula, data, groupby=None, intercept=False, ci=95,
-             palette="husl"):
-    """Plot the coefficients from a linear model.
-
-    Parameters
-    ----------
-    formula : string
-        patsy formula for ols model
-    data : dataframe
-        data for the plot; formula terms must appear in columns
-    groupby : grouping object, optional
-        object to group data with to fit conditional models
-    intercept : bool, optional
-        if False, strips the intercept term before plotting
-    ci : float, optional
-        size of confidence intervals
-    palette : seaborn color palette, optional
-        palette for the horizonal plots
-
-    """
-    if not _has_statsmodels:
-        raise ImportError("The `coefplot` function requires statsmodels")
-    import statsmodels.formula.api as sf
-
-    alpha = 1 - ci / 100
-    if groupby is None:
-        coefs = sf.ols(formula, data).fit().params
-        cis = sf.ols(formula, data).fit().conf_int(alpha)
-    else:
-        grouped = data.groupby(groupby)
-        coefs = grouped.apply(lambda d: sf.ols(formula, d).fit().params).T
-        cis = grouped.apply(lambda d: sf.ols(formula, d).fit().conf_int(alpha))
-
-    # Possibly ignore the intercept
-    if not intercept:
-        coefs = coefs.ix[1:]
-
-    n_terms = len(coefs)
-
-    # Plot seperately depending on groupby
-    w, h = mpl.rcParams["figure.figsize"]
-    hsize = lambda n: n * (h / 2)
-    wsize = lambda n: n * (w / (4 * (n / 5)))
-    if groupby is None:
-        colors = itertools.cycle(color_palette(palette, n_terms))
-        f, ax = plt.subplots(1, 1, figsize=(wsize(n_terms), hsize(1)))
-        for i, term in enumerate(coefs.index):
-            color = next(colors)
-            low, high = cis.ix[term]
-            ax.plot([i, i], [low, high], c=color,
-                    solid_capstyle="round", lw=2.5)
-            ax.plot(i, coefs.ix[term], "o", c=color, ms=8)
-        ax.set_xlim(-.5, n_terms - .5)
-        ax.axhline(0, ls="--", c="dimgray")
-        ax.set_xticks(range(n_terms))
-        ax.set_xticklabels(coefs.index)
-
-    else:
-        n_groups = len(coefs.columns)
-        f, axes = plt.subplots(n_terms, 1, sharex=True,
-                               figsize=(wsize(n_groups), hsize(n_terms)))
-        if n_terms == 1:
-            axes = [axes]
-        colors = itertools.cycle(color_palette(palette, n_groups))
-        for ax, term in zip(axes, coefs.index):
-            for i, group in enumerate(coefs.columns):
-                color = next(colors)
-                low, high = cis.ix[(group, term)]
-                ax.plot([i, i], [low, high], c=color,
-                        solid_capstyle="round", lw=2.5)
-                ax.plot(i, coefs.loc[term, group], "o", c=color, ms=8)
-            ax.set_xlim(-.5, n_groups - .5)
-            ax.axhline(0, ls="--", c="dimgray")
-            ax.set_title(term)
-        ax.set_xlabel(groupby)
-        ax.set_xticks(range(n_groups))
-        ax.set_xticklabels(coefs.columns)
-
-
-def interactplot(x1, x2, y, data=None, filled=False, cmap="RdBu_r",
-                 colorbar=True, levels=30, logistic=False,
-                 contour_kws=None, scatter_kws=None, ax=None, **kwargs):
-    """Visualize a continuous two-way interaction with a contour plot.
-
-    Parameters
-    ----------
-    x1, x2, y, strings or array-like
-        Either the two independent variables and the dependent variable,
-        or keys to extract them from `data`
-    data : DataFrame
-        Pandas DataFrame with the data in the columns.
-    filled : bool
-        Whether to plot with filled or unfilled contours
-    cmap : matplotlib colormap
-        Colormap to represent yhat in the countour plot.
-    colorbar : bool
-        Whether to draw the colorbar for interpreting the color values.
-    levels : int or sequence
-        Number or position of contour plot levels.
-    logistic : bool
-        Fit a logistic regression model instead of linear regression.
-    contour_kws : dictionary
-        Keyword arguments for contour[f]().
-    scatter_kws : dictionary
-        Keyword arguments for plot().
-    ax : matplotlib axis
-        Axis to draw plot in.
-
-    Returns
-    -------
-    ax : Matplotlib axis
-        Axis with the contour plot.
-
-    """
-    if not _has_statsmodels:
-        raise ImportError("The `interactplot` function requires statsmodels")
-    from statsmodels.regression.linear_model import OLS
-    from statsmodels.genmod.generalized_linear_model import GLM
-    from statsmodels.genmod.families import Binomial
-
-    # Handle the form of the data
-    if data is not None:
-        x1 = data[x1]
-        x2 = data[x2]
-        y = data[y]
-    if hasattr(x1, "name"):
-        xlabel = x1.name
-    else:
-        xlabel = None
-    if hasattr(x2, "name"):
-        ylabel = x2.name
-    else:
-        ylabel = None
-    if hasattr(y, "name"):
-        clabel = y.name
-    else:
-        clabel = None
-    x1 = np.asarray(x1)
-    x2 = np.asarray(x2)
-    y = np.asarray(y)
-
-    # Initialize the scatter keyword dictionary
-    if scatter_kws is None:
-        scatter_kws = {}
-    if not ("color" in scatter_kws or "c" in scatter_kws):
-        scatter_kws["color"] = "#222222"
-    if "alpha" not in scatter_kws:
-        scatter_kws["alpha"] = 0.75
-
-    # Intialize the contour keyword dictionary
-    if contour_kws is None:
-        contour_kws = {}
-
-    # Initialize the axis
-    if ax is None:
-        ax = plt.gca()
-
-    # Plot once to let matplotlib sort out the axis limits
-    ax.plot(x1, x2, "o", **scatter_kws)
-
-    # Find the plot limits
-    x1min, x1max = ax.get_xlim()
-    x2min, x2max = ax.get_ylim()
-
-    # Make the grid for the contour plot
-    x1_points = np.linspace(x1min, x1max, 100)
-    x2_points = np.linspace(x2min, x2max, 100)
-    xx1, xx2 = np.meshgrid(x1_points, x2_points)
-
-    # Fit the model with an interaction
-    X = np.c_[np.ones(x1.size), x1, x2, x1 * x2]
-    if logistic:
-        lm = GLM(y, X, family=Binomial()).fit()
-    else:
-        lm = OLS(y, X).fit()
-
-    # Evaluate the model on the grid
-    eval = np.vectorize(lambda x1_, x2_: lm.predict([1, x1_, x2_, x1_ * x2_]))
-    yhat = eval(xx1, xx2)
-
-    # Default color limits put the midpoint at mean(y)
-    y_bar = y.mean()
-    c_min = min(np.percentile(y, 2), yhat.min())
-    c_max = max(np.percentile(y, 98), yhat.max())
-    delta = max(c_max - y_bar, y_bar - c_min)
-    c_min, cmax = y_bar - delta, y_bar + delta
-    contour_kws.setdefault("vmin", c_min)
-    contour_kws.setdefault("vmax", c_max)
-
-    # Draw the contour plot
-    func_name = "contourf" if filled else "contour"
-    contour = getattr(ax, func_name)
-    c = contour(xx1, xx2, yhat, levels, cmap=cmap, **contour_kws)
-
-    # Draw the scatter again so it's visible
-    ax.plot(x1, x2, "o", **scatter_kws)
-
-    # Draw a colorbar, maybe
-    if colorbar:
-        bar = plt.colorbar(c)
-
-    # Label the axes
-    if xlabel is not None:
-        ax.set_xlabel(xlabel)
-    if ylabel is not None:
-        ax.set_ylabel(ylabel)
-    if clabel is not None and colorbar:
-        clabel = "P(%s)" % clabel if logistic else clabel
-        bar.set_label(clabel, labelpad=15, rotation=270)
-
-    return ax
-
-
-def corrplot(data, names=None, annot=True, sig_stars=True, sig_tail="both",
-             sig_corr=True, cmap=None, cmap_range=None, cbar=True,
-             diag_names=True, method=None, ax=None, **kwargs):
-    """Plot a correlation matrix with colormap and r values.
-
-    NOTE: This function is deprecated in favor of :func:`heatmap` and will
-    be removed in a forthcoming release.
-
-    Parameters
-    ----------
-    data : Dataframe or nobs x nvars array
-        Rectangular input data with variabes in the columns.
-    names : sequence of strings
-        Names to associate with variables if `data` is not a DataFrame.
-    annot : bool
-        Whether to annotate the upper triangle with correlation coefficients.
-    sig_stars : bool
-        If True, get significance with permutation test and denote with stars.
-    sig_tail : both | upper | lower
-        Direction for significance test. Also controls the default colorbar.
-    sig_corr : bool
-        If True, use FWE-corrected p values for the sig stars.
-    cmap : colormap
-        Colormap name as string or colormap object.
-    cmap_range : None, "full", (low, high)
-        Either truncate colormap at (-max(abs(r)), max(abs(r))), use the
-        full range (-1, 1), or specify (min, max) values for the colormap.
-    cbar : bool
-        If true, plot the colorbar legend.
-    method: None (pearson) | kendall | spearman
-        Correlation method to compute pairwise correlations. Methods other
-        than the default pearson correlation will not have a significance
-        computed.
-    ax : matplotlib axis
-        Axis to draw plot in.
-    kwargs : other keyword arguments
-        Passed to ax.matshow()
-
-    Returns
-    -------
-    ax : matplotlib axis
-        Axis object with plot.
-
-    """
-    warnings.warn(("The `corrplot` function has been deprecated in favor "
-                   "of `heatmap` and will be removed in a forthcoming "
-                   "release. Please update your code."))
-
-    if not isinstance(data, pd.DataFrame):
-        if names is None:
-            names = ["var_%d" % i for i in range(data.shape[1])]
-        data = pd.DataFrame(data, columns=names, dtype=np.float)
-
-    # Calculate the correlation matrix of the dataframe
-    if method is None:
-        corrmat = data.corr()
-    else:
-        corrmat = data.corr(method=method)
-
-    # Pandas will drop non-numeric columns; let's keep track of that operation
-    names = corrmat.columns
-    data = data[names]
-
-    # Get p values with a permutation test
-    if annot and sig_stars and method is None:
-        p_mat = algo.randomize_corrmat(data.values.T, sig_tail, sig_corr)
-    else:
-        p_mat = None
-
-    # Sort out the color range
-    if cmap_range is None:
-        triu = np.triu_indices(len(corrmat), 1)
-        vmax = min(1, np.max(np.abs(corrmat.values[triu])) * 1.15)
-        vmin = -vmax
-        if sig_tail == "both":
-            cmap_range = vmin, vmax
-        elif sig_tail == "upper":
-            cmap_range = 0, vmax
-        elif sig_tail == "lower":
-            cmap_range = vmin, 0
-    elif cmap_range == "full":
-        cmap_range = (-1, 1)
-
-    # Find a colormapping, somewhat intelligently
-    if cmap is None:
-        if min(cmap_range) >= 0:
-            cmap = "OrRd"
-        elif max(cmap_range) <= 0:
-            cmap = "PuBu_r"
-        else:
-            cmap = "coolwarm"
-    if cmap == "jet":
-        # Paternalism
-        raise ValueError("Never use the 'jet' colormap!")
-
-    # Plot using the more general symmatplot function
-    ax = symmatplot(corrmat, p_mat, names, cmap, cmap_range,
-                    cbar, annot, diag_names, ax, **kwargs)
-
-    return ax
-
-
-def symmatplot(mat, p_mat=None, names=None, cmap="Greys", cmap_range=None,
-               cbar=True, annot=True, diag_names=True, ax=None, **kwargs):
-    """Plot a symmetric matrix with colormap and statistic values.
-
-    NOTE: This function is deprecated in favor of :func:`heatmap` and will
-    be removed in a forthcoming release.
-
-    """
-    warnings.warn(("The `symmatplot` function has been deprecated in favor "
-                   "of `heatmap` and will be removed in a forthcoming "
-                   "release. Please update your code."))
-
-    if ax is None:
-        ax = plt.gca()
-
-    nvars = len(mat)
-    if isinstance(mat, pd.DataFrame):
-        plotmat = mat.values.copy()
-        mat = mat.values
-    else:
-        plotmat = mat.copy()
-    plotmat[np.triu_indices(nvars)] = np.nan
-
-    if cmap_range is None:
-        vmax = np.nanmax(plotmat) * 1.15
-        vmin = np.nanmin(plotmat) * 1.15
-    elif len(cmap_range) == 2:
-        vmin, vmax = cmap_range
-    else:
-        raise ValueError("cmap_range argument not understood")
-
-    mat_img = ax.matshow(plotmat, cmap=cmap, vmin=vmin, vmax=vmax, **kwargs)
-
-    if cbar:
-        plt.colorbar(mat_img, shrink=.75)
-
-    if p_mat is None:
-        p_mat = np.ones((nvars, nvars))
-
-    if annot:
-        for i, j in zip(*np.triu_indices(nvars, 1)):
-            val = mat[i, j]
-            stars = utils.sig_stars(p_mat[i, j])
-            ax.text(j, i, "\n%.2g\n%s" % (val, stars),
-                    fontdict=dict(ha="center", va="center"))
-    else:
-        fill = np.ones_like(plotmat)
-        fill[np.tril_indices_from(fill, -1)] = np.nan
-        ax.matshow(fill, cmap="Greys", vmin=0, vmax=0, zorder=2)
-
-    if names is None:
-        names = ["var%d" % i for i in range(nvars)]
-
-    if diag_names:
-        for i, name in enumerate(names):
-            ax.text(i, i, name, fontdict=dict(ha="center", va="center",
-                                              weight="bold", rotation=45))
-        ax.set_xticklabels(())
-        ax.set_yticklabels(())
-    else:
-        ax.xaxis.set_ticks_position("bottom")
-        xnames = names if annot else names[:-1]
-        ax.set_xticklabels(xnames, rotation=90)
-        ynames = names if annot else names[1:]
-        ax.set_yticklabels(ynames)
-
-    minor_ticks = np.linspace(-.5, nvars - 1.5, nvars)
-    ax.set_xticks(minor_ticks, True)
-    ax.set_yticks(minor_ticks, True)
-    major_ticks = np.linspace(0, nvars - 1, nvars)
-    xticks = major_ticks if annot else major_ticks[:-1]
-    ax.set_xticks(xticks)
-    yticks = major_ticks if annot else major_ticks[1:]
-    ax.set_yticks(yticks)
-    ax.grid(False, which="major")
-    ax.grid(True, which="minor", linestyle="-")
-
-    return ax
-
-
-def pairplot(data, hue=None, hue_order=None, palette=None,
-             vars=None, x_vars=None, y_vars=None,
-             kind="scatter", diag_kind="hist", markers=None,
-             size=2.5, aspect=1, dropna=True,
-             plot_kws=None, diag_kws=None, grid_kws=None):
-    """Plot pairwise relationships in a dataset.
-
-    By default, this function will create a grid of Axes such that each
-    variable in ``data`` will by shared in the y-axis across a single row and
-    in the x-axis across a single column. The diagonal Axes are treated
-    differently, drawing a plot to show the univariate distribution of the data
-    for the variable in that column.
-
-    It is also possible to show a subset of variables or plot different
-    variables on the rows and columns.
-
-    This is a high-level interface for :class:`PairGrid` that is intended to
-    make it easy to draw a few common styles. You should use :class`PairGrid`
-    directly if you need more flexibility.
-
-    Parameters
-    ----------
-    data : DataFrame
-        Tidy (long-form) dataframe where each column is a variable and
-        each row is an observation.
-    hue : string (variable name), optional
-        Variable in ``data`` to map plot aspects to different colors.
-    hue_order : list of strings
-        Order for the levels of the hue variable in the palette
-    palette : dict or seaborn color palette
-        Set of colors for mapping the ``hue`` variable. If a dict, keys
-        should be values  in the ``hue`` variable.
-    vars : list of variable names, optional
-        Variables within ``data`` to use, otherwise use every column with
-        a numeric datatype.
-    {x, y}_vars : lists of variable names, optional
-        Variables within ``data`` to use separately for the rows and
-        columns of the figure; i.e. to make a non-square plot.
-    kind : {'scatter', 'reg'}, optional
-        Kind of plot for the non-identity relationships.
-    diag_kind : {'hist', 'kde'}, optional
-        Kind of plot for the diagonal subplots.
-    markers : single matplotlib marker code or list, optional
-        Either the marker to use for all datapoints or a list of markers with
-        a length the same as the number of levels in the hue variable so that
-        differently colored points will also have different scatterplot
-        markers.
-    size : scalar, optional
-        Height (in inches) of each facet.
-    aspect : scalar, optional
-        Aspect * size gives the width (in inches) of each facet.
-    dropna : boolean, optional
-        Drop missing values from the data before plotting.
-    {plot, diag, grid}_kws : dicts, optional
-        Dictionaries of keyword arguments.
-
-    Returns
-    -------
-    grid : PairGrid
-        Returns the underlying ``PairGrid`` instance for further tweaking.
-
-    See Also
-    --------
-    PairGrid : Subplot grid for more flexible plotting of pairwise
-               relationships.
-
-    Examples
-    --------
-
-    Draw scatterplots for joint relationships and histograms for univariate
-    distributions:
-
-    .. plot::
-        :context: close-figs
-
-        >>> import seaborn as sns; sns.set(style="ticks", color_codes=True)
-        >>> iris = sns.load_dataset("iris")
-        >>> g = sns.pairplot(iris)
-
-    Show different levels of a categorical variable by the color of plot
-    elements:
-
-    .. plot::
-        :context: close-figs
-
-        >>> g = sns.pairplot(iris, hue="species")
-
-    Use a different color palette:
-
-    .. plot::
-        :context: close-figs
-
-        >>> g = sns.pairplot(iris, hue="species", palette="husl")
-
-    Use different markers for each level of the hue variable:
-
-    .. plot::
-        :context: close-figs
-
-        >>> g = sns.pairplot(iris, hue="species", markers=["o", "s", "D"])
-
-    Plot a subset of variables:
-
-    .. plot::
-        :context: close-figs
-
-        >>> g = sns.pairplot(iris, vars=["sepal_width", "sepal_length"])
-
-    Draw larger plots:
-
-    .. plot::
-        :context: close-figs
-
-        >>> g = sns.pairplot(iris, size=3,
-        ...                  vars=["sepal_width", "sepal_length"])
-
-    Plot different variables in the rows and columns:
-
-    .. plot::
-        :context: close-figs
-
-        >>> g = sns.pairplot(iris,
-        ...                  x_vars=["sepal_width", "sepal_length"],
-        ...                  y_vars=["petal_width", "petal_length"])
-
-    Use kernel density estimates for univariate plots:
-
-    .. plot::
-        :context: close-figs
-
-        >>> g = sns.pairplot(iris, diag_kind="kde")
-
-    Fit linear regression models to the scatter plots:
-
-    .. plot::
-        :context: close-figs
-
-        >>> g = sns.pairplot(iris, kind="reg")
-
-    Pass keyword arguments down to the underlying functions (it may be easier
-    to use :class:`PairGrid` directly):
-
-    .. plot::
-        :context: close-figs
-
-        >>> g = sns.pairplot(iris, diag_kind="kde", markers="+",
-        ...                  plot_kws=dict(s=50, edgecolor="b", linewidth=1),
-        ...                  diag_kws=dict(shade=True))
-
-    """
-    if plot_kws is None:
-        plot_kws = {}
-    if diag_kws is None:
-        diag_kws = {}
-    if grid_kws is None:
-        grid_kws = {}
-
-    # Set up the PairGrid
-    diag_sharey = diag_kind == "hist"
-    grid = PairGrid(data, vars=vars, x_vars=x_vars, y_vars=y_vars, hue=hue,
-                    hue_order=hue_order, palette=palette,
-                    diag_sharey=diag_sharey,
-                    size=size, aspect=aspect, dropna=dropna, **grid_kws)
-
-    # Add the markers here as PairGrid has figured out how many levels of the
-    # hue variable are needed and we don't want to duplicate that process
-    if markers is not None:
-        if grid.hue_names is None:
-            n_markers = 1
-        else:
-            n_markers = len(grid.hue_names)
-        if not isinstance(markers, list):
-            markers = [markers] * n_markers
-        if len(markers) != n_markers:
-            raise ValueError(("markers must be a singeton or a list of markers"
-                              " for each level of the hue variable"))
-        grid.hue_kws = {"marker": markers}
-
-    # Maybe plot on the diagonal
-    if grid.square_grid:
-        if diag_kind == "hist":
-            grid.map_diag(plt.hist, **diag_kws)
-        elif diag_kind == "kde":
-            diag_kws["legend"] = False
-            grid.map_diag(kdeplot, **diag_kws)
-
-    # Maybe plot on the off-diagonals
-    if grid.square_grid and diag_kind is not None:
-        plotter = grid.map_offdiag
-    else:
-        plotter = grid.map
-
-    if kind == "scatter":
-        plot_kws.setdefault("edgecolor", "white")
-        plotter(plt.scatter, **plot_kws)
-    elif kind == "reg":
-        plotter(regplot, **plot_kws)
-
-    # Add a legend
-    if hue is not None:
-        grid.add_legend()
-
-    return grid
+msg = (
+    "The `linearmodels` module has been renamed `regression`."
+)
+warnings.warn(msg)
+from .regression import *
diff --git a/seaborn/matrix.py b/seaborn/matrix.py
index 5ff9ff9..45af3b3 100644
--- a/seaborn/matrix.py
+++ b/seaborn/matrix.py
@@ -1,4 +1,5 @@
 """Functions to visualize matrices of data."""
+from __future__ import division
 import itertools
 
 import matplotlib as mpl
@@ -10,9 +11,12 @@ import pandas as pd
 from scipy.spatial import distance
 from scipy.cluster import hierarchy
 
+from . import cm
 from .axisgrid import Grid
-from .palettes import cubehelix_palette
-from .utils import despine, axis_ticklabels_overlap, relative_luminance
+from .utils import (despine, axis_ticklabels_overlap, relative_luminance,
+                    to_utf8)
+
+from .external.six import string_types
 
 
 __all__ = ["heatmap", "clustermap"]
@@ -21,7 +25,7 @@ __all__ = ["heatmap", "clustermap"]
 def _index_to_label(index):
     """Convert a pandas index or multiindex to an axis label."""
     if isinstance(index, pd.MultiIndex):
-        return "-".join(map(str, index.names))
+        return "-".join(map(to_utf8, index.names))
     else:
         return index.name
 
@@ -29,7 +33,7 @@ def _index_to_label(index):
 def _index_to_ticklabels(index):
     """Convert a pandas index or multiindex into ticklabels."""
     if isinstance(index, pd.MultiIndex):
-        return ["-".join(map(str, i)) for i in index.values]
+        return ["-".join(map(to_utf8, i)) for i in index.values]
     else:
         return index.values
 
@@ -109,16 +113,11 @@ class _HeatMapper(object):
         # Validate the mask and convet to DataFrame
         mask = _matrix_mask(data, mask)
 
-        # Reverse the rows so the plot looks like the matrix
-        plot_data = plot_data[::-1]
-        data = data.iloc[::-1]
-        mask = mask.iloc[::-1]
-
         plot_data = np.ma.masked_where(np.asarray(mask), plot_data)
 
         # Get good names for the rows and columns
         xtickevery = 1
-        if isinstance(xticklabels, int) and xticklabels > 1:
+        if isinstance(xticklabels, int):
             xtickevery = xticklabels
             xticklabels = _index_to_ticklabels(data.columns)
         elif xticklabels is True:
@@ -127,34 +126,36 @@ class _HeatMapper(object):
             xticklabels = []
 
         ytickevery = 1
-        if isinstance(yticklabels, int) and yticklabels > 1:
+        if isinstance(yticklabels, int):
             ytickevery = yticklabels
             yticklabels = _index_to_ticklabels(data.index)
         elif yticklabels is True:
             yticklabels = _index_to_ticklabels(data.index)
         elif yticklabels is False:
             yticklabels = []
-        else:
-            yticklabels = yticklabels[::-1]
 
         # Get the positions and used label for the ticks
         nx, ny = data.T.shape
 
-        if xticklabels == []:
+        if not len(xticklabels):
             self.xticks = []
             self.xticklabels = []
+        elif isinstance(xticklabels, string_types) and xticklabels == "auto":
+            self.xticks = "auto"
+            self.xticklabels = _index_to_ticklabels(data.columns)
         else:
-            xstart, xend, xstep = 0, nx, xtickevery
-            self.xticks = np.arange(xstart, xend, xstep) + .5
-            self.xticklabels = xticklabels[xstart:xend:xstep]
+            self.xticks, self.xticklabels = self._skip_ticks(xticklabels,
+                                                             xtickevery)
 
-        if yticklabels == []:
+        if not len(yticklabels):
             self.yticks = []
             self.yticklabels = []
+        elif isinstance(yticklabels, string_types) and yticklabels == "auto":
+            self.yticks = "auto"
+            self.yticklabels = _index_to_ticklabels(data.index)
         else:
-            ystart, yend, ystep = (ny - 1) % ytickevery, ny, ytickevery
-            self.yticks = np.arange(ystart, yend, ystep) + .5
-            self.yticklabels = yticklabels[ystart:yend:ystep]
+            self.yticks, self.yticklabels = self._skip_ticks(yticklabels,
+                                                             ytickevery)
 
         # Get good names for the axis labels
         xlabel = _index_to_label(data.columns)
@@ -177,9 +178,9 @@ class _HeatMapper(object):
                 annot_data = None
         else:
             try:
-                annot_data = annot.values[::-1]
+                annot_data = annot.values
             except AttributeError:
-                annot_data = annot[::-1]
+                annot_data = annot
             if annot.shape != plot_data.shape:
                 raise ValueError('Data supplied to "annot" must be the same '
                                  'shape as the data to plot.')
@@ -206,39 +207,34 @@ class _HeatMapper(object):
             vmin = np.percentile(calc_data, 2) if robust else calc_data.min()
         if vmax is None:
             vmax = np.percentile(calc_data, 98) if robust else calc_data.max()
-
-        # Simple heuristics for whether these data should  have a divergent map
-        divergent = ((vmin < 0) and (vmax > 0)) or center is not None
-
-        # Now set center to 0 so math below makes sense
-        if center is None:
-            center = 0
-
-        # A divergent map should be symmetric around the center value
-        if divergent:
-            vlim = max(abs(vmin - center), abs(vmax - center))
-            vmin, vmax = -vlim, vlim
-        self.divergent = divergent
-
-        # Now add in the centering value and set the limits
-        vmin += center
-        vmax += center
-        self.vmin = vmin
-        self.vmax = vmax
+        self.vmin, self.vmax = vmin, vmax
 
         # Choose default colormaps if not provided
         if cmap is None:
-            if divergent:
-                self.cmap = "RdBu_r"
+            if center is None:
+                self.cmap = cm.rocket
             else:
-                self.cmap = cubehelix_palette(light=.95, as_cmap=True)
+                self.cmap = cm.icefire
+        elif isinstance(cmap, string_types):
+            self.cmap = mpl.cm.get_cmap(cmap)
+        elif isinstance(cmap, list):
+            self.cmap = mpl.colors.ListedColormap(cmap)
         else:
             self.cmap = cmap
 
+        # Recenter a divergent colormap
+        if center is not None:
+            vrange = max(vmax - center, center - vmin)
+            normlize = mpl.colors.Normalize(center - vrange, center + vrange)
+            cmin, cmax = normlize([vmin, vmax])
+            cc = np.linspace(cmin, cmax, 256)
+            self.cmap = mpl.colors.ListedColormap(self.cmap(cc))
+
     def _annotate_heatmap(self, ax, mesh):
         """Add textual labels with the value in each cell."""
         mesh.update_scalarmappable()
-        xpos, ypos = np.meshgrid(ax.get_xticks(), ax.get_yticks())
+        height, width = self.annot_data.shape
+        xpos, ypos = np.meshgrid(np.arange(width) + .5, np.arange(height) + .5)
         for x, y, m, color, val in zip(xpos.flat, ypos.flat,
                                        mesh.get_array(), mesh.get_facecolors(),
                                        self.annot_data.flat):
@@ -250,6 +246,35 @@ class _HeatMapper(object):
                 text_kwargs.update(self.annot_kws)
                 ax.text(x, y, annotation, **text_kwargs)
 
+    def _skip_ticks(self, labels, tickevery):
+        """Return ticks and labels at evenly spaced intervals."""
+        n = len(labels)
+        if tickevery == 0:
+            ticks, labels = [], []
+        elif tickevery == 1:
+            ticks, labels = np.arange(n) + .5, labels
+        else:
+            start, end, step = 0, n, tickevery
+            ticks = np.arange(start, end, step) + .5
+            labels = labels[start:end:step]
+        return ticks, labels
+
+    def _auto_ticks(self, ax, labels, axis):
+        """Determine ticks and ticklabels that minimize overlap."""
+        transform = ax.figure.dpi_scale_trans.inverted()
+        bbox = ax.get_window_extent().transformed(transform)
+        size = [bbox.width, bbox.height][axis]
+        axis = [ax.xaxis, ax.yaxis][axis]
+        tick, = axis.set_ticks([0])
+        fontsize = tick.label.get_size()
+        max_ticks = int(size // (fontsize / 72))
+        if max_ticks < 1:
+            return [], []
+        tick_every = len(labels) // max_ticks + 1
+        tick_every = 1 if tick_every == 0 else tick_every
+        ticks, labels = self._skip_ticks(labels, tick_every)
+        return ticks, labels
+
     def plot(self, ax, cax, kws):
         """Draw the heatmap on the provided Axes."""
         # Remove all the Axes spines
@@ -262,10 +287,29 @@ class _HeatMapper(object):
         # Set the axis limits
         ax.set(xlim=(0, self.data.shape[1]), ylim=(0, self.data.shape[0]))
 
+        # Possibly add a colorbar
+        if self.cbar:
+            cb = ax.figure.colorbar(mesh, cax, ax, **self.cbar_kws)
+            cb.outline.set_linewidth(0)
+            # If rasterized is passed to pcolormesh, also rasterize the
+            # colorbar to avoid white lines on the PDF rendering
+            if kws.get('rasterized', False):
+                cb.solids.set_rasterized(True)
+
         # Add row and column labels
-        ax.set(xticks=self.xticks, yticks=self.yticks)
-        xtl = ax.set_xticklabels(self.xticklabels)
-        ytl = ax.set_yticklabels(self.yticklabels, rotation="vertical")
+        if isinstance(self.xticks, string_types) and self.xticks == "auto":
+            xticks, xticklabels = self._auto_ticks(ax, self.xticklabels, 0)
+        else:
+            xticks, xticklabels = self.xticks, self.xticklabels
+
+        if isinstance(self.yticks, string_types) and self.yticks == "auto":
+            yticks, yticklabels = self._auto_ticks(ax, self.yticklabels, 1)
+        else:
+            yticks, yticklabels = self.yticks, self.yticklabels
+
+        ax.set(xticks=xticks, yticks=yticks)
+        xtl = ax.set_xticklabels(xticklabels)
+        ytl = ax.set_yticklabels(yticklabels, rotation="vertical")
 
         # Possibly rotate them if they overlap
         plt.draw()
@@ -281,29 +325,18 @@ class _HeatMapper(object):
         if self.annot:
             self._annotate_heatmap(ax, mesh)
 
-        # Possibly add a colorbar
-        if self.cbar:
-            cb = ax.figure.colorbar(mesh, cax, ax, **self.cbar_kws)
-            cb.outline.set_linewidth(0)
-            # If rasterized is passed to pcolormesh, also rasterize the
-            # colorbar to avoid white lines on the PDF rendering
-            if kws.get('rasterized', False):
-                cb.solids.set_rasterized(True)
+        # Invert the y axis to show the plot in matrix form
+        ax.invert_yaxis()
 
 
 def heatmap(data, vmin=None, vmax=None, cmap=None, center=None, robust=False,
             annot=None, fmt=".2g", annot_kws=None,
             linewidths=0, linecolor="white",
             cbar=True, cbar_kws=None, cbar_ax=None,
-            square=False, ax=None, xticklabels=True, yticklabels=True,
-            mask=None,
-            **kwargs):
+            square=False, xticklabels="auto", yticklabels="auto",
+            mask=None, ax=None, **kwargs):
     """Plot rectangular data as a color-encoded matrix.
 
-    This function tries to infer a good colormap to use from the data, but
-    this is not guaranteed to work, so take care to make sure the kind of
-    colormap (sequential or diverging) and its limits are appropriate.
-
     This is an Axes-level function and will draw the heatmap into the
     currently-active Axes if none is provided to the ``ax`` argument.  Part of
     this Axes space will be taken and used to plot a colormap, unless ``cbar``
@@ -317,15 +350,14 @@ def heatmap(data, vmin=None, vmax=None, cmap=None, center=None, robust=False,
         columns and rows.
     vmin, vmax : floats, optional
         Values to anchor the colormap, otherwise they are inferred from the
-        data and other keyword arguments. When a diverging dataset is inferred,
-        one of these values may be ignored.
-    cmap : matplotlib colormap name or object, optional
-        The mapping from data values to color space. If not provided, this
-        will be either a cubehelix map (if the function infers a sequential
-        dataset) or ``RdBu_r`` (if the function infers a diverging dataset).
+        data and other keyword arguments.
+    cmap : matplotlib colormap name or object, or list of colors, optional
+        The mapping from data values to color space. If not provided, the
+        default will depend on whether ``center`` is set.
     center : float, optional
-        The value at which to center the colormap. Passing this value implies
-        use of a diverging colormap.
+        The value at which to center the colormap when plotting divergant data.
+        Using this parameter will change the default ``cmap`` if none is
+        specified.
     robust : bool, optional
         If True and ``vmin`` or ``vmax`` are absent, the colormap range is
         computed with robust quantiles instead of the extreme values.
@@ -351,22 +383,17 @@ def heatmap(data, vmin=None, vmax=None, cmap=None, center=None, robust=False,
     square : boolean, optional
         If True, set the Axes aspect to "equal" so each cell will be
         square-shaped.
-    ax : matplotlib Axes, optional
-        Axes in which to draw the plot, otherwise use the currently-active
-        Axes.
-    xticklabels : list-like, int, or bool, optional
+    xticklabels, yticklabels : "auto", bool, list-like, or int, optional
         If True, plot the column names of the dataframe. If False, don't plot
         the column names. If list-like, plot these alternate labels as the
         xticklabels. If an integer, use the column names but plot only every
-        n label.
-    yticklabels : list-like, int, or bool, optional
-        If True, plot the row names of the dataframe. If False, don't plot
-        the row names. If list-like, plot these alternate labels as the
-        yticklabels. If an integer, use the index names but plot only every
-        n label.
+        n label. If "auto", try to densely plot non-overlapping labels.
     mask : boolean array or DataFrame, optional
         If passed, data will not be shown in cells where ``mask`` is True.
         Cells with missing values are automatically masked.
+    ax : matplotlib Axes, optional
+        Axes in which to draw the plot, otherwise use the currently-active
+        Axes.
     kwargs : other keyword arguments
         All other keyword arguments are passed to ``ax.pcolormesh``.
 
@@ -375,6 +402,11 @@ def heatmap(data, vmin=None, vmax=None, cmap=None, center=None, robust=False,
     ax : matplotlib Axes
         Axes object with the heatmap.
 
+    See also
+    --------
+    clustermap : Plot a matrix using hierachical clustering to arrange the
+                 rows and columns.
+
     Examples
     --------
 
@@ -395,13 +427,13 @@ def heatmap(data, vmin=None, vmax=None, cmap=None, center=None, robust=False,
 
         >>> ax = sns.heatmap(uniform_data, vmin=0, vmax=1)
 
-    Plot a heatmap for data centered on 0:
+    Plot a heatmap for data centered on 0 with a diverging colormap:
 
     .. plot::
         :context: close-figs
 
         >>> normal_data = np.random.randn(10, 12)
-        >>> ax = sns.heatmap(normal_data)
+        >>> ax = sns.heatmap(normal_data, center=0)
 
     Plot a dataframe with meaningful row and column labels:
 
@@ -567,10 +599,8 @@ class _DendrogramPlotter(object):
         if np.product(self.shape) >= 10000:
             UserWarning('This will be slow... (gentle suggestion: '
                         '"pip install fastcluster")')
-
-        pairwise_dists = distance.pdist(self.array, metric=self.metric)
-        linkage = hierarchy.linkage(pairwise_dists, method=self.method)
-        del pairwise_dists
+        linkage = hierarchy.linkage(self.array, method=self.method,
+                                    metric=self.metric)
         return linkage
 
     def _calculate_linkage_fastcluster(self):
@@ -586,9 +616,8 @@ class _DendrogramPlotter(object):
                                               method=self.method,
                                               metric=self.metric)
         else:
-            pairwise_dists = distance.pdist(self.array, metric=self.metric)
-            linkage = fastcluster.linkage(pairwise_dists, method=self.method)
-            del pairwise_dists
+            linkage = fastcluster.linkage(self.array, method=self.method,
+                                          metric=self.metric)
             return linkage
 
     @property
@@ -759,10 +788,10 @@ class ClusterGrid(Grid):
                                     width_ratios=width_ratios,
                                     height_ratios=height_ratios)
 
-        self.ax_row_dendrogram = self.fig.add_subplot(self.gs[nrows - 1, 0:2],
-                                                      axisbg="white")
-        self.ax_col_dendrogram = self.fig.add_subplot(self.gs[0:2, ncols - 1],
-                                                      axisbg="white")
+        self.ax_row_dendrogram = self.fig.add_subplot(self.gs[nrows - 1, 0:2])
+        self.ax_col_dendrogram = self.fig.add_subplot(self.gs[0:2, ncols - 1])
+        self.ax_row_dendrogram.set_axis_off()
+        self.ax_col_dendrogram.set_axis_off()
 
         self.ax_row_colors = None
         self.ax_col_colors = None
@@ -795,6 +824,7 @@ class ClusterGrid(Grid):
                     colors = colors.ix[data.columns]
 
                 # Replace na's with background color
+                # TODO We should set these to transparent instead
                 colors = colors.fillna('white')
 
                 # Extract color values and labels from frame/series
@@ -802,7 +832,10 @@ class ClusterGrid(Grid):
                     labels = list(colors.columns)
                     colors = colors.T.values
                 else:
-                    labels = [colors.name]
+                    if colors.name is None:
+                        labels = [""]
+                    else:
+                        labels = [colors.name]
                     colors = colors.values
 
             colors = _convert_colors(colors)
@@ -1017,8 +1050,11 @@ class ClusterGrid(Grid):
         kws.pop('center', None)
         kws.pop('vmin', None)
         kws.pop('vmax', None)
+        kws.pop('robust', None)
         kws.pop('xticklabels', None)
         kws.pop('yticklabels', None)
+
+        # Plot the row colors
         if self.row_colors is not None:
             matrix, cmap = self.color_list_to_matrix_and_cmap(
                 self.row_colors, yind, axis=0)
@@ -1038,6 +1074,7 @@ class ClusterGrid(Grid):
         else:
             despine(self.ax_row_colors, left=True, bottom=True)
 
+        # Plot the column colors
         if self.col_colors is not None:
             matrix, cmap = self.color_list_to_matrix_and_cmap(
                 self.col_colors, xind, axis=1)
@@ -1063,12 +1100,12 @@ class ClusterGrid(Grid):
         self.mask = self.mask.iloc[yind, xind]
 
         # Try to reorganize specified tick labels, if provided
-        xtl = kws.pop("xticklabels", True)
+        xtl = kws.pop("xticklabels", "auto")
         try:
             xtl = np.asarray(xtl)[xind]
         except (TypeError, IndexError):
             pass
-        ytl = kws.pop("yticklabels", True)
+        ytl = kws.pop("yticklabels", "auto")
         try:
             ytl = np.asarray(ytl)[yind]
         except (TypeError, IndexError):
@@ -1077,9 +1114,16 @@ class ClusterGrid(Grid):
         heatmap(self.data2d, ax=self.ax_heatmap, cbar_ax=self.cax,
                 cbar_kws=colorbar_kws, mask=self.mask,
                 xticklabels=xtl, yticklabels=ytl, **kws)
+
+        xtl_rot = self.ax_heatmap.get_xticklabels()[0].get_rotation()
+        ytl_rot = self.ax_heatmap.get_yticklabels()[0].get_rotation()
+
         self.ax_heatmap.yaxis.set_ticks_position('right')
         self.ax_heatmap.yaxis.set_label_position('right')
 
+        plt.setp(self.ax_heatmap.get_xticklabels(), rotation=xtl_rot)
+        plt.setp(self.ax_heatmap.get_yticklabels(), rotation=ytl_rot)
+
     def plot(self, metric, method, colorbar_kws, row_cluster, col_cluster,
              row_linkage, col_linkage, **kws):
         colorbar_kws = {} if colorbar_kws is None else colorbar_kws
@@ -1104,11 +1148,11 @@ def clustermap(data, pivot_kws=None, method='average', metric='euclidean',
                row_cluster=True, col_cluster=True,
                row_linkage=None, col_linkage=None,
                row_colors=None, col_colors=None, mask=None, **kwargs):
-    """Plot a hierarchically clustered heatmap of a pandas DataFrame
+    """Plot a matrix dataset as a hierarchically-clustered heatmap.
 
     Parameters
     ----------
-    data: pandas.DataFrame
+    data: 2D array-like
         Rectangular data for clustering. Cannot contain NAs.
     pivot_kws : dict, optional
         If `data` is a tidy dataframe, can provide keyword arguments for
@@ -1180,64 +1224,69 @@ def clustermap(data, pivot_kws=None, method='average', metric='euclidean',
     .. plot::
         :context: close-figs
 
-        >>> import seaborn as sns; sns.set()
-        >>> flights = sns.load_dataset("flights")
-        >>> flights = flights.pivot("month", "year", "passengers")
-        >>> g = sns.clustermap(flights)
+        >>> import seaborn as sns; sns.set(color_codes=True)
+        >>> iris = sns.load_dataset("iris")
+        >>> species = iris.pop("species")
+        >>> g = sns.clustermap(iris)
+
+    Use a different similarity metric:
 
-    Don't cluster one of the axes:
+    .. plot::
+        :context: close-figs
+
+        >>> g = sns.clustermap(iris, metric="correlation")
+
+    Use a different clustering method:
 
     .. plot::
         :context: close-figs
 
-        >>> g = sns.clustermap(flights, col_cluster=False)
+        >>> g = sns.clustermap(iris, method="single")
 
-    Use a different colormap and add lines to separate the cells:
+    Use a different colormap and ignore outliers in colormap limits:
 
     .. plot::
         :context: close-figs
 
-        >>> cmap = sns.cubehelix_palette(as_cmap=True, rot=-.3, light=1)
-        >>> g = sns.clustermap(flights, cmap=cmap, linewidths=.5)
+        >>> g = sns.clustermap(iris, cmap="mako", robust=True)
 
-    Use a different figure size:
+    Change the size of the figure:
 
     .. plot::
         :context: close-figs
 
-        >>> g = sns.clustermap(flights, cmap=cmap, figsize=(7, 5))
+        >>> g = sns.clustermap(iris, figsize=(6, 7))
 
-    Standardize the data across the columns:
+    Plot one of the axes in its original organization:
 
     .. plot::
         :context: close-figs
 
-        >>> g = sns.clustermap(flights, standard_scale=1)
+        >>> g = sns.clustermap(iris, col_cluster=False)
 
-    Normalize the data across the rows:
+    Add colored labels:
 
     .. plot::
         :context: close-figs
 
-        >>> g = sns.clustermap(flights, z_score=0)
+        >>> lut = dict(zip(species.unique(), "rbg"))
+        >>> row_colors = species.map(lut)
+        >>> g = sns.clustermap(iris, row_colors=row_colors)
 
-    Use a different clustering method:
+    Standardize the data within the columns:
 
     .. plot::
         :context: close-figs
 
-        >>> g = sns.clustermap(flights, method="single", metric="cosine")
+        >>> g = sns.clustermap(iris, standard_scale=1)
 
-    Add colored labels on one of the axes:
+    Normalize the data within the rows:
 
     .. plot::
         :context: close-figs
 
-        >>> season_colors = (sns.color_palette("BuPu", 3) +
-        ...                  sns.color_palette("RdPu", 3) +
-        ...                  sns.color_palette("YlGn", 3) +
-        ...                  sns.color_palette("OrRd", 3))
-        >>> g = sns.clustermap(flights, row_colors=season_colors)
+        >>> g = sns.clustermap(iris, z_score=0)
+
 
     """
     plotter = ClusterGrid(data, pivot_kws=pivot_kws, figsize=figsize,
diff --git a/seaborn/miscplot.py b/seaborn/miscplot.py
index 8eac76b..8b70040 100644
--- a/seaborn/miscplot.py
+++ b/seaborn/miscplot.py
@@ -4,7 +4,7 @@ import matplotlib as mpl
 import matplotlib.pyplot as plt
 
 
-__call__ = ["palplot", "puppyplot"]
+__all__ = ["palplot"]
 
 
 def palplot(pal, size=1):
@@ -27,23 +27,3 @@ def palplot(pal, size=1):
     ax.set_yticks([-.5, .5])
     ax.set_xticklabels([])
     ax.set_yticklabels([])
-
-
-def puppyplot(grown_up=False):
-    """Plot today's daily puppy. Only works in the IPython notebook."""
-    from .external.six.moves.urllib.request import urlopen
-    from IPython.display import HTML
-    try:
-        from bs4 import BeautifulSoup
-        url = "http://www.dailypuppy.com"
-        if grown_up:
-            url += "/dogs"
-        html_doc = urlopen(url)
-        soup = BeautifulSoup(html_doc)
-        puppy = soup.find("div", {"class": "daily_puppy"})
-        return HTML(str(puppy.img))
-    except ImportError:
-        html = ('<img  src="http://cdn-www.dailypuppy.com/dog-images/'
-                'decker-the-nova-scotia-duck-tolling-retriever_'
-                '72926_2013-11-04_w450.jpg" style="width:450px;"/>')
-        return HTML(html)
diff --git a/seaborn/palettes.py b/seaborn/palettes.py
index ac5edbe..c0965b1 100644
--- a/seaborn/palettes.py
+++ b/seaborn/palettes.py
@@ -59,7 +59,7 @@ class _ColorPalette(list):
 def color_palette(palette=None, n_colors=None, desat=None):
     """Return a list of colors defining a color palette.
 
-    Availible seaborn palette names:
+    Available seaborn palette names:
         deep, muted, bright, pastel, dark, colorblind
 
     Other options:
@@ -68,7 +68,7 @@ def color_palette(palette=None, n_colors=None, desat=None):
     Calling this function with ``palette=None`` will return the current
     matplotlib color cycle.
 
-    Matplotlib paletes can be specified as reversed palettes by appending
+    Matplotlib palettes can be specified as reversed palettes by appending
     "_r" to the name or as dark palettes by appending "_d" to the name.
     (These options are mutually exclusive, but the resulting list of colors
     can also be reversed).
@@ -172,12 +172,11 @@ def color_palette(palette=None, n_colors=None, desat=None):
             raise ValueError("No.")
         elif palette in SEABORN_PALETTES:
             palette = SEABORN_PALETTES[palette]
-        elif palette in dir(mpl.cm):
-            palette = mpl_palette(palette, n_colors)
-        elif palette[:-2] in dir(mpl.cm):
-            palette = mpl_palette(palette, n_colors)
         else:
-            raise ValueError("%s is not a valid palette name" % palette)
+            try:
+                palette = mpl_palette(palette, n_colors)
+            except ValueError:
+                raise ValueError("%s is not a valid palette name" % palette)
 
     if desat is not None:
         palette = [desaturate(c, desat) for c in palette]
@@ -394,18 +393,21 @@ def mpl_palette(name, n_colors=6):
         >>> sns.palplot(sns.mpl_palette("GnBu_d"))
 
     """
-    brewer_qual_pals = {"Accent": 8, "Dark2": 8, "Paired": 12,
-                        "Pastel1": 9, "Pastel2": 8,
-                        "Set1": 9, "Set2": 8, "Set3": 12}
+    mpl_qual_pals = {"Accent": 8, "Dark2": 8, "Paired": 12,
+                     "Pastel1": 9, "Pastel2": 8,
+                     "Set1": 9, "Set2": 8, "Set3": 12,
+                     "tab10": 10, "tab20": 20, "tab20b": 20, "tab20c": 20}
 
     if name.endswith("_d"):
         pal = ["#333333"]
         pal.extend(color_palette(name.replace("_d", "_r"), 2))
         cmap = blend_palette(pal, n_colors, as_cmap=True)
     else:
-        cmap = getattr(mpl.cm, name)
-    if name in brewer_qual_pals:
-        bins = np.linspace(0, 1, brewer_qual_pals[name])[:n_colors]
+        cmap = mpl.cm.get_cmap(name)
+        if cmap is None:
+            raise ValueError("{} is not a valid colormap".format(name))
+    if name in mpl_qual_pals:
+        bins = np.linspace(0, 1, mpl_qual_pals[name])[:n_colors]
     else:
         bins = np.linspace(0, 1, n_colors + 2)[1:-1]
     palette = list(map(tuple, cmap(bins)[:, :3]))
@@ -788,7 +790,7 @@ def cubehelix_palette(n_colors=6, start=0, rot=.4, gamma=1.0, hue=0.8,
     This produces a colormap with linearly-decreasing (or increasing)
     brightness. That means that information will be preserved if printed to
     black and white or viewed by someone who is colorblind.  "cubehelix" is
-    also availible as a matplotlib-based palette, but this function gives the
+    also available as a matplotlib-based palette, but this function gives the
     user more control over the look of the palette and has a different set of
     defaults.
 
diff --git a/seaborn/rcmod.py b/seaborn/rcmod.py
index 7c9bf2f..3eca091 100644
--- a/seaborn/rcmod.py
+++ b/seaborn/rcmod.py
@@ -53,7 +53,6 @@ _style_keys = (
     )
 
 _context_keys = (
-    "figure.figsize",
 
     "font.size",
     "axes.labelsize",
@@ -186,9 +185,9 @@ def axes_style(style=None, rc=None):
             "xtick.color": dark_gray,
             "ytick.color": dark_gray,
             "axes.axisbelow": True,
-            "image.cmap": "Greys",
+            "image.cmap": "rocket",
             "font.family": ["sans-serif"],
-            "font.sans-serif": ["Arial", "Liberation Sans",
+            "font.sans-serif": ["Arial", "DejaVu Sans", "Liberation Sans",
                                 "Bitstream Vera Sans", "sans-serif"],
             "grid.linestyle": "-",
             "lines.solid_capstyle": "round",
@@ -348,7 +347,6 @@ def plotting_context(context=None, font_scale=1, rc=None):
         # Set up dictionary of default parameters
         base_context = {
 
-            "figure.figsize": np.array([8, 5.5]),
             "font.size": 12,
             "axes.labelsize": 11,
             "axes.titlesize": 12,
@@ -369,6 +367,7 @@ def plotting_context(context=None, font_scale=1, rc=None):
 
             "xtick.major.pad": 7,
             "ytick.major.pad": 7,
+
             }
 
         # Scale all the parameters by the same factor depending on the context
diff --git a/seaborn/linearmodels.py b/seaborn/regression.py
similarity index 75%
copy from seaborn/linearmodels.py
copy to seaborn/regression.py
index 2c90617..55530c1 100644
--- a/seaborn/linearmodels.py
+++ b/seaborn/regression.py
@@ -24,13 +24,10 @@ from .external.six.moves import range
 from . import utils
 from . import algorithms as algo
 from .palettes import color_palette
-from .axisgrid import FacetGrid, PairGrid, _facet_docs
-from .distributions import kdeplot
+from .axisgrid import FacetGrid, _facet_docs
 
 
-__all__ = ["lmplot", "regplot", "residplot",
-           "coefplot", "interactplot",
-           "pairplot"]
+__all__ = ["lmplot", "regplot", "residplot"]
 
 
 class _LinearPlotter(object):
@@ -166,11 +163,15 @@ class _RegressionPlotter(_LinearPlotter):
                 cis.append(None)
             else:
                 units = None
-                if self.units is not None:
-                    units = self.units[x == val]
-                boots = algo.bootstrap(_y, func=self.x_estimator,
-                                       n_boot=self.n_boot, units=units)
-                _ci = utils.ci(boots, self.x_ci)
+                if self.x_ci == "sd":
+                    sd = np.std(_y)
+                    _ci = est - sd, est + sd
+                else:
+                    if self.units is not None:
+                        units = self.units[x == val]
+                    boots = algo.bootstrap(_y, func=self.x_estimator,
+                                           n_boot=self.n_boot, units=units)
+                    _ci = utils.ci(boots, self.x_ci)
                 cis.append(_ci)
 
         return vals, points, cis
@@ -246,7 +247,16 @@ class _RegressionPlotter(_LinearPlotter):
         """More general regression function using statsmodels objects."""
         X, y = np.c_[np.ones(len(self.x)), self.x], self.y
         grid = np.c_[np.ones(len(grid)), grid]
-        reg_func = lambda _x, _y: model(_y, _x, **kwargs).fit().predict(grid)
+        import statsmodels.genmod.generalized_linear_model as glm
+
+        def reg_func(_x, _y):
+            try:
+                yhat = model(_y, _x, **kwargs).fit().predict(grid)
+            except glm.PerfectSeparationError:
+                yhat = np.empty(len(grid))
+                yhat.fill(np.nan)
+            return yhat
+
         yhat = reg_func(X, y)
         if self.ci is None:
             return yhat, None
@@ -415,7 +425,7 @@ _regression_docs = dict(
     x_estimator : callable that maps vector -> scalar, optional
         Apply this function to each unique value of ``x`` and plot the
         resulting estimate. This is useful when ``x`` is a discrete variable.
-        If ``x_ci`` is not ``None``, this estimate will be bootstrapped and a
+        If ``x_ci`` is given, this estimate will be bootstrapped and a
         confidence interval will be drawn.\
     """),
     x_bins=dedent("""\
@@ -429,10 +439,11 @@ _regression_docs = dict(
         ``x_estimator`` is ``numpy.mean``.\
     """),
     x_ci=dedent("""\
-    x_ci : "ci", int in [0, 100] or None, optional
+    x_ci : "ci", "sd", int in [0, 100] or None, optional
         Size of the confidence interval used when plotting a central tendency
-        for discrete values of ``x``. If "ci", defer to the value of the``ci``
-        parameter.\
+        for discrete values of ``x``. If ``"ci"``, defer to the value of the
+        ``ci`` parameter. If ``"sd"``, skip bootstrappig and show the standard
+        deviation of the observations in each bin.\
     """),
     scatter=dedent("""\
     scatter : bool, optional
@@ -833,7 +844,6 @@ regplot.__doc__ = dedent("""\
     pairplot : Combine :func:`regplot` and :class:`PairGrid` (when used with
                ``kind="reg"``).
     residplot : Plot the residuals of a linear regression model.
-    interactplot : Plot a two-way interaction between continuous variables
 
     Notes
     -----
@@ -1050,6 +1060,11 @@ def coefplot(formula, data, groupby=None, intercept=False, ci=95,
         palette for the horizonal plots
 
     """
+    msg = (
+        "The `coefplot` function has been deprecated and will be removed "
+        "in a future version."
+    )
+    warnings.warn(msg, UserWarning)
     if not _has_statsmodels:
         raise ImportError("The `coefplot` function requires statsmodels")
     import statsmodels.formula.api as sf
@@ -1144,6 +1159,11 @@ def interactplot(x1, x2, y, data=None, filled=False, cmap="RdBu_r",
         Axis with the contour plot.
 
     """
+    msg = (
+        "The `interactplot` function has been deprecated and will be removed "
+        "in a future version."
+    )
+    warnings.warn(msg, UserWarning)
     if not _has_statsmodels:
         raise ImportError("The `interactplot` function requires statsmodels")
     from statsmodels.regression.linear_model import OLS
@@ -1241,390 +1261,3 @@ def interactplot(x1, x2, y, data=None, filled=False, cmap="RdBu_r",
         bar.set_label(clabel, labelpad=15, rotation=270)
 
     return ax
-
-
-def corrplot(data, names=None, annot=True, sig_stars=True, sig_tail="both",
-             sig_corr=True, cmap=None, cmap_range=None, cbar=True,
-             diag_names=True, method=None, ax=None, **kwargs):
-    """Plot a correlation matrix with colormap and r values.
-
-    NOTE: This function is deprecated in favor of :func:`heatmap` and will
-    be removed in a forthcoming release.
-
-    Parameters
-    ----------
-    data : Dataframe or nobs x nvars array
-        Rectangular input data with variabes in the columns.
-    names : sequence of strings
-        Names to associate with variables if `data` is not a DataFrame.
-    annot : bool
-        Whether to annotate the upper triangle with correlation coefficients.
-    sig_stars : bool
-        If True, get significance with permutation test and denote with stars.
-    sig_tail : both | upper | lower
-        Direction for significance test. Also controls the default colorbar.
-    sig_corr : bool
-        If True, use FWE-corrected p values for the sig stars.
-    cmap : colormap
-        Colormap name as string or colormap object.
-    cmap_range : None, "full", (low, high)
-        Either truncate colormap at (-max(abs(r)), max(abs(r))), use the
-        full range (-1, 1), or specify (min, max) values for the colormap.
-    cbar : bool
-        If true, plot the colorbar legend.
-    method: None (pearson) | kendall | spearman
-        Correlation method to compute pairwise correlations. Methods other
-        than the default pearson correlation will not have a significance
-        computed.
-    ax : matplotlib axis
-        Axis to draw plot in.
-    kwargs : other keyword arguments
-        Passed to ax.matshow()
-
-    Returns
-    -------
-    ax : matplotlib axis
-        Axis object with plot.
-
-    """
-    warnings.warn(("The `corrplot` function has been deprecated in favor "
-                   "of `heatmap` and will be removed in a forthcoming "
-                   "release. Please update your code."))
-
-    if not isinstance(data, pd.DataFrame):
-        if names is None:
-            names = ["var_%d" % i for i in range(data.shape[1])]
-        data = pd.DataFrame(data, columns=names, dtype=np.float)
-
-    # Calculate the correlation matrix of the dataframe
-    if method is None:
-        corrmat = data.corr()
-    else:
-        corrmat = data.corr(method=method)
-
-    # Pandas will drop non-numeric columns; let's keep track of that operation
-    names = corrmat.columns
-    data = data[names]
-
-    # Get p values with a permutation test
-    if annot and sig_stars and method is None:
-        p_mat = algo.randomize_corrmat(data.values.T, sig_tail, sig_corr)
-    else:
-        p_mat = None
-
-    # Sort out the color range
-    if cmap_range is None:
-        triu = np.triu_indices(len(corrmat), 1)
-        vmax = min(1, np.max(np.abs(corrmat.values[triu])) * 1.15)
-        vmin = -vmax
-        if sig_tail == "both":
-            cmap_range = vmin, vmax
-        elif sig_tail == "upper":
-            cmap_range = 0, vmax
-        elif sig_tail == "lower":
-            cmap_range = vmin, 0
-    elif cmap_range == "full":
-        cmap_range = (-1, 1)
-
-    # Find a colormapping, somewhat intelligently
-    if cmap is None:
-        if min(cmap_range) >= 0:
-            cmap = "OrRd"
-        elif max(cmap_range) <= 0:
-            cmap = "PuBu_r"
-        else:
-            cmap = "coolwarm"
-    if cmap == "jet":
-        # Paternalism
-        raise ValueError("Never use the 'jet' colormap!")
-
-    # Plot using the more general symmatplot function
-    ax = symmatplot(corrmat, p_mat, names, cmap, cmap_range,
-                    cbar, annot, diag_names, ax, **kwargs)
-
-    return ax
-
-
-def symmatplot(mat, p_mat=None, names=None, cmap="Greys", cmap_range=None,
-               cbar=True, annot=True, diag_names=True, ax=None, **kwargs):
-    """Plot a symmetric matrix with colormap and statistic values.
-
-    NOTE: This function is deprecated in favor of :func:`heatmap` and will
-    be removed in a forthcoming release.
-
-    """
-    warnings.warn(("The `symmatplot` function has been deprecated in favor "
-                   "of `heatmap` and will be removed in a forthcoming "
-                   "release. Please update your code."))
-
-    if ax is None:
-        ax = plt.gca()
-
-    nvars = len(mat)
-    if isinstance(mat, pd.DataFrame):
-        plotmat = mat.values.copy()
-        mat = mat.values
-    else:
-        plotmat = mat.copy()
-    plotmat[np.triu_indices(nvars)] = np.nan
-
-    if cmap_range is None:
-        vmax = np.nanmax(plotmat) * 1.15
-        vmin = np.nanmin(plotmat) * 1.15
-    elif len(cmap_range) == 2:
-        vmin, vmax = cmap_range
-    else:
-        raise ValueError("cmap_range argument not understood")
-
-    mat_img = ax.matshow(plotmat, cmap=cmap, vmin=vmin, vmax=vmax, **kwargs)
-
-    if cbar:
-        plt.colorbar(mat_img, shrink=.75)
-
-    if p_mat is None:
-        p_mat = np.ones((nvars, nvars))
-
-    if annot:
-        for i, j in zip(*np.triu_indices(nvars, 1)):
-            val = mat[i, j]
-            stars = utils.sig_stars(p_mat[i, j])
-            ax.text(j, i, "\n%.2g\n%s" % (val, stars),
-                    fontdict=dict(ha="center", va="center"))
-    else:
-        fill = np.ones_like(plotmat)
-        fill[np.tril_indices_from(fill, -1)] = np.nan
-        ax.matshow(fill, cmap="Greys", vmin=0, vmax=0, zorder=2)
-
-    if names is None:
-        names = ["var%d" % i for i in range(nvars)]
-
-    if diag_names:
-        for i, name in enumerate(names):
-            ax.text(i, i, name, fontdict=dict(ha="center", va="center",
-                                              weight="bold", rotation=45))
-        ax.set_xticklabels(())
-        ax.set_yticklabels(())
-    else:
-        ax.xaxis.set_ticks_position("bottom")
-        xnames = names if annot else names[:-1]
-        ax.set_xticklabels(xnames, rotation=90)
-        ynames = names if annot else names[1:]
-        ax.set_yticklabels(ynames)
-
-    minor_ticks = np.linspace(-.5, nvars - 1.5, nvars)
-    ax.set_xticks(minor_ticks, True)
-    ax.set_yticks(minor_ticks, True)
-    major_ticks = np.linspace(0, nvars - 1, nvars)
-    xticks = major_ticks if annot else major_ticks[:-1]
-    ax.set_xticks(xticks)
-    yticks = major_ticks if annot else major_ticks[1:]
-    ax.set_yticks(yticks)
-    ax.grid(False, which="major")
-    ax.grid(True, which="minor", linestyle="-")
-
-    return ax
-
-
-def pairplot(data, hue=None, hue_order=None, palette=None,
-             vars=None, x_vars=None, y_vars=None,
-             kind="scatter", diag_kind="hist", markers=None,
-             size=2.5, aspect=1, dropna=True,
-             plot_kws=None, diag_kws=None, grid_kws=None):
-    """Plot pairwise relationships in a dataset.
-
-    By default, this function will create a grid of Axes such that each
-    variable in ``data`` will by shared in the y-axis across a single row and
-    in the x-axis across a single column. The diagonal Axes are treated
-    differently, drawing a plot to show the univariate distribution of the data
-    for the variable in that column.
-
-    It is also possible to show a subset of variables or plot different
-    variables on the rows and columns.
-
-    This is a high-level interface for :class:`PairGrid` that is intended to
-    make it easy to draw a few common styles. You should use :class`PairGrid`
-    directly if you need more flexibility.
-
-    Parameters
-    ----------
-    data : DataFrame
-        Tidy (long-form) dataframe where each column is a variable and
-        each row is an observation.
-    hue : string (variable name), optional
-        Variable in ``data`` to map plot aspects to different colors.
-    hue_order : list of strings
-        Order for the levels of the hue variable in the palette
-    palette : dict or seaborn color palette
-        Set of colors for mapping the ``hue`` variable. If a dict, keys
-        should be values  in the ``hue`` variable.
-    vars : list of variable names, optional
-        Variables within ``data`` to use, otherwise use every column with
-        a numeric datatype.
-    {x, y}_vars : lists of variable names, optional
-        Variables within ``data`` to use separately for the rows and
-        columns of the figure; i.e. to make a non-square plot.
-    kind : {'scatter', 'reg'}, optional
-        Kind of plot for the non-identity relationships.
-    diag_kind : {'hist', 'kde'}, optional
-        Kind of plot for the diagonal subplots.
-    markers : single matplotlib marker code or list, optional
-        Either the marker to use for all datapoints or a list of markers with
-        a length the same as the number of levels in the hue variable so that
-        differently colored points will also have different scatterplot
-        markers.
-    size : scalar, optional
-        Height (in inches) of each facet.
-    aspect : scalar, optional
-        Aspect * size gives the width (in inches) of each facet.
-    dropna : boolean, optional
-        Drop missing values from the data before plotting.
-    {plot, diag, grid}_kws : dicts, optional
-        Dictionaries of keyword arguments.
-
-    Returns
-    -------
-    grid : PairGrid
-        Returns the underlying ``PairGrid`` instance for further tweaking.
-
-    See Also
-    --------
-    PairGrid : Subplot grid for more flexible plotting of pairwise
-               relationships.
-
-    Examples
-    --------
-
-    Draw scatterplots for joint relationships and histograms for univariate
-    distributions:
-
-    .. plot::
-        :context: close-figs
-
-        >>> import seaborn as sns; sns.set(style="ticks", color_codes=True)
-        >>> iris = sns.load_dataset("iris")
-        >>> g = sns.pairplot(iris)
-
-    Show different levels of a categorical variable by the color of plot
-    elements:
-
-    .. plot::
-        :context: close-figs
-
-        >>> g = sns.pairplot(iris, hue="species")
-
-    Use a different color palette:
-
-    .. plot::
-        :context: close-figs
-
-        >>> g = sns.pairplot(iris, hue="species", palette="husl")
-
-    Use different markers for each level of the hue variable:
-
-    .. plot::
-        :context: close-figs
-
-        >>> g = sns.pairplot(iris, hue="species", markers=["o", "s", "D"])
-
-    Plot a subset of variables:
-
-    .. plot::
-        :context: close-figs
-
-        >>> g = sns.pairplot(iris, vars=["sepal_width", "sepal_length"])
-
-    Draw larger plots:
-
-    .. plot::
-        :context: close-figs
-
-        >>> g = sns.pairplot(iris, size=3,
-        ...                  vars=["sepal_width", "sepal_length"])
-
-    Plot different variables in the rows and columns:
-
-    .. plot::
-        :context: close-figs
-
-        >>> g = sns.pairplot(iris,
-        ...                  x_vars=["sepal_width", "sepal_length"],
-        ...                  y_vars=["petal_width", "petal_length"])
-
-    Use kernel density estimates for univariate plots:
-
-    .. plot::
-        :context: close-figs
-
-        >>> g = sns.pairplot(iris, diag_kind="kde")
-
-    Fit linear regression models to the scatter plots:
-
-    .. plot::
-        :context: close-figs
-
-        >>> g = sns.pairplot(iris, kind="reg")
-
-    Pass keyword arguments down to the underlying functions (it may be easier
-    to use :class:`PairGrid` directly):
-
-    .. plot::
-        :context: close-figs
-
-        >>> g = sns.pairplot(iris, diag_kind="kde", markers="+",
-        ...                  plot_kws=dict(s=50, edgecolor="b", linewidth=1),
-        ...                  diag_kws=dict(shade=True))
-
-    """
-    if plot_kws is None:
-        plot_kws = {}
-    if diag_kws is None:
-        diag_kws = {}
-    if grid_kws is None:
-        grid_kws = {}
-
-    # Set up the PairGrid
-    diag_sharey = diag_kind == "hist"
-    grid = PairGrid(data, vars=vars, x_vars=x_vars, y_vars=y_vars, hue=hue,
-                    hue_order=hue_order, palette=palette,
-                    diag_sharey=diag_sharey,
-                    size=size, aspect=aspect, dropna=dropna, **grid_kws)
-
-    # Add the markers here as PairGrid has figured out how many levels of the
-    # hue variable are needed and we don't want to duplicate that process
-    if markers is not None:
-        if grid.hue_names is None:
-            n_markers = 1
-        else:
-            n_markers = len(grid.hue_names)
-        if not isinstance(markers, list):
-            markers = [markers] * n_markers
-        if len(markers) != n_markers:
-            raise ValueError(("markers must be a singeton or a list of markers"
-                              " for each level of the hue variable"))
-        grid.hue_kws = {"marker": markers}
-
-    # Maybe plot on the diagonal
-    if grid.square_grid:
-        if diag_kind == "hist":
-            grid.map_diag(plt.hist, **diag_kws)
-        elif diag_kind == "kde":
-            diag_kws["legend"] = False
-            grid.map_diag(kdeplot, **diag_kws)
-
-    # Maybe plot on the off-diagonals
-    if grid.square_grid and diag_kind is not None:
-        plotter = grid.map_offdiag
-    else:
-        plotter = grid.map
-
-    if kind == "scatter":
-        plot_kws.setdefault("edgecolor", "white")
-        plotter(plt.scatter, **plot_kws)
-    elif kind == "reg":
-        plotter(regplot, **plot_kws)
-
-    # Add a legend
-    if hue is not None:
-        grid.add_legend()
-
-    return grid
diff --git a/seaborn/tests/test_axisgrid.py b/seaborn/tests/test_axisgrid.py
index 3f1dc5d..1e39a64 100644
--- a/seaborn/tests/test_axisgrid.py
+++ b/seaborn/tests/test_axisgrid.py
@@ -10,15 +10,17 @@ from distutils.version import LooseVersion
 import nose.tools as nt
 import numpy.testing as npt
 from numpy.testing.decorators import skipif
-import pandas.util.testing as tm
+try:
+    import pandas.testing as tm
+except ImportError:
+    import pandas.util.testing as tm
 
 from . import PlotTestCase
 from .. import axisgrid as ag
 from .. import rcmod
 from ..palettes import color_palette
-from ..distributions import kdeplot
+from ..distributions import kdeplot, _freedman_diaconis_bins
 from ..categorical import pointplot
-from ..linearmodels import pairplot
 from ..utils import categorical_order
 
 rs = np.random.RandomState(0)
@@ -267,9 +269,10 @@ class TestFacetGrid(PlotTestCase):
 
     def test_subplot_kws(self):
 
-        g = ag.FacetGrid(self.df, subplot_kws=dict(axisbg="blue"))
+        g = ag.FacetGrid(self.df, despine=False,
+                         subplot_kws=dict(projection="polar"))
         for ax in g.axes.flat:
-            nt.assert_equal(ax.get_axis_bgcolor(), "blue")
+            nt.assert_true("PolarAxesSubplot" in str(type(ax)))
 
     @skipif(old_matplotlib)
     def test_gridspec_kws(self):
@@ -932,6 +935,26 @@ class TestPairGrid(PlotTestCase):
                 nt.assert_equal(ptch.fill, False)
 
     @skipif(old_matplotlib)
+    def test_map_diag_color(self):
+
+        color = "red"
+        rgb_color = mpl.colors.colorConverter.to_rgba(color)
+
+        g1 = ag.PairGrid(self.df)
+        g1.map_diag(plt.hist, color=color)
+
+        for ax in g1.diag_axes:
+            for patch in ax.patches:
+                nt.assert_equals(patch.get_facecolor(), rgb_color)
+
+        g2 = ag.PairGrid(self.df)
+        g2.map_diag(kdeplot, color='red')
+
+        for ax in g2.diag_axes:
+            for line in ax.lines:
+                nt.assert_equals(line.get_color(), color)
+
+    @skipif(old_matplotlib)
     def test_map_diag_and_offdiag(self):
 
         vars = ["x", "y", "z"]
@@ -1123,7 +1146,7 @@ class TestPairGrid(PlotTestCase):
     def test_pairplot(self):
 
         vars = ["x", "y", "z"]
-        g = pairplot(self.df)
+        g = ag.pairplot(self.df)
 
         for ax in g.diag_axes:
             nt.assert_equal(len(ax.patches), 10)
@@ -1152,7 +1175,7 @@ class TestPairGrid(PlotTestCase):
     def test_pairplot_reg(self):
 
         vars = ["x", "y", "z"]
-        g = pairplot(self.df, kind="reg")
+        g = ag.pairplot(self.df, kind="reg")
 
         for ax in g.diag_axes:
             nt.assert_equal(len(ax.patches), 10)
@@ -1187,7 +1210,7 @@ class TestPairGrid(PlotTestCase):
     def test_pairplot_kde(self):
 
         vars = ["x", "y", "z"]
-        g = pairplot(self.df, diag_kind="kde")
+        g = ag.pairplot(self.df, diag_kind="kde")
 
         for ax in g.diag_axes:
             nt.assert_equal(len(ax.lines), 1)
@@ -1217,12 +1240,12 @@ class TestPairGrid(PlotTestCase):
 
         vars = ["x", "y", "z"]
         markers = ["o", "x", "s", "d"]
-        g = pairplot(self.df, hue="a", vars=vars, markers=markers)
+        g = ag.pairplot(self.df, hue="a", vars=vars, markers=markers)
         nt.assert_equal(g.hue_kws["marker"], markers)
         plt.close("all")
 
         with nt.assert_raises(ValueError):
-            g = pairplot(self.df, hue="a", vars=vars, markers=markers[:-2])
+            g = ag.pairplot(self.df, hue="a", vars=vars, markers=markers[:-2])
 
 
 class TestJointGrid(PlotTestCase):
@@ -1253,6 +1276,11 @@ class TestJointGrid(PlotTestCase):
         npt.assert_array_equal(g.x, self.x)
         npt.assert_array_equal(g.y, self.y)
 
+    def test_margin_grid_from_dataframe_bad_variable(self):
+
+        with nt.assert_raises(ValueError):
+            g = ag.JointGrid("x", "bad_column", self.data)
+
     def test_margin_grid_axis_labels(self):
 
         g = ag.JointGrid("x", "y", self.data)
@@ -1359,3 +1387,108 @@ class TestJointGrid(PlotTestCase):
 
         nt.assert_equal(joint_bounds[2], marg_x_bounds[2])
         nt.assert_equal(joint_bounds[3], marg_y_bounds[3])
+
+
+class TestJointPlot(PlotTestCase):
+
+    rs = np.random.RandomState(sum(map(ord, "jointplot")))
+    x = rs.randn(100)
+    y = rs.randn(100)
+    data = pd.DataFrame(dict(x=x, y=y))
+
+    def test_scatter(self):
+
+        g = ag.jointplot("x", "y", self.data)
+        nt.assert_equal(len(g.ax_joint.collections), 1)
+
+        x, y = g.ax_joint.collections[0].get_offsets().T
+        npt.assert_array_equal(self.x, x)
+        npt.assert_array_equal(self.y, y)
+
+        x_bins = _freedman_diaconis_bins(self.x)
+        nt.assert_equal(len(g.ax_marg_x.patches), x_bins)
+
+        y_bins = _freedman_diaconis_bins(self.y)
+        nt.assert_equal(len(g.ax_marg_y.patches), y_bins)
+
+    def test_reg(self):
+
+        g = ag.jointplot("x", "y", self.data, kind="reg")
+        nt.assert_equal(len(g.ax_joint.collections), 2)
+
+        x, y = g.ax_joint.collections[0].get_offsets().T
+        npt.assert_array_equal(self.x, x)
+        npt.assert_array_equal(self.y, y)
+
+        x_bins = _freedman_diaconis_bins(self.x)
+        nt.assert_equal(len(g.ax_marg_x.patches), x_bins)
+
+        y_bins = _freedman_diaconis_bins(self.y)
+        nt.assert_equal(len(g.ax_marg_y.patches), y_bins)
+
+        nt.assert_equal(len(g.ax_joint.lines), 1)
+        nt.assert_equal(len(g.ax_marg_x.lines), 1)
+        nt.assert_equal(len(g.ax_marg_y.lines), 1)
+
+    def test_resid(self):
+
+        g = ag.jointplot("x", "y", self.data, kind="resid")
+        nt.assert_equal(len(g.ax_joint.collections), 1)
+        nt.assert_equal(len(g.ax_joint.lines), 1)
+        nt.assert_equal(len(g.ax_marg_x.lines), 0)
+        nt.assert_equal(len(g.ax_marg_y.lines), 1)
+
+    def test_hex(self):
+
+        g = ag.jointplot("x", "y", self.data, kind="hex")
+        nt.assert_equal(len(g.ax_joint.collections), 1)
+
+        x_bins = _freedman_diaconis_bins(self.x)
+        nt.assert_equal(len(g.ax_marg_x.patches), x_bins)
+
+        y_bins = _freedman_diaconis_bins(self.y)
+        nt.assert_equal(len(g.ax_marg_y.patches), y_bins)
+
+    def test_kde(self):
+
+        g = ag.jointplot("x", "y", self.data, kind="kde")
+
+        nt.assert_true(len(g.ax_joint.collections) > 0)
+        nt.assert_equal(len(g.ax_marg_x.collections), 1)
+        nt.assert_equal(len(g.ax_marg_y.collections), 1)
+
+        nt.assert_equal(len(g.ax_marg_x.lines), 1)
+        nt.assert_equal(len(g.ax_marg_y.lines), 1)
+
+    def test_color(self):
+
+        g = ag.jointplot("x", "y", self.data, color="purple")
+
+        purple = mpl.colors.colorConverter.to_rgb("purple")
+        scatter_color = g.ax_joint.collections[0].get_facecolor()[0, :3]
+        nt.assert_equal(tuple(scatter_color), purple)
+
+        hist_color = g.ax_marg_x.patches[0].get_facecolor()[:3]
+        nt.assert_equal(hist_color, purple)
+
+    def test_annotation(self):
+
+        g = ag.jointplot("x", "y", self.data)
+        nt.assert_equal(len(g.ax_joint.legend_.get_texts()), 1)
+
+        g = ag.jointplot("x", "y", self.data, stat_func=None)
+        nt.assert_is(g.ax_joint.legend_, None)
+
+    def test_hex_customise(self):
+
+        # test that default gridsize can be overridden
+        g = ag.jointplot("x", "y", self.data, kind="hex",
+                         joint_kws=dict(gridsize=5))
+        nt.assert_equal(len(g.ax_joint.collections), 1)
+        a = g.ax_joint.collections[0].get_array()
+        nt.assert_equal(28, a.shape[0])  # 28 hexagons expected for gridsize 5
+
+    def test_bad_kind(self):
+
+        with nt.assert_raises(ValueError):
+            ag.jointplot("x", "y", self.data, kind="not_a_kind")
diff --git a/seaborn/tests/test_categorical.py b/seaborn/tests/test_categorical.py
index be54281..5eb470e 100644
--- a/seaborn/tests/test_categorical.py
+++ b/seaborn/tests/test_categorical.py
@@ -17,18 +17,19 @@ from .. import palettes
 
 
 pandas_has_categoricals = LooseVersion(pd.__version__) >= "0.15"
+mpl_barplot_change = LooseVersion("2.0.1")
 
 
 class CategoricalFixture(PlotTestCase):
     """Test boxplot (also base class for things like violinplots)."""
     rs = np.random.RandomState(30)
     n_total = 60
-    x = rs.randn(n_total / 3, 3)
+    x = rs.randn(int(n_total / 3), 3)
     x_df = pd.DataFrame(x, columns=pd.Series(list("XYZ"), name="big"))
     y = pd.Series(rs.randn(n_total), name="y_data")
-    g = pd.Series(np.repeat(list("abc"), n_total / 3), name="small")
-    h = pd.Series(np.tile(list("mn"), n_total / 2), name="medium")
-    u = pd.Series(np.tile(list("jkh"), n_total / 3))
+    g = pd.Series(np.repeat(list("abc"), int(n_total / 3)), name="small")
+    h = pd.Series(np.tile(list("mn"), int(n_total / 2)), name="medium")
+    u = pd.Series(np.tile(list("jkh"), int(n_total / 3)))
     df = pd.DataFrame(dict(y=y, g=g, h=h, u=u))
     x_df["W"] = g
 
@@ -82,7 +83,7 @@ class TestCategoricalPlotter(CategoricalFixture):
 
         # Test an object array that looks 1D but isn't
         x_notreally_1d = np.array([self.x.ravel(),
-                                   self.x.ravel()[:self.n_total / 2]])
+                                   self.x.ravel()[:int(self.n_total / 2)]])
         p.establish_variables(data=x_notreally_1d)
         nt.assert_equal(len(p.plot_data), 2)
         nt.assert_equal(len(p.plot_data[0]), self.n_total)
@@ -366,12 +367,12 @@ class TestCategoricalPlotter(CategoricalFixture):
         # Test palette mapping the x position
         p.establish_variables("g", "y", data=self.df)
         p.establish_colors(None, None, 1)
-        nt.assert_equal(p.colors, palettes.color_palette("deep", 3))
+        nt.assert_equal(p.colors, palettes.color_palette(n_colors=3))
 
         # Test palette mapping the hue position
         p.establish_variables("g", "y", "h", data=self.df)
         p.establish_colors(None, None, 1)
-        nt.assert_equal(p.colors, palettes.color_palette("deep", 2))
+        nt.assert_equal(p.colors, palettes.color_palette(n_colors=2))
 
     def test_default_palette_with_many_levels(self):
 
@@ -601,17 +602,51 @@ class TestCategoricalStatPlotter(CategoricalFixture):
         npt.assert_array_equal(p.confint[2],
                                np.zeros((3, 2)) * np.nan)
 
-    def test_estimator_value_label(self):
+    def test_sd_error_bars(self):
 
         p = cat._CategoricalStatPlotter()
-        p.establish_variables("g", "y", data=self.df)
-        p.estimate_statistic(np.mean, None, 100)
-        nt.assert_equal(p.value_label, "mean(y)")
+
+        g = pd.Series(np.repeat(list("abc"), 100))
+        y = pd.Series(np.random.RandomState(0).randn(300))
+
+        p.establish_variables(g, y)
+        p.estimate_statistic(np.mean, "sd", None)
+
+        nt.assert_equal(p.statistic.shape, (3,))
+        nt.assert_equal(p.confint.shape, (3, 2))
+
+        npt.assert_array_almost_equal(p.statistic,
+                                      y.groupby(g).mean())
+
+        for ci, (_, grp_y) in zip(p.confint, y.groupby(g)):
+            mean = grp_y.mean()
+            half_ci = np.std(grp_y)
+            ci_want = mean - half_ci, mean + half_ci
+            npt.assert_array_almost_equal(ci_want, ci, 2)
+
+    def test_nested_sd_error_bars(self):
 
         p = cat._CategoricalStatPlotter()
-        p.establish_variables("g", "y", data=self.df)
-        p.estimate_statistic(np.median, None, 100)
-        nt.assert_equal(p.value_label, "median(y)")
+
+        g = pd.Series(np.repeat(list("abc"), 100))
+        h = pd.Series(np.tile(list("xy"), 150))
+        y = pd.Series(np.random.RandomState(0).randn(300))
+
+        p.establish_variables(g, y, h)
+        p.estimate_statistic(np.mean, "sd", None)
+
+        nt.assert_equal(p.statistic.shape, (3, 2))
+        nt.assert_equal(p.confint.shape, (3, 2, 2))
+
+        npt.assert_array_almost_equal(p.statistic,
+                                      y.groupby([g, h]).mean().unstack())
+
+        for ci_g, (_, grp_y) in zip(p.confint, y.groupby(g)):
+            for ci, hue_y in zip(ci_g, [grp_y[::2], grp_y[1::2]]):
+                mean = hue_y.mean()
+                half_ci = np.std(hue_y)
+                ci_want = mean - half_ci, mean + half_ci
+                npt.assert_array_almost_equal(ci_want, ci, 2)
 
     def test_draw_cis(self):
 
@@ -699,12 +734,13 @@ class TestBoxPlotter(CategoricalFixture):
     default_kws = dict(x=None, y=None, hue=None, data=None,
                        order=None, hue_order=None,
                        orient=None, color=None, palette=None,
-                       saturation=.75, width=.8,
+                       saturation=.75, width=.8, dodge=True,
                        fliersize=5, linewidth=None)
 
     def test_nested_width(self):
 
-        p = cat._BoxPlotter(**self.default_kws)
+        kws = self.default_kws.copy()
+        p = cat._BoxPlotter(**kws)
         p.establish_variables("g", "y", "h", data=self.df)
         nt.assert_equal(p.nested_width, .4 * .98)
 
@@ -714,6 +750,12 @@ class TestBoxPlotter(CategoricalFixture):
         p.establish_variables("g", "y", "h", data=self.df)
         nt.assert_equal(p.nested_width, .3 * .98)
 
+        kws = self.default_kws.copy()
+        kws["dodge"] = False
+        p = cat._BoxPlotter(**kws)
+        p.establish_variables("g", "y", "h", data=self.df)
+        nt.assert_equal(p.nested_width, .8)
+
     def test_hue_offsets(self):
 
         p = cat._BoxPlotter(**self.default_kws)
@@ -745,14 +787,14 @@ class TestBoxPlotter(CategoricalFixture):
     def test_box_colors(self):
 
         ax = cat.boxplot("g", "y", data=self.df, saturation=1)
-        pal = palettes.color_palette("deep", 3)
+        pal = palettes.color_palette(n_colors=3)
         for patch, color in zip(ax.artists, pal):
             nt.assert_equal(patch.get_facecolor()[:3], color)
 
         plt.close("all")
 
         ax = cat.boxplot("g", "y", "h", data=self.df, saturation=1)
-        pal = palettes.color_palette("deep", 2)
+        pal = palettes.color_palette(n_colors=2)
         for patch, color in zip(ax.artists, pal * 2):
             nt.assert_equal(patch.get_facecolor()[:3], color)
 
@@ -850,7 +892,7 @@ class TestViolinPlotter(CategoricalFixture):
                        order=None, hue_order=None,
                        bw="scott", cut=2, scale="area", scale_hue=True,
                        gridsize=100, width=.8, inner="box", split=False,
-                       orient=None, linewidth=None,
+                       dodge=True, orient=None, linewidth=None,
                        color=None, palette=None, saturation=.75)
 
     def test_split_error(self):
@@ -1558,11 +1600,11 @@ class TestStripPlotter(CategoricalFixture):
 
             npt.assert_equal(ax.collections[i].get_facecolors()[0, :3], pal[i])
 
-    def test_split_nested_stripplot_vertical(self):
+    def test_dodge_nested_stripplot_vertical(self):
 
         pal = palettes.color_palette()
 
-        ax = cat.stripplot("g", "y", "h", data=self.df, split=True)
+        ax = cat.stripplot("g", "y", "h", data=self.df, dodge=True)
         for i, (_, group_vals) in enumerate(self.y.groupby(self.g)):
             for j, (_, vals) in enumerate(group_vals.groupby(self.h)):
 
@@ -1575,12 +1617,12 @@ class TestStripPlotter(CategoricalFixture):
                 npt.assert_equal(fc, pal[j])
 
     @skipif(not pandas_has_categoricals)
-    def test_split_nested_stripplot_horizontal(self):
+    def test_dodge_nested_stripplot_horizontal(self):
 
         df = self.df.copy()
         df.g = df.g.astype("category")
 
-        ax = cat.stripplot("y", "g", "h", data=df, split=True)
+        ax = cat.stripplot("y", "g", "h", data=df, dodge=True)
         for i, (_, group_vals) in enumerate(self.y.groupby(self.g)):
             for j, (_, vals) in enumerate(group_vals.groupby(self.h)):
 
@@ -1589,10 +1631,10 @@ class TestStripPlotter(CategoricalFixture):
                 npt.assert_array_equal(x, vals)
                 npt.assert_array_equal(y, np.ones(len(x)) * i + [-.2, .2][j])
 
-    def test_unsplit_nested_stripplot_vertical(self):
+    def test_nested_stripplot_vertical(self):
 
         # Test a simple vertical strip plot
-        ax = cat.stripplot("g", "y", "h", data=self.df, split=False)
+        ax = cat.stripplot("g", "y", "h", data=self.df, dodge=False)
         for i, (_, group_vals) in enumerate(self.y.groupby(self.g)):
 
             x, y = ax.collections[i].get_offsets().T
@@ -1601,12 +1643,12 @@ class TestStripPlotter(CategoricalFixture):
             npt.assert_array_equal(y, group_vals)
 
     @skipif(not pandas_has_categoricals)
-    def test_unsplit_nested_stripplot_horizontal(self):
+    def test_nested_stripplot_horizontal(self):
 
         df = self.df.copy()
         df.g = df.g.astype("category")
 
-        ax = cat.stripplot("y", "g", "h", data=df, split=False)
+        ax = cat.stripplot("y", "g", "h", data=df, dodge=False)
         for i, (_, group_vals) in enumerate(self.y.groupby(self.g)):
 
             x, y = ax.collections[i].get_offsets().T
@@ -1626,20 +1668,14 @@ class TestStripPlotter(CategoricalFixture):
 class TestSwarmPlotter(CategoricalFixture):
 
     default_kws = dict(x=None, y=None, hue=None, data=None,
-                       order=None, hue_order=None, split=False,
+                       order=None, hue_order=None, dodge=False,
                        orient=None, color=None, palette=None)
 
-    def test_overlap(self):
-
-        p = cat._SwarmPlotter(**self.default_kws)
-        nt.assert_false(p.overlap((0, 0), (1, 1), np.sqrt(1.999)))
-        nt.assert_true(p.overlap((0, 0), (1, 1), np.sqrt(2.001)))
-
     def test_could_overlap(self):
 
         p = cat._SwarmPlotter(**self.default_kws)
         neighbors = p.could_overlap((1, 1), [(0, 0), (1, .5), (.5, .5)], 1)
-        nt.assert_equal(neighbors, [(1, .5), (.5, .5)])
+        npt.assert_array_equal(neighbors, [(1, .5), (.5, .5)])
 
     def test_position_candidates(self):
 
@@ -1649,16 +1685,18 @@ class TestSwarmPlotter(CategoricalFixture):
         candidates = p.position_candidates(xy_i, neighbors, 1)
         dx1 = 1.05
         dx2 = np.sqrt(1 - .5 ** 2) * 1.05
-        nt.assert_equal(candidates,
-                        [(0, 1), (-dx1, 1), (dx1, 1), (dx2, 1), (-dx2, 1)])
+        npt.assert_array_equal(candidates,
+                               [(0, 1), (-dx1, 1), (dx1, 1),
+                                (dx2, 1), (-dx2, 1)])
 
-    def test_prune_candidates(self):
+    def test_find_first_non_overlapping_candidate(self):
 
         p = cat._SwarmPlotter(**self.default_kws)
-        candidates = [(.5, 1), (1, 1)]
-        neighbors = [(0, 1)]
-        candidates = p.prune_candidates(candidates, neighbors, 1)
-        npt.assert_array_equal(candidates, np.array([(1, 1)]))
+        candidates = [(.5, 1), (1, 1), (1.5, 1)]
+        neighbors = np.array([(0, 1)])
+
+        first = p.first_non_overlapping_candidate(candidates, neighbors, 1)
+        npt.assert_array_equal(first, (1, 1))
 
     def test_beeswarm(self):
 
@@ -1707,11 +1745,11 @@ class TestSwarmPlotter(CategoricalFixture):
             fc = ax.collections[i].get_facecolors()[0, :3]
             npt.assert_equal(fc, pal[i])
 
-    def test_split_nested_swarmplot_vetical(self):
+    def test_dodge_nested_swarmplot_vetical(self):
 
         pal = palettes.color_palette()
 
-        ax = cat.swarmplot("g", "y", "h", data=self.df, split=True)
+        ax = cat.swarmplot("g", "y", "h", data=self.df, dodge=True)
         for i, (_, group_vals) in enumerate(self.y.groupby(self.g)):
             for j, (_, vals) in enumerate(group_vals.groupby(self.h)):
 
@@ -1721,11 +1759,11 @@ class TestSwarmPlotter(CategoricalFixture):
                 fc = ax.collections[i * 2 + j].get_facecolors()[0, :3]
                 npt.assert_equal(fc, pal[j])
 
-    def test_split_nested_swarmplot_horizontal(self):
+    def test_dodge_nested_swarmplot_horizontal(self):
 
         pal = palettes.color_palette()
 
-        ax = cat.swarmplot("y", "g", "h", data=self.df, orient="h", split=True)
+        ax = cat.swarmplot("y", "g", "h", data=self.df, orient="h", dodge=True)
         for i, (_, group_vals) in enumerate(self.y.groupby(self.g)):
             for j, (_, vals) in enumerate(group_vals.groupby(self.h)):
 
@@ -1735,7 +1773,7 @@ class TestSwarmPlotter(CategoricalFixture):
                 fc = ax.collections[i * 2 + j].get_facecolors()[0, :3]
                 npt.assert_equal(fc, pal[j])
 
-    def test_unsplit_nested_swarmplot_vertical(self):
+    def test_nested_swarmplot_vertical(self):
 
         ax = cat.swarmplot("g", "y", "h", data=self.df)
 
@@ -1751,12 +1789,12 @@ class TestSwarmPlotter(CategoricalFixture):
             npt.assert_array_almost_equal(y, vals.iloc[sorter])
 
             _, hue_vals = grouped_hues[i]
-            for hue, fc in zip(hue_vals.values[sorter],
+            for hue, fc in zip(hue_vals.values[sorter.values],
                                points.get_facecolors()):
 
                 npt.assert_equal(fc[:3], pal[hue_names.index(hue)])
 
-    def test_unsplit_nested_swarmplot_horizontal(self):
+    def test_nested_swarmplot_horizontal(self):
 
         ax = cat.swarmplot("y", "g", "h", data=self.df, orient="h")
 
@@ -1772,7 +1810,7 @@ class TestSwarmPlotter(CategoricalFixture):
             npt.assert_array_almost_equal(x, vals.iloc[sorter])
 
             _, hue_vals = grouped_hues[i]
-            for hue, fc in zip(hue_vals.values[sorter],
+            for hue, fc in zip(hue_vals.values[sorter.values],
                                points.get_facecolors()):
 
                 npt.assert_equal(fc[:3], pal[hue_names.index(hue)])
@@ -1784,7 +1822,8 @@ class TestBarPlotter(CategoricalFixture):
                        estimator=np.mean, ci=95, n_boot=100, units=None,
                        order=None, hue_order=None,
                        orient=None, color=None, palette=None,
-                       saturation=.75, errcolor=".26")
+                       saturation=.75, errcolor=".26", errwidth=None,
+                       capsize=None, dodge=True)
 
     def test_nested_width(self):
 
@@ -1798,6 +1837,11 @@ class TestBarPlotter(CategoricalFixture):
         p.establish_variables("h", "y", "g", data=self.df)
         nt.assert_equal(p.nested_width, .8 / 3)
 
+        kws["dodge"] = False
+        p = cat._BarPlotter(**kws)
+        p.establish_variables("h", "y", "g", data=self.df)
+        nt.assert_equal(p.nested_width, .8)
+
     def test_draw_vertical_bars(self):
 
         kws = self.default_kws.copy()
@@ -1816,9 +1860,13 @@ class TestBarPlotter(CategoricalFixture):
         positions = np.arange(len(p.plot_data)) - p.width / 2
         for bar, pos, stat in zip(ax.patches, positions, p.statistic):
             nt.assert_equal(bar.get_x(), pos)
-            nt.assert_equal(bar.get_y(), min(0, stat))
-            nt.assert_equal(bar.get_height(), abs(stat))
             nt.assert_equal(bar.get_width(), p.width)
+            if mpl.__version__ >= mpl_barplot_change:
+                nt.assert_equal(bar.get_y(), 0)
+                nt.assert_equal(bar.get_height(), stat)
+            else:
+                nt.assert_equal(bar.get_y(), min(0, stat))
+                nt.assert_equal(bar.get_height(), abs(stat))
 
     def test_draw_horizontal_bars(self):
 
@@ -1837,10 +1885,14 @@ class TestBarPlotter(CategoricalFixture):
 
         positions = np.arange(len(p.plot_data)) - p.width / 2
         for bar, pos, stat in zip(ax.patches, positions, p.statistic):
-            nt.assert_equal(bar.get_x(), min(0, stat))
             nt.assert_equal(bar.get_y(), pos)
             nt.assert_equal(bar.get_height(), p.width)
-            nt.assert_equal(bar.get_width(), abs(stat))
+            if mpl.__version__ >= mpl_barplot_change:
+                nt.assert_equal(bar.get_x(), 0)
+                nt.assert_equal(bar.get_width(), stat)
+            else:
+                nt.assert_equal(bar.get_x(), min(0, stat))
+                nt.assert_equal(bar.get_width(), abs(stat))
 
     def test_draw_nested_vertical_bars(self):
 
@@ -1860,15 +1912,19 @@ class TestBarPlotter(CategoricalFixture):
         for bar in ax.patches[n_groups:]:
             nt.assert_equal(bar.get_facecolor()[:-1], p.colors[1])
 
-        for bar, stat in zip(ax.patches, p.statistic.T.flat):
-            nt.assert_almost_equal(bar.get_y(), min(0, stat))
-            nt.assert_almost_equal(bar.get_height(), abs(stat))
-
         positions = np.arange(len(p.plot_data))
         for bar, pos in zip(ax.patches[:n_groups], positions):
             nt.assert_almost_equal(bar.get_x(), pos - p.width / 2)
             nt.assert_almost_equal(bar.get_width(), p.nested_width)
 
+        for bar, stat in zip(ax.patches, p.statistic.T.flat):
+            if LooseVersion(mpl.__version__) >= mpl_barplot_change:
+                nt.assert_almost_equal(bar.get_y(), 0)
+                nt.assert_almost_equal(bar.get_height(), stat)
+            else:
+                nt.assert_almost_equal(bar.get_y(), min(0, stat))
+                nt.assert_almost_equal(bar.get_height(), abs(stat))
+
     def test_draw_nested_horizontal_bars(self):
 
         kws = self.default_kws.copy()
@@ -1893,8 +1949,12 @@ class TestBarPlotter(CategoricalFixture):
             nt.assert_almost_equal(bar.get_height(), p.nested_width)
 
         for bar, stat in zip(ax.patches, p.statistic.T.flat):
-            nt.assert_almost_equal(bar.get_x(), min(0, stat))
-            nt.assert_almost_equal(bar.get_width(), abs(stat))
+            if LooseVersion(mpl.__version__) >= mpl_barplot_change:
+                nt.assert_almost_equal(bar.get_x(), 0)
+                nt.assert_almost_equal(bar.get_width(), stat)
+            else:
+                nt.assert_almost_equal(bar.get_x(), min(0, stat))
+                nt.assert_almost_equal(bar.get_width(), abs(stat))
 
     def test_draw_missing_bars(self):
 
@@ -1978,12 +2038,12 @@ class TestBarPlotter(CategoricalFixture):
         ax = cat.barplot("g", "y", data=self.df)
         nt.assert_equal(len(ax.patches), len(self.g.unique()))
         nt.assert_equal(ax.get_xlabel(), "g")
-        nt.assert_equal(ax.get_ylabel(), "mean(y)")
+        nt.assert_equal(ax.get_ylabel(), "y")
         plt.close("all")
 
         ax = cat.barplot("y", "g", orient="h", data=self.df)
         nt.assert_equal(len(ax.patches), len(self.g.unique()))
-        nt.assert_equal(ax.get_xlabel(), "mean(y)")
+        nt.assert_equal(ax.get_xlabel(), "y")
         nt.assert_equal(ax.get_ylabel(), "g")
         plt.close("all")
 
@@ -1991,13 +2051,13 @@ class TestBarPlotter(CategoricalFixture):
         nt.assert_equal(len(ax.patches),
                         len(self.g.unique()) * len(self.h.unique()))
         nt.assert_equal(ax.get_xlabel(), "g")
-        nt.assert_equal(ax.get_ylabel(), "mean(y)")
+        nt.assert_equal(ax.get_ylabel(), "y")
         plt.close("all")
 
         ax = cat.barplot("y", "g", "h", orient="h", data=self.df)
         nt.assert_equal(len(ax.patches),
                         len(self.g.unique()) * len(self.h.unique()))
-        nt.assert_equal(ax.get_xlabel(), "mean(y)")
+        nt.assert_equal(ax.get_xlabel(), "y")
         nt.assert_equal(ax.get_ylabel(), "g")
         plt.close("all")
 
@@ -2201,13 +2261,13 @@ class TestPointPlotter(CategoricalFixture):
         nt.assert_equal(len(ax.collections), 1)
         nt.assert_equal(len(ax.lines), len(self.g.unique()) + 1)
         nt.assert_equal(ax.get_xlabel(), "g")
-        nt.assert_equal(ax.get_ylabel(), "mean(y)")
+        nt.assert_equal(ax.get_ylabel(), "y")
         plt.close("all")
 
         ax = cat.pointplot("y", "g", orient="h", data=self.df)
         nt.assert_equal(len(ax.collections), 1)
         nt.assert_equal(len(ax.lines), len(self.g.unique()) + 1)
-        nt.assert_equal(ax.get_xlabel(), "mean(y)")
+        nt.assert_equal(ax.get_xlabel(), "y")
         nt.assert_equal(ax.get_ylabel(), "g")
         plt.close("all")
 
@@ -2218,7 +2278,7 @@ class TestPointPlotter(CategoricalFixture):
                          len(self.h.unique()) +
                          len(self.h.unique())))
         nt.assert_equal(ax.get_xlabel(), "g")
-        nt.assert_equal(ax.get_ylabel(), "mean(y)")
+        nt.assert_equal(ax.get_ylabel(), "y")
         plt.close("all")
 
         ax = cat.pointplot("y", "g", "h", orient="h", data=self.df)
@@ -2227,7 +2287,7 @@ class TestPointPlotter(CategoricalFixture):
                         (len(self.g.unique()) *
                          len(self.h.unique()) +
                          len(self.h.unique())))
-        nt.assert_equal(ax.get_xlabel(), "mean(y)")
+        nt.assert_equal(ax.get_xlabel(), "y")
         nt.assert_equal(ax.get_ylabel(), "g")
         plt.close("all")
 
@@ -2410,7 +2470,7 @@ class TestLVPlotter(CategoricalFixture):
         self.default_kws = dict(x=None, y=None, hue=None, data=None,
                                 order=None, hue_order=None,
                                 orient=None, color=None, palette=None,
-                                saturation=.75, width=.8,
+                                saturation=.75, width=.8, dodge=True,
                                 k_depth='proportion', linewidth=None,
                                 scale='exponential', outlier_prop=None)
         self.linear_data = np.arange(101)
@@ -2500,14 +2560,14 @@ class TestLVPlotter(CategoricalFixture):
     def test_box_colors(self):
 
         ax = cat.lvplot("g", "y", data=self.df, saturation=1)
-        pal = palettes.color_palette("deep", 3)
+        pal = palettes.color_palette(n_colors=3)
         for patch, color in zip(ax.artists, pal):
             nt.assert_equal(patch.get_facecolor()[:3], color)
 
         plt.close("all")
 
         ax = cat.lvplot("g", "y", "h", data=self.df, saturation=1)
-        pal = palettes.color_palette("deep", 2)
+        pal = palettes.color_palette(n_colors=2)
         for patch, color in zip(ax.artists, pal * 2):
             nt.assert_equal(patch.get_facecolor()[:3], color)
 
diff --git a/seaborn/tests/test_distributions.py b/seaborn/tests/test_distributions.py
index 042b934..a146d6d 100644
--- a/seaborn/tests/test_distributions.py
+++ b/seaborn/tests/test_distributions.py
@@ -3,6 +3,7 @@ import pandas as pd
 import matplotlib as mpl
 import matplotlib.pyplot as plt
 
+from distutils.version import LooseVersion
 import nose.tools as nt
 import numpy.testing as npt
 from numpy.testing.decorators import skipif
@@ -18,6 +19,9 @@ except ImportError:
     _no_statsmodels = True
 
 
+_old_matplotlib = LooseVersion(mpl.__version__) < "1.5"
+
+
 class TestKDE(PlotTestCase):
 
     rs = np.random.RandomState(0)
@@ -110,107 +114,12 @@ class TestKDE(PlotTestCase):
         nt.assert_equal(ax_series.collections[0].get_paths(),
                         ax_values.collections[0].get_paths())
 
+    @skipif(_old_matplotlib)
+    def test_bivariate_kde_colorbar(self):
 
-class TestJointPlot(PlotTestCase):
-
-    rs = np.random.RandomState(sum(map(ord, "jointplot")))
-    x = rs.randn(100)
-    y = rs.randn(100)
-    data = pd.DataFrame(dict(x=x, y=y))
-
-    def test_scatter(self):
-
-        g = dist.jointplot("x", "y", self.data)
-        nt.assert_equal(len(g.ax_joint.collections), 1)
-
-        x, y = g.ax_joint.collections[0].get_offsets().T
-        npt.assert_array_equal(self.x, x)
-        npt.assert_array_equal(self.y, y)
-
-        x_bins = dist._freedman_diaconis_bins(self.x)
-        nt.assert_equal(len(g.ax_marg_x.patches), x_bins)
-
-        y_bins = dist._freedman_diaconis_bins(self.y)
-        nt.assert_equal(len(g.ax_marg_y.patches), y_bins)
-
-    def test_reg(self):
-
-        g = dist.jointplot("x", "y", self.data, kind="reg")
-        nt.assert_equal(len(g.ax_joint.collections), 2)
-
-        x, y = g.ax_joint.collections[0].get_offsets().T
-        npt.assert_array_equal(self.x, x)
-        npt.assert_array_equal(self.y, y)
-
-        x_bins = dist._freedman_diaconis_bins(self.x)
-        nt.assert_equal(len(g.ax_marg_x.patches), x_bins)
-
-        y_bins = dist._freedman_diaconis_bins(self.y)
-        nt.assert_equal(len(g.ax_marg_y.patches), y_bins)
-
-        nt.assert_equal(len(g.ax_joint.lines), 1)
-        nt.assert_equal(len(g.ax_marg_x.lines), 1)
-        nt.assert_equal(len(g.ax_marg_y.lines), 1)
-
-    def test_resid(self):
-
-        g = dist.jointplot("x", "y", self.data, kind="resid")
-        nt.assert_equal(len(g.ax_joint.collections), 1)
-        nt.assert_equal(len(g.ax_joint.lines), 1)
-        nt.assert_equal(len(g.ax_marg_x.lines), 0)
-        nt.assert_equal(len(g.ax_marg_y.lines), 1)
-
-    def test_hex(self):
-
-        g = dist.jointplot("x", "y", self.data, kind="hex")
-        nt.assert_equal(len(g.ax_joint.collections), 1)
-
-        x_bins = dist._freedman_diaconis_bins(self.x)
-        nt.assert_equal(len(g.ax_marg_x.patches), x_bins)
-
-        y_bins = dist._freedman_diaconis_bins(self.y)
-        nt.assert_equal(len(g.ax_marg_y.patches), y_bins)
-
-    def test_kde(self):
-
-        g = dist.jointplot("x", "y", self.data, kind="kde")
-
-        nt.assert_true(len(g.ax_joint.collections) > 0)
-        nt.assert_equal(len(g.ax_marg_x.collections), 1)
-        nt.assert_equal(len(g.ax_marg_y.collections), 1)
-
-        nt.assert_equal(len(g.ax_marg_x.lines), 1)
-        nt.assert_equal(len(g.ax_marg_y.lines), 1)
-
-    def test_color(self):
-
-        g = dist.jointplot("x", "y", self.data, color="purple")
-
-        purple = mpl.colors.colorConverter.to_rgb("purple")
-        scatter_color = g.ax_joint.collections[0].get_facecolor()[0, :3]
-        nt.assert_equal(tuple(scatter_color), purple)
-
-        hist_color = g.ax_marg_x.patches[0].get_facecolor()[:3]
-        nt.assert_equal(hist_color, purple)
-
-    def test_annotation(self):
-
-        g = dist.jointplot("x", "y", self.data)
-        nt.assert_equal(len(g.ax_joint.legend_.get_texts()), 1)
-
-        g = dist.jointplot("x", "y", self.data, stat_func=None)
-        nt.assert_is(g.ax_joint.legend_, None)
-
-    def test_hex_customise(self):
-
-        # test that default gridsize can be overridden
-        g = dist.jointplot("x", "y", self.data, kind="hex",
-                           joint_kws=dict(gridsize=5))
-        nt.assert_equal(len(g.ax_joint.collections), 1)
-        a = g.ax_joint.collections[0].get_array()
-        nt.assert_equal(28, a.shape[0])  # 28 hexagons expected for gridsize 5
-
-    def test_bad_kind(self):
-
-        with nt.assert_raises(ValueError):
-            dist.jointplot("x", "y", self.data, kind="not_a_kind")
+        f, ax = plt.subplots()
+        dist.kdeplot(self.x, self.y,
+                     cbar=True, cbar_kws=dict(label="density"),
+                     ax=ax)
+        nt.assert_equal(len(f.axes), 2)
+        nt.assert_equal(f.axes[1].get_ylabel(), "density")
diff --git a/seaborn/tests/test_matrix.py b/seaborn/tests/test_matrix.py
index 140f652..9da9c7f 100644
--- a/seaborn/tests/test_matrix.py
+++ b/seaborn/tests/test_matrix.py
@@ -10,7 +10,10 @@ from scipy.cluster import hierarchy
 
 import nose.tools as nt
 import numpy.testing as npt
-import pandas.util.testing as pdt
+try:
+    import pandas.testing as pdt
+except ImportError:
+    import pandas.util.testing as pdt
 from numpy.testing.decorators import skipif
 
 from . import PlotTestCase
@@ -44,11 +47,11 @@ class TestHeatmap(PlotTestCase):
     def test_ndarray_input(self):
 
         p = mat._HeatMapper(self.x_norm, **self.default_kws)
-        npt.assert_array_equal(p.plot_data, self.x_norm[::-1])
-        pdt.assert_frame_equal(p.data, pd.DataFrame(self.x_norm).ix[::-1])
+        npt.assert_array_equal(p.plot_data, self.x_norm)
+        pdt.assert_frame_equal(p.data, pd.DataFrame(self.x_norm))
 
         npt.assert_array_equal(p.xticklabels, np.arange(8))
-        npt.assert_array_equal(p.yticklabels, np.arange(4)[::-1])
+        npt.assert_array_equal(p.yticklabels, np.arange(4))
 
         nt.assert_equal(p.xlabel, "")
         nt.assert_equal(p.ylabel, "")
@@ -56,11 +59,11 @@ class TestHeatmap(PlotTestCase):
     def test_df_input(self):
 
         p = mat._HeatMapper(self.df_norm, **self.default_kws)
-        npt.assert_array_equal(p.plot_data, self.x_norm[::-1])
-        pdt.assert_frame_equal(p.data, self.df_norm.ix[::-1])
+        npt.assert_array_equal(p.plot_data, self.x_norm)
+        pdt.assert_frame_equal(p.data, self.df_norm)
 
         npt.assert_array_equal(p.xticklabels, np.arange(8))
-        npt.assert_array_equal(p.yticklabels, ["D", "C", "B", "A"])
+        npt.assert_array_equal(p.yticklabels, self.letters.values)
 
         nt.assert_equal(p.xlabel, "")
         nt.assert_equal(p.ylabel, "letters")
@@ -76,12 +79,13 @@ class TestHeatmap(PlotTestCase):
 
         p = mat._HeatMapper(df, **self.default_kws)
 
-        npt.assert_array_equal(p.yticklabels, ["D-4", "C-3", "B-2", "A-1"])
+        combined_tick_labels = ["A-1", "B-2", "C-3", "D-4"]
+        npt.assert_array_equal(p.yticklabels, combined_tick_labels)
         nt.assert_equal(p.ylabel, "letter-number")
 
         p = mat._HeatMapper(df.T, **self.default_kws)
 
-        npt.assert_array_equal(p.xticklabels, ["A-1", "B-2", "C-3", "D-4"])
+        npt.assert_array_equal(p.xticklabels, combined_tick_labels)
         nt.assert_equal(p.xlabel, "letter-number")
 
     def test_mask_input(self):
@@ -92,24 +96,15 @@ class TestHeatmap(PlotTestCase):
         p = mat._HeatMapper(self.x_norm, **kws)
         plot_data = np.ma.masked_where(mask, self.x_norm)
 
-        npt.assert_array_equal(p.plot_data, plot_data[::-1])
+        npt.assert_array_equal(p.plot_data, plot_data)
 
-    def test_default_sequential_vlims(self):
+    def test_default_vlims(self):
 
         p = mat._HeatMapper(self.df_unif, **self.default_kws)
         nt.assert_equal(p.vmin, self.x_unif.min())
         nt.assert_equal(p.vmax, self.x_unif.max())
-        nt.assert_true(not p.divergent)
 
-    def test_default_diverging_vlims(self):
-
-        p = mat._HeatMapper(self.df_norm, **self.default_kws)
-        vlim = max(abs(self.x_norm.min()), abs(self.x_norm.max()))
-        nt.assert_equal(p.vmin, -vlim)
-        nt.assert_equal(p.vmax, vlim)
-        nt.assert_true(p.divergent)
-
-    def test_robust_sequential_vlims(self):
+    def test_robust_vlims(self):
 
         kws = self.default_kws.copy()
         kws["robust"] = True
@@ -133,9 +128,10 @@ class TestHeatmap(PlotTestCase):
         kws = self.default_kws.copy()
         kws["vmin"] = -4
         kws["vmax"] = 5
+        kws["center"] = 0
         p = mat._HeatMapper(self.df_norm, **kws)
 
-        nt.assert_equal(p.vmin, -5)
+        nt.assert_equal(p.vmin, -4)
         nt.assert_equal(p.vmax, 5)
 
     def test_array_with_nans(self):
@@ -169,7 +165,7 @@ class TestHeatmap(PlotTestCase):
         kws = self.default_kws.copy()
         kws["cmap"] = "BuGn"
         p = mat._HeatMapper(self.df_unif, **kws)
-        nt.assert_equal(p.cmap, "BuGn")
+        nt.assert_equal(p.cmap, mpl.cm.BuGn)
 
     def test_centered_vlims(self):
 
@@ -178,8 +174,33 @@ class TestHeatmap(PlotTestCase):
 
         p = mat._HeatMapper(self.df_unif, **kws)
 
-        nt.assert_true(p.divergent)
-        nt.assert_equal(p.vmax - .5, .5 - p.vmin)
+        nt.assert_equal(p.vmin, self.df_unif.values.min())
+        nt.assert_equal(p.vmax, self.df_unif.values.max())
+
+    def test_default_colors(self):
+
+        vals = np.linspace(.2, 1, 9)
+        cmap = mpl.cm.binary
+        ax = mat.heatmap([vals], cmap=cmap)
+        fc = ax.collections[0].get_facecolors()
+        cvals = np.linspace(0, 1, 9)
+        npt.assert_array_almost_equal(fc, cmap(cvals), 2)
+
+    def test_custom_vlim_colors(self):
+
+        vals = np.linspace(.2, 1, 9)
+        cmap = mpl.cm.binary
+        ax = mat.heatmap([vals], vmin=0, cmap=cmap)
+        fc = ax.collections[0].get_facecolors()
+        npt.assert_array_almost_equal(fc, cmap(vals), 2)
+
+    def test_custom_center_colors(self):
+
+        vals = np.linspace(.2, 1, 9)
+        cmap = mpl.cm.binary
+        ax = mat.heatmap([vals], center=.5, cmap=cmap)
+        fc = ax.collections[0].get_facecolors()
+        npt.assert_array_almost_equal(fc, cmap(vals), 2)
 
     def test_tickabels_off(self):
         kws = self.default_kws.copy()
@@ -197,29 +218,29 @@ class TestHeatmap(PlotTestCase):
         kws['yticklabels'] = yticklabels
         p = mat._HeatMapper(self.df_norm, **kws)
         nt.assert_equal(p.xticklabels, xticklabels)
-        nt.assert_equal(p.yticklabels, yticklabels[::-1])
+        nt.assert_equal(p.yticklabels, yticklabels)
 
     def test_custom_ticklabel_interval(self):
 
         kws = self.default_kws.copy()
-        kws['xticklabels'] = 2
-        kws['yticklabels'] = 3
+        xstep, ystep = 2, 3
+        kws['xticklabels'] = xstep
+        kws['yticklabels'] = ystep
         p = mat._HeatMapper(self.df_norm, **kws)
 
         nx, ny = self.df_norm.T.shape
-        ystart = (ny - 1) % 3
-        npt.assert_array_equal(p.xticks, np.arange(0, nx, 2) + .5)
-        npt.assert_array_equal(p.yticks, np.arange(ystart, ny, 3) + .5)
+        npt.assert_array_equal(p.xticks, np.arange(0, nx, xstep) + .5)
+        npt.assert_array_equal(p.yticks, np.arange(0, ny, ystep) + .5)
         npt.assert_array_equal(p.xticklabels,
-                               self.df_norm.columns[::2])
+                               self.df_norm.columns[0:nx:xstep])
         npt.assert_array_equal(p.yticklabels,
-                               self.df_norm.index[::-1][ystart:ny:3])
+                               self.df_norm.index[0:ny:ystep])
 
     def test_heatmap_annotation(self):
 
         ax = mat.heatmap(self.df_norm, annot=True, fmt=".1f",
                          annot_kws={"fontsize": 14})
-        for val, text in zip(self.x_norm[::-1].flat, ax.texts):
+        for val, text in zip(self.x_norm.flat, ax.texts):
             nt.assert_equal(text.get_text(), "{:.1f}".format(val))
             nt.assert_equal(text.get_fontsize(), 14)
 
@@ -241,8 +262,8 @@ class TestHeatmap(PlotTestCase):
         mask = np.isnan(df.values)
         df_masked = np.ma.masked_where(mask, df)
         ax = mat.heatmap(df, annot=True, fmt='.1f', mask=mask)
-        nt.assert_equal(len(df_masked[::-1].compressed()), len(ax.texts))
-        for val, text in zip(df_masked[::-1].compressed(), ax.texts):
+        nt.assert_equal(len(df_masked.compressed()), len(ax.texts))
+        for val, text in zip(df_masked.compressed(), ax.texts):
             nt.assert_equal("{:.1f}".format(val), text.get_text())
 
     def test_heatmap_annotation_mesh_colors(self):
@@ -259,10 +280,16 @@ class TestHeatmap(PlotTestCase):
         ax = mat.heatmap(self.df_norm, annot=annot_data, fmt=".1f",
                          annot_kws={"fontsize": 14})
 
-        for val, text in zip(annot_data.values[::-1].flat, ax.texts):
+        for val, text in zip(annot_data.values.flat, ax.texts):
             nt.assert_equal(text.get_text(), "{:.1f}".format(val))
             nt.assert_equal(text.get_fontsize(), 14)
 
+    def test_heatmap_annotation_with_limited_ticklabels(self):
+        ax = mat.heatmap(self.df_norm, fmt=".2f", annot=True,
+                         xticklabels=False, yticklabels=False)
+        for val, text in zip(self.x_norm.flat, ax.texts):
+            nt.assert_equal(text.get_text(), "{:.2f}".format(val))
+
     def test_heatmap_cbar(self):
 
         f = plt.figure()
@@ -287,18 +314,18 @@ class TestHeatmap(PlotTestCase):
         xtl = [int(l.get_text()) for l in ax.get_xticklabels()]
         nt.assert_equal(xtl, list(self.df_norm.columns))
         ytl = [l.get_text() for l in ax.get_yticklabels()]
-        nt.assert_equal(ytl, list(self.df_norm.index[::-1]))
+        nt.assert_equal(ytl, list(self.df_norm.index))
 
         nt.assert_equal(ax.get_xlabel(), "")
         nt.assert_equal(ax.get_ylabel(), "letters")
 
         nt.assert_equal(ax.get_xlim(), (0, 8))
-        nt.assert_equal(ax.get_ylim(), (0, 4))
+        nt.assert_equal(ax.get_ylim(), (4, 0))
 
     def test_heatmap_ticklabel_rotation(self):
 
         f, ax = plt.subplots(figsize=(2, 2))
-        mat.heatmap(self.df_norm, ax=ax)
+        mat.heatmap(self.df_norm, xticklabels=1, yticklabels=1, ax=ax)
 
         for t in ax.get_xticklabels():
             nt.assert_equal(t.get_rotation(), 0)
@@ -313,7 +340,7 @@ class TestHeatmap(PlotTestCase):
         df.index = [i * 10 for i in df.index]
 
         f, ax = plt.subplots(figsize=(2, 2))
-        mat.heatmap(df, ax=ax)
+        mat.heatmap(df, xticklabels=1, yticklabels=1, ax=ax)
 
         for t in ax.get_xticklabels():
             nt.assert_equal(t.get_rotation(), 90)
@@ -893,7 +920,7 @@ class TestClustermap(PlotTestCase):
         col_labels = [l.get_text() for l in
                       cm.ax_col_colors.get_yticklabels()]
         nt.assert_equal(cm.col_color_labels, ['col_1', 'col_2'])
-        nt.assert_equal(col_labels[::-1], cm.col_color_labels)
+        nt.assert_equal(col_labels, cm.col_color_labels)
 
     def test_row_col_colors_df_shuffled(self):
         # Tests if colors are properly matched, even if given in wrong order
@@ -962,7 +989,7 @@ class TestClustermap(PlotTestCase):
         col_labels = [l.get_text() for l in
                       cm2.ax_col_colors.get_yticklabels()]
         nt.assert_equal(cm2.col_color_labels, ['col_1', 'col_2'])
-        nt.assert_equal(col_labels[::-1], cm2.col_color_labels)
+        nt.assert_equal(col_labels, cm2.col_color_labels)
 
     def test_row_col_colors_series(self):
         kws = self.default_kws.copy()
@@ -1053,7 +1080,7 @@ class TestClustermap(PlotTestCase):
         ytl_actual = [t.get_text() for t in g.ax_heatmap.get_yticklabels()]
 
         xtl_want = xtl[g.dendrogram_col.reordered_ind].astype("<U1")
-        ytl_want = ytl[g.dendrogram_row.reordered_ind].astype("<U1")[::-1]
+        ytl_want = ytl[g.dendrogram_row.reordered_ind].astype("<U1")
 
         npt.assert_array_equal(xtl_actual, xtl_want)
         npt.assert_array_equal(ytl_actual, ytl_want)
diff --git a/seaborn/tests/test_palettes.py b/seaborn/tests/test_palettes.py
index 87c5ed4..4b0ef0e 100644
--- a/seaborn/tests/test_palettes.py
+++ b/seaborn/tests/test_palettes.py
@@ -163,7 +163,7 @@ class TestColorPalettes(object):
 
         pal_forward = palettes.mpl_palette("BuPu", 6)
         pal_reverse = palettes.mpl_palette("BuPu_r", 6)
-        nt.assert_equal(pal_forward, pal_reverse[::-1])
+        npt.assert_array_almost_equal(pal_forward, pal_reverse[::-1])
 
     def test_rgb_from_hls(self):
 
diff --git a/seaborn/tests/test_rcmod.py b/seaborn/tests/test_rcmod.py
index 73f13ee..585d105 100644
--- a/seaborn/tests/test_rcmod.py
+++ b/seaborn/tests/test_rcmod.py
@@ -21,10 +21,7 @@ class RCParamTester(object):
     def assert_rc_params(self, params):
 
         for k, v in params.items():
-            if k == "svg.embed_char_paths":
-                # This param causes test issues and is deprecated anyway
-                continue
-            elif isinstance(v, np.ndarray):
+            if isinstance(v, np.ndarray):
                 npt.assert_array_equal(mpl.rcParams[k], v)
             else:
                 nt.assert_equal((k, mpl.rcParams[k]), (k, v))
diff --git a/seaborn/tests/test_linearmodels.py b/seaborn/tests/test_regression.py
similarity index 96%
rename from seaborn/tests/test_linearmodels.py
rename to seaborn/tests/test_regression.py
index 6e6bc40..3a43a0d 100644
--- a/seaborn/tests/test_linearmodels.py
+++ b/seaborn/tests/test_regression.py
@@ -5,7 +5,10 @@ import pandas as pd
 
 import nose.tools as nt
 import numpy.testing as npt
-import pandas.util.testing as pdt
+try:
+    import pandas.testing as pdt
+except ImportError:
+    import pandas.util.testing as pdt
 from numpy.testing.decorators import skipif
 from nose import SkipTest
 
@@ -16,9 +19,7 @@ except ImportError:
     _no_statsmodels = True
 
 from . import PlotTestCase
-from .. import linearmodels as lm
-from .. import algorithms as algo
-from .. import utils
+from .. import regression as lm
 from ..palettes import color_palette
 
 rs = np.random.RandomState(0)
@@ -155,6 +156,10 @@ class TestRegressionPlotter(PlotTestCase):
         nt.assert_equal(p.ci, 95)
         nt.assert_equal(p.x_ci, 68)
 
+        p = lm._RegressionPlotter("x", "y", data=self.df, ci=95, x_ci="sd")
+        nt.assert_equal(p.ci, 95)
+        nt.assert_equal(p.x_ci, "sd")
+
     @skipif(_no_statsmodels)
     def test_fast_regression(self):
 
@@ -350,6 +355,15 @@ class TestRegressionPlotter(PlotTestCase):
         npt.assert_array_less(0, yhat)
 
     @skipif(_no_statsmodels)
+    def test_logistic_perfect_separation(self):
+
+        y = self.df.x > self.df.x.mean()
+        p = lm._RegressionPlotter("x", y, data=self.df,
+                                  logistic=True, n_boot=10)
+        _, yhat, _ = p.fit_regression(x_range=(-3, 3))
+        nt.assert_true(np.isnan(yhat).all())
+
+    @skipif(_no_statsmodels)
     def test_robust_regression(self):
 
         p_ols = lm._RegressionPlotter("x", "y", data=self.df,
diff --git a/seaborn/tests/test_utils.py b/seaborn/tests/test_utils.py
index 82a2ab5..351b55d 100644
--- a/seaborn/tests/test_utils.py
+++ b/seaborn/tests/test_utils.py
@@ -11,12 +11,14 @@ import nose
 import nose.tools as nt
 from nose.tools import assert_equal, raises
 import numpy.testing as npt
-import pandas.util.testing as pdt
+try:
+    import pandas.testing as pdt
+except ImportError:
+    import pandas.util.testing as pdt
 
 from distutils.version import LooseVersion
 pandas_has_categoricals = LooseVersion(pd.__version__) >= "0.15"
 
-from pandas.util.testing import network
 
 try:
     from bs4 import BeautifulSoup
@@ -25,7 +27,7 @@ except ImportError:
 
 from . import PlotTestCase
 from .. import utils, rcmod
-from ..utils import get_dataset_names, load_dataset
+from ..utils import get_dataset_names, load_dataset, _network
 
 
 a_norm = np.random.randn(100)
@@ -174,6 +176,19 @@ class TestSpineUtils(PlotTestCase):
             else:
                 nt.assert_equal(new_position, self.original_position)
 
+    def test_despine_side_specific_offset(self):
+
+        f, ax = plt.subplots()
+        utils.despine(ax=ax, offset=dict(left=self.offset))
+
+        for side in self.sides:
+            is_visible = ax.spines[side].get_visible()
+            new_position = ax.spines[side].get_position()
+            if is_visible and side == "left":
+                nt.assert_equal(new_position, self.offset_position)
+            else:
+                nt.assert_equal(new_position, self.original_position)
+
     def test_despine_with_offset_specific_axes(self):
         f, (ax1, ax2) = plt.subplots(2, 1)
 
@@ -219,43 +234,6 @@ class TestSpineUtils(PlotTestCase):
         utils.despine(trim=True)
         nt.assert_equal(ax.get_yticks().size, 0)
 
-    def test_offset_spines_warns(self):
-        with warnings.catch_warnings(record=True) as w:
-            warnings.simplefilter("always", category=UserWarning)
-
-            f, ax = plt.subplots()
-            utils.offset_spines(offset=self.offset)
-            nt.assert_true('deprecated' in str(w[0].message))
-            nt.assert_true(issubclass(w[0].category, UserWarning))
-
-    def test_offset_spines(self):
-        with warnings.catch_warnings(record=True) as w:
-            warnings.simplefilter("always", category=UserWarning)
-            f, ax = plt.subplots()
-
-            for side in self.sides:
-                nt.assert_equal(ax.spines[side].get_position(),
-                                self.original_position)
-
-            utils.offset_spines(offset=self.offset)
-
-            for side in self.sides:
-                nt.assert_equal(ax.spines[side].get_position(),
-                                self.offset_position)
-
-    def test_offset_spines_specific_axes(self):
-        with warnings.catch_warnings(record=True) as w:
-            warnings.simplefilter("always", category=UserWarning)
-            f, (ax1, ax2) = plt.subplots(2, 1)
-
-            utils.offset_spines(offset=self.offset, ax=ax2)
-
-            for side in self.sides:
-                nt.assert_equal(ax1.spines[side].get_position(),
-                                self.original_position)
-                nt.assert_equal(ax2.spines[side].get_position(),
-                                self.offset_position)
-
 
 def test_ticklabels_overlap():
 
@@ -346,7 +324,7 @@ if LooseVersion(pd.__version__) >= "0.15":
         finally:
             shutil.rmtree(tmpdir)
 
-    @network(url="https://github.com/mwaskom/seaborn-data")
+    @_network(url="https://github.com/mwaskom/seaborn-data")
     def test_get_dataset_names():
         if not BeautifulSoup:
             raise nose.SkipTest("No BeautifulSoup available for parsing html")
@@ -354,7 +332,7 @@ if LooseVersion(pd.__version__) >= "0.15":
         assert(len(names) > 0)
         assert(u"titanic" in names)
 
-    @network(url="https://github.com/mwaskom/seaborn-data")
+    @_network(url="https://github.com/mwaskom/seaborn-data")
     def test_load_datasets():
         if not BeautifulSoup:
             raise nose.SkipTest("No BeautifulSoup available for parsing html")
@@ -366,7 +344,7 @@ if LooseVersion(pd.__version__) >= "0.15":
             # yield check_load_dataset, name
             check_load_dataset(name)
 
-    @network(url="https://github.com/mwaskom/seaborn-data")
+    @_network(url="https://github.com/mwaskom/seaborn-data")
     def test_load_cached_datasets():
         if not BeautifulSoup:
             raise nose.SkipTest("No BeautifulSoup available for parsing html")
diff --git a/seaborn/timeseries.py b/seaborn/timeseries.py
index 45be355..6278838 100644
--- a/seaborn/timeseries.py
+++ b/seaborn/timeseries.py
@@ -6,6 +6,8 @@ from scipy import stats, interpolate
 import matplotlib as mpl
 import matplotlib.pyplot as plt
 
+import warnings
+
 from .external.six import string_types
 
 from . import utils
@@ -61,10 +63,11 @@ def tsplot(data, time=None, unit=None, condition=None, value=None,
         Names of ways to plot uncertainty across units from set of
         {ci_band, ci_bars, boot_traces, boot_kde, unit_traces, unit_points}.
         Can use one or more than one method.
-    ci : float or list of floats in [0, 100]
-        Confidence interval size(s). If a list, it will stack the error
-        plots for each confidence interval. Only relevant for error styles
-        with "ci" in the name.
+    ci : float or list of floats in [0, 100] or "sd" or None
+        Confidence interval size(s). If a list, it will stack the error plots
+        for each confidence interval. If ``"sd"``, show standard deviation of
+        the observations instead of boostrapped confidence intervals. Only
+        relevant for error styles with "ci" in the name.
     interpolate : boolean
         Whether to do a linear interpolation between each timepoint when
         plotting. The value of this parameter also determines the marker
@@ -143,6 +146,13 @@ def tsplot(data, time=None, unit=None, condition=None, value=None,
 
         >>> ax = sns.tsplot(data=data, ci=[68, 95], color="m")
 
+    Show the standard deviation of the observations:
+
+    .. plot::
+        :context: close-figs
+
+        >>> ax = sns.tsplot(data=data, ci="sd")
+
     Use a different estimator:
 
     .. plot::
@@ -166,6 +176,12 @@ def tsplot(data, time=None, unit=None, condition=None, value=None,
         >>> ax = sns.tsplot(data=data, err_style="unit_traces")
 
     """
+    msg = (
+        "The tsplot function is deprecated and will be removed or replaced "
+        "(in a substantially altered version) in a future release."
+    )
+    warnings.warn(msg, UserWarning)
+
     # Sort out default values for the parameters
     if ax is None:
         ax = plt.gca()
@@ -181,7 +197,7 @@ def tsplot(data, time=None, unit=None, condition=None, value=None,
 
         # Condition is optional
         if condition is None:
-            condition = pd.Series(np.ones(len(data)))
+            condition = pd.Series(1, index=data.index)
             legend = False
             legend_name = None
             n_cond = 1
@@ -274,15 +290,22 @@ def tsplot(data, time=None, unit=None, condition=None, value=None,
             colors = [color] * n_cond
 
     # Do a groupby with condition and plot each trace
+    c = None
     for c, (cond, df_c) in enumerate(data.groupby(condition, sort=False)):
 
         df_c = df_c.pivot(unit, time, value)
         x = df_c.columns.values.astype(np.float)
 
         # Bootstrap the data for confidence intervals
-        boot_data = algo.bootstrap(df_c.values, n_boot=n_boot,
-                                   axis=0, func=estimator)
-        cis = [utils.ci(boot_data, v, axis=0) for v in ci]
+        if "sd" in ci:
+            est = estimator(df_c.values, axis=0)
+            sd = np.std(df_c.values, axis=0)
+            cis = [(est - sd, est + sd)]
+            boot_data = df_c.values
+        else:
+            boot_data = algo.bootstrap(df_c.values, n_boot=n_boot,
+                                       axis=0, func=estimator)
+            cis = [utils.ci(boot_data, v, axis=0) for v in ci]
         central_data = estimator(df_c.values, axis=0)
 
         # Get the color for this condition
@@ -327,6 +350,9 @@ def tsplot(data, time=None, unit=None, condition=None, value=None,
         label = cond if legend else "_nolegend_"
         ax.plot(x, central_data, color=color, label=label, **kwargs)
 
+    if c is None:
+        raise RuntimeError("Invalid input data for tsplot.")
+
     # Pad the sides of the plot only when not interpolating
     ax.set_xlim(x.min(), x.max())
     x_diff = x[1] - x[0]
diff --git a/seaborn/utils.py b/seaborn/utils.py
index f612905..1e30895 100644
--- a/seaborn/utils.py
+++ b/seaborn/utils.py
@@ -15,6 +15,7 @@ from distutils.version import LooseVersion
 pandas_has_categoricals = LooseVersion(pd.__version__) >= "0.15"
 mpl_ge_150 = LooseVersion(mpl.__version__) >= "1.5.0"
 from .external.six.moves.urllib.request import urlopen, urlretrieve
+from .external.six.moves.http_client import HTTPException
 
 
 __all__ = ["desaturate", "saturate", "set_hls_values",
@@ -173,11 +174,13 @@ def despine(fig=None, ax=None, top=True, right=True, left=False,
         Specific axes object to despine.
     top, right, left, bottom : boolean, optional
         If True, remove that spine.
-    offset : int or None  (default), optional
+    offset : int or dict, optional
         Absolute distance, in points, spines should be moved away
-        from the axes (negative values move spines inward).
+        from the axes (negative values move spines inward). A single value
+        applies to all spines; a dict can be used to set offset values per
+        side.
     trim : bool, optional
-        If true, limit spines to the smallest and largest major tick
+        If True, limit spines to the smallest and largest major tick
         on each non-despined axis.
 
     Returns
@@ -199,7 +202,11 @@ def despine(fig=None, ax=None, top=True, right=True, left=False,
             is_visible = not locals()[side]
             ax_i.spines[side].set_visible(is_visible)
             if offset is not None and is_visible:
-                _set_spine_position(ax_i.spines[side], ('outward', offset))
+                try:
+                    val = offset.get(side, 0)
+                except AttributeError:
+                    val = offset
+                _set_spine_position(ax_i.spines[side], ('outward', val))
 
         # Set the ticks appropriately
         if bottom:
@@ -238,44 +245,6 @@ def despine(fig=None, ax=None, top=True, right=True, left=False,
                 ax_i.set_yticks(newticks)
 
 
-def offset_spines(offset=10, fig=None, ax=None):
-    """Simple function to offset spines away from axes.
-
-    Use this immediately after creating figure and axes objects.
-    Offsetting spines after plotting or manipulating the axes
-    objects may result in loss of labels, ticks, and formatting.
-
-    Parameters
-    ----------
-    offset : int, optional
-        Absolute distance, in points, spines should be moved away
-        from the axes (negative values move spines inward).
-    fig : matplotlib figure, optional
-        Figure to despine all axes of, default uses current figure.
-    ax : matplotlib axes, optional
-        Specific axes object to despine
-
-    Returns
-    -------
-    None
-
-    """
-    warn_msg = "`offset_spines` is deprecated and will be removed in v0.5"
-    warnings.warn(warn_msg, UserWarning)
-
-    # Get references to the axes we want
-    if fig is None and ax is None:
-        axes = plt.gcf().axes
-    elif fig is not None:
-        axes = fig.axes
-    elif ax is not None:
-        axes = [ax]
-
-    for ax_i in axes:
-        for spine in ax_i.spines.values():
-            _set_spine_position(spine, ('outward', offset))
-
-
 def _set_spine_position(spine, position):
     """
     Set the spine's position without resetting an associated axis.
@@ -409,12 +378,13 @@ def load_dataset(name, cache=True, data_home=None, **kws):
     cache : boolean, optional
         If True, then cache data locally and use the cache on subsequent calls
     data_home : string, optional
-        The directory in which to cache data. By default, uses ~/seaborn_data/
+        The directory in which to cache data. By default, uses ~/seaborn-data/
     kws : dict, optional
         Passed to pandas.read_csv
 
     """
-    path = "https://github.com/mwaskom/seaborn-data/raw/master/{0}.csv"
+    path = ("https://raw.githubusercontent.com/"
+            "mwaskom/seaborn-data/master/{}.csv")
     full_path = path.format(name)
 
     if cache:
@@ -617,3 +587,29 @@ def to_utf8(obj):
             return obj.decode("utf-8")
         else:
             return obj.__str__()
+
+
+def _network(t=None, url='http://google.com'):
+    """
+    Decorator that will skip a test if `url` is unreachable.
+
+    Parameters
+    ----------
+    t : function, optional
+    url : str, optional
+    """
+    import nose
+
+    if t is None:
+        return lambda x: _network(x, url=url)
+
+    def wrapper(*args, **kwargs):
+        # attempt to connect
+        try:
+            f = urlopen(url)
+        except (IOError, HTTPException):
+            raise nose.SkipTest()
+        else:
+            f.close()
+            return t(*args, **kwargs)
+    return wrapper
diff --git a/seaborn/widgets.py b/seaborn/widgets.py
index 9f450f1..6976f61 100644
--- a/seaborn/widgets.py
+++ b/seaborn/widgets.py
@@ -7,15 +7,21 @@ from matplotlib.colors import LinearSegmentedColormap
 try:
     from ipywidgets import interact, FloatSlider, IntSlider
 except ImportError:
-    try:
-        from IPython.html.widgets import interact, FloatSlider, IntSlider
-    except ImportError:
+    import warnings
+    # ignore ShimWarning raised by IPython, see GH #892
+    with warnings.catch_warnings():
+        warnings.simplefilter("ignore")
         try:
-            from IPython.html.widgets import (interact,
-                                              FloatSliderWidget as FloatSlider,
-                                              IntSliderWidget as IntSlider)
+            from IPython.html.widgets import interact, FloatSlider, IntSlider
         except ImportError:
-            pass
+            try:
+                from IPython.html.widgets import (interact,
+                                                  FloatSliderWidget,
+                                                  IntSliderWidget)
+                FloatSlider = FloatSliderWidget
+                IntSlider = IntSliderWidget
+            except ImportError:
+                pass
 
 
 from .miscplot import palplot
diff --git a/setup.py b/setup.py
index 76ec635..639c478 100644
--- a/setup.py
+++ b/setup.py
@@ -1,6 +1,6 @@
 #! /usr/bin/env python
 #
-# Copyright (C) 2012-2014 Michael Waskom <mwaskom at stanford.edu>
+# Copyright (C) 2012-2016 Michael Waskom
 import os
 # temporarily redirect config directory to prevent matplotlib importing
 # testing that for writeable directory which results in sandbox error in
@@ -25,10 +25,10 @@ Some of the features that seaborn offers are
 DISTNAME = 'seaborn'
 MAINTAINER = 'Michael Waskom'
 MAINTAINER_EMAIL = 'mwaskom at stanford.edu'
-URL = 'http://stanford.edu/~mwaskom/software/seaborn/'
+URL = 'http://seaborn.stanford.edu'
 LICENSE = 'BSD (3-clause)'
 DOWNLOAD_URL = 'https://github.com/mwaskom/seaborn/'
-VERSION = '0.7.1'
+VERSION = '0.8.0'
 
 try:
     from setuptools import setup

-- 
Alioth's /usr/local/bin/git-commit-notice on /srv/git.debian.org/git/debian-science/packages/seaborn.git



More information about the debian-science-commits mailing list