[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