diff -Nru seaborn-0.7.1/debian/changelog seaborn-0.8.0/debian/changelog --- seaborn-0.7.1/debian/changelog 2017-03-24 20:22:51.000000000 +0000 +++ seaborn-0.8.0/debian/changelog 2017-07-24 10:10:14.000000000 +0000 @@ -1,17 +1,14 @@ -seaborn (0.7.1-4) unstable; urgency=medium +seaborn (0.8.0-1) unstable; urgency=medium * Team upload. - * [998c9fc] Revert adding python-tk and python3-tk as a dependency. - (Closes: #858637) + * New upstream version (dropped patches) + * Add python*-pytest to Build-Depends + Closes: #868616 + * cme fix dpkg-control + * debhelper 10 + * Make short description distinct - -- Anton Gladky Fri, 24 Mar 2017 21:22:51 +0100 - -seaborn (0.7.1-3) unstable; urgency=medium - - * Team upload. - * [ef1c513] Add python-tk and python3-tk as a dependency. (Closes: #858576) - - -- Anton Gladky Fri, 24 Mar 2017 08:27:57 +0100 + -- Andreas Tille Mon, 24 Jul 2017 12:10:14 +0200 seaborn (0.7.1-2) unstable; urgency=medium diff -Nru seaborn-0.7.1/debian/compat seaborn-0.8.0/debian/compat --- seaborn-0.7.1/debian/compat 2017-01-23 11:09:45.000000000 +0000 +++ seaborn-0.8.0/debian/compat 2017-07-24 10:10:14.000000000 +0000 @@ -1 +1 @@ -8 +10 diff -Nru seaborn-0.7.1/debian/control seaborn-0.8.0/debian/control --- seaborn-0.7.1/debian/control 2017-03-24 20:21:35.000000000 +0000 +++ seaborn-0.8.0/debian/control 2017-07-24 10:10:14.000000000 +0000 @@ -1,24 +1,35 @@ Source: seaborn +Maintainer: Debian Science Maintainers +Uploaders: Yaroslav Halchenko , + Michael Hanke Section: python Priority: optional -Maintainer: Debian Science Maintainers -Uploaders: Yaroslav Halchenko , Michael Hanke -Build-Depends: debhelper (>= 8), dh-python, - python-setuptools, python3-setuptools, - python-all (>= 2.6.6-3~), python3-all, - python-nose, python3-nose, - xvfb, xauth, - python-numpy, python-scipy, - python-pandas, - python-matplotlib, python-tk, - python-statsmodels, - python-patsy, - python3-numpy, python3-scipy, - python3-pandas, - python3-matplotlib | python-matplotlib (<< 1.2.0~), - python3-tk, - python3-patsy, -Standards-Version: 3.9.5 +Build-Depends: debhelper (>= 10), + dh-python, + python-setuptools, + python3-setuptools, + python-all, + python3-all, + python-nose, + python3-nose, + xvfb, + xauth, + python-numpy, + python-scipy, + python-pandas, + python-matplotlib, + python-tk, + python-statsmodels, + python-patsy, + python-pytest, + python3-numpy, + python3-scipy, + python3-pandas, + python3-matplotlib | python-matplotlib (<< 1.2.0~), + python3-tk, + python3-patsy, + python3-pytest +Standards-Version: 4.0.0 Vcs-Browser: https://anonscm.debian.org/cgit/debian-science/packages/seaborn.git Vcs-Git: https://anonscm.debian.org/git/debian-science/packages/seaborn.git -b debian Homepage: https://github.com/mwaskom/seaborn @@ -27,15 +38,16 @@ Package: python-seaborn Architecture: all -Depends: ${misc:Depends}, ${python:Depends}, - python-numpy, python-scipy, - python-pandas, - python-matplotlib, -Recommends: - python-statsmodels, - python-patsy, - python-bs4, -Description: statistical visualization library +Depends: ${misc:Depends}, + ${python:Depends}, + python-numpy, + python-scipy, + python-pandas, + python-matplotlib +Recommends: python-statsmodels, + python-patsy, + python-bs4 +Description: statistical visualization library for Python Seaborn is a library for making attractive and informative statistical graphics in Python. It is built on top of matplotlib and tightly integrated with the PyData stack, including support for numpy @@ -61,14 +73,15 @@ Package: python3-seaborn Architecture: all -Depends: ${misc:Depends}, ${python3:Depends}, - python3-numpy, python3-scipy, - python3-pandas, - python3-matplotlib, -Recommends: - python3-patsy, - python3-bs4 -Description: statistical visualization library +Depends: ${misc:Depends}, + ${python3:Depends}, + python3-numpy, + python3-scipy, + python3-pandas, + python3-matplotlib +Recommends: python3-patsy, + python3-bs4 +Description: statistical visualization library for Python3 Seaborn is a library for making attractive and informative statistical graphics in Python. It is built on top of matplotlib and tightly integrated with the PyData stack, including support for numpy diff -Nru seaborn-0.7.1/debian/patches/Allow-matplotlib-to-return-an-rgba-tuple-instead-of-a-col.patch seaborn-0.8.0/debian/patches/Allow-matplotlib-to-return-an-rgba-tuple-instead-of-a-col.patch --- seaborn-0.7.1/debian/patches/Allow-matplotlib-to-return-an-rgba-tuple-instead-of-a-col.patch 2017-01-23 11:24:19.000000000 +0000 +++ seaborn-0.8.0/debian/patches/Allow-matplotlib-to-return-an-rgba-tuple-instead-of-a-col.patch 1970-01-01 00:00:00.000000000 +0000 @@ -1,25 +0,0 @@ -From: Ole Streicher -Date: Mon, 23 Jan 2017 12:19:52 +0100 -Subject: Allow matplotlib to return an rgba tuple instead of a color name in - test. - -This is required to have the test succeeding on matplotlib 2.0. - -Closes: #849368 ---- - seaborn/tests/test_axisgrid.py | 2 +- - 1 file changed, 1 insertion(+), 1 deletion(-) - -diff --git a/seaborn/tests/test_axisgrid.py b/seaborn/tests/test_axisgrid.py -index 3f1dc5d..e93d275 100644 ---- a/seaborn/tests/test_axisgrid.py -+++ b/seaborn/tests/test_axisgrid.py -@@ -269,7 +269,7 @@ class TestFacetGrid(PlotTestCase): - - g = ag.FacetGrid(self.df, subplot_kws=dict(axisbg="blue")) - for ax in g.axes.flat: -- nt.assert_equal(ax.get_axis_bgcolor(), "blue") -+ nt.assert_in(ax.get_axis_bgcolor(), ("blue", (0.0, 0.0, 1.0, 1.0))) - - @skipif(old_matplotlib) - def test_gridspec_kws(self): diff -Nru seaborn-0.7.1/debian/patches/Explicitely-transform-results-to-a-list.patch seaborn-0.8.0/debian/patches/Explicitely-transform-results-to-a-list.patch --- seaborn-0.7.1/debian/patches/Explicitely-transform-results-to-a-list.patch 2017-01-23 11:24:19.000000000 +0000 +++ seaborn-0.8.0/debian/patches/Explicitely-transform-results-to-a-list.patch 1970-01-01 00:00:00.000000000 +0000 @@ -1,25 +0,0 @@ -From: Ole Streicher -Date: Mon, 23 Jan 2017 13:14:04 +0100 -Subject: Explicitely transform results to a list. - -Matplotlib now returns a _ColorPalette instead of a list, but slicing it -will return a list. This let the equality check fail. - -Closes: #849368, #850999 ---- - seaborn/tests/test_palettes.py | 2 +- - 1 file changed, 1 insertion(+), 1 deletion(-) - -diff --git a/seaborn/tests/test_palettes.py b/seaborn/tests/test_palettes.py -index 87c5ed4..f0ef385 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]) -+ np.testing.assert_allclose(pal_forward, pal_reverse[::-1]) - - def test_rgb_from_hls(self): - diff -Nru seaborn-0.7.1/debian/patches/series seaborn-0.8.0/debian/patches/series --- seaborn-0.7.1/debian/patches/series 2017-01-23 11:24:19.000000000 +0000 +++ seaborn-0.8.0/debian/patches/series 1970-01-01 00:00:00.000000000 +0000 @@ -1,2 +0,0 @@ -Allow-matplotlib-to-return-an-rgba-tuple-instead-of-a-col.patch -Explicitely-transform-results-to-a-list.patch diff -Nru seaborn-0.7.1/doc/api.rst seaborn-0.8.0/doc/api.rst --- seaborn-0.7.1/doc/api.rst 2016-06-05 02:22:35.000000000 +0000 +++ seaborn-0.8.0/doc/api.rst 2017-07-08 22:40:57.000000000 +0000 @@ -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 @@ .. autosummary:: :toctree: generated/ - jointplot - pairplot distplot kdeplot rugplot @@ -27,28 +58,8 @@ .. 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 @@ palplot -.. _grid_api: - -Axis grids ----------- - -.. autosummary:: - :toctree: generated/ - - FacetGrid - PairGrid - JointGrid - .. _style_api: Style frontend @@ -150,5 +149,3 @@ desaturate saturate set_hls_values - ci_to_errsize - axlabel diff -Nru seaborn-0.7.1/doc/conf.py seaborn-0.8.0/doc/conf.py --- seaborn-0.7.1/doc/conf.py 2016-06-05 02:22:35.000000000 +0000 +++ seaborn-0.8.0/doc/conf.py 2017-07-08 22:40:57.000000000 +0000 @@ -65,7 +65,8 @@ # 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 @@ # 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 @@ # 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_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 -Nru seaborn-0.7.1/doc/index.rst seaborn-0.8.0/doc/index.rst --- seaborn-0.7.1/doc/index.rst 2016-06-05 02:22:35.000000000 +0000 +++ seaborn-0.8.0/doc/index.rst 2017-07-08 22:40:57.000000000 +0000 @@ -19,7 +19,7 @@ -Seaborn: statistical data visualization +seaborn: statistical data visualization ======================================= .. raw:: html @@ -33,9 +33,9 @@ - +
- +
@@ -43,19 +43,19 @@ - +
- +
- +
- +
- +
- +
@@ -92,8 +92,8 @@ whatsnew installing examples/index - api tutorial + api .. raw:: html @@ -104,8 +104,8 @@ * Style functions: :ref:`API ` | :ref:`Tutorial ` * Color palettes: :ref:`API ` | :ref:`Tutorial ` * Distribution plots: :ref:`API ` | :ref:`Tutorial ` -* Regression plots: :ref:`API ` | :ref:`Tutorial ` * Categorical plots: :ref:`API ` | :ref:`Tutorial ` +* Regression plots: :ref:`API ` | :ref:`Tutorial ` * Axis grid objects: :ref:`API ` | :ref:`Tutorial ` .. raw:: html diff -Nru seaborn-0.7.1/doc/installing.rst seaborn-0.8.0/doc/installing.rst --- seaborn-0.7.1/doc/installing.rst 2016-06-05 02:22:35.000000000 +0000 +++ seaborn-0.8.0/doc/installing.rst 2017-07-08 22:40:57.000000000 +0000 @@ -6,25 +6,19 @@ 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 `_ 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 `_. 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 @@ - `scipy `__ -- `matplotlib `__ +- `matplotlib `__ - `pandas `__ @@ -42,48 +36,26 @@ - `statsmodels `__ -The `pip` installation script will attempt to download the mandatory -dependencies if they do not exist at install-time. +The ``pip`` installation script will attempt to download the mandatory +dependencies only if they do not exist at install-time. -I recommend using seaborn with the `Anaconda distribution -`_, as this makes it easy to manage -the main dependencies, which otherwise can be difficult to install. - -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 -` 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 @@ Known issues ~~~~~~~~~~~~ -There is a `bug `_ 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 -`_. 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 -Nru seaborn-0.7.1/doc/introduction.rst seaborn-0.8.0/doc/introduction.rst --- seaborn-0.7.1/doc/introduction.rst 2016-06-05 02:22:35.000000000 +0000 +++ seaborn-0.8.0/doc/introduction.rst 2017-07-08 22:40:57.000000000 +0000 @@ -13,7 +13,7 @@ Some of the features that seaborn offers are -- Several :ref:`built-in themes ` that improve on the default matplotlib aesthetics +- Several :ref:`built-in themes ` for styling matplotlib graphics - Tools for choosing :ref:`color palettes ` to make beautiful plots that reveal patterns in your data - Functions for visualizing :ref:`univariate ` and :ref:`bivariate ` distributions or for :ref:`comparing ` them between subsets of data - Tools that fit and visualize :ref:`linear regression ` models for different kinds of :ref:`independent ` and :ref:`dependent ` variables @@ -33,24 +33,23 @@ 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 `_ and `Bokeh -`_ 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 `, -:ref:`tutorial ` or :ref:`API reference `. +``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 `. Some motivation +behind the kind of plots that seaborn can help to make is explained in the +:ref:`tutorial `. Authoritative documentation on the options afforded +by each function and class can be found by consulting the :ref:`API reference +`. diff -Nru seaborn-0.7.1/doc/Makefile seaborn-0.8.0/doc/Makefile --- seaborn-0.7.1/doc/Makefile 2016-06-05 02:22:35.000000000 +0000 +++ seaborn-0.8.0/doc/Makefile 2017-07-08 22:40:57.000000000 +0000 @@ -18,7 +18,9 @@ help: @echo "Please use \`make ' where 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 -Nru seaborn-0.7.1/doc/releases/v0.6.0.txt seaborn-0.8.0/doc/releases/v0.6.0.txt --- seaborn-0.7.1/doc/releases/v0.6.0.txt 2016-06-05 02:22:35.000000000 +0000 +++ seaborn-0.8.0/doc/releases/v0.6.0.txt 2017-07-08 22:40:57.000000000 +0000 @@ -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 -Nru seaborn-0.7.1/doc/releases/v0.7.0.txt seaborn-0.8.0/doc/releases/v0.7.0.txt --- seaborn-0.7.1/doc/releases/v0.7.0.txt 2016-06-05 02:22:35.000000000 +0000 +++ seaborn-0.8.0/doc/releases/v0.7.0.txt 2017-07-08 22:40:57.000000000 +0000 @@ -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 ` for more information. diff -Nru seaborn-0.7.1/doc/releases/v0.7.1.txt seaborn-0.8.0/doc/releases/v0.7.1.txt --- seaborn-0.7.1/doc/releases/v0.7.1.txt 2016-06-05 02:22:35.000000000 +0000 +++ seaborn-0.8.0/doc/releases/v0.7.1.txt 2017-07-08 22:40:57.000000000 +0000 @@ -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 `_ 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 -Nru seaborn-0.7.1/doc/releases/v0.8.0.txt seaborn-0.8.0/doc/releases/v0.8.0.txt --- seaborn-0.7.1/doc/releases/v0.8.0.txt 1970-01-01 00:00:00.000000000 +0000 +++ seaborn-0.8.0/doc/releases/v0.8.0.txt 2017-07-08 22:40:57.000000000 +0000 @@ -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 upper and lower limits of the colorbar will correspond to the range of the data. See the Github pull request `(#1184) `_ for examples of the behavior. + +- 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 `_ 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 -Nru seaborn-0.7.1/doc/sphinxext/plot_generator.py seaborn-0.8.0/doc/sphinxext/plot_generator.py --- seaborn-0.7.1/doc/sphinxext/plot_generator.py 2016-06-05 02:22:35.000000000 +0000 +++ seaborn-0.8.0/doc/sphinxext/plot_generator.py 2017-07-08 22:40:57.000000000 +0000 @@ -12,7 +12,8 @@ import token import tokenize import shutil -import json + +from seaborn.external import six import matplotlib matplotlib.use('Agg') @@ -20,6 +21,12 @@ 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 @@ 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 @@ 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'): Binary files /tmp/tmp8QY7we/dFXScxlE4U/seaborn-0.7.1/doc/_static/favicon.ico and /tmp/tmp8QY7we/F9tXsfXVjt/seaborn-0.8.0/doc/_static/favicon.ico differ diff -Nru seaborn-0.7.1/doc/_static/style.css seaborn-0.8.0/doc/_static/style.css --- seaborn-0.7.1/doc/_static/style.css 2016-06-05 02:22:35.000000000 +0000 +++ seaborn-0.8.0/doc/_static/style.css 2017-07-08 22:40:57.000000000 +0000 @@ -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 @@ code { color: #49759c !important; - background-color: #f3f5f9 !important; + background-color: #ffffff !important; } .alert-info { diff -Nru seaborn-0.7.1/doc/tutorial/aesthetics.ipynb seaborn-0.8.0/doc/tutorial/aesthetics.ipynb --- seaborn-0.7.1/doc/tutorial/aesthetics.ipynb 2016-06-05 02:22:35.000000000 +0000 +++ seaborn-0.8.0/doc/tutorial/aesthetics.ipynb 2017-07-08 22:40:57.000000000 +0000 @@ -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 of the more complex tools in the library.\n", + "(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 elements:" ] @@ -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 -Nru seaborn-0.7.1/doc/tutorial/axis_grids.ipynb seaborn-0.8.0/doc/tutorial/axis_grids.ipynb --- seaborn-0.7.1/doc/tutorial/axis_grids.ipynb 2016-06-05 02:22:35.000000000 +0000 +++ seaborn-0.8.0/doc/tutorial/axis_grids.ipynb 2017-07-08 22:40:57.000000000 +0000 @@ -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\" `_ plotting, and it is related to the idea of `\"small multiples\" `_. 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; seaborn builds on top of this to directly link the structure of the plot to the structure of your dataset.\n", + "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\" `_. 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; seaborn builds on top of this to directly link the structure of the plot to the structure of your dataset.\n", "\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 `_. 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 generally more strict about how it gets set up. In some cases, arguments either to those functions or to the constructor of the class they rely on will provide a different interface attributes like the figure size, as in the case of :func:`lmplot` where you can set the height and aspect ratio for each facet rather than the overall size of the figure. Any function that uses one of these objects will always return it after plotting, though, and most of these objects have convenience methods for changing how the plot, often in a more abstract and easy way." + "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 generally more strict about how it gets set up. In some cases, arguments either to those functions or to the constructor of the class they rely on will provide a different interface attributes like the figure size, as in the case of :func:`lmplot` where you can set the height and aspect ratio for each facet rather than the overall size of the figure. Any function that uses one of these objects will always return it after plotting, though, and most of these objects have convenience methods for changing how the plot is drawn, often in a more abstract and easy way." ] }, { @@ -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 -Nru seaborn-0.7.1/doc/tutorial/categorical.ipynb seaborn-0.8.0/doc/tutorial/categorical.ipynb --- seaborn-0.7.1/doc/tutorial/categorical.ipynb 2016-06-05 02:22:35.000000000 +0000 +++ seaborn-0.8.0/doc/tutorial/categorical.ipynb 2017-07-08 22:40:57.000000000 +0000 @@ -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 -Nru seaborn-0.7.1/doc/tutorial/color_palettes.ipynb seaborn-0.8.0/doc/tutorial/color_palettes.ipynb --- seaborn-0.7.1/doc/tutorial/color_palettes.ipynb 2016-06-05 02:22:35.000000000 +0000 +++ seaborn-0.8.0/doc/tutorial/color_palettes.ipynb 2017-07-08 22:40:57.000000000 +0000 @@ -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 `_ 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 `_ 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 `. :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 -Nru seaborn-0.7.1/doc/tutorial/distributions.ipynb seaborn-0.8.0/doc/tutorial/distributions.ipynb --- seaborn-0.7.1/doc/tutorial/distributions.ipynb 2016-06-05 02:22:35.000000000 +0000 +++ seaborn-0.8.0/doc/tutorial/distributions.ipynb 2017-07-08 22:40:57.000000000 +0000 @@ -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 ` 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 ` 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 -Nru seaborn-0.7.1/doc/tutorial/regression.ipynb seaborn-0.8.0/doc/tutorial/regression.ipynb --- seaborn-0.7.1/doc/tutorial/regression.ipynb 2016-06-05 02:22:35.000000000 +0000 +++ seaborn-0.8.0/doc/tutorial/regression.ipynb 2017-07-08 22:40:57.000000000 +0000 @@ -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 regression on \"faceted\" plots that allow you to explore interactions with up to three additional categorical variables.\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 relationship, :func:`lmplot` combines :func:`regplot` with :class:`FacetGrid` to provide an easy interface to show a linear regression on \"faceted\" plots that allow you to explore interactions with up to three additional categorical variables.\n", "\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 other matplotlib functions. To control the size, you need to create a figure object yourself." + "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 shape as most other matplotlib functions. To control the size, you need to create a figure object yourself." ] }, { diff -Nru seaborn-0.7.1/doc/tutorial/tools/nb_to_doc.py seaborn-0.8.0/doc/tutorial/tools/nb_to_doc.py --- seaborn-0.7.1/doc/tutorial/tools/nb_to_doc.py 2016-06-05 02:22:35.000000000 +0000 +++ seaborn-0.8.0/doc/tutorial/tools/nb_to_doc.py 2017-07-08 22:40:57.000000000 +0000 @@ -10,15 +10,15 @@ 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 -Nru seaborn-0.7.1/doc/tutorial.rst seaborn-0.8.0/doc/tutorial.rst --- seaborn-0.7.1/doc/tutorial.rst 2016-06-05 02:22:35.000000000 +0000 +++ seaborn-0.8.0/doc/tutorial.rst 2017-07-08 22:40:57.000000000 +0000 @@ -19,8 +19,8 @@ :maxdepth: 2 tutorial/distributions - tutorial/regression tutorial/categorical + tutorial/regression Structured grids ---------------- diff -Nru seaborn-0.7.1/doc/whatsnew.rst seaborn-0.8.0/doc/whatsnew.rst --- seaborn-0.7.1/doc/whatsnew.rst 2016-06-05 02:22:35.000000000 +0000 +++ seaborn-0.8.0/doc/whatsnew.rst 2017-07-08 22:40:57.000000000 +0000 @@ -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 -Nru seaborn-0.7.1/examples/heatmap_annotation.py seaborn-0.8.0/examples/heatmap_annotation.py --- seaborn-0.7.1/examples/heatmap_annotation.py 2016-06-05 02:22:35.000000000 +0000 +++ seaborn-0.8.0/examples/heatmap_annotation.py 2017-07-08 22:40:57.000000000 +0000 @@ -3,6 +3,7 @@ ================== """ +import matplotlib.pyplot as plt import seaborn as sns sns.set() @@ -11,4 +12,5 @@ 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 -Nru seaborn-0.7.1/examples/horizontal_boxplot.py seaborn-0.8.0/examples/horizontal_boxplot.py --- seaborn-0.7.1/examples/horizontal_boxplot.py 2016-06-05 02:22:35.000000000 +0000 +++ seaborn-0.8.0/examples/horizontal_boxplot.py 2017-07-08 22:40:57.000000000 +0000 @@ -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 -Nru seaborn-0.7.1/examples/interactplot.py seaborn-0.8.0/examples/interactplot.py --- seaborn-0.7.1/examples/interactplot.py 2016-06-05 02:22:35.000000000 +0000 +++ seaborn-0.8.0/examples/interactplot.py 1970-01-01 00:00:00.000000000 +0000 @@ -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 -Nru seaborn-0.7.1/examples/jitter_stripplot.py seaborn-0.8.0/examples/jitter_stripplot.py --- seaborn-0.7.1/examples/jitter_stripplot.py 1970-01-01 00:00:00.000000000 +0000 +++ seaborn-0.8.0/examples/jitter_stripplot.py 2017-07-08 22:40:57.000000000 +0000 @@ -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 -Nru seaborn-0.7.1/examples/large_distributions.py seaborn-0.8.0/examples/large_distributions.py --- seaborn-0.7.1/examples/large_distributions.py 1970-01-01 00:00:00.000000000 +0000 +++ seaborn-0.8.0/examples/large_distributions.py 2017-07-08 22:40:57.000000000 +0000 @@ -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 -Nru seaborn-0.7.1/examples/many_facets.py seaborn-0.8.0/examples/many_facets.py --- seaborn-0.7.1/examples/many_facets.py 2016-06-05 02:22:35.000000000 +0000 +++ seaborn-0.8.0/examples/many_facets.py 2017-07-08 22:40:57.000000000 +0000 @@ -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 -Nru seaborn-0.7.1/examples/many_pairwise_correlations.py seaborn-0.8.0/examples/many_pairwise_correlations.py --- seaborn-0.7.1/examples/many_pairwise_correlations.py 2016-06-05 02:22:35.000000000 +0000 +++ seaborn-0.8.0/examples/many_pairwise_correlations.py 2017-07-08 22:40:57.000000000 +0000 @@ -4,7 +4,7 @@ _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 @@ # 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 @@ 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 -Nru seaborn-0.7.1/examples/marginal_ticks.py seaborn-0.8.0/examples/marginal_ticks.py --- seaborn-0.7.1/examples/marginal_ticks.py 2016-06-05 02:22:35.000000000 +0000 +++ seaborn-0.8.0/examples/marginal_ticks.py 2017-07-08 22:40:57.000000000 +0000 @@ -2,7 +2,7 @@ Scatterplot with marginal ticks =============================== -_thumb: .65, .35 +_thumb: .68, .32 """ import numpy as np import seaborn as sns diff -Nru seaborn-0.7.1/examples/multiple_joint_kde.py seaborn-0.8.0/examples/multiple_joint_kde.py --- seaborn-0.7.1/examples/multiple_joint_kde.py 2016-06-05 02:22:35.000000000 +0000 +++ seaborn-0.8.0/examples/multiple_joint_kde.py 2017-07-08 22:40:57.000000000 +0000 @@ -2,7 +2,7 @@ Multiple bivariate KDE plots ============================ -_thumb: .6, .4 +_thumb: .6, .45 """ import seaborn as sns import matplotlib.pyplot as plt diff -Nru seaborn-0.7.1/examples/multiple_regression.py seaborn-0.8.0/examples/multiple_regression.py --- seaborn-0.7.1/examples/multiple_regression.py 2016-06-05 02:22:35.000000000 +0000 +++ seaborn-0.8.0/examples/multiple_regression.py 2017-07-08 22:40:57.000000000 +0000 @@ -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 -Nru seaborn-0.7.1/examples/network_correlations.py seaborn-0.8.0/examples/network_correlations.py --- seaborn-0.7.1/examples/network_correlations.py 2016-06-05 02:22:35.000000000 +0000 +++ seaborn-0.8.0/examples/network_correlations.py 1970-01-01 00:00:00.000000000 +0000 @@ -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 -Nru seaborn-0.7.1/examples/paired_pointplots.py seaborn-0.8.0/examples/paired_pointplots.py --- seaborn-0.7.1/examples/paired_pointplots.py 2016-06-05 02:22:35.000000000 +0000 +++ seaborn-0.8.0/examples/paired_pointplots.py 2017-07-08 22:40:57.000000000 +0000 @@ -1,6 +1,6 @@ """ -Paired discrete plots -===================== +Paired categorical plots +======================== """ import seaborn as sns diff -Nru seaborn-0.7.1/examples/scatterplot_matrix.py seaborn-0.8.0/examples/scatterplot_matrix.py --- seaborn-0.7.1/examples/scatterplot_matrix.py 2016-06-05 02:22:35.000000000 +0000 +++ seaborn-0.8.0/examples/scatterplot_matrix.py 2017-07-08 22:40:57.000000000 +0000 @@ -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 -Nru seaborn-0.7.1/examples/structured_heatmap.py seaborn-0.8.0/examples/structured_heatmap.py --- seaborn-0.7.1/examples/structured_heatmap.py 2016-06-05 02:22:35.000000000 +0000 +++ seaborn-0.8.0/examples/structured_heatmap.py 2017-07-08 22:40:57.000000000 +0000 @@ -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 -Nru seaborn-0.7.1/examples/tips.csv seaborn-0.8.0/examples/tips.csv --- seaborn-0.7.1/examples/tips.csv 2016-06-05 02:22:35.000000000 +0000 +++ seaborn-0.8.0/examples/tips.csv 1970-01-01 00:00:00.000000000 +0000 @@ -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 -Nru seaborn-0.7.1/LICENSE seaborn-0.8.0/LICENSE --- seaborn-0.7.1/LICENSE 2016-06-05 02:22:35.000000000 +0000 +++ seaborn-0.8.0/LICENSE 2017-07-08 22:40:57.000000000 +0000 @@ -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 @@ 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 -Nru seaborn-0.7.1/Makefile seaborn-0.8.0/Makefile --- seaborn-0.7.1/Makefile 2016-06-05 02:22:35.000000000 +0000 +++ seaborn-0.8.0/Makefile 2017-07-08 22:40:57.000000000 +0000 @@ -15,8 +15,8 @@ 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 -Nru seaborn-0.7.1/README.md seaborn-0.8.0/README.md --- seaborn-0.7.1/README.md 2016-06-05 02:22:35.000000000 +0000 +++ seaborn-0.8.0/README.md 2017-07-08 22:40:57.000000000 +0000 @@ -1,53 +1,54 @@ -Seaborn: statistical data visualization +seaborn: statistical data visualization ======================================= 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 @@ - [scipy](http://www.scipy.org/) -- [matplotlib](http://matplotlib.sourceforge.net) +- [matplotlib](http://matplotlib.org/) - [pandas](http://pandas.pydata.org/) @@ -73,7 +74,7 @@ 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 @@ To test seaborn, run `make test` in the source directory. This will run the unit-test and doctest suite (using `nose`). + Development ----------- diff -Nru seaborn-0.7.1/seaborn/apionly.py seaborn-0.8.0/seaborn/apionly.py --- seaborn-0.7.1/seaborn/apionly.py 2016-06-05 02:22:35.000000000 +0000 +++ seaborn-0.8.0/seaborn/apionly.py 2017-07-08 22:40:57.000000000 +0000 @@ -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 -Nru seaborn-0.7.1/seaborn/axisgrid.py seaborn-0.8.0/seaborn/axisgrid.py --- seaborn-0.7.1/seaborn/axisgrid.py 2016-06-05 02:22:35.000000000 +0000 +++ seaborn-0.8.0/seaborn/axisgrid.py 2017-07-08 22:40:57.000000000 +0000 @@ -6,14 +6,17 @@ 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 @@ 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 @@ # 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 @@ 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 @@ 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 @@ 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 @@ # 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 @@ """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 -Nru seaborn-0.7.1/seaborn/categorical.py seaborn-0.8.0/seaborn/categorical.py --- seaborn-0.7.1/seaborn/categorical.py 2016-06-05 02:22:35.000000000 +0000 +++ seaborn-0.8.0/seaborn/categorical.py 2017-07-08 22:40:57.000000000 +0000 @@ -356,16 +356,23 @@ 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 @@ 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 @@ 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 @@ self.gridsize = gridsize self.width = width + self.dodge = dodge if inner is not None: if not any([inner.startswith("quart"), @@ -555,7 +564,8 @@ 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 @@ @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 @@ 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 _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 @@ # 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 _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 @@ 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 @@ 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 @@ # 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 @@ # 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 @@ # 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 @@ @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 @@ 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 @@ 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 @@ 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 @@ @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 @@ 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 @@ 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 @@ 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 @@ 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 @@ {palette} {saturation} {width} + {dodge} fliersize : float, optional Size of the markers used to indicate outlier observations. {linewidth} @@ -2282,6 +2300,15 @@ >>> 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 @@ >>> 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 - + >>> 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 @@ 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 @@ ... 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 - + >>> 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 @@ >>> 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 @@ ... 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 @@ :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 @@ >>> 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 @@ >>> 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 @@ {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 @@ >>> 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 @@ >>> 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 @@ ... 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 @@ {orient} {color} {palette} + {errwidth} + {capsize} {ax_in} Returns @@ -3221,6 +3280,13 @@ >>> 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 @@ >>> 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 @@ 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 @@ {color} {palette} {saturation} + {dodge} {ax_in} kwargs : key, value mappings Other keyword arguments are passed to ``plt.bar``. @@ -3341,6 +3424,18 @@ ... 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 @@ 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 @@ 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 @@ ... 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 @@ 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 @@ 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 @@ {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 @@ >>> 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 - + >>> g = sns.factorplot(x="sex", y="total_bill", + ... hue="smoker", col="time", + ... data=tips, kind="lv", + ... size=4, aspect=.7); """).format(**_categorical_docs) diff -Nru seaborn-0.7.1/seaborn/cm.py seaborn-0.8.0/seaborn/cm.py --- seaborn-0.7.1/seaborn/cm.py 1970-01-01 00:00:00.000000000 +0000 +++ seaborn-0.8.0/seaborn/cm.py 2017-07-08 22:40:57.000000000 +0000 @@ -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 -Nru seaborn-0.7.1/seaborn/distributions.py seaborn-0.8.0/seaborn/distributions.py --- seaborn-0.7.1/seaborn/distributions.py 2016-06-05 02:22:35.000000000 +0000 +++ seaborn-0.8.0/seaborn/distributions.py 2017-07-08 22:40:57.000000000 +0000 @@ -15,12 +15,11 @@ 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 @@ :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 @@ 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 _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 @@ 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 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 @@ 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 @@ >>> 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 @@ 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 @@ 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 @@ 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 -Nru seaborn-0.7.1/seaborn/external/husl.py seaborn-0.8.0/seaborn/external/husl.py --- seaborn-0.7.1/seaborn/external/husl.py 2016-06-05 02:22:35.000000000 +0000 +++ seaborn-0.8.0/seaborn/external/husl.py 2017-07-08 22:40:57.000000000 +0000 @@ -170,7 +170,7 @@ # 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 -Nru seaborn-0.7.1/seaborn/external/six.py seaborn-0.8.0/seaborn/external/six.py --- seaborn-0.7.1/seaborn/external/six.py 2016-06-05 02:22:35.000000000 +0000 +++ seaborn-0.8.0/seaborn/external/six.py 2017-07-08 22:40:57.000000000 +0000 @@ -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 " -__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: # 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 @@ 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 @@ 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 @@ 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 @@ 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 @@ 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 @@ 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 @@ 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 @@ 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 @@ 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 @@ 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 @@ 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 @@ _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 @@ _func_defaults = "func_defaults" _func_globals = "func_globals" - _iterkeys = "iterkeys" - _itervalues = "itervalues" - _iteritems = "iteritems" - _iterlists = "iterlists" - try: advance_iterator = next @@ -445,6 +538,9 @@ 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 @@ 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_globals = operator.attrgetter(_func_globals) -def iterkeys(d, **kw): - """Return an iterator over the keys of a dictionary.""" - return iter(getattr(d, _iterkeys)(**kw)) - -def itervalues(d, **kw): - """Return an iterator over the values of a dictionary.""" - return iter(getattr(d, _itervalues)(**kw)) - -def iteritems(d, **kw): - """Return an iterator over the (key, value) pairs of a dictionary.""" - return iter(getattr(d, _iteritems)(**kw)) - -def iterlists(d, **kw): - """Return an iterator over the (key, [values]) pairs of a dictionary.""" - return iter(getattr(d, _iterlists)(**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") + + viewvalues = operator.methodcaller("values") + + viewitems = operator.methodcaller("items") +else: + def iterkeys(d, **kw): + return d.iterkeys(**kw) + + def itervalues(d, **kw): + return d.itervalues(**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 @@ _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 @@ 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 @@ 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 -Nru seaborn-0.7.1/seaborn/__init__.py seaborn-0.8.0/seaborn/__init__.py --- seaborn-0.7.1/seaborn/__init__.py 2016-06-05 02:22:35.000000000 +0000 +++ seaborn-0.8.0/seaborn/__init__.py 2017-07-08 22:40:57.000000000 +0000 @@ -6,7 +6,7 @@ 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 .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 -Nru seaborn-0.7.1/seaborn/linearmodels.py seaborn-0.8.0/seaborn/linearmodels.py --- seaborn-0.7.1/seaborn/linearmodels.py 2016-06-05 02:22:35.000000000 +0000 +++ seaborn-0.8.0/seaborn/linearmodels.py 2017-07-08 22:40:57.000000000 +0000 @@ -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 -Nru seaborn-0.7.1/seaborn/matrix.py seaborn-0.8.0/seaborn/matrix.py --- seaborn-0.7.1/seaborn/matrix.py 2016-06-05 02:22:35.000000000 +0000 +++ seaborn-0.8.0/seaborn/matrix.py 2017-07-08 22:40:57.000000000 +0000 @@ -1,4 +1,5 @@ """Functions to visualize matrices of data.""" +from __future__ import division import itertools import matplotlib as mpl @@ -10,9 +11,12 @@ 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 @@ 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_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 @@ # 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 @@ 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 @@ 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 @@ 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 @@ 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 @@ # 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 @@ 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 @@ 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 @@ 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 @@ 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 @@ >>> 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 @@ 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 @@ 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 @@ 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 @@ 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 @@ 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 @@ 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 @@ 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 @@ 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 @@ 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 @@ 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 @@ .. 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) - Don't cluster one of the axes: + Use a different similarity metric: .. plot:: :context: close-figs - >>> g = sns.clustermap(flights, col_cluster=False) + >>> g = sns.clustermap(iris, metric="correlation") - Use a different colormap and add lines to separate the cells: + Use a different clustering method: .. 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, method="single") - Use a different figure size: + Use a different colormap and ignore outliers in colormap limits: .. plot:: :context: close-figs - >>> g = sns.clustermap(flights, cmap=cmap, figsize=(7, 5)) + >>> g = sns.clustermap(iris, cmap="mako", robust=True) - Standardize the data across the columns: + Change the size of the figure: .. plot:: :context: close-figs - >>> g = sns.clustermap(flights, standard_scale=1) + >>> g = sns.clustermap(iris, figsize=(6, 7)) - Normalize the data across the rows: + Plot one of the axes in its original organization: .. plot:: :context: close-figs - >>> g = sns.clustermap(flights, z_score=0) + >>> g = sns.clustermap(iris, col_cluster=False) - Use a different clustering method: + Add colored labels: .. plot:: :context: close-figs - >>> g = sns.clustermap(flights, method="single", metric="cosine") + >>> lut = dict(zip(species.unique(), "rbg")) + >>> row_colors = species.map(lut) + >>> g = sns.clustermap(iris, row_colors=row_colors) - Add colored labels on one of the axes: + Standardize the data within the columns: .. 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, standard_scale=1) + + Normalize the data within the rows: + + .. plot:: + :context: close-figs + + >>> g = sns.clustermap(iris, z_score=0) + """ plotter = ClusterGrid(data, pivot_kws=pivot_kws, figsize=figsize, diff -Nru seaborn-0.7.1/seaborn/miscplot.py seaborn-0.8.0/seaborn/miscplot.py --- seaborn-0.7.1/seaborn/miscplot.py 2016-06-05 02:22:35.000000000 +0000 +++ seaborn-0.8.0/seaborn/miscplot.py 2017-07-08 22:40:57.000000000 +0000 @@ -4,7 +4,7 @@ import matplotlib.pyplot as plt -__call__ = ["palplot", "puppyplot"] +__all__ = ["palplot"] def palplot(pal, size=1): @@ -27,23 +27,3 @@ 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 = ('') - return HTML(html) diff -Nru seaborn-0.7.1/seaborn/palettes.py seaborn-0.8.0/seaborn/palettes.py --- seaborn-0.7.1/seaborn/palettes.py 2016-06-05 02:22:35.000000000 +0000 +++ seaborn-0.8.0/seaborn/palettes.py 2017-07-08 22:40:57.000000000 +0000 @@ -59,7 +59,7 @@ 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 @@ 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 @@ 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 @@ >>> 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 @@ 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 -Nru seaborn-0.7.1/seaborn/rcmod.py seaborn-0.8.0/seaborn/rcmod.py --- seaborn-0.7.1/seaborn/rcmod.py 2016-06-05 02:22:35.000000000 +0000 +++ seaborn-0.8.0/seaborn/rcmod.py 2017-07-08 22:40:57.000000000 +0000 @@ -53,7 +53,6 @@ ) _context_keys = ( - "figure.figsize", "font.size", "axes.labelsize", @@ -186,9 +185,9 @@ "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 @@ # 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 @@ "xtick.major.pad": 7, "ytick.major.pad": 7, + } # Scale all the parameters by the same factor depending on the context diff -Nru seaborn-0.7.1/seaborn/regression.py seaborn-0.8.0/seaborn/regression.py --- seaborn-0.7.1/seaborn/regression.py 1970-01-01 00:00:00.000000000 +0000 +++ seaborn-0.8.0/seaborn/regression.py 2017-07-08 22:40:57.000000000 +0000 @@ -0,0 +1,1263 @@ +"""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, _facet_docs + + +__all__ = ["lmplot", "regplot", "residplot"] + + +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.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 + + 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] + 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 + + 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 given, 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", "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. If ``"sd"``, skip bootstrappig and show the standard + deviation of the observations in each bin.\ + """), + 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. + + 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 + + """ + 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 + + 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. + + """ + 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 + 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 diff -Nru seaborn-0.7.1/seaborn/tests/test_axisgrid.py seaborn-0.8.0/seaborn/tests/test_axisgrid.py --- seaborn-0.7.1/seaborn/tests/test_axisgrid.py 2016-06-05 02:22:35.000000000 +0000 +++ seaborn-0.8.0/seaborn/tests/test_axisgrid.py 2017-07-08 22:40:57.000000000 +0000 @@ -10,15 +10,17 @@ 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 @@ 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 @@ 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 @@ 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 @@ 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 @@ 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 @@ 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 @@ 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 @@ 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 -Nru seaborn-0.7.1/seaborn/tests/test_categorical.py seaborn-0.8.0/seaborn/tests/test_categorical.py --- seaborn-0.7.1/seaborn/tests/test_categorical.py 2016-06-05 02:22:35.000000000 +0000 +++ seaborn-0.8.0/seaborn/tests/test_categorical.py 2017-07-08 22:40:57.000000000 +0000 @@ -17,18 +17,19 @@ 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 @@ # 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 @@ # 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 @@ 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 @@ 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 @@ 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 @@ 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 @@ 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 @@ 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 @@ 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 @@ 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 @@ 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 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 @@ 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 @@ 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 @@ 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 @@ 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 @@ 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 @@ 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 @@ 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 @@ 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 @@ 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 @@ 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 @@ 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 @@ 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 @@ 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 @@ 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 @@ 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 @@ 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 @@ (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 @@ 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 @@ 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 -Nru seaborn-0.7.1/seaborn/tests/test_distributions.py seaborn-0.8.0/seaborn/tests/test_distributions.py --- seaborn-0.7.1/seaborn/tests/test_distributions.py 2016-06-05 02:22:35.000000000 +0000 +++ seaborn-0.8.0/seaborn/tests/test_distributions.py 2017-07-08 22:40:57.000000000 +0000 @@ -3,6 +3,7 @@ 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 @@ _no_statsmodels = True +_old_matplotlib = LooseVersion(mpl.__version__) < "1.5" + + class TestKDE(PlotTestCase): rs = np.random.RandomState(0) @@ -110,107 +114,12 @@ 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 -Nru seaborn-0.7.1/seaborn/tests/test_linearmodels.py seaborn-0.8.0/seaborn/tests/test_linearmodels.py --- seaborn-0.7.1/seaborn/tests/test_linearmodels.py 2016-06-05 02:22:35.000000000 +0000 +++ seaborn-0.8.0/seaborn/tests/test_linearmodels.py 1970-01-01 00:00:00.000000000 +0000 @@ -1,566 +0,0 @@ -import numpy as np -import matplotlib as mpl -import matplotlib.pyplot as plt -import pandas as pd - -import nose.tools as nt -import numpy.testing as npt -import pandas.util.testing as pdt -from numpy.testing.decorators import skipif -from nose import SkipTest - -try: - import statsmodels.regression.linear_model as smlm - _no_statsmodels = False -except ImportError: - _no_statsmodels = True - -from . import PlotTestCase -from .. import linearmodels as lm -from .. import algorithms as algo -from .. import utils -from ..palettes import color_palette - -rs = np.random.RandomState(0) - - -class TestLinearPlotter(PlotTestCase): - - rs = np.random.RandomState(77) - df = pd.DataFrame(dict(x=rs.normal(size=60), - d=rs.randint(-2, 3, 60), - y=rs.gamma(4, size=60), - s=np.tile(list("abcdefghij"), 6))) - df["z"] = df.y + rs.randn(60) - df["y_na"] = df.y.copy() - df.loc[[10, 20, 30], 'y_na'] = np.nan - - def test_establish_variables_from_frame(self): - - p = lm._LinearPlotter() - p.establish_variables(self.df, x="x", y="y") - pdt.assert_series_equal(p.x, self.df.x) - pdt.assert_series_equal(p.y, self.df.y) - pdt.assert_frame_equal(p.data, self.df) - - def test_establish_variables_from_series(self): - - p = lm._LinearPlotter() - p.establish_variables(None, x=self.df.x, y=self.df.y) - pdt.assert_series_equal(p.x, self.df.x) - pdt.assert_series_equal(p.y, self.df.y) - nt.assert_is(p.data, None) - - def test_establish_variables_from_array(self): - - p = lm._LinearPlotter() - p.establish_variables(None, - x=self.df.x.values, - y=self.df.y.values) - npt.assert_array_equal(p.x, self.df.x) - npt.assert_array_equal(p.y, self.df.y) - nt.assert_is(p.data, None) - - def test_establish_variables_from_mix(self): - - p = lm._LinearPlotter() - p.establish_variables(self.df, x="x", y=self.df.y) - pdt.assert_series_equal(p.x, self.df.x) - pdt.assert_series_equal(p.y, self.df.y) - pdt.assert_frame_equal(p.data, self.df) - - def test_establish_variables_from_bad(self): - - p = lm._LinearPlotter() - with nt.assert_raises(ValueError): - p.establish_variables(None, x="x", y=self.df.y) - - def test_dropna(self): - - p = lm._LinearPlotter() - p.establish_variables(self.df, x="x", y_na="y_na") - pdt.assert_series_equal(p.x, self.df.x) - pdt.assert_series_equal(p.y_na, self.df.y_na) - - p.dropna("x", "y_na") - mask = self.df.y_na.notnull() - pdt.assert_series_equal(p.x, self.df.x[mask]) - pdt.assert_series_equal(p.y_na, self.df.y_na[mask]) - - -class TestRegressionPlotter(PlotTestCase): - - rs = np.random.RandomState(49) - - grid = np.linspace(-3, 3, 30) - n_boot = 100 - bins_numeric = 3 - bins_given = [-1, 0, 1] - - df = pd.DataFrame(dict(x=rs.normal(size=60), - d=rs.randint(-2, 3, 60), - y=rs.gamma(4, size=60), - s=np.tile(list(range(6)), 10))) - df["z"] = df.y + rs.randn(60) - df["y_na"] = df.y.copy() - - bw_err = rs.randn(6)[df.s.values] * 2 - df.y += bw_err - - p = 1 / (1 + np.exp(-(df.x * 2 + rs.randn(60)))) - df["c"] = [rs.binomial(1, p_i) for p_i in p] - df.loc[[10, 20, 30], 'y_na'] = np.nan - - def test_variables_from_frame(self): - - p = lm._RegressionPlotter("x", "y", data=self.df, units="s") - - pdt.assert_series_equal(p.x, self.df.x) - pdt.assert_series_equal(p.y, self.df.y) - pdt.assert_series_equal(p.units, self.df.s) - pdt.assert_frame_equal(p.data, self.df) - - def test_variables_from_series(self): - - p = lm._RegressionPlotter(self.df.x, self.df.y, units=self.df.s) - - npt.assert_array_equal(p.x, self.df.x) - npt.assert_array_equal(p.y, self.df.y) - npt.assert_array_equal(p.units, self.df.s) - nt.assert_is(p.data, None) - - def test_variables_from_mix(self): - - p = lm._RegressionPlotter("x", self.df.y + 1, data=self.df) - - npt.assert_array_equal(p.x, self.df.x) - npt.assert_array_equal(p.y, self.df.y + 1) - pdt.assert_frame_equal(p.data, self.df) - - def test_dropna(self): - - p = lm._RegressionPlotter("x", "y_na", data=self.df) - nt.assert_equal(len(p.x), pd.notnull(self.df.y_na).sum()) - - p = lm._RegressionPlotter("x", "y_na", data=self.df, dropna=False) - nt.assert_equal(len(p.x), len(self.df.y_na)) - - def test_ci(self): - - p = lm._RegressionPlotter("x", "y", data=self.df, ci=95) - nt.assert_equal(p.ci, 95) - nt.assert_equal(p.x_ci, 95) - - p = lm._RegressionPlotter("x", "y", data=self.df, ci=95, x_ci=68) - nt.assert_equal(p.ci, 95) - nt.assert_equal(p.x_ci, 68) - - @skipif(_no_statsmodels) - def test_fast_regression(self): - - p = lm._RegressionPlotter("x", "y", data=self.df, n_boot=self.n_boot) - - # Fit with the "fast" function, which just does linear algebra - yhat_fast, _ = p.fit_fast(self.grid) - - # Fit using the statsmodels function with an OLS model - yhat_smod, _ = p.fit_statsmodels(self.grid, smlm.OLS) - - # Compare the vector of y_hat values - npt.assert_array_almost_equal(yhat_fast, yhat_smod) - - @skipif(_no_statsmodels) - def test_regress_poly(self): - - p = lm._RegressionPlotter("x", "y", data=self.df, n_boot=self.n_boot) - - # Fit an first-order polynomial - yhat_poly, _ = p.fit_poly(self.grid, 1) - - # Fit using the statsmodels function with an OLS model - yhat_smod, _ = p.fit_statsmodels(self.grid, smlm.OLS) - - # Compare the vector of y_hat values - npt.assert_array_almost_equal(yhat_poly, yhat_smod) - - def test_regress_logx(self): - - x = np.arange(1, 10) - y = np.arange(1, 10) - grid = np.linspace(1, 10, 100) - p = lm._RegressionPlotter(x, y, n_boot=self.n_boot) - - yhat_lin, _ = p.fit_fast(grid) - yhat_log, _ = p.fit_logx(grid) - - nt.assert_greater(yhat_lin[0], yhat_log[0]) - nt.assert_greater(yhat_log[20], yhat_lin[20]) - nt.assert_greater(yhat_lin[90], yhat_log[90]) - - @skipif(_no_statsmodels) - def test_regress_n_boot(self): - - p = lm._RegressionPlotter("x", "y", data=self.df, n_boot=self.n_boot) - - # Fast (linear algebra) version - _, boots_fast = p.fit_fast(self.grid) - npt.assert_equal(boots_fast.shape, (self.n_boot, self.grid.size)) - - # Slower (np.polyfit) version - _, boots_poly = p.fit_poly(self.grid, 1) - npt.assert_equal(boots_poly.shape, (self.n_boot, self.grid.size)) - - # Slowest (statsmodels) version - _, boots_smod = p.fit_statsmodels(self.grid, smlm.OLS) - npt.assert_equal(boots_smod.shape, (self.n_boot, self.grid.size)) - - @skipif(_no_statsmodels) - def test_regress_without_bootstrap(self): - - p = lm._RegressionPlotter("x", "y", data=self.df, - n_boot=self.n_boot, ci=None) - - # Fast (linear algebra) version - _, boots_fast = p.fit_fast(self.grid) - nt.assert_is(boots_fast, None) - - # Slower (np.polyfit) version - _, boots_poly = p.fit_poly(self.grid, 1) - nt.assert_is(boots_poly, None) - - # Slowest (statsmodels) version - _, boots_smod = p.fit_statsmodels(self.grid, smlm.OLS) - nt.assert_is(boots_smod, None) - - def test_numeric_bins(self): - - p = lm._RegressionPlotter(self.df.x, self.df.y) - x_binned, bins = p.bin_predictor(self.bins_numeric) - npt.assert_equal(len(bins), self.bins_numeric) - npt.assert_array_equal(np.unique(x_binned), bins) - - def test_provided_bins(self): - - p = lm._RegressionPlotter(self.df.x, self.df.y) - x_binned, bins = p.bin_predictor(self.bins_given) - npt.assert_array_equal(np.unique(x_binned), self.bins_given) - - def test_bin_results(self): - - p = lm._RegressionPlotter(self.df.x, self.df.y) - x_binned, bins = p.bin_predictor(self.bins_given) - nt.assert_greater(self.df.x[x_binned == 0].min(), - self.df.x[x_binned == -1].max()) - nt.assert_greater(self.df.x[x_binned == 1].min(), - self.df.x[x_binned == 0].max()) - - def test_scatter_data(self): - - p = lm._RegressionPlotter(self.df.x, self.df.y) - x, y = p.scatter_data - npt.assert_array_equal(x, self.df.x) - npt.assert_array_equal(y, self.df.y) - - p = lm._RegressionPlotter(self.df.d, self.df.y) - x, y = p.scatter_data - npt.assert_array_equal(x, self.df.d) - npt.assert_array_equal(y, self.df.y) - - p = lm._RegressionPlotter(self.df.d, self.df.y, x_jitter=.1) - x, y = p.scatter_data - nt.assert_true((x != self.df.d).any()) - npt.assert_array_less(np.abs(self.df.d - x), np.repeat(.1, len(x))) - npt.assert_array_equal(y, self.df.y) - - p = lm._RegressionPlotter(self.df.d, self.df.y, y_jitter=.05) - x, y = p.scatter_data - npt.assert_array_equal(x, self.df.d) - npt.assert_array_less(np.abs(self.df.y - y), np.repeat(.1, len(y))) - - def test_estimate_data(self): - - p = lm._RegressionPlotter(self.df.d, self.df.y, x_estimator=np.mean) - - x, y, ci = p.estimate_data - - npt.assert_array_equal(x, np.sort(np.unique(self.df.d))) - npt.assert_array_almost_equal(y, self.df.groupby("d").y.mean()) - npt.assert_array_less(np.array(ci)[:, 0], y) - npt.assert_array_less(y, np.array(ci)[:, 1]) - - def test_estimate_cis(self): - - # set known good seed to avoid the test stochastically failing - np.random.seed(123) - - p = lm._RegressionPlotter(self.df.d, self.df.y, - x_estimator=np.mean, ci=95) - _, _, ci_big = p.estimate_data - - p = lm._RegressionPlotter(self.df.d, self.df.y, - x_estimator=np.mean, ci=50) - _, _, ci_wee = p.estimate_data - npt.assert_array_less(np.diff(ci_wee), np.diff(ci_big)) - - p = lm._RegressionPlotter(self.df.d, self.df.y, - x_estimator=np.mean, ci=None) - _, _, ci_nil = p.estimate_data - npt.assert_array_equal(ci_nil, [None] * len(ci_nil)) - - def test_estimate_units(self): - - # Seed the RNG locally - np.random.seed(345) - - p = lm._RegressionPlotter("x", "y", data=self.df, - units="s", x_bins=3) - _, _, ci_big = p.estimate_data - ci_big = np.diff(ci_big, axis=1) - - p = lm._RegressionPlotter("x", "y", data=self.df, x_bins=3) - _, _, ci_wee = p.estimate_data - ci_wee = np.diff(ci_wee, axis=1) - - npt.assert_array_less(ci_wee, ci_big) - - def test_partial(self): - - x = self.rs.randn(100) - y = x + self.rs.randn(100) - z = x + self.rs.randn(100) - - p = lm._RegressionPlotter(y, z) - _, r_orig = np.corrcoef(p.x, p.y)[0] - - p = lm._RegressionPlotter(y, z, y_partial=x) - _, r_semipartial = np.corrcoef(p.x, p.y)[0] - nt.assert_less(r_semipartial, r_orig) - - p = lm._RegressionPlotter(y, z, x_partial=x, y_partial=x) - _, r_partial = np.corrcoef(p.x, p.y)[0] - nt.assert_less(r_partial, r_orig) - - @skipif(_no_statsmodels) - def test_logistic_regression(self): - - p = lm._RegressionPlotter("x", "c", data=self.df, - logistic=True, n_boot=self.n_boot) - _, yhat, _ = p.fit_regression(x_range=(-3, 3)) - npt.assert_array_less(yhat, 1) - npt.assert_array_less(0, yhat) - - @skipif(_no_statsmodels) - def test_robust_regression(self): - - p_ols = lm._RegressionPlotter("x", "y", data=self.df, - n_boot=self.n_boot) - _, ols_yhat, _ = p_ols.fit_regression(x_range=(-3, 3)) - - p_robust = lm._RegressionPlotter("x", "y", data=self.df, - robust=True, n_boot=self.n_boot) - _, robust_yhat, _ = p_robust.fit_regression(x_range=(-3, 3)) - - nt.assert_equal(len(ols_yhat), len(robust_yhat)) - - @skipif(_no_statsmodels) - def test_lowess_regression(self): - - p = lm._RegressionPlotter("x", "y", data=self.df, lowess=True) - grid, yhat, err_bands = p.fit_regression(x_range=(-3, 3)) - - nt.assert_equal(len(grid), len(yhat)) - nt.assert_is(err_bands, None) - - def test_regression_options(self): - - with nt.assert_raises(ValueError): - lm._RegressionPlotter("x", "y", data=self.df, - lowess=True, order=2) - - with nt.assert_raises(ValueError): - lm._RegressionPlotter("x", "y", data=self.df, - lowess=True, logistic=True) - - def test_regression_limits(self): - - f, ax = plt.subplots() - ax.scatter(self.df.x, self.df.y) - p = lm._RegressionPlotter("x", "y", data=self.df) - grid, _, _ = p.fit_regression(ax) - xlim = ax.get_xlim() - nt.assert_equal(grid.min(), xlim[0]) - nt.assert_equal(grid.max(), xlim[1]) - - p = lm._RegressionPlotter("x", "y", data=self.df, truncate=True) - grid, _, _ = p.fit_regression() - nt.assert_equal(grid.min(), self.df.x.min()) - nt.assert_equal(grid.max(), self.df.x.max()) - - -class TestRegressionPlots(PlotTestCase): - - rs = np.random.RandomState(56) - df = pd.DataFrame(dict(x=rs.randn(90), - y=rs.randn(90) + 5, - z=rs.randint(0, 1, 90), - g=np.repeat(list("abc"), 30), - h=np.tile(list("xy"), 45), - u=np.tile(np.arange(6), 15))) - bw_err = rs.randn(6)[df.u.values] - df.y += bw_err - - def test_regplot_basic(self): - - f, ax = plt.subplots() - lm.regplot("x", "y", self.df) - nt.assert_equal(len(ax.lines), 1) - nt.assert_equal(len(ax.collections), 2) - - x, y = ax.collections[0].get_offsets().T - npt.assert_array_equal(x, self.df.x) - npt.assert_array_equal(y, self.df.y) - - def test_regplot_selective(self): - - f, ax = plt.subplots() - ax = lm.regplot("x", "y", self.df, scatter=False, ax=ax) - nt.assert_equal(len(ax.lines), 1) - nt.assert_equal(len(ax.collections), 1) - ax.clear() - - f, ax = plt.subplots() - ax = lm.regplot("x", "y", self.df, fit_reg=False) - nt.assert_equal(len(ax.lines), 0) - nt.assert_equal(len(ax.collections), 1) - ax.clear() - - f, ax = plt.subplots() - ax = lm.regplot("x", "y", self.df, ci=None) - nt.assert_equal(len(ax.lines), 1) - nt.assert_equal(len(ax.collections), 1) - ax.clear() - - def test_regplot_scatter_kws_alpha(self): - - f, ax = plt.subplots() - color = np.array([[0.3, 0.8, 0.5, 0.5]]) - ax = lm.regplot("x", "y", self.df, scatter_kws={'color': color}) - nt.assert_is(ax.collections[0]._alpha, None) - nt.assert_equal(ax.collections[0]._facecolors[0, 3], 0.5) - - f, ax = plt.subplots() - color = np.array([[0.3, 0.8, 0.5]]) - ax = lm.regplot("x", "y", self.df, scatter_kws={'color': color}) - nt.assert_equal(ax.collections[0]._alpha, 0.8) - - f, ax = plt.subplots() - color = np.array([[0.3, 0.8, 0.5]]) - ax = lm.regplot("x", "y", self.df, scatter_kws={'color': color, - 'alpha': 0.4}) - nt.assert_equal(ax.collections[0]._alpha, 0.4) - - f, ax = plt.subplots() - color = 'r' - ax = lm.regplot("x", "y", self.df, scatter_kws={'color': color}) - nt.assert_equal(ax.collections[0]._alpha, 0.8) - - def test_regplot_binned(self): - - ax = lm.regplot("x", "y", self.df, x_bins=5) - nt.assert_equal(len(ax.lines), 6) - nt.assert_equal(len(ax.collections), 2) - - def test_lmplot_basic(self): - - g = lm.lmplot("x", "y", self.df) - ax = g.axes[0, 0] - nt.assert_equal(len(ax.lines), 1) - nt.assert_equal(len(ax.collections), 2) - - x, y = ax.collections[0].get_offsets().T - npt.assert_array_equal(x, self.df.x) - npt.assert_array_equal(y, self.df.y) - - def test_lmplot_hue(self): - - g = lm.lmplot("x", "y", data=self.df, hue="h") - ax = g.axes[0, 0] - - nt.assert_equal(len(ax.lines), 2) - nt.assert_equal(len(ax.collections), 4) - - def test_lmplot_markers(self): - - g1 = lm.lmplot("x", "y", data=self.df, hue="h", markers="s") - nt.assert_equal(g1.hue_kws, {"marker": ["s", "s"]}) - - g2 = lm.lmplot("x", "y", data=self.df, hue="h", markers=["o", "s"]) - nt.assert_equal(g2.hue_kws, {"marker": ["o", "s"]}) - - with nt.assert_raises(ValueError): - lm.lmplot("x", "y", data=self.df, hue="h", markers=["o", "s", "d"]) - - def test_lmplot_marker_linewidths(self): - - if mpl.__version__ == "1.4.2": - raise SkipTest - - g = lm.lmplot("x", "y", data=self.df, hue="h", - fit_reg=False, markers=["o", "+"]) - c = g.axes[0, 0].collections - nt.assert_equal(c[0].get_linewidths()[0], 0) - rclw = mpl.rcParams["lines.linewidth"] - nt.assert_equal(c[1].get_linewidths()[0], rclw) - - def test_lmplot_facets(self): - - g = lm.lmplot("x", "y", data=self.df, row="g", col="h") - nt.assert_equal(g.axes.shape, (3, 2)) - - g = lm.lmplot("x", "y", data=self.df, col="u", col_wrap=4) - nt.assert_equal(g.axes.shape, (6,)) - - g = lm.lmplot("x", "y", data=self.df, hue="h", col="u") - nt.assert_equal(g.axes.shape, (1, 6)) - - def test_lmplot_hue_col_nolegend(self): - - g = lm.lmplot("x", "y", data=self.df, col="h", hue="h") - nt.assert_is(g._legend, None) - - def test_lmplot_scatter_kws(self): - - g = lm.lmplot("x", "y", hue="h", data=self.df, ci=None) - red_scatter, blue_scatter = g.axes[0, 0].collections - - red, blue = color_palette(n_colors=2) - npt.assert_array_equal(red, red_scatter.get_facecolors()[0, :3]) - npt.assert_array_equal(blue, blue_scatter.get_facecolors()[0, :3]) - - def test_residplot(self): - - x, y = self.df.x, self.df.y - ax = lm.residplot(x, y) - - resid = y - np.polyval(np.polyfit(x, y, 1), x) - x_plot, y_plot = ax.collections[0].get_offsets().T - - npt.assert_array_equal(x, x_plot) - npt.assert_array_almost_equal(resid, y_plot) - - @skipif(_no_statsmodels) - def test_residplot_lowess(self): - - ax = lm.residplot("x", "y", self.df, lowess=True) - nt.assert_equal(len(ax.lines), 2) - - x, y = ax.lines[1].get_xydata().T - npt.assert_array_equal(x, np.sort(self.df.x)) - - def test_three_point_colors(self): - - x, y = np.random.randn(2, 3) - ax = lm.regplot(x, y, color=(1, 0, 0)) - color = ax.collections[0].get_facecolors() - npt.assert_almost_equal(color[0, :3], - (1, 0, 0)) diff -Nru seaborn-0.7.1/seaborn/tests/test_matrix.py seaborn-0.8.0/seaborn/tests/test_matrix.py --- seaborn-0.7.1/seaborn/tests/test_matrix.py 2016-06-05 02:22:35.000000000 +0000 +++ seaborn-0.8.0/seaborn/tests/test_matrix.py 2017-07-08 22:40:57.000000000 +0000 @@ -10,7 +10,10 @@ 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 @@ 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 @@ 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 @@ 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 @@ 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 @@ 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 @@ 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 @@ 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 @@ 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 @@ 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 @@ 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 @@ 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 @@ 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 @@ 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 @@ 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 @@ ytl_actual = [t.get_text() for t in g.ax_heatmap.get_yticklabels()] xtl_want = xtl[g.dendrogram_col.reordered_ind].astype(" 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, + n_boot=self.n_boot) + _, ols_yhat, _ = p_ols.fit_regression(x_range=(-3, 3)) + + p_robust = lm._RegressionPlotter("x", "y", data=self.df, + robust=True, n_boot=self.n_boot) + _, robust_yhat, _ = p_robust.fit_regression(x_range=(-3, 3)) + + nt.assert_equal(len(ols_yhat), len(robust_yhat)) + + @skipif(_no_statsmodels) + def test_lowess_regression(self): + + p = lm._RegressionPlotter("x", "y", data=self.df, lowess=True) + grid, yhat, err_bands = p.fit_regression(x_range=(-3, 3)) + + nt.assert_equal(len(grid), len(yhat)) + nt.assert_is(err_bands, None) + + def test_regression_options(self): + + with nt.assert_raises(ValueError): + lm._RegressionPlotter("x", "y", data=self.df, + lowess=True, order=2) + + with nt.assert_raises(ValueError): + lm._RegressionPlotter("x", "y", data=self.df, + lowess=True, logistic=True) + + def test_regression_limits(self): + + f, ax = plt.subplots() + ax.scatter(self.df.x, self.df.y) + p = lm._RegressionPlotter("x", "y", data=self.df) + grid, _, _ = p.fit_regression(ax) + xlim = ax.get_xlim() + nt.assert_equal(grid.min(), xlim[0]) + nt.assert_equal(grid.max(), xlim[1]) + + p = lm._RegressionPlotter("x", "y", data=self.df, truncate=True) + grid, _, _ = p.fit_regression() + nt.assert_equal(grid.min(), self.df.x.min()) + nt.assert_equal(grid.max(), self.df.x.max()) + + +class TestRegressionPlots(PlotTestCase): + + rs = np.random.RandomState(56) + df = pd.DataFrame(dict(x=rs.randn(90), + y=rs.randn(90) + 5, + z=rs.randint(0, 1, 90), + g=np.repeat(list("abc"), 30), + h=np.tile(list("xy"), 45), + u=np.tile(np.arange(6), 15))) + bw_err = rs.randn(6)[df.u.values] + df.y += bw_err + + def test_regplot_basic(self): + + f, ax = plt.subplots() + lm.regplot("x", "y", self.df) + nt.assert_equal(len(ax.lines), 1) + nt.assert_equal(len(ax.collections), 2) + + x, y = ax.collections[0].get_offsets().T + npt.assert_array_equal(x, self.df.x) + npt.assert_array_equal(y, self.df.y) + + def test_regplot_selective(self): + + f, ax = plt.subplots() + ax = lm.regplot("x", "y", self.df, scatter=False, ax=ax) + nt.assert_equal(len(ax.lines), 1) + nt.assert_equal(len(ax.collections), 1) + ax.clear() + + f, ax = plt.subplots() + ax = lm.regplot("x", "y", self.df, fit_reg=False) + nt.assert_equal(len(ax.lines), 0) + nt.assert_equal(len(ax.collections), 1) + ax.clear() + + f, ax = plt.subplots() + ax = lm.regplot("x", "y", self.df, ci=None) + nt.assert_equal(len(ax.lines), 1) + nt.assert_equal(len(ax.collections), 1) + ax.clear() + + def test_regplot_scatter_kws_alpha(self): + + f, ax = plt.subplots() + color = np.array([[0.3, 0.8, 0.5, 0.5]]) + ax = lm.regplot("x", "y", self.df, scatter_kws={'color': color}) + nt.assert_is(ax.collections[0]._alpha, None) + nt.assert_equal(ax.collections[0]._facecolors[0, 3], 0.5) + + f, ax = plt.subplots() + color = np.array([[0.3, 0.8, 0.5]]) + ax = lm.regplot("x", "y", self.df, scatter_kws={'color': color}) + nt.assert_equal(ax.collections[0]._alpha, 0.8) + + f, ax = plt.subplots() + color = np.array([[0.3, 0.8, 0.5]]) + ax = lm.regplot("x", "y", self.df, scatter_kws={'color': color, + 'alpha': 0.4}) + nt.assert_equal(ax.collections[0]._alpha, 0.4) + + f, ax = plt.subplots() + color = 'r' + ax = lm.regplot("x", "y", self.df, scatter_kws={'color': color}) + nt.assert_equal(ax.collections[0]._alpha, 0.8) + + def test_regplot_binned(self): + + ax = lm.regplot("x", "y", self.df, x_bins=5) + nt.assert_equal(len(ax.lines), 6) + nt.assert_equal(len(ax.collections), 2) + + def test_lmplot_basic(self): + + g = lm.lmplot("x", "y", self.df) + ax = g.axes[0, 0] + nt.assert_equal(len(ax.lines), 1) + nt.assert_equal(len(ax.collections), 2) + + x, y = ax.collections[0].get_offsets().T + npt.assert_array_equal(x, self.df.x) + npt.assert_array_equal(y, self.df.y) + + def test_lmplot_hue(self): + + g = lm.lmplot("x", "y", data=self.df, hue="h") + ax = g.axes[0, 0] + + nt.assert_equal(len(ax.lines), 2) + nt.assert_equal(len(ax.collections), 4) + + def test_lmplot_markers(self): + + g1 = lm.lmplot("x", "y", data=self.df, hue="h", markers="s") + nt.assert_equal(g1.hue_kws, {"marker": ["s", "s"]}) + + g2 = lm.lmplot("x", "y", data=self.df, hue="h", markers=["o", "s"]) + nt.assert_equal(g2.hue_kws, {"marker": ["o", "s"]}) + + with nt.assert_raises(ValueError): + lm.lmplot("x", "y", data=self.df, hue="h", markers=["o", "s", "d"]) + + def test_lmplot_marker_linewidths(self): + + if mpl.__version__ == "1.4.2": + raise SkipTest + + g = lm.lmplot("x", "y", data=self.df, hue="h", + fit_reg=False, markers=["o", "+"]) + c = g.axes[0, 0].collections + nt.assert_equal(c[0].get_linewidths()[0], 0) + rclw = mpl.rcParams["lines.linewidth"] + nt.assert_equal(c[1].get_linewidths()[0], rclw) + + def test_lmplot_facets(self): + + g = lm.lmplot("x", "y", data=self.df, row="g", col="h") + nt.assert_equal(g.axes.shape, (3, 2)) + + g = lm.lmplot("x", "y", data=self.df, col="u", col_wrap=4) + nt.assert_equal(g.axes.shape, (6,)) + + g = lm.lmplot("x", "y", data=self.df, hue="h", col="u") + nt.assert_equal(g.axes.shape, (1, 6)) + + def test_lmplot_hue_col_nolegend(self): + + g = lm.lmplot("x", "y", data=self.df, col="h", hue="h") + nt.assert_is(g._legend, None) + + def test_lmplot_scatter_kws(self): + + g = lm.lmplot("x", "y", hue="h", data=self.df, ci=None) + red_scatter, blue_scatter = g.axes[0, 0].collections + + red, blue = color_palette(n_colors=2) + npt.assert_array_equal(red, red_scatter.get_facecolors()[0, :3]) + npt.assert_array_equal(blue, blue_scatter.get_facecolors()[0, :3]) + + def test_residplot(self): + + x, y = self.df.x, self.df.y + ax = lm.residplot(x, y) + + resid = y - np.polyval(np.polyfit(x, y, 1), x) + x_plot, y_plot = ax.collections[0].get_offsets().T + + npt.assert_array_equal(x, x_plot) + npt.assert_array_almost_equal(resid, y_plot) + + @skipif(_no_statsmodels) + def test_residplot_lowess(self): + + ax = lm.residplot("x", "y", self.df, lowess=True) + nt.assert_equal(len(ax.lines), 2) + + x, y = ax.lines[1].get_xydata().T + npt.assert_array_equal(x, np.sort(self.df.x)) + + def test_three_point_colors(self): + + x, y = np.random.randn(2, 3) + ax = lm.regplot(x, y, color=(1, 0, 0)) + color = ax.collections[0].get_facecolors() + npt.assert_almost_equal(color[0, :3], + (1, 0, 0)) diff -Nru seaborn-0.7.1/seaborn/tests/test_utils.py seaborn-0.8.0/seaborn/tests/test_utils.py --- seaborn-0.7.1/seaborn/tests/test_utils.py 2016-06-05 02:22:35.000000000 +0000 +++ seaborn-0.8.0/seaborn/tests/test_utils.py 2017-07-08 22:40:57.000000000 +0000 @@ -11,12 +11,14 @@ 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 @@ 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 @@ 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 @@ 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 @@ 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 @@ 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 @@ # 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 -Nru seaborn-0.7.1/seaborn/timeseries.py seaborn-0.8.0/seaborn/timeseries.py --- seaborn-0.7.1/seaborn/timeseries.py 2016-06-05 02:22:35.000000000 +0000 +++ seaborn-0.8.0/seaborn/timeseries.py 2017-07-08 22:40:57.000000000 +0000 @@ -6,6 +6,8 @@ import matplotlib as mpl import matplotlib.pyplot as plt +import warnings + from .external.six import string_types from . import utils @@ -61,10 +63,11 @@ 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 @@ >>> 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 @@ >>> 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 @@ # 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 @@ 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 @@ 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 -Nru seaborn-0.7.1/seaborn/utils.py seaborn-0.8.0/seaborn/utils.py --- seaborn-0.7.1/seaborn/utils.py 2016-06-05 02:22:35.000000000 +0000 +++ seaborn-0.8.0/seaborn/utils.py 2017-07-08 22:40:57.000000000 +0000 @@ -15,6 +15,7 @@ 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 @@ 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 @@ 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 @@ 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 @@ 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 @@ 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 -Nru seaborn-0.7.1/seaborn/widgets.py seaborn-0.8.0/seaborn/widgets.py --- seaborn-0.7.1/seaborn/widgets.py 2016-06-05 02:22:35.000000000 +0000 +++ seaborn-0.8.0/seaborn/widgets.py 2017-07-08 22:40:57.000000000 +0000 @@ -7,15 +7,21 @@ 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 -Nru seaborn-0.7.1/setup.py seaborn-0.8.0/setup.py --- seaborn-0.7.1/setup.py 2016-06-05 02:22:35.000000000 +0000 +++ seaborn-0.8.0/setup.py 2017-07-08 22:40:57.000000000 +0000 @@ -1,6 +1,6 @@ #! /usr/bin/env python # -# Copyright (C) 2012-2014 Michael Waskom +# 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 @@ DISTNAME = 'seaborn' MAINTAINER = 'Michael Waskom' MAINTAINER_EMAIL = 'mwaskom@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 diff -Nru seaborn-0.7.1/.travis.yml seaborn-0.8.0/.travis.yml --- seaborn-0.7.1/.travis.yml 2016-06-05 02:22:35.000000000 +0000 +++ seaborn-0.8.0/.travis.yml 2017-07-08 22:40:57.000000000 +0000 @@ -4,21 +4,14 @@ - 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 @@ - 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;