diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..8a85a0f --- /dev/null +++ b/.gitignore @@ -0,0 +1,3 @@ +*.pyc +*.swp +.ipynb_checkpoints diff --git a/AnatomyOfMatplotlib-Part0-Intro2NumPy.ipynb b/AnatomyOfMatplotlib-Part0-Intro2NumPy.ipynb index c146d40..b2ff673 100644 --- a/AnatomyOfMatplotlib-Part0-Intro2NumPy.ipynb +++ b/AnatomyOfMatplotlib-Part0-Intro2NumPy.ipynb @@ -1,260 +1,297 @@ { - "metadata": { - "name": "", - "signature": "sha256:90ccb5909624353434d7af8f1073a89ba8f8f43775a430cf536d07701670eb19" - }, - "nbformat": 3, - "nbformat_minor": 0, - "worksheets": [ + "cells": [ + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "# Let printing work the same in Python 2 and 3\n", + "from __future__ import print_function" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# NumPy\n", + "The NumPy package provides the \"ndarray\" object. The NumPy array is used to contain data of uniform type with an arbitrary number of dimensions. NumPy then provides basic mathematical and array methods to lay down the foundation for the entire SciPy ecosystem. The following import statement is the generally accepted convention for NumPy." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "import numpy as np" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Array Creation\n", + "There are several ways to make NumPy arrays. An array has three particular attributes that can be queried: shape, size and the number of dimensions." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "a = np.array([1, 2, 3])\n", + "print(a.shape)\n", + "print(a.size)\n", + "print(a.ndim)" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "x = np.arange(100)\n", + "print(x.shape)\n", + "print(x.size)\n", + "print(x.ndim)" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "y = np.random.rand(5, 80)\n", + "print(y.shape)\n", + "print(y.size)\n", + "print(y.ndim)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Array Manipulation\n", + "How to change the shape of an array without a copy!" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "x.shape = (20, 5)\n", + "print(x)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "NumPy can even automatically figure out the size of at most one dimension for you." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "y.shape = (4, 20, -1)\n", + "print(y.shape)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Array Indexing" + ] + }, { - "cells": [ - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "# NumPy\n", - "The NumPy package provides the \"ndarray\" object. The NumPy array is used to contain data of uniform type with an arbitrary number of dimensions. NumPy then provides basic mathematical and array methods to lay down the foundation for the entire SciPy ecosystem. The following import statement is the generally accepted convention for NumPy." - ] - }, - { - "cell_type": "code", - "collapsed": false, - "input": [ - "import numpy as np" - ], - "language": "python", - "metadata": {}, - "outputs": [] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "## Array Creation\n", - "There are several ways to make NumPy arrays. An array has three particular attributes that can be queried: shape, size and the number of dimensions." - ] - }, - { - "cell_type": "code", - "collapsed": false, - "input": [ - "a = np.array([1, 2, 3])\n", - "print a.shape\n", - "print a.size\n", - "print a.ndim" - ], - "language": "python", - "metadata": {}, - "outputs": [] - }, - { - "cell_type": "code", - "collapsed": false, - "input": [ - "x = np.arange(100)\n", - "print x.shape\n", - "print x.size\n", - "print x.ndim" - ], - "language": "python", - "metadata": {}, - "outputs": [] - }, - { - "cell_type": "code", - "collapsed": false, - "input": [ - "y = np.random.rand(5, 80)\n", - "print y.shape\n", - "print y.size\n", - "print y.ndim" - ], - "language": "python", - "metadata": {}, - "outputs": [] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "## Array Manipulation\n", - "How to change the shape of an array without a copy!" - ] - }, - { - "cell_type": "code", - "collapsed": false, - "input": [ - "x.shape = (20, 5)\n", - "print x" - ], - "language": "python", - "metadata": {}, - "outputs": [] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "NumPy can even automatically figure out the size of at most one dimension for you." - ] - }, - { - "cell_type": "code", - "collapsed": false, - "input": [ - "y.shape = (4, 20, -1)\n", - "print y.shape" - ], - "language": "python", - "metadata": {}, - "outputs": [] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "## Array Indexing" - ] - }, - { - "cell_type": "code", - "collapsed": false, - "input": [ - "# Scalar Indexing\n", - "print x[2]" - ], - "language": "python", - "metadata": {}, - "outputs": [] - }, - { - "cell_type": "code", - "collapsed": false, - "input": [ - "# Slicing\n", - "print x[2:5]" - ], - "language": "python", - "metadata": {}, - "outputs": [] - }, - { - "cell_type": "code", - "collapsed": false, - "input": [ - "# Advanced slicing\n", - "print \"First 5 rows\\n\", x[:5]\n", - "print \"Row 18 to the end\\n\", x[18:]\n", - "print \"Last 5 rows\\n\", x[-5:]\n", - "print \"Reverse the rows\\n\", x[::-1]" - ], - "language": "python", - "metadata": {}, - "outputs": [] - }, - { - "cell_type": "code", - "collapsed": false, - "input": [ - "# Boolean Indexing\n", - "print x[(x % 2) == 0]" - ], - "language": "python", - "metadata": {}, - "outputs": [] - }, - { - "cell_type": "code", - "collapsed": false, - "input": [ - "# Fancy Indexing -- Note the use of a list, not tuple!\n", - "print x[[1, 3, 8, 9, 2]]" - ], - "language": "python", - "metadata": {}, - "outputs": [] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "## Broadcasting\n", - "Broadcasting is a very useful feature of NumPy that will let arrays with differing shapes still be used together. In most cases, broadcasting is faster, and it is more memory efficient than the equivalent full array operation." - ] - }, - { - "cell_type": "code", - "collapsed": true, - "input": [ - "print \"Shape of X:\", x.shape\n", - "print \"Shape of Y:\", y.shape" - ], - "language": "python", - "metadata": {}, - "outputs": [] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "Now, here are three identical assignments. The first one takes full advantage of broadcasting by allowing NumPy to automatically add a new dimension to the *left*. The second explicitly adds that dimension with the special NumPy alias \"np.newaxis\". These first two creates a singleton dimension without any new arrays being created. That singleton dimension is then implicitly tiled, much like the third example to match with the RHS of the addition operator. However, unlike the third example, the broadcasting merely re-uses the existing data in memory." - ] - }, - { - "cell_type": "code", - "collapsed": false, - "input": [ - "a = x + y\n", - "print a.shape\n", - "b = x[np.newaxis, :, :] + y\n", - "print b.shape\n", - "c = np.tile(x, (4, 1, 1)) + y\n", - "print c.shape\n", - "print \"Are a and b identical?\", np.all(a == b)\n", - "print \"Are a and c identical?\", np.all(a == c)" - ], - "language": "python", - "metadata": {}, - "outputs": [] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "Another example of broadcasting two 1-D arrays to make a 2-D array." - ] - }, - { - "cell_type": "code", - "collapsed": false, - "input": [ - "x = np.arange(-5, 5, 0.1)\n", - "y = np.arange(-8, 8, 0.25)\n", - "print x.shape, y.shape\n", - "z = x[np.newaxis, :] * y[:, np.newaxis]\n", - "print z.shape" - ], - "language": "python", - "metadata": {}, - "outputs": [] - }, - { - "cell_type": "code", - "collapsed": false, - "input": [ - "# More concisely\n", - "y, x = np.ogrid[-8:8:0.25, -5:5:0.1]\n", - "print x.shape, y.shape\n", - "z = x * y\n", - "print z.shape" - ], - "language": "python", - "metadata": {}, - "outputs": [] - } - ], - "metadata": {} + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "# Scalar Indexing\n", + "print(x[2])" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "# Slicing\n", + "print(x[2:5])" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "# Advanced slicing\n", + "print(\"First 5 rows\\n\", x[:5])\n", + "print(\"Row 18 to the end\\n\", x[18:])\n", + "print(\"Last 5 rows\\n\", x[-5:])\n", + "print(\"Reverse the rows\\n\", x[::-1])" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "# Boolean Indexing\n", + "print(x[(x % 2) == 0])" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "# Fancy Indexing -- Note the use of a list, not tuple!\n", + "print(x[[1, 3, 8, 9, 2]])" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Broadcasting\n", + "Broadcasting is a very useful feature of NumPy that will let arrays with differing shapes still be used together. In most cases, broadcasting is faster, and it is more memory efficient than the equivalent full array operation." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": true + }, + "outputs": [], + "source": [ + "print(\"Shape of X:\", x.shape)\n", + "print(\"Shape of Y:\", y.shape)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Now, here are three identical assignments. The first one takes full advantage of broadcasting by allowing NumPy to automatically add a new dimension to the *left*. The second explicitly adds that dimension with the special NumPy alias \"np.newaxis\". These first two creates a singleton dimension without any new arrays being created. That singleton dimension is then implicitly tiled, much like the third example to match with the RHS of the addition operator. However, unlike the third example, the broadcasting merely re-uses the existing data in memory." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "a = x + y\n", + "print(a.shape)\n", + "b = x[np.newaxis, :, :] + y\n", + "print(b.shape)\n", + "c = np.tile(x, (4, 1, 1)) + y\n", + "print(c.shape)\n", + "print(\"Are a and b identical?\", np.all(a == b))\n", + "print(\"Are a and c identical?\", np.all(a == c))" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Another example of broadcasting two 1-D arrays to make a 2-D array." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "x = np.arange(-5, 5, 0.1)\n", + "y = np.arange(-8, 8, 0.25)\n", + "print(x.shape, y.shape)\n", + "z = x[np.newaxis, :] * y[:, np.newaxis]\n", + "print(z.shape)" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "# More concisely\n", + "y, x = np.ogrid[-8:8:0.25, -5:5:0.1]\n", + "print(x.shape, y.shape)\n", + "z = x * y\n", + "print(z.shape)" + ] } - ] -} \ No newline at end of file + ], + "metadata": { + "kernelspec": { + "display_name": "Python 2", + "language": "python", + "name": "python2" + }, + "language_info": { + "codemirror_mode": { + "name": "ipython", + "version": 2 + }, + "file_extension": ".py", + "mimetype": "text/x-python", + "name": "python", + "nbconvert_exporter": "python", + "pygments_lexer": "ipython2", + "version": "2.7.12" + } + }, + "nbformat": 4, + "nbformat_minor": 0 +} diff --git a/AnatomyOfMatplotlib-Part1-Figures_Subplots_and_layouts.ipynb b/AnatomyOfMatplotlib-Part1-Figures_Subplots_and_layouts.ipynb new file mode 100644 index 0000000..bece646 --- /dev/null +++ b/AnatomyOfMatplotlib-Part1-Figures_Subplots_and_layouts.ipynb @@ -0,0 +1,483 @@ +{ + "cells": [ + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": false, + "slideshow": { + "slide_type": "-" + } + }, + "outputs": [], + "source": [ + "# Let printing work the same in Python 2 and 3\n", + "from __future__ import print_function" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "slideshow": { + "slide_type": "-" + } + }, + "source": [ + "# Matplotlib\n", + "## Introduction\n", + "\n", + "Matplotlib is a library for producing publication-quality figures. mpl (for short) was designed from the beginning to serve two purposes: \n", + "\n", + " 1. allow for interactive, cross-platform control of figures and plots\n", + " 2. make it easy to produce static raster or vector graphics files without the need for any GUIs. \n", + " \n", + "Furthermore, mpl -- much like Python itself -- gives the developer complete control over the appearance of their plots, while still being very usable through a powerful defaults system." + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Online Documentation\n", + "The [matplotlib.org](http://matplotlib.org) project website is the primary online resource for the library's documentation. It contains the [example galleries](https://matplotlib.org/gallery/index.html), [FAQs](http://matplotlib.org/faq/index.html), [API documentation](http://matplotlib.org/api/index.html), and [tutorials](https://matplotlib.org/tutorials/index.html).\n", + "\n", + "## Gallery\n", + "Many users of Matplotlib are often faced with the question, \"I want to make a figure that has X with Y in the same figure, but it needs to look like Z\". Good luck getting an answer from a web search with that query! This is why the [gallery](https://matplotlib.org/gallery/index.html) is so useful, because it showcases the variety of ways one can make figures. Browse through the gallery, click on any figure that has pieces of what you want to see and the code that generated it. Soon enough, you will be like a chef, mixing and matching components to produce your masterpiece!\n", + "\n", + "As always, if you have a new and interesting plot that demonstrates a feature of Matplotlib, feel free to submit a concise, well-commented version of the code for inclusion in the gallery.\n", + "\n", + "## Mailing Lists, StackOverflow, and gitter\n", + "When you are just simply stuck, and cannot figure out how to get something to work, or just need some hints on how to get started, you will find much of the community at the matplotlib-users [mailing list](https://mail.python.org/mailman/listinfo/matplotlib-users). This mailing list is an excellent resource of information with many friendly members who just love to help out newcomers. We love plots, so an image showing what is wrong often gets the quickest responses.\n", + "\n", + "Another community resource is [StackOverflow](http://stackoverflow.com/questions/tagged/matplotlib), so if you need to build up karma points, submit your questions here, and help others out too! \n", + "\n", + "We are also on [Gitter](https://gitter.im/matplotlib/matplotlib).\n", + "\n", + "## Github repository\n", + "### Location\n", + "[Matplotlib](https://github.com/matplotlib) is hosted by GitHub.\n", + "\n", + "### Bug Reports and feature requests\n", + "So, you think you found a bug? Or maybe you think some feature is just too difficult to use? Or missing altogether? Submit your bug reports [here](https://github.com/matplotlib/matplotlib/issues) at Matplotlib's issue tracker. We even have a process for submitting and discussing Matplotlib Enhancement Proposals ([MEPs](https://matplotlib.org/devel/MEP/index.html))." + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# Quick note on \"backends\" and Jupyter notebooks\n", + "\n", + "Matplotlib has multiple \"backends\" that handle converting Matplotlib's in-memory representation of your plot into the colorful output you can look at. This is done either by writing files (e.g., png, svg, pdf) that you can use an external tool to look at or by embedding into your GUI toolkit of choice (Qt, Tk, Wx, etc).\n", + "\n", + "To check what backend Matplotlib is currently using:" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "import matplotlib\n", + "print(matplotlib.__version__)\n", + "print(matplotlib.get_backend())" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "If you are working interactively at an (I)python prompt, the GUI framework is not critical (mostly aesthetic) however when working in Jupyter we need to pick a backend that integrates with Jupyter (javascript) framework.\n", + "\n", + "To select the backend use ``matplotlib.use(\"backend_name\")``, in this case we want ``'nbagg'``\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "matplotlib.use('nbagg')\n", + "print(matplotlib.get_backend())" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "which must be done *before* you `import matplotlib.pyplot as plt`.\n", + "\n", + "You can also set the backend via an 'ipython magic' ``%matplotlib backend_name``. In addition to setting the backend, the magic also calls `plt.ion()`, which puts Matplotlib in 'interacitve mode' (the inverse is `plt.ioff()`). In 'interactive mode' figures are shown (injected into the web page in the notebook) as soon as they are created. Otherwise, figures are not shown until you explicitly call `plt.show()`.\n", + "\n", + "\n", + "In these tutorials we will mostly work in non-interactive mode for better control of when\n", + "figures are shown in the notebooks.\n", + "This also better mimics the behavior you can expect in regular python scripts.\n" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# On with the show!\n", + "Matplotlib is a large project and can seem daunting at first. However, by learning the components, it should begin to feel much smaller and more approachable.\n", + "\n", + "## Anatomy of a \"Plot\"\n", + "\n", + "People use \"plot\" to mean many different things. Here, we'll be using a consistent terminology (mirrored by the names of the underlying classes, etc):\n", + "\n", + "\n", + "\n", + "The ``Figure`` is the top-level container in this hierarchy. It is the overall window/page that everything is drawn on. You can have multiple independent figures and ``Figure``s can contain multiple ``Axes``. \n", + "\n", + "Most plotting ocurs on an ``Axes``. The axes is effectively the area that we plot data on and any ticks/labels/etc associated with it. Usually we'll set up an Axes with a call to ``subplot`` (which places Axes on a regular grid), so in most cases, ``Axes`` and ``Subplot`` are synonymous.\n", + "\n", + "Each ``Axes`` has an ``XAxis`` and a ``YAxis``. These contain the ticks, tick locations, labels, etc. In this tutorial, we'll mostly control ticks, tick labels, and data limits through other mechanisms, so we won't touch the individual ``Axis`` part of things all that much. However, it is worth mentioning here to explain where the term ``Axes`` comes from.\n" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Getting Started\n", + "\n", + "In this tutorial, we'll use the following import statements. These abbreviations are semi-standardized, and most tutorials, other scientific python code that you'll find elsewhere will use them as well." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "import numpy as np\n", + "import matplotlib.pyplot as plt" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### Figures\n", + "\n", + "Now let's create a figure..." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "fig = plt.figure(facecolor=(1, 0, 0, .1)) # red background to see where the figure is" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Awww, nothing happened! This is because by default mpl will not show anything until told to do so, as we mentioned earlier in the \"backend\" discussion.\n", + "\n", + "Instead, we'll need to call ``plt.show()``" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "plt.show()" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Great, a blank figure! Not terribly useful yet.\n", + "\n", + "\n", + "However, while we're on the topic, you can control the size of the figure through the ``figsize`` argument, which expects a tuple of ``(width, height)`` in inches. \n", + "\n", + "A really useful utility function is [`figaspect`](https://matplotlib.org/api/_as_gen/matplotlib.figure.figaspect.html?highlight=figaspect#matplotlib.figure.figaspect)" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "# Twice as tall as it is wide:\n", + "fig = plt.figure(figsize=plt.figaspect(2.0), facecolor=(1, 0, 0, .1))\n", + "plt.show()" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# Axes\n", + "\n", + "All plotting is done with respect to an [`Axes`](http://matplotlib.org/api/axes_api.html#matplotlib.axes.Axes). An *Axes* is made up of [`Axis`](http://matplotlib.org/api/axis_api.html#matplotlib.axis.Axis) objects and many other things. An *Axes* object must belong to a *Figure* (and only one *Figure*). Most commands you will ever issue will be with respect to this *Axes* object.\n", + "\n", + "Typically, you'll set up a `Figure`, and then add an `Axes` to it. \n", + "\n", + "You can use `fig.add_axes`, but in most cases, you'll find that adding a subplot will fit your needs perfectly. (Again a \"subplot\" is just an axes on a grid system.) " + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "fig = plt.figure()\n", + "ax = fig.add_subplot(111) # We'll explain the \"111\" later. Basically, 1 row and 1 column.\n", + "ax.set(xlim=[0.5, 4.5], ylim=[-2, 8], title='An Example Axes',\n", + " ylabel='Y-Axis', xlabel='X-Axis')\n", + "plt.show()" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "\n", + "Notice the call to ``set``. Matplotlib's objects typically have lots of \"explicit setters\" -- in other words, functions that start with ``set_`` and control a particular option. \n", + "\n", + "To demonstrate this (and as an example of IPython's tab-completion), try typing `ax.set_` in a code cell, then hit the `` key. You'll see a long list of `Axes` methods that start with `set`.\n", + "\n", + "For example, we could have written the third line above as:" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "ax.set_xlim([0.5, 4.5])\n", + "ax.set_ylim([-2, 8])\n", + "ax.set_title('A Different Example Axes Title')\n", + "ax.set_ylabel('Y-Axis (changed)')\n", + "ax.set_xlabel('X-Axis (changed)')\n", + "plt.show()" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Clearly this can get repitive quickly. Therefore, Matplotlib's `set` method can be very handy. It takes each kwarg you pass it and tries to call the corresponding \"setter\". For example, `foo.set(bar='blah')` would call `foo.set_bar('blah')`.\n", + "\n", + "Note that the `set` method doesn't just apply to `Axes`; it applies to more-or-less all matplotlib objects.\n", + "\n", + "However, there are cases where you'll want to use things like `ax.set_xlabel('Some Label', size=25)` to control other options for a particular function." + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Basic Plotting\n", + "\n", + "Most plotting happens on an `Axes`. Therefore, if you're plotting something on an axes, then you'll use one of its methods.\n", + "\n", + "We'll talk about different plotting methods in more depth in the next section. For now, let's focus on two methods: `plot` and `scatter`.\n", + "\n", + "`plot` draws points with lines connecting them. `scatter` draws unconnected points, optionally scaled or colored by additional variables.\n", + "\n", + "As a basic example:" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "fig = plt.figure()\n", + "ax = fig.add_subplot(111)\n", + "ax.plot([1, 2, 3, 4], [10, 20, 25, 30], color='lightblue', linewidth=3)\n", + "ax.scatter([0.3, 3.8, 1.2, 2.5], [11, 25, 9, 26], c=[1, 2, 3, 5], marker='^')\n", + "ax.set_xlim(0.5, 4.5)\n", + "plt.show()" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Axes methods vs. pyplot\n", + "\n", + "Interestingly, just about all methods of an *Axes* object exist as a function in the *pyplot* module (and vice-versa). For example, when calling `plt.xlim(1, 10)`, *pyplot* calls `ax.set_xlim(1, 10)` on whichever *Axes* is \"current\". Here is an equivalent version of the above example using just pyplot." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "plt.plot([1, 2, 3, 4], [10, 20, 25, 30], color='lightblue', linewidth=3)\n", + "plt.scatter([0.3, 3.8, 1.2, 2.5], [11, 25, 9, 26], c=[1, 2, 3, 5], marker='^')\n", + "plt.xlim(0.5, 4.5)\n", + "plt.show()" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "That is a bit terser and has fewer local varialbes, so, why will most of my examples not follow the pyplot approach? Because [PEP20](http://www.python.org/dev/peps/pep-0020/) \"The Zen of Python\" says:\n", + "\n", + "\"Explicit is better than implicit\"\n", + "\n", + "While very simple plots, with short scripts would benefit from the conciseness of the pyplot implicit approach, when doing more complicated plots, or working within larger scripts, you will want to explicitly pass around the *Axes* and/or *Figure* object to operate upon.\n", + "\n", + "The advantage of keeping which axes we're working with very clear in our code will become more obvious when we start to have multiple axes in one figure." + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### Multiple Axes\n", + "\n", + "We've mentioned before that a figure can have more than one `Axes` on it. If you want your axes to be on a regular grid system, then it's easiest to use `plt.subplots(...)` to create a figure and add the axes to it automatically.\n", + "\n", + "For example:" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "fig, axes = plt.subplots(nrows=2, ncols=2)\n", + "plt.show()" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "`plt.subplots(...)` created a new figure and added 4 subplots to it. The `axes` object that was returned is a 2D numpy object array. Each item in the array is one of the subplots. They're laid out as you see them on the figure. \n", + "\n", + "Therefore, when we want to work with one of these axes, we can index the `axes` array and use that item's methods.\n", + "\n", + "For example:" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "fig, axes = plt.subplots(nrows=2, ncols=2)\n", + "axes[0,0].set(title='Upper Left')\n", + "axes[0,1].set(title='Upper Right')\n", + "axes[1,0].set(title='Lower Left')\n", + "axes[1,1].set(title='Lower Right')\n", + "\n", + "# To iterate over all items in a multidimensional numpy array, use the `flat` attribute\n", + "for ax in axes.flat:\n", + " # Remove all xticks and yticks...\n", + " ax.set(xticks=[], yticks=[])\n", + " \n", + "plt.show()" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "One really nice thing about `plt.subplots()` is that when it's called with no arguments, it creates a new figure with a single subplot. \n", + "\n", + "Any time you see something like\n", + "\n", + "```\n", + "fig = plt.figure()\n", + "ax = fig.add_subplot(111)\n", + "```\n", + "\n", + "You can replace it with:\n", + "\n", + "```\n", + "fig, ax = plt.subplots()\n", + "```\n", + "\n", + "We'll be using that approach for the rest of the examples. It's much cleaner. \n", + "\n", + "However, keep in mind that we're still creating a figure and adding axes to it. When we start making plot layouts that can't be described by `subplots`, we'll go back to creating the figure first and then adding axes to it one-by-one." + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Quick Exercise: Exercise 1.1\n", + "--------------\n", + "\n", + "Let's use some of what we've been talking about. Can you reproduce this figure?\n", + "\n", + "\n", + "\n", + "Here's the data and some code to get you started." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "%load exercises/1.1-subplots_and_basic_plotting.py" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "import numpy as np\n", + "import matplotlib.pyplot as plt\n", + "\n", + "# Try to reproduce the figure shown in images/exercise_1-1.png\n", + "\n", + "# Our data...\n", + "x = np.linspace(0, 10, 100)\n", + "y1, y2, y3 = np.cos(x), np.cos(x + 1), np.cos(x + 2)\n", + "names = ['Signal 1', 'Signal 2', 'Signal 3']\n", + "\n", + "# Can you figure out what to do next to plot x vs y1, y2, and y3 on one figure?\n" + ] + } + ], + "metadata": { + "kernelspec": { + "display_name": "Python 3", + "language": "python", + "name": "python3" + }, + "language_info": { + "codemirror_mode": { + "name": "ipython", + "version": 3 + }, + "file_extension": ".py", + "mimetype": "text/x-python", + "name": "python", + "nbconvert_exporter": "python", + "pygments_lexer": "ipython3", + "version": "3.6.5" + } + }, + "nbformat": 4, + "nbformat_minor": 1 +} diff --git a/AnatomyOfMatplotlib-Part1-pyplot.ipynb b/AnatomyOfMatplotlib-Part1-pyplot.ipynb deleted file mode 100644 index d7d75cb..0000000 --- a/AnatomyOfMatplotlib-Part1-pyplot.ipynb +++ /dev/null @@ -1,844 +0,0 @@ -{ - "metadata": { - "name": "", - "signature": "sha256:c7159e6f4ecac56d72f7333ed9bb24bbfeb4c66fba3000a1b2cb3c382fd148fd" - }, - "nbformat": 3, - "nbformat_minor": 0, - "worksheets": [ - { - "cells": [ - { - "cell_type": "code", - "collapsed": false, - "input": [ - "# Turning on inline plots -- just for use in ipython notebooks.\n", - "%matplotlib inline" - ], - "language": "python", - "metadata": { - "slideshow": { - "slide_type": "-" - } - }, - "outputs": [] - }, - { - "cell_type": "markdown", - "metadata": { - "slideshow": { - "slide_type": "-" - } - }, - "source": [ - "# Matplotlib\n", - "## Introduction\n", - "Matplotlib is a library for producing publication-quality figures. mpl (for short) was designed from the bottom-up to serve dual-purposes. First, to allow for interactive, cross-platform control of figures and plots, and second, to make it very easy to produce static raster or vector graphics files without the need for any GUIs. Furthermore, mpl -- much like Python itself -- gives the developer complete control over the appearance of their plots, while still being very usable through a powerful defaults system.\n", - "\n", - "## Online Documentation\n", - "The [matplotlib.org](http://matplotlib.org) project website is the primary online resource for the library's documentation. It contains [examples](http://matplotlib.org/examples/index.html), [FAQs](http://matplotlib.org/faq/index.html), [API documentation](http://matplotlib.org/api/index.html), and, most importantly, the [gallery](http://matplotlib.org/gallery.html).\n", - "\n", - "## Gallery\n", - "Many users of matplotlib are often faced with the question, \"I want to make a plot that has X with Y in the same figure, but it needs to look like Z\". Good luck getting an answer from a web search with that query. This is why the [gallery](http://matplotlib.org/gallery.html) is so useful, because it showcases the variety of ways one can make plots. Browse through the gallery, click on any figure that has pieces of what you want to see the code that generated it. Soon enough, you will be like a chef, mixing and matching components to produce your masterpiece!\n", - "\n", - "As always, if you have a new and interesting plot that demonstrates a feature of matplotlib, feel free to submit a well-commented version of the example code for inclusion.\n", - "\n", - "## Mailing Lists and StackOverflow\n", - "When you are just simply stuck, and can not figure out how to get something to work, or just need some hints on how to get started, you will find much of the community at the matplotlib-users [mailing list](http://sourceforge.net/mail/?group_id=80706). This mailing list is an excellent resource of information with many friendly members who just love to help out newcomers. The number one rule to remember with this list is to be persistant. While many questions do get answered fairly quickly, some do fall through the cracks, or the one person who knows the answer isn't available. Therefore, try again with your questions rephrased, or with a plot showing your attempts so far. We love plots, so an image showing what is wrong often gets the quickest responses.\n", - "\n", - "Another community resource is [StackOverflow](http://stackoverflow.com/questions/tagged/matplotlib), so if you need to build up karma points, submit your questions here, and help others out too!\n", - "\n", - "# Github repository\n", - "## Location\n", - "[Matplotlib](https://github.com/matplotlib) is hosted by GitHub.\n", - "\n", - "## Bug Reports and feature requests\n", - "So, you think you found a bug? Or maybe you think some feature is just too difficult to use? Or missing altogether? Submit your bug reports [here](https://github.com/matplotlib/matplotlib/issues) at matplotlib's issue tracker. We even have a process for submitting and discussing Matplotlib Enhancement Proposals ([MEPs](https://github.com/matplotlib/matplotlib/wiki)).\n", - "\n", - "## What is this \"backend\" thing I keep hearing about?\n", - "Matplotlib has multiple backends. The backends allow mpl to be used on a variety of platforms with a variety of GUI toolkits (GTK, Qt, Wx, etc.), all of them written so that most of the time, you will not need to care which backend you are using. However, bugs do occur, and so two of the most important pieces of information you can provide in a bug report is which version of matplotlib, and which backend." - ] - }, - { - "cell_type": "code", - "collapsed": false, - "input": [ - "import matplotlib\n", - "print matplotlib.__version__\n", - "print matplotlib.get_backend()" - ], - "language": "python", - "metadata": {}, - "outputs": [] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "# On with the show!\n", - "Matplotlib is a large project and can seem daunting at first. However, by learning the components, it should begin to feel much smaller and more approachable.\n", - "\n", - "We start with the most important import statements you will ever need for matplotlib" - ] - }, - { - "cell_type": "code", - "collapsed": false, - "input": [ - "import numpy as np\n", - "import matplotlib.pyplot as plt" - ], - "language": "python", - "metadata": {}, - "outputs": [] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "# pyplot\n", - "The pyplot module is where everything in matplotlib comes together. It is the launching point for (1) preparing your figures, (2) making plots, and (3) doing any modifications and decorations you want. It all comes together here. Let us take a look at those three catagories of pyplot functions.\n", - "\n", - "## Plotting Preparation\n", - "\n", - "Function | Description \n", - ":-----------------|:----------------------------------------------------------\n", - "`autoscale` | Autoscale the axis view to the data (toggle).\n", - "`axes` | Add an axes to the figure. \n", - "`axis` | Convenience method to get or set axis properties.\n", - "`cla` | Clear the current axes. \n", - "`clf` | Clear the current figure. \n", - "`clim` | Set the color limits of the current image. \n", - "`delaxes` | Remove an axes from the current figure. \n", - "`locator_params` | Control behavior of tick locators. \n", - "`margins` | Set or retrieve autoscaling margins.\n", - "`figure` | Creates a new figure. \n", - "`gca` | Return the current axis instance. \n", - "`gcf` | Return a reference to the current figure. \n", - "`gci` | Get the current colorable artist. \n", - "`hold` | Set the hold state. \n", - "`ioff` | Turn interactive mode off. \n", - "`ion` | Turn interactive mode on. \n", - "`ishold` | Return the hold status of the current axes. \n", - "`isinteractive` | Return status of interactive mode. \n", - "`rc` | Set the current rc params. \n", - "`rc_context` | Return a context manager for managing rc settings. \n", - "`rcdefaults` | Restore the default rc params. \n", - "`savefig` | Save the current figure. \n", - "`sca` | Set the current Axes instance. \n", - "`sci` | Set the current image. \n", - "`set_cmap` | Set the default colormap\n", - "`setp` | Set a property on an artist object\n", - "`show` | Display a figure\n", - "`subplot` | Return a subplot axes positioned by the given grid definition. \n", - "`subplot2grid` | Create a subplot in a grid. \n", - "`subplot_tool` | Launch a subplot tool window for a figure. \n", - "`subplots` | Create a figure with a set of subplots already made. \n", - "`subplots_adjust` | Tune the subplot layout. \n", - "`switch_backend` | Switch the default backend. \n", - "`tick_params` | Change the appearance of ticks and tick labels. \n", - "`ticklabel_format`| Change the ScalarFormatter used by default for linear axes. \n", - "`tight_layout` | Automatically adjust subplot parameters to give specified padding. \n", - "`xkcd` | Turns on [XKCD](http://xkcd.com/) sketch-style drawing mode. \n", - "`xlabel` | Set the *x* axis label of the current axis. \n", - "`xlim` | Get or set the *x* limits of the current axes. \n", - "`xscale` | Set the scaling of the *x*-axis. \n", - "`xticks` | Get or set the *x*-limits of the current tick locations and labels. \n", - "`ylabel` | Set the *y* axis label of the current axis. \n", - "`ylim` | Get or set the *y*-limits of the current axes. \n", - "`yscale` | Set the scaling of the *y*-axis. \n", - "`yticks` | Get or set the *y*-limits of the current tick locations and labels. \n", - "\n", - "## Plotting Functions\n", - "\n", - "Function | Description\n", - ":-----------------|:--------------------------------------------\n", - "`acorr` | Plot the autocorrelation of *x*\n", - "`bar` | Make a bar plot\n", - "`barbs` | Plot a 2-D field of barbs\n", - "`barh` | Make a horizontal bar plot\n", - "`boxplot` | Make a box and whisker plot\n", - "`broken_barh` | Plot horizontal bars\n", - "`cohere` | Plot the coherence between *x* and *y*\n", - "`contour` | Plot contours\n", - "`contourf` | Plot filled contours\n", - "`csd` | Plot cross-spectral density\n", - "`errorbar` | Plot an errorbar graph\n", - "`eventplot` | Plot identical parallel lines at specific positions\n", - "`fill` | Plot filled polygons\n", - "`fill_between` | Make filled polygons between two curves\n", - "`fill_betweenx` | Make filled polygons between two horizontal curves\n", - "`hexbin` | Make a hexagonal binning plot\n", - "`hist` | Plot a histogram\n", - "`hist2d` | Make a 2D histogram plot\n", - "`imshow` | Display an image on the axes\n", - "`loglog` | Make a plot with log scaling on both the *x* and *y* axis\n", - "`matshow` | Display an array as a matrix in a new figure window\n", - "`pcolor` | Create a pseudocolor plot of a 2-D array\n", - "`pcolormesh` | Plot a quadrilateral mesh\n", - "`pie` | Plot a pie chart\n", - "`plot` | Plot lines and/or markers\n", - "`plot_date` | Plot with data with dates\n", - "`polar` | Make a polar plot\n", - "`psd` | Plot the power spectral density\n", - "`quiver` | Plot a 2-D field of arrows\n", - "`scatter` | Make a scatter plot of x vs y\n", - "`semilogx` | Make a plot with log scaling on the *x* axis \n", - "`semilogy` | Make a plot with log scaling on the *y* axis\n", - "`specgram` | Plot a spectrogram\n", - "`spy` | Plot the sparsity pattern on a 2-D array\n", - "`stackplot` | Draws a stacked area plot\n", - "`stem` | Create a stem plot\n", - "`step` | Make a step plot\n", - "`streamplot` | Draws streamlines of a vector flow\n", - "`tricontour` | Draw contours on an unstructured triangular grid\n", - "`tricontourf` | Draw filled contours on an unstructured triangular grid\n", - "`tripcolor` | Create a pseudocolor plot of an unstructured triangular grid\n", - "`triplot` | Draw a unstructured triangular grid as lines and/or markers\n", - "`xcorr` | Plot the cross-correlation between *x* and *y*\n", - "\n", - "## Plot modifiers\n", - "\n", - "Function | Description \n", - ":-----------------|:---------------------------------------------------------------------\n", - "`annotate` | Create an annotation: a piece of text referring to a data point\n", - "`arrow` | Add an arrow to the axes\n", - "`axhline` | Add a horizontal line across the axis\n", - "`axhspan` | Add a horizontal span (rectangle) across the axis\n", - "`axvline` | Add a vertical line across the axes\n", - "`axvspan` | Add a vertical span (rectangle) across the axes\n", - "`box` | Turn the axes box on or off\n", - "`clabel` | Label a contour plot\n", - "`colorbar` | Add a colorbar to a plot\n", - "`grid` | Turn the axes grids on or off\n", - "`hlines` | Plot horizontal lines\n", - "`legend` | Place a legend on the current axes\n", - "`minorticks_off` | Remove minor ticks from the current plot\n", - "`minorticks_on` | Display minor ticks on the current plot\n", - "`quiverkey` | Add a key to a quiver plot\n", - "`rgrids` | Get or set the radial gridlines on a polar plot\n", - "`suptitle` | Add a centered title to the figure\n", - "`table` | Add a table to the current axes\n", - "`text` | Add text to the axes\n", - "`title` | Set a title of the current axes\n", - "`vlines` | Plot vertical lines\n", - "`xlabel` | Set the *x* axis label of the current axis\n", - "`ylabel` | Set the *y* axis label of the current axis" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "# Figure\n", - "## Introduction\n", - "All plotting is done through the [`Figure`](http://matplotlib.org/api/figure_api.html#matplotlib.figure.Figure) object. You can create as many figures as you need. Figures can't do much by themselves, but no plotting can happen without them. They are, literally, the \"canvas\" of your plot." - ] - }, - { - "cell_type": "code", - "collapsed": false, - "input": [ - "fig = plt.figure()" - ], - "language": "python", - "metadata": {}, - "outputs": [] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "Awww, nothing happened! This is because by default mpl will not show anything until told to do so. In other words, the \"interactive mode\" is turned off. This is very useful for scripting where we would not ever want to see the intermediate results. For those who wishes to experiment and want to see their plot as they issue commands, there is the \"plt.ion()\" command they can issue before creating their first figure of their session. For the purpoase of this tutorial, we will leave interactivity off.\n", - "\n", - "## Figure properties\n", - "* figsize : tuple of integers, width, height in inches.\n", - " \n", - "* dpi : integer, esolution of the figure in dots per inch." - ] - }, - { - "cell_type": "code", - "collapsed": false, - "input": [ - "fig = plt.figure(figsize=(10, 4))\n", - "fig.gca() # needed for the ipython-inline to display anything\n", - "plt.show()" - ], - "language": "python", - "metadata": {}, - "outputs": [] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "A really useful utility function is [`figaspect`](http://matplotlib.org/api/figure_api.html?highlight=figaspect#matplotlib.figure.figaspect)" - ] - }, - { - "cell_type": "code", - "collapsed": false, - "input": [ - "# Twice as tall\n", - "fig = plt.figure(figsize=plt.figaspect(2.0))\n", - "fig.gca()\n", - "plt.show()" - ], - "language": "python", - "metadata": {}, - "outputs": [] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "## Breakdown of a figure\n", - "Open the file \"plot_demo.svg\" included with this notebook in a new tab." - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "# Axes\n", - "All plotting is done with respect to an [`Axes`](http://matplotlib.org/api/axes_api.html#matplotlib.axes.Axes). An *Axes* is made up of [`Axis`](http://matplotlib.org/api/axis_api.html#matplotlib.axis.Axis) objects and many other things. An *Axes* object must belong to a *Figure* (and only one *Figure*). Most commands you will ever issue will be with respect to this *Axes* object." - ] - }, - { - "cell_type": "code", - "collapsed": false, - "input": [ - "fig = plt.figure()\n", - "ax = fig.add_subplot(111)\n", - "ax.plot([1, 2, 3, 4], [10, 20, 25, 30])\n", - "ax.set_xlim(0.5, 4.5)\n", - "plt.show()" - ], - "language": "python", - "metadata": {}, - "outputs": [] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "Interestingly, just about all methods of an *Axes* object exist as a function in the *pyplot* module (and vice-versa). For example, when calling `plt.xlim(1, 10)`, *pyplot* calls `ax.set_xlim(1, 10)` on whichever *Axes* is \"current\". Here is an equivalent version of the above example using just pyplot." - ] - }, - { - "cell_type": "code", - "collapsed": false, - "input": [ - "plt.plot([1, 2, 3, 4], [10, 20, 25, 30])\n", - "plt.xlim(0.5, 4.5)\n", - "plt.show()" - ], - "language": "python", - "metadata": {}, - "outputs": [] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "Much cleaner, and much clearer! So, why will most of my examples not follow the pyplot approach? Because [PEP20](http://www.python.org/dev/peps/pep-0020/) \"The Zen of Python\" says:\n", - "\n", - "\"Explicit is better than implicit\"\n", - "\n", - "While very simple plots, with short scripts would benefit from the conciseness of the pyplot implicit approach, when doing more complicated plots, or working within larger scripts, you will want to explicitly pass around the *Axes* and/or *Figure* object to operate upon." - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "## Limits and autoscaling\n", - "By default, matplotlib will attempt to determine limits for you that encompasses all the data you have plotted. This is the \"autoscale\" feature. For line and image plots, the limits are not padded, while plots such as scatter plots and bar plots are given some padding." - ] - }, - { - "cell_type": "code", - "collapsed": false, - "input": [ - "fig, (ax1, ax2) = plt.subplots(1, 2, figsize=plt.figaspect(0.5))\n", - "ax1.plot([-10, -5, 0, 5, 10, 15], [-1.2, 2, 3.5, -0.3, -4, 1])\n", - "ax2.scatter([-10, -5, 0, 5, 10, 15], [-1.2, 2, 3.5, -0.3, -4, 1])\n", - "plt.show()" - ], - "language": "python", - "metadata": {}, - "outputs": [] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "A trick with limits is to specify only half of a limit. When done **after** a plot is made, this has the effect of allowing the user to anchor a limit while letting matplotlib to autoscale the rest of it." - ] - }, - { - "cell_type": "code", - "collapsed": false, - "input": [ - "# Good -- setting limits after plotting is done\n", - "fig, (ax1, ax2) = plt.subplots(1, 2, figsize=plt.figaspect(0.5))\n", - "ax1.plot([-10, -5, 0, 5, 10, 15], [-1.2, 2, 3.5, -0.3, -4, 1])\n", - "ax2.scatter([-10, -5, 0, 5, 10, 15], [-1.2, 2, 3.5, -0.3, -4, 1])\n", - "ax1.set_ylim(bottom=-10)\n", - "ax2.set_xlim(right=25)\n", - "plt.show()" - ], - "language": "python", - "metadata": {}, - "outputs": [] - }, - { - "cell_type": "code", - "collapsed": false, - "input": [ - "# Bad -- Setting limits before plotting is done\n", - "fig, (ax1, ax2) = plt.subplots(1, 2, figsize=plt.figaspect(0.5))\n", - "ax1.set_ylim(bottom=-10)\n", - "ax2.set_xlim(right=25)\n", - "ax1.plot([-10, -5, 0, 5, 10, 15], [-1.2, 2, 3.5, -0.3, -4, 1])\n", - "ax2.scatter([-10, -5, 0, 5, 10, 15], [-1.2, 2, 3.5, -0.3, -4, 1])\n", - "plt.show()" - ], - "language": "python", - "metadata": {}, - "outputs": [] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "### Exercise 1.1\n", - "How would you make a plot with a y-axis such that it starts at 1000 at the bottom, and goes to 500 at the top?\n", - "\n", - "Hint: [`set_ylim`](http://matplotlib.org/api/axes_api.html#matplotlib.axes.Axes.set_ylim)" - ] - }, - { - "cell_type": "code", - "collapsed": false, - "input": [ - "%load exercises/1.1-limits.py" - ], - "language": "python", - "metadata": {}, - "outputs": [] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "## Labels and Legends\n", - "You can label just about anything in mpl. You can provide a label to your plot, which allows your legend to automatically build itself. The X and Y axis can also be labeled, as well as the subplot itself via the title." - ] - }, - { - "cell_type": "code", - "collapsed": false, - "input": [ - "fig = plt.figure()\n", - "ax = fig.add_subplot(111)\n", - "ax.plot([1, 2, 3, 4], [10, 20, 25, 30], label='Philadelphia')\n", - "ax.plot([1, 2, 3, 4], [30, 23, 13, 4], label='Boston')\n", - "ax.set_ylabel('Temperature (deg C)')\n", - "ax.set_xlabel('Time')\n", - "ax.set_title(\"A tale of two cities\")\n", - "ax.legend()\n", - "plt.show()" - ], - "language": "python", - "metadata": {}, - "outputs": [] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "Also, if you happen to be plotting something that you do not want to appear in the legend, just set the label to \"\\_nolegend\\_\"." - ] - }, - { - "cell_type": "code", - "collapsed": false, - "input": [ - "fig, ax = plt.subplots(1, 1)\n", - "ax.bar([1, 2, 3, 4], [10, 20, 25, 30], label=\"Foobar\")\n", - "ax.plot([1, 2, 3, 4], [10, 20, 25, 30], label=\"_nolegend_\")\n", - "ax.legend()\n", - "plt.show()" - ], - "language": "python", - "metadata": {}, - "outputs": [] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "## Ticks, Tick Lines, Tick Labels and Tickers\n", - "This is a constant source of confusion:\n", - "\n", - "* A Tick is the *location* of a Tick Label.\n", - "* A Tick Line is the line that denotes the location of the tick.\n", - "* A Tick Label is the text that is displayed at that tick.\n", - "* A [`Ticker`](http://matplotlib.org/api/ticker_api.html#module-matplotlib.ticker) automatically determines the ticks for an Axis and formats the tick labels.\n", - "\n", - "[`tick_params()`](http://matplotlib.org/api/axes_api.html#matplotlib.axes.Axes.tick_params) is often used to help configure your tickers." - ] - }, - { - "cell_type": "code", - "collapsed": false, - "input": [ - "fig = plt.figure()\n", - "ax = fig.add_subplot(111)\n", - "ax.plot([1, 2, 3, 4], [10, 20, 25, 30])\n", - "ax.xaxis.set_ticks(range(1, 5)) # Set ticks at 1, 2, 3, 4\n", - "ax.xaxis.set_ticklabels([3, 100, -12, \"foo\"]) # Label ticks as \"3\", \"100\", \"-12\", and \"foo\"\n", - "ax.tick_params(axis='y', direction='inout', length=10)\n", - "plt.show()" - ], - "language": "python", - "metadata": {}, - "outputs": [] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "# Subplots\n", - "While an *Axes* object can only belong to one *Figure*, A *Figure* can have many *Axes* objects. These are typically called \"subaxes\" or \"subplots\". They act just like regular *Axes*." - ] - }, - { - "cell_type": "code", - "collapsed": false, - "input": [ - "fig = plt.figure(figsize=(10, 5))\n", - "ax = fig.add_subplot(121)\n", - "ax.plot([1, 2, 3, 4], [10, 20, 25, 30], label='Philadelphia')\n", - "ax.plot([1, 2, 3, 4], [30, 23, 13, 4], label='Boston')\n", - "ax.set_title('A tale of two cities')\n", - "ax.legend()\n", - "\n", - "t = np.linspace(0, 7, 25)\n", - "z = 2 * np.sin(t) + 5\n", - "ax = fig.add_subplot(122)\n", - "ax.scatter(t, z, label='Philadelphia')\n", - "ax.set_title(\"Observed Tide\")\n", - "ax.legend()\n", - "\n", - "fig.suptitle('A title for the whole figure')\n", - "plt.show()" - ], - "language": "python", - "metadata": {}, - "outputs": [] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "There are many ways to add and modify subplots in a figure.\n", - "\n", - "* [`plt.subplots()`](http://matplotlib.org/api/pyplot_api.html#matplotlib.pyplot.subplots)\n", - "* [`plt.subplot()`](http://matplotlib.org/api/pyplot_api.html#matplotlib.pyplot.subplot) and [`fig.add_subplot()`](http://matplotlib.org/api/figure_api.html?#matplotlib.figure.Figure.add_subplot) Which should be familiar to all Matlab users\n", - "* [`plt.axes()`](http://matplotlib.org/api/pyplot_api.html?#matplotlib.pyplot.axes)\n", - "* [`plt.subplot2grid()`](http://matplotlib.org/api/pyplot_api.html?#matplotlib.pyplot.subplot2grid)\n", - "* `plt.subplot_tool()` Interactive modification of subplot spacing.\n", - "\n", - "## Spacing\n", - "The spacing between the subplots can be adjusted using [`plt.subplots_adjust()`](http://matplotlib.org/api/pyplot_api.html?#matplotlib.pyplot.subplots_adjust). Play around with the example below to see how the different arguments affect the spacing." - ] - }, - { - "cell_type": "code", - "collapsed": false, - "input": [ - "fig, axes = plt.subplots(2, 2, figsize=(9, 9))\n", - "plt.subplots_adjust(wspace=0.5, hspace=0.3,\n", - " left=0.125, right=0.9,\n", - " top=0.9, bottom=0.1)\n", - "plt.show()" - ], - "language": "python", - "metadata": {}, - "outputs": [] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "A common complaint with matplotlib users is that the labels do not fit with the subplots, or the label of one subplot spills onto another subplot's area. Matplotlib does not currently have any sort of robust layout engine, as it is a design decision to minimize the amount of \"magic\" that matplotlib performs. We intend to let users have complete, 100% control over their plots. LaTeX users would be quite familiar with the amount of frustration that can occur with placement of figures in their documents.\n", - "\n", - "That said, there have been some efforts to develop tools that users can use to help address the most common compaints. The \"[Tight Layout](http://matplotlib.org/users/tight_layout_guide.html)\" feature, when invoked, will attempt to resize margins, and subplots so that nothing overlaps." - ] - }, - { - "cell_type": "code", - "collapsed": false, - "input": [ - "def example_plot(ax):\n", - " ax.plot([1, 2])\n", - " ax.set_xlabel('x-label', fontsize=16)\n", - " ax.set_ylabel('y-label', fontsize=8)\n", - " ax.set_title('Title', fontsize=24)\n", - "\n", - "fig, ((ax1, ax2), (ax3, ax4)) = plt.subplots(nrows=2, ncols=2)\n", - "example_plot(ax1)\n", - "example_plot(ax2)\n", - "example_plot(ax3)\n", - "example_plot(ax4)\n", - "#plt.tight_layout()\n", - "plt.show()" - ], - "language": "python", - "metadata": {}, - "outputs": [] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "As a last bit of an FAQ, this \"tight_layout\" feature is unrelated to the so-called \"bbox_inches='tight'\" feature that will be discussed separately." - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "## GridSpec\n", - "Under the hood, matplotlib utilizes [`GridSpec`](http://matplotlib.org/api/gridspec_api.html) to lay out the subplots. While `plt.subplots()` is fine for simple cases, sometimes you will need more advanced subplot layouts. In such cases, you should use GridSpec directly. GridSpec is outside the scope of this tutorial, but it is handy to know that it exists. [Here](http://matplotlib.org/users/gridspec.html) is a guide on how to use it." - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "## Sharing axes\n", - "There will be times when you want to have the x axis and/or the y axis of your subplots to be \"shared\". Sharing an axis means that the axis in one or more subplots will be tied together such that any change in one of the axis changes all of the other shared axes. This works very nicely with autoscaling arbitrary datasets that may have overlapping domains. Furthermore, when interacting with the plots (panning and zooming), all of the shared axes will pan and zoom automatically." - ] - }, - { - "cell_type": "code", - "collapsed": false, - "input": [ - "# going out of inline mode to demonstrate the zooming and panning\n", - "%matplotlib\n", - "\n", - "fig, (ax1, ax2) = plt.subplots(1, 2, sharex=True, sharey=True)\n", - "ax1.plot([1, 2, 3, 4], [1, 2, 3, 4])\n", - "ax2.plot([3, 4, 5, 6], [6, 5, 4, 3])\n", - "plt.show()" - ], - "language": "python", - "metadata": {}, - "outputs": [] - }, - { - "cell_type": "code", - "collapsed": false, - "input": [ - "# Go back to inline mode\n", - "%matplotlib inline" - ], - "language": "python", - "metadata": {}, - "outputs": [] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "## \"Twinning\" axes\n", - "Sometimes one may want to overlay two plots on the same axes, but the scales may be entirely different. You can simply treat them as separate plots, but then twin them." - ] - }, - { - "cell_type": "code", - "collapsed": false, - "input": [ - "fig, ax1 = plt.subplots(1, 1)\n", - "ax1.plot([1, 2, 3, 4], [1, 2, 3, 4])\n", - "ax2 = ax1.twinx()\n", - "ax2.scatter([1, 2, 3, 4], [60, 50, 40, 30])\n", - "ax1.set_xlabel('X')\n", - "ax1.set_ylabel('First scale')\n", - "ax2.set_ylabel('Other scale')\n", - "plt.show()" - ], - "language": "python", - "metadata": {}, - "outputs": [] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "# Axis Spines\n", - "Spines are the axis lines for a plot. Each plot can have four spines: \"top\", \"bottom\", \"left\" and \"right\". By default, they are set so that they frame the plot, but they can be individually positioned and configured via the [`set_position()`](http://matplotlib.org/api/spines_api.html#matplotlib.spines.Spine.set_position) method of the spine. Here are some different configurations." - ] - }, - { - "cell_type": "code", - "collapsed": false, - "input": [ - "fig, ax = plt.subplots(1, 1)\n", - "ax.plot([-2, 2, 3, 4], [-10, 20, 25, 5])\n", - "ax.spines['top'].set_visible(False)\n", - "ax.xaxis.set_ticks_position('bottom') # no ticklines at the top\n", - "ax.spines['right'].set_visible(False)\n", - "ax.yaxis.set_ticks_position('left') # no ticklines on the right\n", - "\n", - "# \"outward\"\n", - "# Move the two remaining spines \"out\" away from the plot by 10 points\n", - "ax.spines['bottom'].set_position(('outward', 10))\n", - "ax.spines['left'].set_position(('outward', 10))\n", - "\n", - "# \"data\"\n", - "# Have the spines stay intersected at (0,0)\n", - "#ax.spines['bottom'].set_position(('data', 0))\n", - "#ax.spines['left'].set_position(('data', 0))\n", - "\n", - "# \"axes\"\n", - "# Have the two remaining spines placed at a fraction of the axes\n", - "#ax.spines['bottom'].set_position(('axes', 0.75))\n", - "#ax.spines['left'].set_position(('axes', 0.25))\n", - "\n", - "plt.show()" - ], - "language": "python", - "metadata": {}, - "outputs": [] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "## Exercise 1.2\n", - "Create a plot that have outward spines on the left and bottom with tick labels, and \"centered\" spines with no tick labels and tickmarks *through* the spines.\n", - "\n", - "Hints:\n", - "[`tick_params()`](http://matplotlib.org/api/axes_api.html#matplotlib.axes.Axes.tick_params)\n", - "[`set_position()`](http://matplotlib.org/api/spines_api.html#matplotlib.spines.Spine.set_position)" - ] - }, - { - "cell_type": "code", - "collapsed": false, - "input": [ - "%load exercises/1.2-spines.py" - ], - "language": "python", - "metadata": {}, - "outputs": [] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "# Colorbars\n", - "Colorbars are much like legends because they help to describe the data being displayed. While legends describe plots, i.e., plot(), scatter(), hist(), stem(), colorbars describe images. To be really specific and technical, they can be used for any \"ScalarMappable\", which will be discussed in the `Artists` section. Let us take a look at a very simple example of a colorbar for a simple 2D image." - ] - }, - { - "cell_type": "code", - "collapsed": false, - "input": [ - "y, x = np.ogrid[-6:6:20j, -10:10:30j]\n", - "z = np.hypot(x, y)\n", - "plt.imshow(z)\n", - "plt.colorbar()\n", - "plt.show()" - ], - "language": "python", - "metadata": {}, - "outputs": [] - }, - { - "cell_type": "code", - "collapsed": false, - "input": [ - "plt.imshow(z)\n", - "plt.colorbar(orientation='horizontal', shrink=0.75) # We can make colorbars do all sorts of things!\n", - "plt.show()" - ], - "language": "python", - "metadata": {}, - "outputs": [] - }, - { - "cell_type": "code", - "collapsed": false, - "input": [ - "plt.imshow(z)\n", - "cbar = plt.colorbar(extend='both', aspect=10)\n", - "cbar.set_label('distance') # And we can even add a label to it\n", - "plt.show()" - ], - "language": "python", - "metadata": {}, - "outputs": [] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "Colorbars in matplotlib can be difficult at times, and the documentation can sometimes be a bit unhelpful (patches welcome!). One of the most common problems that come up is when mixing subplots with a single colorbar:" - ] - }, - { - "cell_type": "code", - "collapsed": false, - "input": [ - "fig, (ax1, ax2) = plt.subplots(1, 2)\n", - "ax1.imshow(z)\n", - "im = ax2.imshow(z) # Note, due to a bug, you will need to save the\n", - " # returned image object when calling imshow() from an Axes\n", - " # and pass that to plt.colorbar() so that it knows what\n", - " # image to build a colorbar from. This will be fixed for v1.3.1.\n", - "plt.colorbar(im)\n", - "plt.show()" - ], - "language": "python", - "metadata": {}, - "outputs": [] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "Looks terrible, right? What is happening is that a colorbar in matplotlib is just a very squashed subplot with an image of the colormap and axis ticks and labels. When told to create a colorbar for an image, matplotlib will simply \"steal\" space from that image's subplot and create a new subplot. There are a couple ways to deal with this issue. First, if you preallocate space for the colorbar (by creating your own Axes object to add to the Figure), you can pass that preallocated Axes to the \"cax\" argument of [`plt.colorbar()`](http://matplotlib.org/api/pyplot_api.html#matplotlib.pyplot.colorbar), and it won't have to steal any space. The easier option is to pass a list of all the axes objects to `plt.colorbar(..., ax)`, and it will steal space equally from them." - ] - }, - { - "cell_type": "code", - "collapsed": false, - "input": [ - "fig, (ax1, ax2) = plt.subplots(1, 2)\n", - "ax1.imshow(z)\n", - "im = ax2.imshow(z)\n", - "plt.colorbar(im, ax=[ax1, ax2], shrink=0.5)\n", - "plt.show()" - ], - "language": "python", - "metadata": {}, - "outputs": [] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "There is also a third, very powerful, option called [`axes_grid1`](http://matplotlib.org/mpl_toolkits/axes_grid/users/overview.html), which we will discuss in the `mpl_toolkits` section." - ] - } - ], - "metadata": {} - } - ] -} \ No newline at end of file diff --git a/AnatomyOfMatplotlib-Part2-HowToSpeakMPL.ipynb b/AnatomyOfMatplotlib-Part2-HowToSpeakMPL.ipynb deleted file mode 100644 index 7375057..0000000 --- a/AnatomyOfMatplotlib-Part2-HowToSpeakMPL.ipynb +++ /dev/null @@ -1,623 +0,0 @@ -{ - "metadata": { - "name": "", - "signature": "sha256:e1f772cda181207fb767d95705c04a7a3d95f8d83188cf282ca42ddd7bde2d9c" - }, - "nbformat": 3, - "nbformat_minor": 0, - "worksheets": [ - { - "cells": [ - { - "cell_type": "code", - "collapsed": false, - "input": [ - "# Turning on inline plots -- just for use in ipython notebooks.\n", - "%matplotlib inline\n", - "import numpy as np\n", - "import matplotlib.pyplot as plt" - ], - "language": "python", - "metadata": {}, - "outputs": [] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "# How to speak \"MPL\"\n", - "In the previous part, you learned how matplotlib organizes plot-making by figures and axes. We broke down the components of a basic figure and learned how to create them. You also learned how to add one or more axes to a figure, and how to tie them together. You even learned how to change some of the basic appearances of the axes. Finally, we went over some of the many kinds of figures that matplotlib can generate. With all that knowledge, you should be off making great and wonderful figures. Why are you still here?\n", - "\n", - "\"We don't know how to control our plots and figures!\" says some random voice in the back of the room.\n", - "\n", - "Of course! While the previous section may have taught you some of the structure and syntax of matplotlib, it did not describe much of the substance and vocabulary of the library. This section will go over many of the properties that are used throughout the library. Note that while many of the examples in this section may show one way of setting a particular property, that property may be applicible elsewhere in completely different context. This is the \"language\" of matplotlib.\n", - "\n", - "# Colors\n", - "This is, perhaps, the most important piece of vocabulary in matplotlib. Given that matplotlib is a plotting library, colors are associated with everything that is plotted in your figures. Matplotlib supports a [very robust language](http://matplotlib.org/api/colors_api.html#module-matplotlib.colors) for specifying colors that should be familiar to a wide variety of users.\n", - "\n", - "### Colornames\n", - "First, colors can be given as strings. For very basic colors, you can even get away with just a single letter:\n", - "\n", - "- b: blue\n", - "- g: green\n", - "- r: red\n", - "- c: cyan\n", - "- m: magenta\n", - "- y: yellow\n", - "- k: black\n", - "- w: white\n", - "\n", - "Other colornames that are allowed are the HTML/CSS colornames such as \"burlywood\" and \"chartreuse\" are valid. See the [full list](http://www.w3schools.com/html/html_colornames.asp) of the 147 colornames. For the British speaking and poor spellers among us (Note, I am not implying that British speakers are poor spellers!), we allow \"grey\" where-ever \"gray\" appears in that list of colornames. All of these colornames are case-insensitive.\n", - "\n", - "### Hex values\n", - "Colors can also be specified by supplying an HTML/CSS hex string, such as `'#0000FF'` for blue.\n", - "\n", - "### 256 Shades of Gray\n", - "A gray level can be given instead of a color by passing a string representation of a number between 0 and 1, inclusive. `'0.0'` is black, while `'1.0'` is white. `'0.75'` would be a lighter shade of gray.\n", - "\n", - "### RGB[A] tuples\n", - "You may come upon instances where the previous ways of specifying colors do not work. This can sometimes happen in some of the deeper, stranger levels of the code. When all else fails, the universal language of colors for matplotlib is the RGB[A] tuple. This is the \"Red\", \"Green\", \"Blue\", and sometimes \"Alpha\" tuple of floats in the range of [0, 1]. One means full saturation of that channel, so a red RGBA tuple would be `(1.0, 0.0, 0.0, 1.0)`, whereas a partly transparent green RGBA tuple would be `(0.0, 1.0, 0.0, 0.75)`. The documentation will usually specify whether it accepts RGB or RGBA tuples. Sometimes, a list of tuples would be required for multiple colors, and you can even supply a Nx3 or Nx4 numpy array in such cases.\n", - "\n", - "In functions such as `plot()` and `scatter()`, while it may appear that they can take a color specification, what they really need is a \"format specification\", which includes color as part of the format. Unfortunately, such specifications are string only and so RGB[A] tuples are not supported for such arguments (but you can still pass an RGB[A] tuple for a \"color\" argument).\n", - "\n", - "Note, oftentimes there is a separate argument for \"alpha\" where-ever you can specify a color. The value for \"alpha\" will usually take precedence over the alpha value in the RGBA tuple. There is no easy way around this problem.\n" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "## Exercise 2.1\n", - "Try out some different string representations of colors (you can't do RGB[A] tuples here)." - ] - }, - { - "cell_type": "code", - "collapsed": false, - "input": [ - "%load exercises/2.1-colors.py" - ], - "language": "python", - "metadata": {}, - "outputs": [] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "# Markers\n", - "[Markers](http://matplotlib.org/api/markers_api.html) are commonly used in [`plot()`](http://matplotlib.org/api/pyplot_api.html#matplotlib.pyplot.plot) and [`scatter()`](http://matplotlib.org/api/pyplot_api.html#matplotlib.pyplot.scatter) plots, but also show up elsewhere. There is a wide set of markers available, and custom markers can even be specified.\n", - "\n", - "marker | description ||marker | description ||marker | description ||marker | description \n", - ":----------|:--------------||:---------|:--------------||:---------|:--------------||:---------|:--------------\n", - "\".\" | point ||\"+\" | plus ||\",\" | pixel ||\"x\" | cross\n", - "\"o\" | circle ||\"D\" | diamond ||\"d\" | thin_diamond || |\n", - "\"8\" | octagon ||\"s\" | square ||\"p\" | pentagon ||\"\\*\" | star\n", - "\"|\" | vertical line||\"\\_\" | horizontal line ||\"h\" | hexagon1 ||\"H\" | hexagon2\n", - "0 | tickleft ||4 | caretleft ||\"<\" | triangle_left ||\"3\" | tri_left\n", - "1 | tickright ||5 | caretright ||\">\" | triangle_right||\"4\" | tri_right\n", - "2 | tickup ||6 | caretup ||\"^\" | triangle_up ||\"2\" | tri_up\n", - "3 | tickdown ||7 | caretdown ||\"v\" | triangle_down ||\"1\" | tri_down\n", - "\"None\" | nothing ||`None` | nothing ||\" \" | nothing ||\"\" | nothing" - ] - }, - { - "cell_type": "code", - "collapsed": false, - "input": [ - "xs, ys = np.mgrid[:4, 9:0:-1]\n", - "markers = [\".\", \"+\", \",\", \"x\", \"o\", \"D\", \"d\", \"\", \"8\", \"s\", \"p\", \"*\", \"|\", \"_\", \"h\", \"H\", 0, 4, \"<\", \"3\",\n", - " 1, 5, \">\", \"4\", 2, 6, \"^\", \"2\", 3, 7, \"v\", \"1\", \"None\", None, \" \", \"\"]\n", - "descripts = [\"point\", \"plus\", \"pixel\", \"cross\", \"circle\", \"diamond\", \"thin diamond\", \"\",\n", - " \"octagon\", \"square\", \"pentagon\", \"star\", \"vertical bar\", \"horizontal bar\", \"hexagon 1\", \"hexagon 2\",\n", - " \"tick left\", \"caret left\", \"triangle left\", \"tri left\", \"tick right\", \"caret right\", \"triangle right\", \"tri right\",\n", - " \"tick up\", \"caret up\", \"triangle up\", \"tri up\", \"tick down\", \"caret down\", \"triangle down\", \"tri down\",\n", - " \"Nothing\", \"Nothing\", \"Nothing\", \"Nothing\"]\n", - "fig, ax = plt.subplots(1, 1, figsize=(14, 4))\n", - "for x, y, m, d in zip(xs.T.flat, ys.T.flat, markers, descripts):\n", - " ax.scatter(x, y, marker=m, s=100)\n", - " ax.text(x + 0.1, y - 0.1, d, size=14)\n", - "ax.set_axis_off()\n", - "plt.show()" - ], - "language": "python", - "metadata": {}, - "outputs": [] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "## Exercise 2.2\n", - "Try out some different markers and colors" - ] - }, - { - "cell_type": "code", - "collapsed": false, - "input": [ - "%load exercises/2.2-markers.py" - ], - "language": "python", - "metadata": {}, - "outputs": [] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "# Linestyles\n", - "Line styles are about as commonly used as colors. There are a few predefined linestyles available to use. Note that there are some advanced techniques to specify some custom line styles. [Here](http://matplotlib.org/1.3.0/examples/lines_bars_and_markers/line_demo_dash_control.html) is an example of a custom dash pattern.\n", - "\n", - "linestyle | description\n", - "-------------------|------------------------------\n", - "'-' | solid\n", - "'--' | dashed\n", - "'-.' | dashdot\n", - "':' | dotted\n", - "'None' | draw nothing\n", - "' ' | draw nothing\n", - "'' | draw nothing\n", - "\n", - "Also, don't mix up \".-\" (line with dot markers) and \"-.\" (dash-dot line) when using the plot or scatter functions." - ] - }, - { - "cell_type": "code", - "collapsed": false, - "input": [ - "t = np.arange(0.0, 5.0, 0.2)\n", - "plt.plot(t, t, '-', t, t**2, '--', t, t**3, '-.', t, -t, ':')\n", - "plt.show()" - ], - "language": "python", - "metadata": {}, - "outputs": [] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "It is a bit confusing, but the line styles mentioned above are only valid for lines. Whenever you are dealing with the linestyles of the edges of \"Patch\" objects, you will need to use words instead of the symbols. So \"solid\" instead of \"-\", and \"dashdot\" instead of \"-.\". Hopefully, this issue will be fixed for the v1.5 release and allow these specifications to be used interchangably." - ] - }, - { - "cell_type": "code", - "collapsed": false, - "input": [ - "fig, ax = plt.subplots(1, 1)\n", - "ax.bar([1, 2, 3, 4], [10, 20, 15, 13], ls='dashed', ec='r', lw=5)\n", - "plt.show()" - ], - "language": "python", - "metadata": {}, - "outputs": [] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "# Plot attributes\n", - "With just about any plot you can make, there are many attributes that can be modified to make the lines and markers suit your needs. Note that for many plotting functions, matplotlib will cycle the colors for each dataset you plot. However, you are free to explicitly state which colors you want used for which plots. For the [`plt.plot()`](http://matplotlib.org/api/pyplot_api.html#matplotlib.pyplot.plot) and [`plt.scatter()`](http://matplotlib.org/api/pyplot_api.html#matplotlib.pyplot.scatter) functions, you can mix the specification for the colors, linestyles, and markers in a single string." - ] - }, - { - "cell_type": "code", - "collapsed": false, - "input": [ - "t = np.arange(0., 5., 0.2)\n", - "# red dashes, blue squares and green triangles\n", - "plt.plot(t, t, 'r--', t, t**2, 'bs', t, t**3, 'g^')\n", - "plt.show()" - ], - "language": "python", - "metadata": {}, - "outputs": [] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "| Property | Value Type \n", - "|------------------------|-------------------------------------------------\n", - "|alpha | float \n", - "|color or c | any matplotlib color \n", - "|dash_capstyle | ['butt', 'round' 'projecting'] \n", - "|dash_joinstyle | ['miter' 'round' 'bevel']\n", - "|dashes | sequence of on/off ink in points \n", - "|drawstyle | [ \u2018default\u2019 \u2018steps\u2019 \u2018steps-pre\u2019\n", - "| | \u2018steps-mid\u2019 \u2018steps-post\u2019 ]\n", - "|linestyle or ls | [ '-' '--' '-.' ':' 'None' ' ' ''] \n", - "| | and any drawstyle in combination with a \n", - "| | linestyle, e.g. 'steps--'. \n", - "|linewidth or lw | float value in points \n", - "|marker | [ 0 1 2 3 4 5 6 7 'o' 'd' 'D' 'h' 'H'\n", - "| | '' 'None' ' ' `None` '8' 'p' ','\n", - "| | '+' 'x' '.' 's' '\\*' '\\_' '|'\n", - "| | '1' '2' '3' '4' 'v' '<' '>' '^' ]\n", - "|markeredgecolor or mec | any matplotlib color\n", - "|markeredgewidth or mew | float value in points\n", - "|markerfacecolor or mfc | any matplotlib color\n", - "|markersize or ms | float\n", - "|solid_capstyle | ['butt' 'round' 'projecting']\n", - "|solid_joinstyle | ['miter' 'round' 'bevel']\n", - "|visible | [`True` `False`]\n", - "|zorder | any number\n", - "\n", - "## Exercise 2.3\n", - "Make a plot that has a dotted red line, with large yellow diamond markers that have a green edge" - ] - }, - { - "cell_type": "code", - "collapsed": false, - "input": [ - "%load exercises/2.3-properties.py" - ], - "language": "python", - "metadata": {}, - "outputs": [] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "# Colormaps\n", - "Another very important property of many figures is the colormap. The job of a colormap is to relate a scalar value to a color. In addition to the regular portion of the colormap, an \"over\", \"under\" and \"bad\" color can be optionally defined as well. NaNs will trigger the \"bad\" part of the colormap.\n", - "\n", - "As we all know, we create figures in order to convey information visually to our readers. There is much care and consideration that have gone into the design of these colormaps. Your choice in which colormap to use depends on what you are displaying. In mpl, the \"jet\" colormap is used by default, but it will often not be the colormap you would want to use. Much discussion has taken place on the mailing lists with regards to what colormap should be default. Ultimately, it doesn't really matter what the default colormap will be because an arbitrary colormap will be a poor choice for many datasets.\n", - "\n", - "I want to acknowedge Nicolas Rougier and Tony Yu for putting significant effort in educating users in proper colormap selections. Here is the full gallery of all the pre-defined colormaps, organized by the types of data they are usually used for." - ] - }, - { - "cell_type": "code", - "collapsed": false, - "input": [ - "%load http://matplotlib.org/mpl_examples/color/colormaps_reference.py # For those with v1.2 or higher" - ], - "language": "python", - "metadata": {}, - "outputs": [] - }, - { - "cell_type": "code", - "collapsed": false, - "input": [ - "\"\"\"\n", - "Reference for colormaps included with Matplotlib.\n", - "\n", - "This reference example shows all colormaps included with Matplotlib. Note that\n", - "any colormap listed here can be reversed by appending \"_r\" (e.g., \"pink_r\").\n", - "These colormaps are divided into the following categories:\n", - "\n", - "Sequential:\n", - " These colormaps are approximately monochromatic colormaps varying smoothly\n", - " between two color tones---usually from low saturation (e.g. white) to high\n", - " saturation (e.g. a bright blue). Sequential colormaps are ideal for\n", - " representing most scientific data since they show a clear progression from\n", - " low-to-high values.\n", - "\n", - "Diverging:\n", - " These colormaps have a median value (usually light in color) and vary\n", - " smoothly to two different color tones at high and low values. Diverging\n", - " colormaps are ideal when your data has a median value that is significant\n", - " (e.g. 0, such that positive and negative values are represented by\n", - " different colors of the colormap).\n", - "\n", - "Qualitative:\n", - " These colormaps vary rapidly in color. Qualitative colormaps are useful for\n", - " choosing a set of discrete colors. For example::\n", - "\n", - " color_list = plt.cm.Set3(np.linspace(0, 1, 12))\n", - "\n", - " gives a list of RGB colors that are good for plotting a series of lines on\n", - " a dark background.\n", - "\n", - "Miscellaneous:\n", - " Colormaps that don't fit into the categories above.\n", - "\n", - "\"\"\"\n", - "import numpy as np\n", - "import matplotlib.pyplot as plt\n", - "\n", - "\n", - "cmaps = [('Sequential', ['binary', 'Blues', 'BuGn', 'BuPu', 'gist_yarg',\n", - " 'GnBu', 'Greens', 'Greys', 'Oranges', 'OrRd',\n", - " 'PuBu', 'PuBuGn', 'PuRd', 'Purples', 'RdPu',\n", - " 'Reds', 'YlGn', 'YlGnBu', 'YlOrBr', 'YlOrRd']),\n", - " ('Sequential (2)', ['afmhot', 'autumn', 'bone', 'cool', 'copper',\n", - " 'gist_gray', 'gist_heat', 'gray', 'hot', 'pink',\n", - " 'spring', 'summer', 'winter']),\n", - " ('Diverging', ['BrBG', 'bwr', 'coolwarm', 'PiYG', 'PRGn', 'PuOr',\n", - " 'RdBu', 'RdGy', 'RdYlBu', 'RdYlGn', 'seismic']),\n", - " ('Qualitative', ['Accent', 'Dark2', 'hsv', 'Paired', 'Pastel1',\n", - " 'Pastel2', 'Set1', 'Set2', 'Set3', 'spectral']),\n", - " ('Miscellaneous', ['gist_earth', 'gist_ncar', 'gist_rainbow',\n", - " 'gist_stern', 'jet', 'brg', 'CMRmap', 'cubehelix',\n", - " 'gnuplot', 'gnuplot2', 'ocean', 'rainbow',\n", - " 'terrain', 'flag', 'prism'])]\n", - "\n", - "\n", - "nrows = max(len(cmap_list) for cmap_category, cmap_list in cmaps)\n", - "gradient = np.linspace(0, 1, 256)\n", - "gradient = np.vstack((gradient, gradient))\n", - "\n", - "def plot_color_gradients(cmap_category, cmap_list):\n", - " fig, axes = plt.subplots(nrows=nrows)\n", - " fig.subplots_adjust(top=0.95, bottom=0.01, left=0.2, right=0.99)\n", - " axes[0].set_title(cmap_category + ' colormaps', fontsize=14)\n", - "\n", - " for ax, name in zip(axes, cmap_list):\n", - " ax.imshow(gradient, aspect='auto', cmap=plt.get_cmap(name))\n", - " pos = list(ax.get_position().bounds)\n", - " x_text = pos[0] - 0.01\n", - " y_text = pos[1] + pos[3]/2.\n", - " fig.text(x_text, y_text, name, va='center', ha='right', fontsize=10)\n", - "\n", - " # Turn off *all* ticks & spines, not just the ones with colormaps.\n", - " for ax in axes:\n", - " ax.set_axis_off()\n", - "\n", - "for cmap_category, cmap_list in cmaps:\n", - " plot_color_gradients(cmap_category, cmap_list)\n", - "\n", - "plt.show()\n" - ], - "language": "python", - "metadata": {}, - "outputs": [] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "When colormaps are created in mpl, they get \"registered\" with a name. This allows one to specify a colormap to use by name." - ] - }, - { - "cell_type": "code", - "collapsed": false, - "input": [ - "fig, (ax1, ax2) = plt.subplots(1, 2)\n", - "z = np.random.random((10, 10))\n", - "ax1.imshow(z, interpolation='none', cmap='gray')\n", - "ax2.imshow(z, interpolation='none', cmap='coolwarm')\n", - "plt.show()" - ], - "language": "python", - "metadata": {}, - "outputs": [] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "# Mathtext\n", - "Oftentimes, you just simply need that superscript or some other math text in your labels. Matplotlib provides a very easy way to do this for those familiar with LaTeX. Any text that is surrounded by dollar signs will be treated as \"[mathtext](http://matplotlib.org/users/mathtext.html#mathtext-tutorial)\". Do note that because backslashes are prevelent in LaTeX, it is often a good idea to prepend an `r` to your string literal so that Python will not treat the backslashes as escape characters." - ] - }, - { - "cell_type": "code", - "collapsed": false, - "input": [ - "plt.scatter([1, 2, 3, 4], [4, 3, 2, 1])\n", - "plt.title(r'$\\sigma_i=15$', fontsize=20)\n", - "plt.show()" - ], - "language": "python", - "metadata": {}, - "outputs": [] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "# Annotations and Arrows\n", - "There are two ways one can place arbitrary text anywhere they want on a plot. The first is a simple [`text()`](http://matplotlib.org/api/pyplot_api.html#matplotlib.pyplot.text). Then there is the fancier [`annotate()`](http://matplotlib.org/api/pyplot_api.html#matplotlib.pyplot.annotate) function that can help \"point out\" what you want to annotate." - ] - }, - { - "cell_type": "code", - "collapsed": false, - "input": [ - "t = np.arange(0.0, 5.0, 0.01)\n", - "s = np.cos(2*np.pi*t)\n", - "plt.plot(t, s, lw=2)\n", - "\n", - "plt.annotate('local max', xy=(2, 1), xytext=(3, 1.5),\n", - " arrowprops=dict(facecolor='black', shrink=0.05))\n", - "\n", - "plt.ylim(-2, 2)\n", - "plt.show()" - ], - "language": "python", - "metadata": {}, - "outputs": [] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "There are all sorts of boxes for your text, and arrows you can use, and there are many different ways to connect the text to the point that you want to annotate. For a complete tutorial on this topic, go to the [Annotation Guide](http://matplotlib.org/users/annotations_guide.html). In the meantime, here is a table of the kinds of arrows that can be drawn " - ] - }, - { - "cell_type": "code", - "collapsed": false, - "input": [ - "import matplotlib.patches as mpatches\n", - "\n", - "styles = mpatches.ArrowStyle.get_styles()\n", - "\n", - "ncol=2\n", - "nrow = (len(styles)+1) // ncol\n", - "figheight = (nrow+0.5)\n", - "fig = plt.figure(1, (4.0*ncol/0.85, figheight/0.85))\n", - "fontsize = 0.4 * 70\n", - "\n", - "ax = fig.add_axes([0, 0, 1, 1])\n", - "ax.set_xlim(0, 4*ncol)\n", - "ax.set_ylim(0, figheight)\n", - "\n", - "def to_texstring(s):\n", - " s = s.replace(\"<\", r\"$<$\")\n", - " s = s.replace(\">\", r\"$>$\")\n", - " s = s.replace(\"|\", r\"$|$\")\n", - " return s\n", - "\n", - "for i, (stylename, styleclass) in enumerate(sorted(styles.items())):\n", - " x = 3.2 + (i//nrow)*4\n", - " y = (figheight - 0.7 - i%nrow)\n", - " p = mpatches.Circle((x, y), 0.2, fc=\"w\")\n", - " ax.add_patch(p)\n", - "\n", - " ax.annotate(to_texstring(stylename), (x, y),\n", - " (x-1.2, y),\n", - " ha=\"right\", va=\"center\",\n", - " size=fontsize,\n", - " arrowprops=dict(arrowstyle=stylename,\n", - " patchB=p,\n", - " shrinkA=50,\n", - " shrinkB=5,\n", - " fc=\"w\", ec=\"k\",\n", - " connectionstyle=\"arc3,rad=-0.25\",\n", - " ),\n", - " bbox=dict(boxstyle=\"square\", fc=\"w\"))\n", - "\n", - "ax.set_axis_off()\n", - "plt.show()\n" - ], - "language": "python", - "metadata": {}, - "outputs": [] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "## Exercise 2.4\n", - "Point out a local minimum with a fancy red arrow." - ] - }, - { - "cell_type": "code", - "collapsed": false, - "input": [ - "%load exercises/2.4-arrows.py" - ], - "language": "python", - "metadata": {}, - "outputs": [] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "# Hatches\n", - "A Patch object can have a hatching defined for it.\n", - "\n", - "* / - diagonal hatching\n", - "* \\ - back diagonal\n", - "* | - vertical\n", - "* \\- - horizontal\n", - "* \\+ - crossed\n", - "* x - crossed diagonal\n", - "* o - small circle\n", - "* O - large circle (upper-case 'o')\n", - "* . - dots\n", - "* \\* - stars\n", - " \n", - "Letters can be combined, in which case all the specified\n", - "hatchings are done. If same letter repeats, it increases the\n", - "density of hatching of that pattern." - ] - }, - { - "cell_type": "code", - "collapsed": false, - "input": [ - "bars = plt.bar([1, 2, 3, 4], [10, 12, 15, 17])\n", - "plt.setp(bars[0], hatch='x', facecolor='w')\n", - "plt.show()" - ], - "language": "python", - "metadata": {}, - "outputs": [] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "# Transforms\n", - "The topic of transforms in matplotlib, that is the ability to map the coordinates specified by your data to the coordinates of your figure, is very advanced and will not be covered in this tutorial. For those who are interested in learning about them, see the [transformation tutorial](http://matplotlib.org/users/transforms_tutorial.html). For those who are really daring, there are the developer guides to [transforms](http://matplotlib.org/devel/transformations.html) and [scales](http://matplotlib.org/devel/add_new_projection.html). While most users will never, ever need to understand matplotlib transforms to the level described in those links, it is important to be aware of them, and their critical role in figure-making.\n", - "\n", - "In a figure, there are four coordinate systems: *display*, *figure*, *axes*, and *data*. Transforms are used to convert coordinates in one system into another system for various uses. This is how matplotlib knows exactly where to place the ticks and ticklabels, even when you change the axis limits. The ticker says that the tick and label \"1.5\", for example, are to go at data x-coordinate 1.5. The transform says that location is at 0.4 in axes x-coordinate space. Meanwhile, the xlabel of \"Distance\" is placed at axes x-coordinate space of 0.5 (half-way). Meanwhile, a legend might be placed at a location relative to the figure coordinates.\n", - "\n", - "Furthermore, the transform system is what is used to allow various scales to work, such as log scales. The transform system is what is used to make the polar plots work seamlessly. Whether you realize it or not, you use the transforms system in matplotlib all the time. Everything drawn in matplotlib has a transform associated with it. Most of the time, you will never notice this, and will happily operate within the *data* coordinate system. But when you want to do some more advanced plots, with some eye-catching visual tricks, the transform system will be there for you." - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "# Managing the unmanagable -- Introducing matplotlibrc\n", - "Matplotlib's greatest strength is its ability to give you complete control over every single aspect of your plots and figures. Matplotlib's second greatest strength is its ability to take as much control over as much of your plots and figures as you want. You, as the user, would never consider to use matplotlib if you had to specify all of these things for every single plot. Most of the time, the defaults are exactly what you want them to be.\n", - "\n", - "Matplotlib uses the matplotlibrc configuration file to define the plethora of defaults found in matplotlib. You can control the defaults of almost every property in matplotlib: figure size and dpi, line width, color and style, axes, axis and grid properties, text and font properties and so on. Just modify your rc file and re-run your scripts to produce your improved figures.\n", - "\n", - "To display where the currently active matplotlibrc file was loaded from, one can do the following:" - ] - }, - { - "cell_type": "code", - "collapsed": false, - "input": [ - "import matplotlib\n", - "print matplotlib.matplotlib_fname()" - ], - "language": "python", - "metadata": {}, - "outputs": [] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "You can also change the rc settings during runtime within a python script or interactively from the python shell. All of the rc settings are stored in a dictionary-like variable called [`matplotlib.rcParams`](http://matplotlib.org/api/matplotlib_configuration_api.html#matplotlib.matplotlib.rcParams), which is global to the matplotlib package. `rcParams` can be modified directly. Newer versions of matplotlib can use [`rc()`](http://matplotlib.org/api/matplotlib_configuration_api.html#matplotlib.rc), for example:" - ] - }, - { - "cell_type": "code", - "collapsed": false, - "input": [ - "import matplotlib as mpl\n", - "import matplotlib.pyplot as plt\n", - "mpl.rcdefaults() # for when re-running this cell\n", - "\n", - "fig, (ax1, ax2) = plt.subplots(1, 2)\n", - "ax1.plot([1, 2, 3, 4])\n", - "\n", - "mpl.rc('lines', linewidth=2, linestyle='-.')\n", - "# Equivalent older, but still valid syntax\n", - "#mpl.rcParams['lines.linewidth'] = 2\n", - "#mpl.rcParams['lines.linestyle'] = '-.'\n", - "ax2.plot([1, 2, 3, 4])\n", - "plt.show()" - ], - "language": "python", - "metadata": {}, - "outputs": [] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "To learn more, please see this guide on [customizing matplotlib](http://matplotlib.org/users/customizing.html)." - ] - } - ], - "metadata": {} - } - ] -} \ No newline at end of file diff --git a/AnatomyOfMatplotlib-Part2-Plotting_Methods_Overview.ipynb b/AnatomyOfMatplotlib-Part2-Plotting_Methods_Overview.ipynb new file mode 100644 index 0000000..ac00986 --- /dev/null +++ b/AnatomyOfMatplotlib-Part2-Plotting_Methods_Overview.ipynb @@ -0,0 +1,470 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# Part 2: Visual Overview of Plotting Functions\n", + "\n", + "We've talked a lot about laying things out, etc, but we haven't talked about actually plotting data yet. Matplotlib has a number of different plotting functions -- many more than we'll cover here, in fact. There's a more complete list in the pyplot documentation, and Matplotlib gallery is a great place to get examples of all of them. \n", + "\n", + "However, a full list and/or the gallery can be a bit overwhelming at first. Instead we'll condense it down and give you a look at some of the ones you're most likely to use, and then go over a subset of those in more detail.\n", + "\n", + "Here's a simplified visual overview of matplotlib's most commonly used plot types. Let's browse through these, and then we'll go over a few in more detail. Clicking on any of these images will take you to the code that generated them. We'll skip that for now, but feel browse through it later." + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## The Basics: 1D series/points\n", + "### What we've mentioned so far\n", + "\n", + "\n", + "### Other common plot types\n", + "\n", + "\n", + "\n", + "## 2D Arrays and Images\n", + "\n", + "\n", + "\n", + "\n", + "## Vector Fields\n", + "\n", + "\n", + "## Data Distributions\n", + "" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# Detailed Examples (of a few of these)" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "# Let's get our standard imports out of the way\n", + "from __future__ import print_function\n", + "import numpy as np\n", + "import matplotlib\n", + "matplotlib.use('nbagg')\n", + "import matplotlib.pyplot as plt" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# Input Data: 1D Series\n", + "\n", + "We've briefly mentioned `ax.plot(x, y)` and `ax.scatter(x, y)` to draw lines and points, respectively. We'll cover some of their options (markers, colors, linestyles, etc) in the next section. Let's move on to a couple of other common plot types.\n", + "\n", + "### Bar Plots: `ax.bar(...)` and `ax.barh(...)`\n", + "\n", + "\n", + "Bar plots are one of the most common plot types. Matplotlib's `ax.bar(...)` method can also plot general rectangles, but the default is optimized for a simple sequence of x, y values, where the rectangles have a constant width. There's also `ax.barh(...)` (for horizontal), which makes a constant-height assumption instead of a constant-width assumption." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "np.random.seed(1)\n", + "x = np.arange(5)\n", + "y = np.random.randn(5)\n", + "\n", + "fig, axes = plt.subplots(ncols=2, figsize=plt.figaspect(1./2))\n", + "\n", + "vert_bars = axes[0].bar(x, y, color='lightblue', align='center')\n", + "horiz_bars = axes[1].barh(x, y, color='lightblue', align='center')\n", + "\n", + "# I'll also introduce axhline & axvline to draw a line all the way across the axes\n", + "# This can be a quick-n-easy way to draw an axis \"spine\".\n", + "axes[0].axhline(0, color='gray', linewidth=2)\n", + "axes[1].axvline(0, color='gray', linewidth=2)\n", + "\n", + "plt.show()" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Note that we held on to what `ax.bar(...)` returned. Matplotlib plotting methods return an `Artist` or a sequence of artists. Anything you can see in a Matplotlib figure/axes/etc is an `Artist` of some sort. Most of the time, you will not need to retain these returned objects. You will want to capture them for special customizing that may not be possible through the normal plotting mechanism.\n", + "\n", + "Let's re-visit that last example and modify what's plotted. In the case of `bar`, a container artist is returned, so we'll modify its contents instead of the container itself (thus, `for bar in vert_bars`)." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "fig, ax = plt.subplots()\n", + "vert_bars = ax.bar(x, y, color='lightblue', align='center')\n", + "\n", + "# We could have also done this with two separate calls to `ax.bar` and numpy boolean indexing.\n", + "for bar, height in zip(vert_bars, y):\n", + " if height < 0:\n", + " bar.set(color='salmon', edgecolor='darkred', linewidth=3)\n", + "\n", + "plt.show()" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Keep in mind that any plotting method in matplotlib returns the artists that are plotted. We'll use it again, particularly when we get to adding colorbars to images." + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### Filled Regions: `ax.fill(x, y)`, `fill_between(...)`, etc\n", + "\n", + "\n", + "Of these functions, `ax.fill_between(...)` is probably the one you'll use the most often. In its most basic form, it fills between the given y-values and 0:" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "np.random.seed(1)\n", + "y = np.random.randn(100).cumsum()\n", + "x = np.linspace(0, 10, 100)\n", + "\n", + "fig, ax = plt.subplots()\n", + "ax.fill_between(x, y, color='lightblue')\n", + "plt.show()" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "However, it can also be used to fill between two curves. This is particularly useful when you want to show an envelope of some sort (e.g. error, confidence, amplitude, etc)." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "x = np.linspace(0, 10, 200)\n", + "y1 = 2 * x + 1\n", + "y2 = 3 * x + 1.2\n", + "y_mean = 0.5 * x * np.cos(2*x) + 2.5 * x + 1.1\n", + "\n", + "fig, ax = plt.subplots()\n", + "\n", + "# Plot the envelope with `fill_between`\n", + "ax.fill_between(x, y1, y2, color='yellow')\n", + "\n", + "# Plot the \"centerline\" with `plot`\n", + "ax.plot(x, y_mean, color='black')\n", + "\n", + "plt.show()" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## `data` keyword argument\n", + "\n", + "When using nested data structures such as h5py objects, Pandas DataFrames, or XArrays, the data can be accessed via `[]` like dictionary elements. This can get very repetitive and tedious as one types out a plotting command accessing those elements. So, the `data` keyword argument was added to almost all of the plotting functions in v1.5. With this feature, one can pass in a single dictionary-like object as `data`, and use the string key names in the place of the usual input data arguments.\n", + "\n", + "Let's revisit the above example:" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "x = np.linspace(0, 10, 200)\n", + "data_obj = {'x': x,\n", + " 'y1': 2 * x + 1,\n", + " 'y2': 3 * x + 1.2,\n", + " 'mean': 0.5 * x * np.cos(2*x) + 2.5 * x + 1.1}\n", + "\n", + "fig, ax = plt.subplots()\n", + "\n", + "# Plot the envelope with `fill_between`\n", + "ax.fill_between('x', 'y1', 'y2', color='yellow', data=data_obj)\n", + "\n", + "# Plot the \"centerline\" with `plot`\n", + "ax.plot('x', 'mean', color='black', data=data_obj)\n", + "\n", + "plt.show()" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# Exercise 2.1:\n", + "\n", + "Now let's try combining `bar` and `fill_between` to make a nice prediction of what will happen as this class progresses:\n", + "\n", + "Can you reproduce the figure below?\n", + "" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "%load exercises/2.1-bar_and_fill_between.py" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "import numpy as np\n", + "import matplotlib.pyplot as plt\n", + "np.random.seed(1)\n", + "\n", + "# Generate data...\n", + "y_raw = np.random.randn(1000).cumsum() + 15\n", + "x_raw = np.linspace(0, 24, y_raw.size)\n", + "\n", + "# Get averages of every 100 samples...\n", + "x_pos = x_raw.reshape(-1, 100).min(axis=1)\n", + "y_avg = y_raw.reshape(-1, 100).mean(axis=1)\n", + "y_err = y_raw.reshape(-1, 100).ptp(axis=1)\n", + "\n", + "bar_width = x_pos[1] - x_pos[0]\n", + "\n", + "# Make a made up future prediction with a fake confidence\n", + "x_pred = np.linspace(0, 30)\n", + "y_max_pred = y_avg[0] + y_err[0] + 2.3 * x_pred\n", + "y_min_pred = y_avg[0] - y_err[0] + 1.2 * x_pred\n", + "\n", + "# Just so you don't have to guess at the colors...\n", + "barcolor, linecolor, fillcolor = 'wheat', 'salmon', 'lightblue'\n", + "\n", + "# Now you're on your own!\n" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# Input Data: 2D Arrays or Images\n", + "\n", + "There are several options for plotting 2D datasets. `imshow`, `pcolor`, and `pcolormesh` have a lot of overlap, at first glance. The image below is meant to clarify that somewhat.\n", + "\n", + "\n", + "\n", + "\n", + "In short, `imshow` can interpolate and display large arrays very quickly, while `pcolormesh` and `pcolor` are much slower, but can handle flexible (i.e. more than just rectangular) arrangements of cells.\n", + "\n", + "We won't dwell too much on the differences and overlaps here. They have overlapping capabilities, but different default behavior because their primary use-cases are a bit different (there's also `matshow`, which is `imshow` with different defaults). \n", + "\n", + "Instead we'll focus on what they have in common.\n", + "\n", + "`imshow`, `pcolor`, `pcolormesh`, `scatter`, and any other Matplotlib plotting methods that map a range of data values onto a colormap will return artists that are instances of `ScalarMappable.` In practice, what that means is a) you can display a colorbar for them, and b) they share several keyword arguments." + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### Colorbars\n", + "\n", + "Let's add a colorbar to the figure to display what colors correspond to values of `data` we've plotted. " + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "from matplotlib.cbook import get_sample_data\n", + "data = np.load('assets/bivariate_normal.npy')\n", + "\n", + "fig, ax = plt.subplots()\n", + "im = ax.imshow(data, cmap='gist_earth')\n", + "fig.colorbar(im)\n", + "plt.show()" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "You may notice that `colorbar` is a `Figure` method and not an `Axes` method. That's because `colorbar` doesn't operate on the axes. Instead, it shrinks the current axes by a bit, adds a _new_ axes to the figure, and places the colorbar on that axes.\n", + "\n", + "The new axes that `fig.colorbar` creates is fairly limited in where it can be positioned. For example, it's always outside the axes it \"steals\" room from. Sometimes you may want to avoid \"stealing\" room from an axes or maybe even have the colorbar _inside_ another axes. In that case, you can manually create the axes for the colorbar and position it where you'd like:" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "fig, ax = plt.subplots()\n", + "cax = fig.add_axes([0.27, 0.8, 0.5, 0.05])\n", + "\n", + "im = ax.imshow(data, cmap='gist_earth')\n", + "fig.colorbar(im, cax=cax, orientation='horizontal')\n", + "plt.show()" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "One note: In the last module in this tutorial, we'll briefly cover `axes_grid`, which is very useful for aligning colorbars and/or other axes with images displayed with `imshow`. " + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + " ### Shared parameters for `imshow`, `pcolormesh`, `contour`, `scatter`, etc\n", + " \n", + " As we mentioned earlier, any plotting method that creates a `ScalarMappable` will have some common kwargs. The ones you'll use the most frequently are:\n", + " \n", + " * `cmap` : The colormap (or name of the colormap) used to display the input. (We'll go over the different colormaps in the next section.)\n", + " * `vmin` : The minimum data value that will correspond to the \"bottom\" of the colormap (defaults to the minimum of your input data).\n", + " * `vmax` : The maximum data value that will correspond to the \"top\" of the colormap (defaults to the maximum of your input data).\n", + " * `norm` : A `Normalize` instance to control how the data values are mapped to the colormap. By default, this will be a linear scaling between `vmin` and `vmax`, but other norms are available (e.g. `LogNorm`, `PowerNorm`, etc).\n", + " \n", + "`vmin` and `vmax` are particularly useful. Quite often, you'll want the colors to be mapped to a set range of data values, which aren't the min/max of your input data. For example, you might want a symmetric ranges of values around 0.\n", + "\n", + "See the documentation for longer discussions of [colormaps](https://matplotlib.org/tutorials/colors/colormaps.html) and [norms](https://matplotlib.org/tutorials/colors/colormapnorms.html).\n", + "\n", + "As an example of that, let's use a divergent colormap with the data we showed earlier. " + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "from matplotlib.cbook import get_sample_data\n", + "data = np.load('assets/bivariate_normal.npy')\n", + "\n", + "fig, ax = plt.subplots()\n", + "im = ax.imshow(data, cmap='seismic')\n", + "fig.colorbar(im)\n", + "plt.show()" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "In this case, we'd really like the white in the colormap to correspond to 0. A quick way to do this is to make the `vmin` equal to the negative of the `vmax`. " + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "fig, ax = plt.subplots()\n", + "im = ax.imshow(data, \n", + " cmap='seismic',\n", + " vmin=-2, vmax=2)\n", + "fig.colorbar(im)\n", + "plt.show()" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "`vmin` and `vmax` are also very useful when we want multiple plots to share one colorbar, as our next exercise will do.\n", + "\n", + "## Exercise 2.2:\n", + "\n", + "Can you reproduce the figure below?\n", + "" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "%load exercises/2.2-vmin_vmax_imshow_and_colorbars.py" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "import numpy as np\n", + "import matplotlib.pyplot as plt\n", + "np.random.seed(1)\n", + "\n", + "plt.style.use('classic')\n", + "\n", + "# Generate random data with different ranges...\n", + "data1 = np.random.random((10, 10))\n", + "data2 = 2 * np.random.random((10, 10))\n", + "data3 = 3 * np.random.random((10, 10))\n", + "\n", + "# Set up our figure and axes...\n", + "fig, axes = plt.subplots(ncols=3, figsize=plt.figaspect(0.5))\n", + "fig.tight_layout() # Make the subplots fill up the figure a bit more...\n", + "cax = fig.add_axes([0.25, 0.1, 0.55, 0.03]) # Add an axes for the colorbar\n", + "\n", + "# Now you're on your own!\n" + ] + } + ], + "metadata": { + "kernelspec": { + "display_name": "Python 3", + "language": "python", + "name": "python3" + }, + "language_info": { + "codemirror_mode": { + "name": "ipython", + "version": 3 + }, + "file_extension": ".py", + "mimetype": "text/x-python", + "name": "python", + "nbconvert_exporter": "python", + "pygments_lexer": "ipython3", + "version": "3.6.6" + } + }, + "nbformat": 4, + "nbformat_minor": 1 +} diff --git a/AnatomyOfMatplotlib-Part3-Artists.ipynb b/AnatomyOfMatplotlib-Part3-Artists.ipynb deleted file mode 100644 index 125dc6b..0000000 --- a/AnatomyOfMatplotlib-Part3-Artists.ipynb +++ /dev/null @@ -1,280 +0,0 @@ -{ - "metadata": { - "name": "", - "signature": "sha256:8e508bf3316b2a5e920e25f9597d595277a37bede03ba337428c5c16762373a7" - }, - "nbformat": 3, - "nbformat_minor": 0, - "worksheets": [ - { - "cells": [ - { - "cell_type": "code", - "collapsed": false, - "input": [ - "# Turning on inline plots -- just for use in ipython notebooks.\n", - "%matplotlib inline\n", - "import numpy as np\n", - "import matplotlib.pyplot as plt" - ], - "language": "python", - "metadata": {}, - "outputs": [] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "# Artists\n", - "Anything that can be displayed in a Figure is an [`Artist`](http://matplotlib.org/users/artists.html). There are two main classes of Artists: primatives and containers. Below is a sample of these primitives." - ] - }, - { - "cell_type": "code", - "collapsed": false, - "input": [ - "\"\"\"\n", - "Show examples of matplotlib artists\n", - "http://matplotlib.org/api/artist_api.html\n", - "\n", - "Several examples of standard matplotlib graphics primitives (artists)\n", - "are drawn using matplotlib API. Full list of artists and the\n", - "documentation is available at\n", - "http://matplotlib.org/api/artist_api.html\n", - "\n", - "Copyright (c) 2010, Bartosz Telenczuk\n", - "\n", - "License: This work is licensed under the BSD. A copy should be\n", - "included with this source code, and is also available at\n", - "http://www.opensource.org/licenses/bsd-license.php\n", - "\"\"\"\n", - "\n", - "from matplotlib.collections import PatchCollection\n", - "import matplotlib.path as mpath\n", - "import matplotlib.patches as mpatches\n", - "import matplotlib.lines as mlines\n", - "\n", - "fig, ax = plt.subplots(1, 1, figsize=(7,7))\n", - "\n", - "# create 3x3 grid to plot the artists\n", - "pos = np.mgrid[0.2:0.8:3j, 0.2:0.8:3j].reshape(2, -1)\n", - "patches = []\n", - "\n", - "# add a circle\n", - "art = mpatches.Circle(pos[:, 0], 0.1, ec=\"none\")\n", - "patches.append(art)\n", - "plt.text(pos[0, 0], pos[1, 0] - 0.15, \"Circle\", ha=\"center\", size=14)\n", - "\n", - "# add a rectangle\n", - "art = mpatches.Rectangle(pos[:, 1] - [0.025, 0.05], 0.05, 0.1, ec=\"none\")\n", - "patches.append(art)\n", - "plt.text(pos[0, 1], pos[1, 1] - 0.15, \"Rectangle\", ha=\"center\", size=14)\n", - "\n", - "# add a wedge\n", - "wedge = mpatches.Wedge(pos[:, 2], 0.1, 30, 270, ec=\"none\")\n", - "patches.append(wedge)\n", - "plt.text(pos[0, 2], pos[1, 2] - 0.15, \"Wedge\", ha=\"center\", size=14)\n", - "\n", - "# add a Polygon\n", - "polygon = mpatches.RegularPolygon(pos[:, 3], 5, 0.1)\n", - "patches.append(polygon)\n", - "plt.text(pos[0, 3], pos[1, 3] - 0.15, \"Polygon\", ha=\"center\", size=14)\n", - "\n", - "#add an ellipse\n", - "ellipse = mpatches.Ellipse(pos[:, 4], 0.2, 0.1)\n", - "patches.append(ellipse)\n", - "plt.text(pos[0, 4], pos[1, 4] - 0.15, \"Ellipse\", ha=\"center\", size=14)\n", - "\n", - "#add an arrow\n", - "arrow = mpatches.Arrow(pos[0, 5] - 0.05, pos[1, 5] - 0.05, 0.1, 0.1, width=0.1)\n", - "patches.append(arrow)\n", - "plt.text(pos[0, 5], pos[1, 5] - 0.15, \"Arrow\", ha=\"center\", size=14)\n", - "\n", - "# add a path patch\n", - "Path = mpath.Path\n", - "verts = np.array([\n", - " (0.158, -0.257),\n", - " (0.035, -0.11),\n", - " (-0.175, 0.20),\n", - " (0.0375, 0.20),\n", - " (0.085, 0.115),\n", - " (0.22, 0.32),\n", - " (0.3, 0.005),\n", - " (0.20, -0.05),\n", - " (0.158, -0.257),\n", - " ])\n", - "verts = verts - verts.mean(0)\n", - "codes = [Path.MOVETO,\n", - " Path.CURVE4, Path.CURVE4, Path.CURVE4, Path.LINETO,\n", - " Path.CURVE4, Path.CURVE4, Path.CURVE4, Path.CLOSEPOLY]\n", - "\n", - "path = mpath.Path(verts / 2.5 + pos[:, 6], codes)\n", - "patch = mpatches.PathPatch(path)\n", - "patches.append(patch)\n", - "plt.text(pos[0, 6], pos[1, 6] - 0.15, \"PathPatch\", ha=\"center\", size=14)\n", - "\n", - "# add a fancy box\n", - "fancybox = mpatches.FancyBboxPatch(\n", - " pos[:, 7] - [0.025, 0.05], 0.05, 0.1,\n", - " boxstyle=mpatches.BoxStyle(\"Round\", pad=0.02))\n", - "patches.append(fancybox)\n", - "plt.text(pos[0, 7], pos[1, 7] - 0.15, \"FancyBoxPatch\", ha=\"center\", size=14)\n", - "\n", - "# add a line\n", - "x,y = np.array([[-0.06, 0.0, 0.1], [0.05,-0.05, 0.05]])\n", - "line = mlines.Line2D(x+pos[0, 8], y+pos[1, 8], lw=5.)\n", - "plt.text(pos[0, 8], pos[1, 8] - 0.15, \"Line2D\", ha=\"center\", size=14)\n", - "\n", - "collection = PatchCollection(patches)\n", - "ax.add_collection(collection)\n", - "ax.add_line(line)\n", - "ax.set_axis_off()\n", - "\n", - "plt.show()" - ], - "language": "python", - "metadata": {}, - "outputs": [] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "Containers are objects like *Figure* and *Axes*. Containers are given primitives to draw. The plotting functions we discussed back in Part 1 are convenience functions that generate these primitives and places them into the appropriate containers. In fact, most of those functions will return artist objects (or a list of artist objects) as well as store them into the appropriate axes container.\n", - "\n", - "As discussed in Part 2, there is a wide range of properties that can be defined for your plots. These properties are processed and passed down to the primitives, for your convenience. Ultimately, you can override anything you want just by directly setting a property to the object itself." - ] - }, - { - "cell_type": "code", - "collapsed": false, - "input": [ - "fig, ax = plt.subplots(1, 1)\n", - "lines = plt.plot([1, 2, 3, 4], [1, 2, 3, 4], 'b', [1, 2, 3, 4], [4, 3, 2, 1], 'r')\n", - "lines[0].set(linewidth=5)\n", - "lines[1].set(linewidth=10, alpha=0.7)\n", - "plt.show()" - ], - "language": "python", - "metadata": {}, - "outputs": [] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "To see what properties are set for an artist, use [`getp()`](http://matplotlib.org/api/artist_api.html#matplotlib.artist.getp)" - ] - }, - { - "cell_type": "code", - "collapsed": false, - "input": [ - "fig, ax = plt.subplots(1, 1)\n", - "print plt.getp(fig.patch)" - ], - "language": "python", - "metadata": {}, - "outputs": [] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "# Collections\n", - "In addition to the Figure and Axes containers, there is another special type of container called a [`Collection`](http://matplotlib.org/api/collections_api.html). A Collection usually contains a list of primitives of the same kind that should all be treated similiarly. For example, a [`CircleCollection`](http://matplotlib.org/api/collections_api.html#matplotlib.collections.CircleCollection) would have a list of [`Circle`](http://matplotlib.org/api/artist_api.html#matplotlib.patches.Circle) objects all with the same color, size, and edge width. Individual values for artists in the collection can also be set." - ] - }, - { - "cell_type": "code", - "collapsed": false, - "input": [ - "from matplotlib.collections import LineCollection\n", - "fig, ax = plt.subplots(1, 1)\n", - "lc = LineCollection([[(4, 10), (16, 10)],\n", - " [(2, 2), (10, 15), (6, 7)],\n", - " [(14, 3), (1, 1), (3, 5)]])\n", - "lc.set_color('r')\n", - "lc.set_linewidth(5)\n", - "ax.add_collection(lc)\n", - "ax.set_xlim(0, 18)\n", - "ax.set_ylim(0, 18)\n", - "plt.show()" - ], - "language": "python", - "metadata": {}, - "outputs": [] - }, - { - "cell_type": "code", - "collapsed": false, - "input": [ - "# Now show how to set individual properties in a collection\n", - "fig, ax = plt.subplots(1, 1)\n", - "lc = LineCollection([[(4, 10), (16, 10)],\n", - " [(2, 2), (10, 15), (6, 7)],\n", - " [(14, 3), (1, 1), (3, 5)]])\n", - "lc.set_color(['r', 'blue', (0.2, 0.9, 0.3)])\n", - "lc.set_linewidth([4, 3, 6])\n", - "ax.add_collection(lc)\n", - "ax.set_xlim(0, 18)\n", - "ax.set_ylim(0, 18)\n", - "plt.show()" - ], - "language": "python", - "metadata": {}, - "outputs": [] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "There are other kinds of collections that are not just simply a list of primitives, but are Artists in their own right. These special kinds of collections take advantage of various optimizations that can be assumed when rendering similar or identical things. You actually do use these collections all the time whether you realize it or not. Markers are (indirectly) implemented this way (so, whenever you do `plot()` or `scatter()`, for example)." - ] - }, - { - "cell_type": "code", - "collapsed": false, - "input": [ - "from matplotlib.collections import RegularPolyCollection\n", - "\n", - "fig, ax = plt.subplots(1, 1)\n", - "offsets = np.random.rand(20, 2)\n", - "collection = RegularPolyCollection(\n", - " numsides=5, # a pentagon\n", - " sizes=(50,),\n", - " offsets=offsets,\n", - " transOffset=ax.transData,\n", - " )\n", - "ax.add_collection(collection)\n", - "plt.show()" - ], - "language": "python", - "metadata": {}, - "outputs": [] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "## Exercise 3.1\n", - "Give yourselves 4 gold stars!\n", - "\n", - "Hint: [StarPolygonCollection](http://matplotlib.org/api/collections_api.html#matplotlib.collections.StarPolygonCollection)" - ] - }, - { - "cell_type": "code", - "collapsed": false, - "input": [ - "%load exercises/3.1-goldstar.py" - ], - "language": "python", - "metadata": {}, - "outputs": [] - } - ], - "metadata": {} - } - ] -} \ No newline at end of file diff --git a/AnatomyOfMatplotlib-Part3-HowToSpeakMPL.ipynb b/AnatomyOfMatplotlib-Part3-HowToSpeakMPL.ipynb new file mode 100644 index 0000000..e3c93fe --- /dev/null +++ b/AnatomyOfMatplotlib-Part3-HowToSpeakMPL.ipynb @@ -0,0 +1,615 @@ +{ + "cells": [ + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "# Let printing work the same in Python 2 and 3\n", + "from __future__ import print_function\n", + "# Turning on notebook plots -- just for use in jupyter notebooks.\n", + "import matplotlib\n", + "matplotlib.use('nbagg')\n", + "import numpy as np\n", + "import matplotlib.pyplot as plt" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# How to speak \"MPL\"\n", + "In the previous parts, you learned how Matplotlib organizes plot-making by figures and axes. We broke down the components of a basic figure and learned how to create them. You also learned how to add one or more axes to a figure, and how to tie them together. You even learned how to change some of the basic appearances of the axes. Finally, we went over some of the many plotting methods that Matplotlib has to draw on those axes. With all that knowledge, you should be off making great and wonderful figures.\n", + "\n", + "Why are you still here?\n", + "\n", + "\"We don't know how to control our plots and figures!\" says some random voice in the back of the room.\n", + "\n", + "Of course! While the previous sections may have taught you some of the structure and syntax of Matplotlib, it did not describe much of the substance and vocabulary of the library. This section will go over many of the properties that are used throughout the library. Note that while many of the examples in this section may show one way of setting a particular property, that property may be applicible elsewhere in completely different context. This is the \"language\" of Matplotlib.\n", + "\n", + "# Colors\n", + "This is, perhaps, the most important piece of vocabulary in Matplotlib. Given that Matplotlib is a plotting library, colors are associated with everything that is plotted in your figures. Matplotlib supports a [very robust language](http://matplotlib.org/api/colors_api.html#module-matplotlib.colors) for specifying colors that should be familiar to a wide variety of users.\n", + "\n", + "### Colornames\n", + "First, colors can be given as strings. For very basic colors, you can even get away with just a single letter:\n", + "\n", + "- b: blue\n", + "- g: green\n", + "- r: red\n", + "- c: cyan\n", + "- m: magenta\n", + "- y: yellow\n", + "- k: black\n", + "- w: white\n", + "\n", + "Other colornames that are allowed are the HTML/CSS colornames such as \"burlywood\" and \"chartreuse\". See the [full list](https://www.w3schools.com/Colors/colors_names.asp) of the 140 color names. \n", + "\n", + "Matplotlib supports the [xkcd color names](https://xkcd.com/color/rgb/) prefxed by `'xkcd:'`.\n", + "\n", + "Matplotlib also understands `{'tab:blue', 'tab:orange', 'tab:green', 'tab:red', 'tab:purple', 'tab:brown', 'tab:pink', 'tab:gray', 'tab:olive', 'tab:cyan'}` which are the Tableau Colors from the ‘T10’ categorical palette (and the default color cycle);\n", + "\n", + "### Hex values\n", + "Colors can also be specified by supplying a HTML/CSS hex string, such as `'#0000FF'` for blue. Support for an optional alpha channel was added for v2.0.\n", + "\n", + "### 256 Shades of Gray\n", + "A gray level can be given instead of a color by passing a string representation of a number between 0 and 1, inclusive. `'0.0'` is black, while `'1.0'` is white. `'0.75'` would be a light shade of gray.\n", + "\n", + "### Cycle references\n", + "With the advent of fancier color cycles coming from the many available styles, users needed a way to reference those colors in the style without explicitly knowing what they are. So, in v2.0, the ability to reference the first 10 iterations of the color cycle was added. Whereever one could specify a color, you can supply a 2 character string of 'C#'. So, 'C0' would be the first color, 'C1' would be the second, and so on and so forth up to 'C9'.\n", + "\n", + "### RGB[A] tuples\n", + "You may come upon instances where the previous ways of specifying colors do not work. When all else fails, the universal language of colors for matplotlib is the RGB[A] tuple. This is the \"Red\", \"Green\", \"Blue\", and sometimes \"Alpha\" tuple of floats in the range of [0, 1]. One means full saturation of that channel, so a red RGBA tuple would be `(1.0, 0.0, 0.0, 1.0)`, whereas a partly transparent green RGBA tuple would be `(0.0, 1.0, 0.0, 0.75)`. The documentation will usually specify whether it accepts RGB or RGBA tuples. Sometimes, a list of tuples would be required for multiple colors, and you can even supply a Nx3 or Nx4 numpy array in such cases.\n", + "\n", + "In functions such as `plot()` and `scatter()`, while it may appear that they can take a color specification, what they really need is a \"format specification\", which includes color as part of the format. Unfortunately, such specifications are string only and so RGB[A] tuples are not supported for such arguments (but you can still pass an RGB[A] tuple for a \"color\" argument).\n", + "\n", + "Oftentimes there is a separate argument for \"alpha\" where-ever you can specify a color. The value for \"alpha\" will usually take precedence over the alpha value in the RGBA tuple. There is no easy way around this inconsistency.\n", + "\n" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Exercise 3.1\n", + "Try out some different string representations of colors (you can't do RGB[A] tuples here)." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "%load exercises/3.1-colors.py\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "t = np.arange(0.0, 5.0, 0.2)\n", + "plt.plot(t, t, t, t**2, t, t**3)\n", + "plt.show()" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# Markers\n", + "[Markers](http://matplotlib.org/api/markers_api.html) are commonly used in [`plot()`](http://matplotlib.org/api/pyplot_api.html#matplotlib.pyplot.plot) and [`scatter()`](http://matplotlib.org/api/pyplot_api.html#matplotlib.pyplot.scatter) plots, but also show up elsewhere. There is a wide set of markers available, and custom markers can even be specified.\n", + "\n", + "marker | description | marker | description | marker | description | marker | description \n", + ":----------|:--------------|:----------|:----------------|:---------|:--------------|:----------|:--------------\n", + "\".\" | point | \"+\" | plus | \",\" | pixel | \"x\" | cross\n", + "\"o\" | circle | \"D\" | diamond | \"d\" | thin_diamond | |\n", + "\"8\" | octagon | \"s\" | square | \"p\" | pentagon | \"\\*\" | star\n", + "\"|\" | vertical line| \"\\_\" | horizontal line | \"h\" | hexagon1 | \"H\" | hexagon2\n", + "0 | tickleft | 4 | caretleft | \"<\" | triangle_left | \"3\" | tri_left\n", + "1 | tickright | 5 | caretright | \">\" | triangle_right| \"4\" | tri_right\n", + "2 | tickup | 6 | caretup | \"^\" | triangle_up | \"2\" | tri_up\n", + "3 | tickdown | 7 | caretdown | \"v\" | triangle_down | \"1\" | tri_down\n", + "\"None\" | nothing | `None` | default | \" \" | nothing | \"\" | nothing" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "xs, ys = np.mgrid[:4, 9:0:-1]\n", + "markers = [\".\", \"+\", \",\", \"x\", \"o\", \"D\", \"d\", \"\", \"8\", \"s\", \"p\", \"*\", \"|\", \"_\", \"h\", \"H\", 0, 4, \"<\", \"3\",\n", + " 1, 5, \">\", \"4\", 2, 6, \"^\", \"2\", 3, 7, \"v\", \"1\", \"None\", None, \" \", \"\"]\n", + "descripts = [\"point\", \"plus\", \"pixel\", \"cross\", \"circle\", \"diamond\", \"thin diamond\", \"\",\n", + " \"octagon\", \"square\", \"pentagon\", \"star\", \"vertical bar\", \"horizontal bar\", \"hexagon 1\", \"hexagon 2\",\n", + " \"tick left\", \"caret left\", \"triangle left\", \"tri left\", \"tick right\", \"caret right\", \"triangle right\", \"tri right\",\n", + " \"tick up\", \"caret up\", \"triangle up\", \"tri up\", \"tick down\", \"caret down\", \"triangle down\", \"tri down\",\n", + " \"Nothing\", \"default\", \"Nothing\", \"Nothing\"]\n", + "fig, ax = plt.subplots(1, 1, figsize=(7.5, 4))\n", + "for x, y, m, d in zip(xs.T.flat, ys.T.flat, markers, descripts):\n", + " ax.scatter(x, y, marker=m, s=100)\n", + " ax.text(x + 0.1, y - 0.1, d, size=14)\n", + "ax.set_axis_off()\n", + "plt.show()" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Exercise 3.2\n", + "Try out some different markers and colors" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "%load exercises/3.2-markers.py" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "t = np.arange(0.0, 5.0, 0.2)\n", + "plt.plot(t, t, , t, t**2, , t, t**3, )\n", + "plt.show()" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# Linestyles\n", + "Line styles are about as commonly used as colors. There are a few predefined linestyles available to use. Note that there are some advanced techniques to specify some custom line styles. [Here](http://matplotlib.org/1.3.0/examples/lines_bars_and_markers/line_demo_dash_control.html) is an example of a custom dash pattern.\n", + "\n", + "linestyle | description\n", + "-------------------|------------------------------\n", + "'-' | solid\n", + "'--' | dashed\n", + "'-.' | dashdot\n", + "':' | dotted\n", + "'None' | draw nothing\n", + "' ' | draw nothing\n", + "'' | draw nothing\n", + "\n", + "Also, don't mix up \".-\" (line with dot markers) and \"-.\" (dash-dot line) when using the ``plot`` function!" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "t = np.arange(0.0, 5.0, 0.2)\n", + "plt.plot(t, t, '-', t, t**2, '--', t, t**3, '-.', t, -t, ':')\n", + "plt.show()" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "It is a bit confusing, but the line styles mentioned above are only valid for lines. Whenever you are dealing with the linestyles of the edges of \"Patch\" objects, you will need to use words instead of the symbols. So \"solid\" instead of \"-\", and \"dashdot\" instead of \"-.\". This issue will be fixed for the v2.1 release and allow these specifications to be used interchangably." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "fig, ax = plt.subplots(1, 1)\n", + "ax.bar([1, 2, 3, 4], [10, 20, 15, 13], ls='dashed', ec='r', lw=5)\n", + "plt.show()" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# Plot attributes\n", + "With just about any plot you can make, there are many attributes that can be modified to make the lines and markers suit your needs. Note that for many plotting functions, Matplotlib will cycle the colors for each dataset you plot. However, you are free to explicitly state which colors you want used for which plots. For [`plt.plot()`](http://matplotlib.org/api/pyplot_api.html#matplotlib.pyplot.plot), you can mix the specification for the colors, linestyles, and markers in a single string." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "t = np.arange(0., 5., 0.2)\n", + "# red dashes, blue squares and green triangles\n", + "plt.plot(t, t, 'r--', t, t**2, 'bs', t, t**3, 'g^')\n", + "plt.show()" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "| Property | Value Type \n", + "|------------------------|-------------------------------------------------\n", + "|alpha | float \n", + "|color or c | any matplotlib color \n", + "|dash_capstyle | ['butt', 'round' 'projecting'] \n", + "|dash_joinstyle | ['miter' 'round' 'bevel']\n", + "|dashes | sequence of on/off ink in points \n", + "|drawstyle | [ ‘default’ ‘steps’ ‘steps-pre’\n", + "| | ‘steps-mid’ ‘steps-post’ ]\n", + "|linestyle or ls | [ '-' '--' '-.' ':' 'None' ' ' ''] \n", + "| | and any drawstyle in combination with a \n", + "| | linestyle, e.g. 'steps--'. \n", + "|linewidth or lw | float value in points \n", + "|marker | [ 0 1 2 3 4 5 6 7 'o' 'd' 'D' 'h' 'H'\n", + "| | '' 'None' ' ' `None` '8' 'p' ','\n", + "| | '+' 'x' '.' 's' '\\*' '\\_' '|'\n", + "| | '1' '2' '3' '4' 'v' '<' '>' '^' ]\n", + "|markeredgecolor or mec | any matplotlib color\n", + "|markeredgewidth or mew | float value in points\n", + "|markerfacecolor or mfc | any matplotlib color\n", + "|markersize or ms | float\n", + "|solid_capstyle | ['butt' 'round' 'projecting']\n", + "|solid_joinstyle | ['miter' 'round' 'bevel']\n", + "|visible | [`True` `False`]\n", + "|zorder | any number\n", + "\n", + "## Exercise 3.3\n", + "Make a plot that has a dotted red line, with large yellow diamond markers that have a green edge" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "%load exercises/3.3-properties.py" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "t = np.arange(0.0, 5.0, 0.1)\n", + "a = np.exp(-t) * np.cos(2*np.pi*t)\n", + "plt.plot(t, a, )\n", + "plt.show()" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# Colormaps\n", + "Another very important property of many figures is the colormap. The job of a colormap is to relate a scalar value to a color. In addition to the regular portion of the colormap, an \"over\", \"under\" and \"bad\" color can be optionally defined as well. NaNs will trigger the \"bad\" part of the colormap.\n", + "\n", + "As we all know, we create figures in order to convey information visually to our readers. There is much care and consideration that have gone into the design of these colormaps. Your choice in which colormap to use depends on what you are displaying. In mpl, the \"jet\" colormap has historically been used by default, but it will often not be the colormap you would want to use. Much discussion has taken place on the mailing lists with regards to what colormap should be default. The v2.0 release of Matplotlib adopted a new default colormap, 'viridis', along with some other stylistic changes to the defaults.\n", + "\n", + "I want to acknowedge Nicolas Rougier and Tony Yu for putting significant effort in educating users in proper colormap selections. Furthermore, thanks goes to Nathaniel Smith and Stéfan van der Walt for developing the new perceptually uniform colormaps such as viridis. [Here is the talk](https://www.youtube.com/watch?v=xAoljeRJ3lU) they gave at SciPy 2015 that does an excelent job explaining colormaps.\n", + "\n", + "Here is the full gallery of all the pre-defined colormaps, organized by the types of data they are usually used for." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "# %load http://matplotlib.org/mpl_examples/color/colormaps_reference.py\n", + "\"\"\"\n", + "==================\n", + "Colormap reference\n", + "==================\n", + "\n", + "Reference for colormaps included with Matplotlib.\n", + "\n", + "This reference example shows all colormaps included with Matplotlib. Note that\n", + "any colormap listed here can be reversed by appending \"_r\" (e.g., \"pink_r\").\n", + "These colormaps are divided into the following categories:\n", + "\n", + "Sequential:\n", + " These colormaps are approximately monochromatic colormaps varying smoothly\n", + " between two color tones---usually from low saturation (e.g. white) to high\n", + " saturation (e.g. a bright blue). Sequential colormaps are ideal for\n", + " representing most scientific data since they show a clear progression from\n", + " low-to-high values.\n", + "\n", + "Diverging:\n", + " These colormaps have a median value (usually light in color) and vary\n", + " smoothly to two different color tones at high and low values. Diverging\n", + " colormaps are ideal when your data has a median value that is significant\n", + " (e.g. 0, such that positive and negative values are represented by\n", + " different colors of the colormap).\n", + "\n", + "Qualitative:\n", + " These colormaps vary rapidly in color. Qualitative colormaps are useful for\n", + " choosing a set of discrete colors. For example::\n", + "\n", + " color_list = plt.cm.Set3(np.linspace(0, 1, 12))\n", + "\n", + " gives a list of RGB colors that are good for plotting a series of lines on\n", + " a dark background.\n", + "\n", + "Miscellaneous:\n", + " Colormaps that don't fit into the categories above.\n", + "\n", + "\"\"\"\n", + "import numpy as np\n", + "import matplotlib.pyplot as plt\n", + "\n", + "\n", + "# Have colormaps separated into categories:\n", + "# http://matplotlib.org/examples/color/colormaps_reference.html\n", + "cmaps = [('Perceptually Uniform Sequential', [\n", + " 'viridis', 'plasma', 'inferno', 'magma']),\n", + " ('Sequential', [\n", + " 'Greys', 'Purples', 'Blues', 'Greens', 'Oranges', 'Reds',\n", + " 'YlOrBr', 'YlOrRd', 'OrRd', 'PuRd', 'RdPu', 'BuPu',\n", + " 'GnBu', 'PuBu', 'YlGnBu', 'PuBuGn', 'BuGn', 'YlGn']),\n", + " ('Sequential (2)', [\n", + " 'binary', 'gist_yarg', 'gist_gray', 'gray', 'bone', 'pink',\n", + " 'spring', 'summer', 'autumn', 'winter', 'cool', 'Wistia',\n", + " 'hot', 'afmhot', 'gist_heat', 'copper']),\n", + " ('Diverging', [\n", + " 'PiYG', 'PRGn', 'BrBG', 'PuOr', 'RdGy', 'RdBu',\n", + " 'RdYlBu', 'RdYlGn', 'Spectral', 'coolwarm', 'bwr', 'seismic']),\n", + " ('Qualitative', [\n", + " 'Pastel1', 'Pastel2', 'Paired', 'Accent',\n", + " 'Dark2', 'Set1', 'Set2', 'Set3',\n", + " 'tab10', 'tab20', 'tab20b', 'tab20c']),\n", + " ('Miscellaneous', [\n", + " 'flag', 'prism', 'ocean', 'gist_earth', 'terrain', 'gist_stern',\n", + " 'gnuplot', 'gnuplot2', 'CMRmap', 'cubehelix', 'brg', 'hsv',\n", + " 'gist_rainbow', 'rainbow', 'jet', 'nipy_spectral', 'gist_ncar'])]\n", + "\n", + "\n", + "nrows = max(len(cmap_list) for cmap_category, cmap_list in cmaps)\n", + "gradient = np.linspace(0, 1, 256)\n", + "gradient = np.vstack((gradient, gradient))\n", + "\n", + "\n", + "def plot_color_gradients(cmap_category, cmap_list, nrows):\n", + " fig, axes = plt.subplots(nrows=nrows)\n", + " fig.subplots_adjust(top=0.95, bottom=0.01, left=0.2, right=0.99)\n", + " axes[0].set_title(cmap_category + ' colormaps', fontsize=14)\n", + "\n", + " for ax, name in zip(axes, cmap_list):\n", + " ax.imshow(gradient, aspect='auto', cmap=plt.get_cmap(name))\n", + " pos = list(ax.get_position().bounds)\n", + " x_text = pos[0] - 0.01\n", + " y_text = pos[1] + pos[3]/2.\n", + " fig.text(x_text, y_text, name, va='center', ha='right', fontsize=10)\n", + "\n", + " # Turn off *all* ticks & spines, not just the ones with colormaps.\n", + " for ax in axes:\n", + " ax.set_axis_off()\n", + "\n", + "\n", + "for cmap_category, cmap_list in cmaps:\n", + " plot_color_gradients(cmap_category, cmap_list, nrows)\n", + "\n", + "plt.show()\n" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "When colormaps are created in mpl, they get \"registered\" with a name. This allows one to specify a colormap to use by name." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "fig, (ax1, ax2) = plt.subplots(1, 2)\n", + "z = np.random.random((10, 10))\n", + "ax1.imshow(z, interpolation='none', cmap='gray')\n", + "ax2.imshow(z, interpolation='none', cmap='coolwarm')\n", + "plt.show()" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# Mathtext\n", + "Oftentimes, you just simply need that superscript or some other math text in your labels. Matplotlib provides a very easy way to do this for those familiar with LaTeX. Any text that is surrounded by dollar signs will be treated as \"[mathtext](http://matplotlib.org/users/mathtext.html#mathtext-tutorial)\". Do note that because backslashes are prevelent in LaTeX, it is often a good idea to prepend an `r` to your string literal so that Python will not treat the backslashes as escape characters." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "plt.scatter([1, 2, 3, 4], [4, 3, 2, 1])\n", + "plt.title(r'$\\sigma_i=15$', fontsize=20)\n", + "plt.show()" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# Hatches\n", + "A Patch object can have a hatching defined for it.\n", + "\n", + "* / - diagonal hatching\n", + "* \\ - back diagonal\n", + "* | - vertical\n", + "* \\- - horizontal\n", + "* \\+ - crossed\n", + "* x - crossed diagonal\n", + "* o - small circle\n", + "* O - large circle (upper-case 'o')\n", + "* . - dots\n", + "* \\* - stars\n", + " \n", + "Letters can be combined, in which case all the specified\n", + "hatchings are done. Repeating a character increases the\n", + "density of hatching of that pattern." + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# Property Cycles\n", + "In case you haven't noticed, when you do multiple plot calls in the same axes -- and not specify any colors -- the color for each plot is different! The default style in Matplotlib will cycle through a list of colors if you don't specify any. This feature has been in Matplotlib for a long time and it is similar to Matlab behavior.\n", + "\n", + "In v1.5, this feature was extended so that one can cycle through other properties besides just color. Now, you can cycle linestyles, markers, hatch styles -- just about any property that can be specified is now possible to be cycled.\n", + "\n", + "This feature is still being refined, and there has been significant improvements in its usability since v1.5, but here is a basic example that will work for v2.0 or greater (for v1.5, you may need to have this cycler expression quoted)." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "import matplotlib as mpl\n", + "from matplotlib.rcsetup import cycler\n", + "mpl.rc('axes', prop_cycle=cycler('color', 'rgc') +\n", + " cycler('lw', [1, 4, 6]) +\n", + " cycler('linestyle', ['-', '-.', ':']))\n", + "t = np.arange(0.0, 5.0, 0.2)\n", + "plt.plot(t, t)\n", + "plt.plot(t, t**2)\n", + "plt.plot(t, t**3)\n", + "plt.show()" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Ugly tie contest!" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "mpl.rc('axes', prop_cycle=cycler('color', ['r', 'orange', 'c', 'y']) +\n", + " cycler('hatch', ['x', 'xx-', '+O.', '*']))\n", + "x = np.array([0.7, 0.3, 0.385, 0.6153, 0.7, np.nan, 0.6, 0.4, 0.2, 0.5, 0.8, 0.6])\n", + "y = [0.65, 0.65, 0.1, 0.1, 0.65, np.nan, 0, 0, -5, -6, -5, 0]\n", + "plt.fill(x+1, y)\n", + "plt.fill(x+2, y)\n", + "plt.fill(x+3, y)\n", + "plt.fill(x+4, y)\n", + "plt.show()" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# Transforms\n", + "The topic of transforms in Matplotlib, that is the ability to map the coordinates specified by your data to the coordinates of your figure, is very advanced and will not be covered in this tutorial. For those who are interested in learning about them, see the [transformation tutorial](http://matplotlib.org/users/transforms_tutorial.html). For those who are really daring, there are the developer guides to [transforms](http://matplotlib.org/devel/transformations.html) and [scales](http://matplotlib.org/devel/add_new_projection.html). While most users will never, ever need to understand Matplotlib transforms to the level described in those links, it is important to be aware of them, and their critical role in figure-making.\n", + "\n", + "In a figure, there are four coordinate systems: *display*, *figure*, *axes*, and *data*. Transforms are used to convert coordinates in one system into another system for various uses. This is how Matplotlib knows exactly where to place the ticks and ticklabels, even when you change the axis limits. The ticker says that the tick and label \"1.5\", for example, are to go at data x-coordinate 1.5. The transform says that location is at 0.4 in axes x-coordinate space. Meanwhile, the xlabel of \"Distance\" is placed at axes x-coordinate space of 0.5 (half-way). Meanwhile, a legend might be placed at a location relative to the figure coordinates.\n", + "\n", + "Furthermore, the transform system is what is used to allow various scales to work, such as log scales. The transform system is what is used to make the polar plots work seamlessly. Whether you realize it or not, you use the transforms system in Matplotlib all the time. Everything drawn in Matplotlib has a transform associated with it. Most of the time, you will never notice this, and will happily operate within the *data* coordinate system. But when you want to do some more advanced plots, with some eye-catching visual tricks, the transform system will be there for you." + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# Managing the unmanagable -- Introducing matplotlibrc\n", + "Matplotlib's greatest strength is its ability to give you complete control over every single aspect of your plots and figures. Matplotlib's second greatest strength is its ability to take as much control over as much of your plots and figures as you want. You, as the user, would never consider to use Matplotlib if you had to specify all of these things for every single plot. Most of the time, the defaults are exactly what you want them to be.\n", + "\n", + "Matplotlib uses the matplotlibrc configuration file to define the plethora of defaults found in the library. You can control the defaults of almost every property in Matplotlib: figure size and dpi, line width, color and style, axes, axis and grid properties, text and font properties and so on. Just modify your rc file and re-run your scripts to produce your improved figures.\n", + "\n", + "To display where the currently active matplotlibrc file was loaded from, one can do the following:" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "import matplotlib\n", + "print(matplotlib.matplotlib_fname())" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "You can also change the rc settings during runtime within a python script or interactively from the python shell. All of the rc settings are stored in a dictionary-like variable called [`matplotlib.rcParams`](http://matplotlib.org/api/matplotlib_configuration_api.html#matplotlib.matplotlib.rcParams), which is global to the matplotlib package. `rcParams` can be modified directly. Newer versions of matplotlib can use [`rc()`](http://matplotlib.org/api/matplotlib_configuration_api.html#matplotlib.rc), for example:" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "import matplotlib as mpl\n", + "import matplotlib.pyplot as plt\n", + "mpl.rcdefaults() # for when re-running this cell\n", + "\n", + "fig, (ax1, ax2) = plt.subplots(1, 2)\n", + "ax1.plot([1, 2, 3, 4])\n", + "\n", + "mpl.rc('lines', linewidth=2, linestyle='-.')\n", + "# Equivalent older, but still valid syntax\n", + "#mpl.rcParams['lines.linewidth'] = 2\n", + "#mpl.rcParams['lines.linestyle'] = '-.'\n", + "ax2.plot([1, 2, 3, 4])\n", + "plt.show()" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "To learn more, please see this guide on [customizing matplotlib](http://matplotlib.org/users/customizing.html)." + ] + } + ], + "metadata": { + "kernelspec": { + "display_name": "Python 3", + "language": "python", + "name": "python3" + }, + "language_info": { + "codemirror_mode": { + "name": "ipython", + "version": 3 + }, + "file_extension": ".py", + "mimetype": "text/x-python", + "name": "python", + "nbconvert_exporter": "python", + "pygments_lexer": "ipython3", + "version": "3.7.3" + } + }, + "nbformat": 4, + "nbformat_minor": 2 +} diff --git a/AnatomyOfMatplotlib-Part4-Limits_Legends_and_Layouts.ipynb b/AnatomyOfMatplotlib-Part4-Limits_Legends_and_Layouts.ipynb new file mode 100644 index 0000000..ec20839 --- /dev/null +++ b/AnatomyOfMatplotlib-Part4-Limits_Legends_and_Layouts.ipynb @@ -0,0 +1,566 @@ +{ + "cells": [ + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "from __future__ import print_function\n", + "\n", + "# Import conventions we'll be using here. See Part 1\n", + "import matplotlib\n", + "matplotlib.use('nbagg')\n", + "import matplotlib.pyplot as plt\n", + "import numpy as np" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# Limits, Legends, and Layouts\n", + "\n", + "In this section, we'll focus on what happens around the edges of the axes: Ticks, ticklabels, limits, layouts, and legends." + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# Limits and autoscaling\n", + "\n", + "By default, Matplotlib will attempt to determine limits for you that encompasses all the data you have plotted. This is the \"autoscale\" feature. For image plots, the limits are not padded while plots such as scatter plots and bar plots are given some padding." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "fig, (ax1, ax2) = plt.subplots(nrows=1, ncols=2, figsize=plt.figaspect(0.5))\n", + "\n", + "ax1.plot([-10, -5, 0, 5, 10, 15], [-1.2, 2, 3.5, -0.3, -4, 1])\n", + "ax2.scatter([-10, -5, 0, 5, 10, 15], [-1.2, 2, 3.5, -0.3, -4, 1])\n", + "\n", + "plt.show()" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### `ax.margins(...)`\n", + "\n", + "If you'd like to add a bit of \"padding\" to a plot, `ax.margins()` is a very handy way to do so. Instead of choosing \"even-ish\" numbers as min/max ranges for each axis, `margins` will make Matplotlib calculate the min/max of each axis by taking the range of the data and adding on a fractional amount of padding.\n", + "\n", + "As an example:" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "fig, (ax1, ax2) = plt.subplots(1, 2, figsize=plt.figaspect(0.5))\n", + "\n", + "ax1.plot([-10, -5, 0, 5, 10, 15], [-1.2, 2, 3.5, -0.3, -4, 1])\n", + "ax2.scatter([-10, -5, 0, 5, 10, 15], [-1.2, 2, 3.5, -0.3, -4, 1])\n", + "\n", + "ax1.margins(x=0.0, y=0.1) # 10% padding in the y-direction only\n", + "ax2.margins(0.05) # 5% padding in all directions\n", + "\n", + "plt.show()" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### `ax.axis(...)`\n", + "\n", + "The `ax.axis(...)` method is a convienent way of controlling the axes limits and enabling/disabling autoscaling.\n", + "\n", + "If you ever need to get all of the current plot limits, calling `ax.axis()` with no arguments will return the xmin/max/etc:\n", + "\n", + " xmin, xmax, ymin, ymax = ax.axis()\n", + " \n", + "If you'd like to manually set all of the x/y limits at once, you can use `ax.axis` for this, as well (note that we're calling it with a single argument that's a sequence, not 4 individual arguments):\n", + "\n", + " ax.axis([xmin, xmax, ymin, ymax])\n", + " \n", + "However, you'll probably use `axis` mostly with either the `\"tight\"` or `\"equal\"` options. There are other options as well; see the documentation for full details. In a nutshell, though:\n", + "\n", + " * *tight*: Set axes limits to the exact range of the data\n", + " * *equal*: Set axes scales such that one cm/inch in the y-direction is the same as one cm/inch in the x-direction. In Matplotlib terms, this sets the aspect ratio of the plot to 1. That _doesn't_ mean that the axes \"box\" will be square.\n", + " \n", + "And as an example:" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "fig, axes = plt.subplots(nrows=3)\n", + "\n", + "for ax in axes:\n", + " ax.plot([-10, -5, 0, 5, 10, 15], [-1.2, 2, 3.5, -0.3, -4, 1])\n", + "\n", + "axes[0].set_title('Normal Autoscaling', y=0.7, x=0.8)\n", + "\n", + "axes[1].set_title('ax.axis(\"tight\")', y=0.7, x=0.8)\n", + "axes[1].axis('tight')\n", + "\n", + "axes[2].set_title('ax.axis(\"equal\")', y=0.7, x=0.8)\n", + "axes[2].axis('equal')\n", + "\n", + "plt.show()" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### Manually setting only one limit\n", + "\n", + "Another trick with limits is to specify only half of a limit. When done **after** a plot is made, this has the effect of allowing the user to anchor a limit while letting Matplotlib autoscale the rest of it." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "# Good -- setting limits after plotting is done\n", + "fig, (ax1, ax2) = plt.subplots(1, 2, figsize=plt.figaspect(0.5))\n", + "ax1.plot([-10, -5, 0, 5, 10, 15], [-1.2, 2, 3.5, -0.3, -4, 1])\n", + "ax2.scatter([-10, -5, 0, 5, 10, 15], [-1.2, 2, 3.5, -0.3, -4, 1])\n", + "ax1.set_ylim(bottom=-10)\n", + "ax2.set_xlim(right=25)\n", + "plt.show()" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "# Bad -- Setting limits before plotting is done\n", + "fig, (ax1, ax2) = plt.subplots(1, 2, figsize=plt.figaspect(0.5))\n", + "ax1.set_ylim(bottom=-10)\n", + "ax2.set_xlim(right=25)\n", + "ax1.plot([-10, -5, 0, 5, 10, 15], [-1.2, 2, 3.5, -0.3, -4, 1])\n", + "ax2.scatter([-10, -5, 0, 5, 10, 15], [-1.2, 2, 3.5, -0.3, -4, 1])\n", + "plt.show()" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# Legends\n", + "\n", + "As you've seen in some of the examples so far, the X and Y axis can also be labeled, as well as the subplot itself via the title. \n", + "\n", + "However, another thing you can label is the line/point/bar/etc that you plot. You can provide a label to your plot, which allows your legend to automatically build itself. " + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "fig, ax = plt.subplots()\n", + "ax.plot([1, 2, 3, 4], [10, 20, 25, 30], label='Philadelphia')\n", + "ax.plot([1, 2, 3, 4], [30, 23, 13, 4], label='Boston')\n", + "ax.set(ylabel='Temperature (deg C)', xlabel='Time', title='A tale of two cities')\n", + "ax.legend()\n", + "plt.show()" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "In `classic` mode, legends will go in the upper right corner by default (you can control this with the `loc` kwarg). As of v2.0, by default Matplotlib will choose a location to avoid overlapping plot elements as much as possible. To force this option, you can pass in:\n", + "\n", + " ax.legend(loc=\"best\")\n", + " \n", + "Also, if you happen to be plotting something that you do not want to appear in the legend, just set the label to \"\\_nolegend\\_\"." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "fig, ax = plt.subplots(1, 1)\n", + "ax.bar([1, 2, 3, 4], [10, 20, 25, 30], label=\"Foobar\", align='center', color='lightblue')\n", + "ax.plot([1, 2, 3, 4], [10, 20, 25, 30], label=\"_nolegend_\", marker='o', color='darkred')\n", + "ax.legend(loc='best')\n", + "plt.show()" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# Exercise 4.1\n", + "\n", + "Once again, let's use a bit of what we've learned. Try to reproduce the following figure:\n", + "\n", + "\n", + "\n", + "Hint: You'll need to combine `ax.axis(...)` and `ax.margins(...)`. Here's the data and some code to get you started:" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "%load exercises/4.1-legends_and_scaling.py" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": true + }, + "outputs": [], + "source": [ + "import numpy as np\n", + "import matplotlib.pyplot as plt\n", + "\n", + "plt.style.use('classic')\n", + "\n", + "t = np.linspace(0, 2 * np.pi, 150)\n", + "x1, y1 = np.cos(t), np.sin(t)\n", + "x2, y2 = 2 * x1, 2 * y1\n", + "\n", + "colors = ['darkred', 'darkgreen']\n", + "\n", + "# Try to plot the two circles, scale the axes as shown and add a legend\n", + "# Hint: it's easiest to combine `ax.axis(...)` and `ax.margins(...)` to scale the axes" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# Dealing with the boundaries: Layout, ticks, spines, etc\n", + "\n", + "One key thing we haven't talked about yet is all of the annotation on the outside of the axes, the borders of the axes, and how to adjust the amount of space around the axes. We won't go over every detail, but this next section should give you a reasonable working knowledge of how to configure what happens around the edges of your axes.\n", + "\n", + "## Ticks, Tick Lines, Tick Labels and Tickers\n", + "This is a constant source of confusion:\n", + "\n", + "* A Tick is the *location* of a Tick Label.\n", + "* A Tick Line is the line that denotes the location of the tick.\n", + "* A Tick Label is the text that is displayed at that tick.\n", + "* A [`Ticker`](http://matplotlib.org/api/ticker_api.html#module-matplotlib.ticker) automatically determines the ticks for an Axis and formats the tick labels.\n", + "\n", + "[`tick_params()`](https://matplotlib.org/api/axes_api.html#ticks-and-tick-labels) is often used to help configure your tickers." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "fig, ax = plt.subplots()\n", + "ax.plot([1, 2, 3, 4], [10, 20, 25, 30])\n", + "\n", + "# Manually set ticks and tick labels *on the x-axis* (note ax.xaxis.set, not ax.set!)\n", + "ax.xaxis.set(ticks=range(1, 5), ticklabels=[3, 100, -12, \"foo\"]) \n", + "\n", + "# Make the y-ticks a bit longer and go both in and out...\n", + "ax.tick_params(axis='y', direction='inout', length=10)\n", + "\n", + "plt.show()" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "A commonly-asked question is \"How do I plot categories?\"\n", + "\n", + "Starting in version 2.0 of mpl, just like any other data.\n", + "\n", + "For example:" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "data = [('apples', 2), ('oranges', 3), ('peaches', 1)]\n", + "fruit, value = zip(*data)\n", + "\n", + "fig, ax = plt.subplots()\n", + "ax.bar(fruit, value, align='center', color='gray')\n", + "plt.show()" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Subplot Spacing\n", + "The spacing between the subplots can be adjusted using [`fig.subplots_adjust()`](http://matplotlib.org/api/pyplot_api.html?#matplotlib.pyplot.subplots_adjust). Play around with the example below to see how the different arguments affect the spacing." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "fig, axes = plt.subplots(2, 2, figsize=(9, 9))\n", + "fig.subplots_adjust(wspace=0.5, hspace=0.3,\n", + " left=0.125, right=0.9,\n", + " top=0.9, bottom=0.1)\n", + "plt.show()" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "A common \"gotcha\" is that the labels are not automatically adjusted to avoid overlapping those of another subplot. Matplotlib does not currently have any sort of robust layout engine, as it is a design decision to minimize the amount of \"magical plotting\". We intend to let users have complete, 100% control over their plots. LaTeX users would be quite familiar with the amount of frustration that can occur with automatic placement of figures in their documents.\n", + "\n", + "That said, there have been some efforts to develop tools that users can use to help address the most common compaints. The \"[Tight Layout](http://matplotlib.org/users/tight_layout_guide.html)\" feature, when invoked, will attempt to resize margins and subplots so that nothing overlaps.\n", + "\n", + "If you have multiple subplots, and want to avoid overlapping titles/axis labels/etc, `fig.tight_layout` is a great way to do so:" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "def example_plot(ax):\n", + " ax.plot([1, 2])\n", + " ax.set_xlabel('x-label', fontsize=16)\n", + " ax.set_ylabel('y-label', fontsize=8)\n", + " ax.set_title('Title', fontsize=24)\n", + "\n", + "fig, ((ax1, ax2), (ax3, ax4)) = plt.subplots(nrows=2, ncols=2)\n", + "example_plot(ax1)\n", + "example_plot(ax2)\n", + "example_plot(ax3)\n", + "example_plot(ax4)\n", + "\n", + "# Enable fig.tight_layout to compare...\n", + "#fig.tight_layout()\n", + "\n", + "plt.show()" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## GridSpec\n", + "Under the hood, Matplotlib utilizes [`GridSpec`](http://matplotlib.org/api/gridspec_api.html) to lay out the subplots. While `plt.subplots()` is fine for simple cases, sometimes you will need more advanced subplot layouts. In such cases, you should use GridSpec directly. GridSpec is outside the scope of this tutorial, but it is handy to know that it exists. [Here](http://matplotlib.org/users/gridspec.html) is a guide on how to use it." + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Sharing axes\n", + "There will be times when you want to have the x axis and/or the y axis of your subplots to be \"shared\". Sharing an axis means that the axis in one or more subplots will be tied together such that any change in one of the axis changes all of the other shared axes. This works very nicely with autoscaling arbitrary datasets that may have overlapping domains. Furthermore, when interacting with the plots (panning and zooming), all of the shared axes will pan and zoom automatically." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "fig, (ax1, ax2) = plt.subplots(1, 2, sharex=True, sharey=True)\n", + "ax1.plot([1, 2, 3, 4], [1, 2, 3, 4])\n", + "ax2.plot([3, 4, 5, 6], [6, 5, 4, 3])\n", + "plt.show()" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## \"Twinning\" axes\n", + "Sometimes one may want to overlay two plots on the same axes, but the scales may be entirely different. You can simply treat them as separate plots, but then twin them." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "fig, ax1 = plt.subplots(1, 1)\n", + "ax1.plot([1, 2, 3, 4], [1, 2, 3, 4])\n", + "ax2 = ax1.twinx()\n", + "ax2.scatter([1, 2, 3, 4], [60, 50, 40, 30])\n", + "ax1.set(xlabel='X', ylabel='First scale')\n", + "ax2.set(ylabel='Other scale')\n", + "plt.show()" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# Axis Spines\n", + "Spines are the axis lines for a plot. Each plot can have four spines: \"top\", \"bottom\", \"left\" and \"right\". By default, they are set so that they frame the plot, but they can be individually positioned and configured via the [`set_position()`](http://matplotlib.org/api/spines_api.html#matplotlib.spines.Spine.set_position) method of the spine. Here are some different configurations." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "fig, ax = plt.subplots()\n", + "ax.plot([-2, 2, 3, 4], [-10, 20, 25, 5])\n", + "ax.spines['top'].set_visible(False)\n", + "ax.xaxis.set_ticks_position('bottom') # no ticklines at the top\n", + "ax.spines['right'].set_visible(False)\n", + "ax.yaxis.set_ticks_position('left') # no ticklines on the right\n", + "\n", + "# \"outward\"\n", + "# Move the two remaining spines \"out\" away from the plot by 10 points\n", + "#ax.spines['bottom'].set_position(('outward', 10))\n", + "#ax.spines['left'].set_position(('outward', 10))\n", + "\n", + "# \"data\"\n", + "# Have the spines stay intersected at (0,0)\n", + "#ax.spines['bottom'].set_position(('data', 0))\n", + "#ax.spines['left'].set_position(('data', 0))\n", + "\n", + "# \"axes\"\n", + "# Have the two remaining spines placed at a fraction of the axes\n", + "#ax.spines['bottom'].set_position(('axes', 0.75))\n", + "#ax.spines['left'].set_position(('axes', 0.3))\n", + "\n", + "plt.show()" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# Exercise 4.2\n", + "\n", + "This one is a bit trickier. Once again, try to reproduce the figure below:\n", + "\n", + "\n", + "\n", + "\n", + "A few key hints: The two subplots have no vertical space between them (this means that the `hspace` is `0`). Note that the bottom spine is at 0 in data coordinates and the tick lines are missing from the right and top sides.\n", + "\n", + "Because you're going to be doing a lot of the same things to both subplots, to avoid repitive code you might consider writing a function that takes an `Axes` object and makes the spine changes, etc to it. \n", + "\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "%load exercises/4.2-spines_ticks_and_subplot_spacing.py" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "import matplotlib.pyplot as plt\n", + "import numpy as np\n", + "\n", + "# Try to reproduce the figure shown in images/exercise_4.2.png\n", + "# This one is a bit trickier!\n", + "\n", + "# Here's the data...\n", + "data = [('dogs', 4, 4), ('frogs', -3, 1), ('cats', 1, 5), ('goldfish', -2, 2)]\n", + "animals, friendliness, popularity = zip(*data)" + ] + } + ], + "metadata": { + "kernelspec": { + "display_name": "Python 2", + "language": "python", + "name": "python2" + }, + "language_info": { + "codemirror_mode": { + "name": "ipython", + "version": 2 + }, + "file_extension": ".py", + "mimetype": "text/x-python", + "name": "python", + "nbconvert_exporter": "python", + "pygments_lexer": "ipython2", + "version": "2.7.12" + } + }, + "nbformat": 4, + "nbformat_minor": 0 +} diff --git a/AnatomyOfMatplotlib-Part4-mpl_toolkits.ipynb b/AnatomyOfMatplotlib-Part4-mpl_toolkits.ipynb deleted file mode 100644 index eef1537..0000000 --- a/AnatomyOfMatplotlib-Part4-mpl_toolkits.ipynb +++ /dev/null @@ -1,362 +0,0 @@ -{ - "metadata": { - "name": "", - "signature": "sha256:e9c856312773c2ed88df57c5620883f24768b7e7288be4fc8f9bd7f0d7d73ba0" - }, - "nbformat": 3, - "nbformat_minor": 0, - "worksheets": [ - { - "cells": [ - { - "cell_type": "code", - "collapsed": false, - "input": [ - "# Not using inline mode here because I want to demo interactivity\n", - "%matplotlib\n", - "import numpy as np\n", - "import matplotlib.pyplot as plt" - ], - "language": "python", - "metadata": {}, - "outputs": [] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "# mpl_toolkits" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "In addition to the core library of matplotlib, there are a few additional utilities that are set apart from matplotlib proper for some reason or another, but are often shipped with matplotlib.\n", - "\n", - "* [Basemap](http://matplotlib.org/basemap/) - shipped separately from matplotlib due to size of mapping data that are included.\n", - "* [mplot3d](http://matplotlib.org/mpl_toolkits/mplot3d/index.html#toolkit-mplot3d-index) - shipped with matplotlib to provide very simple, rudimentary 3D plots in the same style as matplotlib's 2D plots.\n", - "* [axes_grid1](http://matplotlib.org/mpl_toolkits/axes_grid/users/overview.html) - An enhanced SubplotAxes. Very Enhanced..." - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "# mplot3d\n", - "By taking advantage of matplotlib's z-order layering engine, mplot3d emulates 3D plotting by projecting 3D data into 2D space, layer by layer. While it isn't going to replace any of the true 3D plotting libraries anytime soon, its goal is to allow for matplotlib users to produce 3D plots with the same amount of simplicity as 2D plots are." - ] - }, - { - "cell_type": "code", - "collapsed": false, - "input": [ - "from mpl_toolkits.mplot3d import Axes3D, axes3d\n", - "\n", - "fig, ax = plt.subplots(1, 1, subplot_kw={'projection': '3d'})\n", - "X, Y, Z = axes3d.get_test_data(0.05)\n", - "ax.plot_wireframe(X, Y, Z, rstride=10, cstride=10)\n", - "\n", - "plt.show()" - ], - "language": "python", - "metadata": {}, - "outputs": [] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "# axes_grid1\n", - "This module was originally intended as a collection of helper classes to ease the displaying of (possibly multiple) images with matplotlib. Some of the functionality has come to be useful for non-image plotting as well. Some classes deals with the sizing and positioning of multiple Axes relative to each other ([`ImageGrid`](http://matplotlib.org/mpl_toolkits/axes_grid/users/overview.html#imagegrid), [`RGB Axes`](http://matplotlib.org/mpl_toolkits/axes_grid/users/overview.html#rgb-axes), and [`AxesDivider`](http://matplotlib.org/mpl_toolkits/axes_grid/users/overview.html#axesdivider)). The [`ParasiteAxes`](http://matplotlib.org/mpl_toolkits/axes_grid/users/overview.html#parasiteaxes) allow for the plotting of multiple datasets in the same axes, but with each their own x or y scale. Also, there is the [`AnchoredArtist`](http://matplotlib.org/mpl_toolkits/axes_grid/users/overview.html#anchoredartists) that can be used to anchor particular artist objects in place.\n", - "\n", - "One can get a sense of the neat things that can be done with this toolkit by browsing through its user guide linked above. There is one particular feature that is an absolute must-have for me -- automatic allocation of space for colorbars." - ] - }, - { - "cell_type": "code", - "collapsed": false, - "input": [ - "from mpl_toolkits.axes_grid1 import AxesGrid\n", - "fig = plt.figure()\n", - "grid = AxesGrid(fig, 111, # similar to subplot(111)\n", - " nrows_ncols = (2, 2),\n", - " axes_pad = 0.2,\n", - " share_all=True,\n", - " label_mode = \"L\", # similar to \"label_outer\"\n", - " cbar_location = \"right\",\n", - " cbar_mode=\"single\",\n", - " )\n", - "\n", - "extent = (-3,4,-4,3)\n", - "for i in range(4):\n", - " im = grid[i].imshow(Z, extent=extent, interpolation=\"nearest\")\n", - " \n", - "grid.cbar_axes[0].colorbar(im)\n", - "plt.show()" - ], - "language": "python", - "metadata": {}, - "outputs": [] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "This next feature is commonly requested on the mailing lists. The problem is that most people who request it don't quite know how to describe it. We call it \"Parasite Axes\"." - ] - }, - { - "cell_type": "code", - "collapsed": false, - "input": [ - "%load http://matplotlib.org/mpl_examples/axes_grid/demo_parasite_axes2.py" - ], - "language": "python", - "metadata": {}, - "outputs": [] - }, - { - "cell_type": "code", - "collapsed": false, - "input": [ - "from mpl_toolkits.axes_grid1 import host_subplot\n", - "import mpl_toolkits.axisartist as AA\n", - "import matplotlib.pyplot as plt\n", - "\n", - "if 1:\n", - "\n", - " host = host_subplot(111, axes_class=AA.Axes)\n", - " plt.subplots_adjust(right=0.75)\n", - "\n", - " par1 = host.twinx()\n", - " par2 = host.twinx()\n", - "\n", - " offset = 60\n", - " new_fixed_axis = par2.get_grid_helper().new_fixed_axis\n", - " par2.axis[\"right\"] = new_fixed_axis(loc=\"right\",\n", - " axes=par2,\n", - " offset=(offset, 0))\n", - " \n", - " par2.axis[\"right\"].toggle(all=True)\n", - "\n", - "\n", - "\n", - " host.set_xlim(0, 2)\n", - " host.set_ylim(0, 2)\n", - "\n", - " host.set_xlabel(\"Distance\")\n", - " host.set_ylabel(\"Density\")\n", - " par1.set_ylabel(\"Temperature\")\n", - " par2.set_ylabel(\"Velocity\")\n", - "\n", - " p1, = host.plot([0, 1, 2], [0, 1, 2], label=\"Density\")\n", - " p2, = par1.plot([0, 1, 2], [0, 3, 2], label=\"Temperature\")\n", - " p3, = par2.plot([0, 1, 2], [50, 30, 15], label=\"Velocity\")\n", - "\n", - " par1.set_ylim(0, 4)\n", - " par2.set_ylim(1, 65)\n", - "\n", - " host.legend()\n", - "\n", - " host.axis[\"left\"].label.set_color(p1.get_color())\n", - " par1.axis[\"right\"].label.set_color(p2.get_color())\n", - " par2.axis[\"right\"].label.set_color(p3.get_color())\n", - "\n", - " plt.draw()\n", - " plt.show()\n", - "\n", - " #plt.savefig(\"Test\")\n" - ], - "language": "python", - "metadata": {}, - "outputs": [] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "And finally, as a nice, teaser of what else axes_grid1 can do..." - ] - }, - { - "cell_type": "code", - "collapsed": false, - "input": [ - "%load http://matplotlib.org/mpl_toolkits/axes_grid/examples/demo_floating_axes.py" - ], - "language": "python", - "metadata": {}, - "outputs": [] - }, - { - "cell_type": "code", - "collapsed": false, - "input": [ - "from matplotlib.transforms import Affine2D\n", - "\n", - "import mpl_toolkits.axisartist.floating_axes as floating_axes\n", - "\n", - "import numpy as np\n", - "import mpl_toolkits.axisartist.angle_helper as angle_helper\n", - "from matplotlib.projections import PolarAxes\n", - "from mpl_toolkits.axisartist.grid_finder import FixedLocator, MaxNLocator, \\\n", - " DictFormatter\n", - "\n", - "def setup_axes1(fig, rect):\n", - " \"\"\"\n", - " A simple one.\n", - " \"\"\"\n", - " tr = Affine2D().scale(2, 1).rotate_deg(30)\n", - "\n", - " grid_helper = floating_axes.GridHelperCurveLinear(tr, extremes=(0, 4, 0, 4))\n", - "\n", - " ax1 = floating_axes.FloatingSubplot(fig, rect, grid_helper=grid_helper)\n", - " fig.add_subplot(ax1)\n", - "\n", - " aux_ax = ax1.get_aux_axes(tr)\n", - "\n", - " grid_helper.grid_finder.grid_locator1._nbins = 4\n", - " grid_helper.grid_finder.grid_locator2._nbins = 4\n", - "\n", - " return ax1, aux_ax\n", - "\n", - "\n", - "def setup_axes2(fig, rect):\n", - " \"\"\"\n", - " With custom locator and formatter.\n", - " Note that the extreme values are swapped.\n", - " \"\"\"\n", - "\n", - " #tr_scale = Affine2D().scale(np.pi/180., 1.)\n", - "\n", - " tr = PolarAxes.PolarTransform()\n", - "\n", - " pi = np.pi\n", - " angle_ticks = [(0, r\"$0$\"),\n", - " (.25*pi, r\"$\\frac{1}{4}\\pi$\"),\n", - " (.5*pi, r\"$\\frac{1}{2}\\pi$\")]\n", - " grid_locator1 = FixedLocator([v for v, s in angle_ticks])\n", - " tick_formatter1 = DictFormatter(dict(angle_ticks))\n", - "\n", - " grid_locator2 = MaxNLocator(2)\n", - "\n", - " grid_helper = floating_axes.GridHelperCurveLinear(tr,\n", - " extremes=(.5*pi, 0, 2, 1),\n", - " grid_locator1=grid_locator1,\n", - " grid_locator2=grid_locator2,\n", - " tick_formatter1=tick_formatter1,\n", - " tick_formatter2=None,\n", - " )\n", - "\n", - " ax1 = floating_axes.FloatingSubplot(fig, rect, grid_helper=grid_helper)\n", - " fig.add_subplot(ax1)\n", - "\n", - " # create a parasite axes whose transData in RA, cz\n", - " aux_ax = ax1.get_aux_axes(tr)\n", - "\n", - " aux_ax.patch = ax1.patch # for aux_ax to have a clip path as in ax\n", - " ax1.patch.zorder=0.9 # but this has a side effect that the patch is\n", - " # drawn twice, and possibly over some other\n", - " # artists. So, we decrease the zorder a bit to\n", - " # prevent this.\n", - "\n", - " return ax1, aux_ax\n", - "\n", - "\n", - "def setup_axes3(fig, rect):\n", - " \"\"\"\n", - " Sometimes, things like axis_direction need to be adjusted.\n", - " \"\"\"\n", - "\n", - " # rotate a bit for better orientation\n", - " tr_rotate = Affine2D().translate(-95, 0)\n", - "\n", - " # scale degree to radians\n", - " tr_scale = Affine2D().scale(np.pi/180., 1.)\n", - "\n", - " tr = tr_rotate + tr_scale + PolarAxes.PolarTransform()\n", - "\n", - " grid_locator1 = angle_helper.LocatorHMS(4)\n", - " tick_formatter1 = angle_helper.FormatterHMS()\n", - "\n", - " grid_locator2 = MaxNLocator(3)\n", - "\n", - " ra0, ra1 = 8.*15, 14.*15\n", - " cz0, cz1 = 0, 14000\n", - " grid_helper = floating_axes.GridHelperCurveLinear(tr,\n", - " extremes=(ra0, ra1, cz0, cz1),\n", - " grid_locator1=grid_locator1,\n", - " grid_locator2=grid_locator2,\n", - " tick_formatter1=tick_formatter1,\n", - " tick_formatter2=None,\n", - " )\n", - "\n", - " ax1 = floating_axes.FloatingSubplot(fig, rect, grid_helper=grid_helper)\n", - " fig.add_subplot(ax1)\n", - "\n", - " # adjust axis\n", - " ax1.axis[\"left\"].set_axis_direction(\"bottom\")\n", - " ax1.axis[\"right\"].set_axis_direction(\"top\")\n", - "\n", - " ax1.axis[\"bottom\"].set_visible(False)\n", - " ax1.axis[\"top\"].set_axis_direction(\"bottom\")\n", - " ax1.axis[\"top\"].toggle(ticklabels=True, label=True)\n", - " ax1.axis[\"top\"].major_ticklabels.set_axis_direction(\"top\")\n", - " ax1.axis[\"top\"].label.set_axis_direction(\"top\")\n", - "\n", - " ax1.axis[\"left\"].label.set_text(r\"cz [km$^{-1}$]\")\n", - " ax1.axis[\"top\"].label.set_text(r\"$\\alpha_{1950}$\")\n", - "\n", - "\n", - " # create a parasite axes whose transData in RA, cz\n", - " aux_ax = ax1.get_aux_axes(tr)\n", - "\n", - " aux_ax.patch = ax1.patch # for aux_ax to have a clip path as in ax\n", - " ax1.patch.zorder=0.9 # but this has a side effect that the patch is\n", - " # drawn twice, and possibly over some other\n", - " # artists. So, we decrease the zorder a bit to\n", - " # prevent this.\n", - "\n", - " return ax1, aux_ax\n", - "\n", - "\n", - "\n", - "if 1:\n", - " import matplotlib.pyplot as plt\n", - " fig = plt.figure(1, figsize=(8, 4))\n", - " fig.subplots_adjust(wspace=0.3, left=0.05, right=0.95)\n", - "\n", - " ax1, aux_ax2 = setup_axes1(fig, 131)\n", - " aux_ax2.bar([0, 1, 2, 3], [3, 2, 1, 3])\n", - " \n", - " #theta = np.random.rand(10) #*.5*np.pi\n", - " #radius = np.random.rand(10) #+1.\n", - " #aux_ax1.scatter(theta, radius)\n", - "\n", - "\n", - " ax2, aux_ax2 = setup_axes2(fig, 132)\n", - "\n", - " theta = np.random.rand(10)*.5*np.pi\n", - " radius = np.random.rand(10)+1.\n", - " aux_ax2.scatter(theta, radius)\n", - "\n", - "\n", - " ax3, aux_ax3 = setup_axes3(fig, 133)\n", - "\n", - " theta = (8 + np.random.rand(10)*(14-8))*15. # in degrees\n", - " radius = np.random.rand(10)*14000.\n", - " aux_ax3.scatter(theta, radius)\n", - "\n", - " plt.show()\n", - "\n" - ], - "language": "python", - "metadata": {}, - "outputs": [] - } - ], - "metadata": {} - } - ] -} \ No newline at end of file diff --git a/AnatomyOfMatplotlib-Part5-Artists.ipynb b/AnatomyOfMatplotlib-Part5-Artists.ipynb new file mode 100644 index 0000000..4da8545 --- /dev/null +++ b/AnatomyOfMatplotlib-Part5-Artists.ipynb @@ -0,0 +1,331 @@ +{ + "cells": [ + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "# Let printing work the same in Python 2 and 3\n", + "from __future__ import print_function\n", + "# Turning on inline plots -- just for use in ipython notebooks.\n", + "import matplotlib\n", + "matplotlib.use('nbagg')\n", + "import numpy as np\n", + "import matplotlib.pyplot as plt" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# Artists\n", + "Anything that can be displayed in a Figure is an [`Artist`](http://matplotlib.org/users/artists.html). There are two main classes of Artists: primatives and containers. Below is a sample of these primitives." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "\"\"\"\n", + "Show examples of matplotlib artists\n", + "http://matplotlib.org/api/artist_api.html\n", + "\n", + "Several examples of standard matplotlib graphics primitives (artists)\n", + "are drawn using matplotlib API. Full list of artists and the\n", + "documentation is available at\n", + "http://matplotlib.org/api/artist_api.html\n", + "\n", + "Copyright (c) 2010, Bartosz Telenczuk\n", + "\n", + "License: This work is licensed under the BSD. A copy should be\n", + "included with this source code, and is also available at\n", + "http://www.opensource.org/licenses/bsd-license.php\n", + "\"\"\"\n", + "\n", + "from matplotlib.collections import PatchCollection\n", + "import matplotlib.path as mpath\n", + "import matplotlib.patches as mpatches\n", + "import matplotlib.lines as mlines\n", + "\n", + "fig, ax = plt.subplots(1, 1, figsize=(7,7))\n", + "\n", + "# create 3x3 grid to plot the artists\n", + "pos = np.mgrid[0.2:0.8:3j, 0.2:0.8:3j].reshape(2, -1)\n", + "patches = []\n", + "\n", + "# add a circle\n", + "art = mpatches.Circle(pos[:, 0], 0.1, ec=\"none\")\n", + "patches.append(art)\n", + "plt.text(pos[0, 0], pos[1, 0] - 0.15, \"Circle\", ha=\"center\", size=14)\n", + "\n", + "# add a rectangle\n", + "art = mpatches.Rectangle(pos[:, 1] - [0.025, 0.05], 0.05, 0.1, ec=\"none\")\n", + "patches.append(art)\n", + "plt.text(pos[0, 1], pos[1, 1] - 0.15, \"Rectangle\", ha=\"center\", size=14)\n", + "\n", + "# add a wedge\n", + "wedge = mpatches.Wedge(pos[:, 2], 0.1, 30, 270, ec=\"none\")\n", + "patches.append(wedge)\n", + "plt.text(pos[0, 2], pos[1, 2] - 0.15, \"Wedge\", ha=\"center\", size=14)\n", + "\n", + "# add a Polygon\n", + "polygon = mpatches.RegularPolygon(pos[:, 3], 5, 0.1)\n", + "patches.append(polygon)\n", + "plt.text(pos[0, 3], pos[1, 3] - 0.15, \"Polygon\", ha=\"center\", size=14)\n", + "\n", + "#add an ellipse\n", + "ellipse = mpatches.Ellipse(pos[:, 4], 0.2, 0.1)\n", + "patches.append(ellipse)\n", + "plt.text(pos[0, 4], pos[1, 4] - 0.15, \"Ellipse\", ha=\"center\", size=14)\n", + "\n", + "#add an arrow\n", + "arrow = mpatches.Arrow(pos[0, 5] - 0.05, pos[1, 5] - 0.05, 0.1, 0.1, width=0.1)\n", + "patches.append(arrow)\n", + "plt.text(pos[0, 5], pos[1, 5] - 0.15, \"Arrow\", ha=\"center\", size=14)\n", + "\n", + "# add a path patch\n", + "Path = mpath.Path\n", + "verts = np.array([\n", + " (0.158, -0.257),\n", + " (0.035, -0.11),\n", + " (-0.175, 0.20),\n", + " (0.0375, 0.20),\n", + " (0.085, 0.115),\n", + " (0.22, 0.32),\n", + " (0.3, 0.005),\n", + " (0.20, -0.05),\n", + " (0.158, -0.257),\n", + " ])\n", + "verts = verts - verts.mean(0)\n", + "codes = [Path.MOVETO,\n", + " Path.CURVE4, Path.CURVE4, Path.CURVE4, Path.LINETO,\n", + " Path.CURVE4, Path.CURVE4, Path.CURVE4, Path.CLOSEPOLY]\n", + "\n", + "path = mpath.Path(verts / 2.5 + pos[:, 6], codes)\n", + "patch = mpatches.PathPatch(path)\n", + "patches.append(patch)\n", + "plt.text(pos[0, 6], pos[1, 6] - 0.15, \"PathPatch\", ha=\"center\", size=14)\n", + "\n", + "# add a fancy box\n", + "fancybox = mpatches.FancyBboxPatch(\n", + " pos[:, 7] - [0.025, 0.05], 0.05, 0.1,\n", + " boxstyle=mpatches.BoxStyle(\"Round\", pad=0.02))\n", + "patches.append(fancybox)\n", + "plt.text(pos[0, 7], pos[1, 7] - 0.15, \"FancyBoxPatch\", ha=\"center\", size=14)\n", + "\n", + "# add a line\n", + "x,y = np.array([[-0.06, 0.0, 0.1], [0.05,-0.05, 0.05]])\n", + "line = mlines.Line2D(x+pos[0, 8], y+pos[1, 8], lw=5.)\n", + "plt.text(pos[0, 8], pos[1, 8] - 0.15, \"Line2D\", ha=\"center\", size=14)\n", + "\n", + "collection = PatchCollection(patches)\n", + "ax.add_collection(collection)\n", + "ax.add_line(line)\n", + "ax.set_axis_off()\n", + "\n", + "plt.show()" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Containers are objects like *Figure* and *Axes*. Containers are given primitives to draw. The plotting functions we discussed back in Parts 1 & 2 are convenience functions that generate these primitives and places them into the appropriate containers. In fact, most of those functions will return artist objects (or a list of artist objects) as well as store them into the appropriate axes container.\n", + "\n", + "As discussed in Part 3, there is a wide range of properties that can be defined for your plots. These properties are processed and applied to their primitives. Ultimately, you can override anything you want just by directly setting a property to the object itself." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "fig, ax = plt.subplots(1, 1)\n", + "lines = plt.plot([1, 2, 3, 4], [1, 2, 3, 4], 'b', [1, 2, 3, 4], [4, 3, 2, 1], 'r')\n", + "lines[0].set(linewidth=5)\n", + "lines[1].set(linewidth=10, alpha=0.7)\n", + "plt.show()" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "To see what properties are set for an artist, use [`getp()`](https://matplotlib.org/api/artist_api.html#functions)" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "fig = plt.figure()\n", + "print(plt.getp(fig.patch))\n", + "plt.close(fig)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# Collections\n", + "In addition to the Figure and Axes containers, there is another special type of container called a [`Collection`](http://matplotlib.org/api/collections_api.html). A Collection usually contains a list of primitives of the same kind that should all be treated similiarly. For example, a [`CircleCollection`](http://matplotlib.org/api/collections_api.html#matplotlib.collections.CircleCollection) would have a list of [`Circle`](https://matplotlib.org/api/_as_gen/matplotlib.patches.Circle.html) objects all with the same color, size, and edge width. Individual property values for artists in the collection can also be set (in some cases)." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "from matplotlib.collections import LineCollection\n", + "fig, ax = plt.subplots(1, 1)\n", + "# A collection of 3 lines\n", + "lc = LineCollection([[(4, 10), (16, 10)],\n", + " [(2, 2), (10, 15), (6, 7)],\n", + " [(14, 3), (1, 1), (3, 5)]])\n", + "lc.set_color('r')\n", + "lc.set_linewidth(5)\n", + "ax.add_collection(lc)\n", + "ax.set_xlim(0, 18)\n", + "ax.set_ylim(0, 18)\n", + "plt.show()" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "# Now set individual properties in a collection\n", + "fig, ax = plt.subplots(1, 1)\n", + "lc = LineCollection([[(4, 10), (16, 10)],\n", + " [(2, 2), (10, 15), (6, 7)],\n", + " [(14, 3), (1, 1), (3, 5)]])\n", + "lc.set_color(['r', 'blue', (0.2, 0.9, 0.3)])\n", + "lc.set_linewidth([4, 3, 6])\n", + "ax.add_collection(lc)\n", + "ax.set_xlim(0, 18)\n", + "ax.set_ylim(0, 18)\n", + "plt.show()" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "There are other kinds of collections that are not just simply a list of primitives, but are Artists in their own right. These special kinds of collections take advantage of various optimizations that can be assumed when rendering similar or identical things. You use these collections all the time whether you realize it or not! Markers are implemented this way (so, whenever you do `plot()` or `scatter()`, for example)." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "from matplotlib.collections import RegularPolyCollection\n", + "\n", + "fig, ax = plt.subplots(1, 1)\n", + "offsets = np.random.rand(20, 2)\n", + "collection = RegularPolyCollection(\n", + " numsides=5, # a pentagon\n", + " sizes=(150,),\n", + " offsets=offsets,\n", + " transOffset=ax.transData,\n", + " )\n", + "ax.add_collection(collection)\n", + "plt.show()" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Exercise 5.1\n", + "Give yourselves 4 gold stars!\n", + "\n", + "Hint: [StarPolygonCollection](http://matplotlib.org/api/collections_api.html#matplotlib.collections.StarPolygonCollection)" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "%load exercises/5.1-goldstar.py" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "from matplotlib.collections import StarPolygonCollection\n", + "\n", + "fig, ax = plt.subplots(1, 1)\n", + "\n", + "collection = StarPolygonCollection(5,\n", + " offsets=[(0.5, 0.5)],\n", + " transOffset=ax.transData)\n", + "ax.add_collection(collection)\n", + "plt.show()" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": true + }, + "outputs": [], + "source": [] + } + ], + "metadata": { + "kernelspec": { + "display_name": "Python 2", + "language": "python", + "name": "python2" + }, + "language_info": { + "codemirror_mode": { + "name": "ipython", + "version": 2 + }, + "file_extension": ".py", + "mimetype": "text/x-python", + "name": "python", + "nbconvert_exporter": "python", + "pygments_lexer": "ipython2", + "version": "2.7.12" + } + }, + "nbformat": 4, + "nbformat_minor": 0 +} diff --git a/AnatomyOfMatplotlib-Part6-mpl_toolkits.ipynb b/AnatomyOfMatplotlib-Part6-mpl_toolkits.ipynb new file mode 100644 index 0000000..9ecb7d3 --- /dev/null +++ b/AnatomyOfMatplotlib-Part6-mpl_toolkits.ipynb @@ -0,0 +1,368 @@ +{ + "cells": [ + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "import matplotlib\n", + "matplotlib.use('nbagg')\n", + "import numpy as np\n", + "import matplotlib.pyplot as plt" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# mpl_toolkits" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "In addition to the core library of Matplotlib, there are a few additional utilities that are set apart from Matplotlib proper for some reason or another, but are often shipped with Matplotlib.\n", + "\n", + "* [Basemap](http://matplotlib.org/basemap/) - shipped separately from matplotlib due to size of mapping data that are included.\n", + "* [mplot3d](http://matplotlib.org/mpl_toolkits/mplot3d/index.html#toolkit-mplot3d-index) - shipped with matplotlib to provide very simple, rudimentary 3D plots in the same style as matplotlib's 2D plots.\n", + "* [axes_grid1](http://matplotlib.org/mpl_toolkits/axes_grid/users/overview.html) - An enhanced SubplotAxes. Very Enhanced..." + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# mplot3d\n", + "By taking advantage of Matplotlib's z-order layering engine, mplot3d emulates 3D plotting by projecting 3D data into 2D space, layer by layer. While it isn't going to replace any of the true 3D plotting libraries anytime soon, its goal is to allow for Matplotlib users to produce 3D plots with the same amount of simplicity as 2D plots." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "from mpl_toolkits.mplot3d import Axes3D, axes3d\n", + "\n", + "fig, ax = plt.subplots(1, 1, subplot_kw={'projection': '3d'})\n", + "X, Y, Z = axes3d.get_test_data(0.05)\n", + "ax.plot_wireframe(X, Y, Z, rstride=10, cstride=10)\n", + "\n", + "plt.show()" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# axes_grid1\n", + "This module was originally intended as a collection of helper classes to ease the displaying of (possibly multiple) images with Matplotlib. Some of the functionality has come to be useful for non-image plotting as well. Some classes deals with the sizing and positioning of multiple Axes relative to each other ([`ImageGrid`](http://matplotlib.org/mpl_toolkits/axes_grid/users/overview.html#imagegrid), [`RGB Axes`](http://matplotlib.org/mpl_toolkits/axes_grid/users/overview.html#rgb-axes), and [`AxesDivider`](http://matplotlib.org/mpl_toolkits/axes_grid/users/overview.html#axesdivider)). The [`ParasiteAxes`](http://matplotlib.org/mpl_toolkits/axes_grid/users/overview.html#parasiteaxes) allow for the plotting of multiple datasets in the same axes, but with each their own x or y scale. Also, there is the [`AnchoredArtist`](http://matplotlib.org/mpl_toolkits/axes_grid/users/overview.html#anchoredartists) that can be used to anchor particular artist objects in place.\n", + "\n", + "One can get a sense of the neat things that can be done with this toolkit by browsing through its user guide linked above. There is one particular feature that is an absolute must-have for me -- automatic allocation of space for colorbars." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "from mpl_toolkits.axes_grid1 import AxesGrid\n", + "fig = plt.figure()\n", + "grid = AxesGrid(fig, 111, # similar to subplot(111)\n", + " nrows_ncols = (2, 2),\n", + " axes_pad = 0.2,\n", + " share_all=True,\n", + " label_mode = \"L\", # similar to \"label_outer\"\n", + " cbar_location = \"right\",\n", + " cbar_mode=\"single\",\n", + " )\n", + "\n", + "extent = (-3,4,-4,3)\n", + "for i in range(4):\n", + " im = grid[i].imshow(Z, extent=extent, interpolation=\"nearest\")\n", + " \n", + "grid.cbar_axes[0].colorbar(im)\n", + "plt.show()" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "This next feature is commonly requested on the mailing lists. The problem is that most people who request it don't quite know how to describe it. We call it \"Parasite Axes\"." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "# %load http://matplotlib.org/mpl_examples/axes_grid/demo_parasite_axes2.py\n", + "\"\"\"\n", + "Parasite axis demo\n", + "\n", + "The following code is an example of a parasite axis. It aims to show a user how\n", + "to plot multiple different values onto one single plot. Notice how in this\n", + "example, par1 and par2 are both calling twinx meaning both are tied directly to\n", + "the x-axis. From there, each of those two axis can behave separately from the\n", + "each other, meaning they can take on separate values from themselves as well as\n", + "the x-axis.\n", + "\"\"\"\n", + "from mpl_toolkits.axes_grid1 import host_subplot\n", + "import mpl_toolkits.axisartist as AA\n", + "import matplotlib.pyplot as plt\n", + "\n", + "host = host_subplot(111, axes_class=AA.Axes)\n", + "plt.subplots_adjust(right=0.75)\n", + "\n", + "par1 = host.twinx()\n", + "par2 = host.twinx()\n", + "\n", + "offset = 60\n", + "new_fixed_axis = par2.get_grid_helper().new_fixed_axis\n", + "par2.axis[\"right\"] = new_fixed_axis(loc=\"right\",\n", + " axes=par2,\n", + " offset=(offset, 0))\n", + "\n", + "par2.axis[\"right\"].toggle(all=True)\n", + "\n", + "host.set_xlim(0, 2)\n", + "host.set_ylim(0, 2)\n", + "\n", + "host.set_xlabel(\"Distance\")\n", + "host.set_ylabel(\"Density\")\n", + "par1.set_ylabel(\"Temperature\")\n", + "par2.set_ylabel(\"Velocity\")\n", + "\n", + "p1, = host.plot([0, 1, 2], [0, 1, 2], label=\"Density\")\n", + "p2, = par1.plot([0, 1, 2], [0, 3, 2], label=\"Temperature\")\n", + "p3, = par2.plot([0, 1, 2], [50, 30, 15], label=\"Velocity\")\n", + "\n", + "par1.set_ylim(0, 4)\n", + "par2.set_ylim(1, 65)\n", + "\n", + "host.legend()\n", + "\n", + "host.axis[\"left\"].label.set_color(p1.get_color())\n", + "par1.axis[\"right\"].label.set_color(p2.get_color())\n", + "par2.axis[\"right\"].label.set_color(p3.get_color())\n", + "\n", + "plt.show()\n" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "And finally, as a nice teaser of what else axes_grid1 can do..." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "# %load http://matplotlib.org/mpl_toolkits/axes_grid/examples/demo_floating_axes.py\n", + "\"\"\"\n", + "Demo of the floating axes.\n", + "\n", + "This demo shows features of functions in floating_axes:\n", + " * Using scatter function and bar function with changing the\n", + " shape of the plot.\n", + " * Using GridHelperCurveLinear to rotate the plot and set the\n", + " boundary of the plot.\n", + " * Using FloatingSubplot to create a subplot using the return\n", + " value from GridHelperCurveLinear.\n", + " * Making sector plot by adding more features to GridHelperCurveLinear.\n", + "\"\"\"\n", + "from matplotlib.transforms import Affine2D\n", + "import mpl_toolkits.axisartist.floating_axes as floating_axes\n", + "import numpy as np\n", + "import mpl_toolkits.axisartist.angle_helper as angle_helper\n", + "from matplotlib.projections import PolarAxes\n", + "from mpl_toolkits.axisartist.grid_finder import (FixedLocator, MaxNLocator,\n", + " DictFormatter)\n", + "import matplotlib.pyplot as plt\n", + "\n", + "\n", + "def setup_axes1(fig, rect):\n", + " \"\"\"\n", + " A simple one.\n", + " \"\"\"\n", + " tr = Affine2D().scale(2, 1).rotate_deg(30)\n", + "\n", + " grid_helper = floating_axes.GridHelperCurveLinear(\n", + " tr, extremes=(-0.5, 3.5, 0, 4))\n", + "\n", + " ax1 = floating_axes.FloatingSubplot(fig, rect, grid_helper=grid_helper)\n", + " fig.add_subplot(ax1)\n", + "\n", + " aux_ax = ax1.get_aux_axes(tr)\n", + "\n", + " grid_helper.grid_finder.grid_locator1._nbins = 4\n", + " grid_helper.grid_finder.grid_locator2._nbins = 4\n", + "\n", + " return ax1, aux_ax\n", + "\n", + "\n", + "def setup_axes2(fig, rect):\n", + " \"\"\"\n", + " With custom locator and formatter.\n", + " Note that the extreme values are swapped.\n", + " \"\"\"\n", + " tr = PolarAxes.PolarTransform()\n", + "\n", + " pi = np.pi\n", + " angle_ticks = [(0, r\"$0$\"),\n", + " (.25*pi, r\"$\\frac{1}{4}\\pi$\"),\n", + " (.5*pi, r\"$\\frac{1}{2}\\pi$\")]\n", + " grid_locator1 = FixedLocator([v for v, s in angle_ticks])\n", + " tick_formatter1 = DictFormatter(dict(angle_ticks))\n", + "\n", + " grid_locator2 = MaxNLocator(2)\n", + "\n", + " grid_helper = floating_axes.GridHelperCurveLinear(\n", + " tr, extremes=(.5*pi, 0, 2, 1),\n", + " grid_locator1=grid_locator1,\n", + " grid_locator2=grid_locator2,\n", + " tick_formatter1=tick_formatter1,\n", + " tick_formatter2=None)\n", + "\n", + " ax1 = floating_axes.FloatingSubplot(fig, rect, grid_helper=grid_helper)\n", + " fig.add_subplot(ax1)\n", + "\n", + " # create a parasite axes whose transData in RA, cz\n", + " aux_ax = ax1.get_aux_axes(tr)\n", + "\n", + " aux_ax.patch = ax1.patch # for aux_ax to have a clip path as in ax\n", + " ax1.patch.zorder = 0.9 # but this has a side effect that the patch is\n", + " # drawn twice, and possibly over some other\n", + " # artists. So, we decrease the zorder a bit to\n", + " # prevent this.\n", + "\n", + " return ax1, aux_ax\n", + "\n", + "\n", + "def setup_axes3(fig, rect):\n", + " \"\"\"\n", + " Sometimes, things like axis_direction need to be adjusted.\n", + " \"\"\"\n", + "\n", + " # rotate a bit for better orientation\n", + " tr_rotate = Affine2D().translate(-95, 0)\n", + "\n", + " # scale degree to radians\n", + " tr_scale = Affine2D().scale(np.pi/180., 1.)\n", + "\n", + " tr = tr_rotate + tr_scale + PolarAxes.PolarTransform()\n", + "\n", + " grid_locator1 = angle_helper.LocatorHMS(4)\n", + " tick_formatter1 = angle_helper.FormatterHMS()\n", + "\n", + " grid_locator2 = MaxNLocator(3)\n", + "\n", + " ra0, ra1 = 8.*15, 14.*15\n", + " cz0, cz1 = 0, 14000\n", + " grid_helper = floating_axes.GridHelperCurveLinear(\n", + " tr, extremes=(ra0, ra1, cz0, cz1),\n", + " grid_locator1=grid_locator1,\n", + " grid_locator2=grid_locator2,\n", + " tick_formatter1=tick_formatter1,\n", + " tick_formatter2=None)\n", + "\n", + " ax1 = floating_axes.FloatingSubplot(fig, rect, grid_helper=grid_helper)\n", + " fig.add_subplot(ax1)\n", + "\n", + " # adjust axis\n", + " ax1.axis[\"left\"].set_axis_direction(\"bottom\")\n", + " ax1.axis[\"right\"].set_axis_direction(\"top\")\n", + "\n", + " ax1.axis[\"bottom\"].set_visible(False)\n", + " ax1.axis[\"top\"].set_axis_direction(\"bottom\")\n", + " ax1.axis[\"top\"].toggle(ticklabels=True, label=True)\n", + " ax1.axis[\"top\"].major_ticklabels.set_axis_direction(\"top\")\n", + " ax1.axis[\"top\"].label.set_axis_direction(\"top\")\n", + "\n", + " ax1.axis[\"left\"].label.set_text(r\"cz [km$^{-1}$]\")\n", + " ax1.axis[\"top\"].label.set_text(r\"$\\alpha_{1950}$\")\n", + "\n", + " # create a parasite axes whose transData in RA, cz\n", + " aux_ax = ax1.get_aux_axes(tr)\n", + "\n", + " aux_ax.patch = ax1.patch # for aux_ax to have a clip path as in ax\n", + " ax1.patch.zorder = 0.9 # but this has a side effect that the patch is\n", + " # drawn twice, and possibly over some other\n", + " # artists. So, we decrease the zorder a bit to\n", + " # prevent this.\n", + "\n", + " return ax1, aux_ax\n", + "\n", + "\n", + "##########################################################\n", + "fig = plt.figure(figsize=(8, 4))\n", + "fig.subplots_adjust(wspace=0.3, left=0.05, right=0.95)\n", + "\n", + "ax1, aux_ax1 = setup_axes1(fig, 131)\n", + "aux_ax1.bar([0, 1, 2, 3], [3, 2, 1, 3])\n", + "\n", + "ax2, aux_ax2 = setup_axes2(fig, 132)\n", + "theta = np.random.rand(10)*.5*np.pi\n", + "radius = np.random.rand(10) + 1.\n", + "aux_ax2.scatter(theta, radius)\n", + "\n", + "ax3, aux_ax3 = setup_axes3(fig, 133)\n", + "\n", + "theta = (8 + np.random.rand(10)*(14 - 8))*15. # in degrees\n", + "radius = np.random.rand(10)*14000.\n", + "aux_ax3.scatter(theta, radius)\n", + "\n", + "plt.show()\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [] + } + ], + "metadata": { + "kernelspec": { + "display_name": "Python 2", + "language": "python", + "name": "python2" + }, + "language_info": { + "codemirror_mode": { + "name": "ipython", + "version": 2 + }, + "file_extension": ".py", + "mimetype": "text/x-python", + "name": "python", + "nbconvert_exporter": "python", + "pygments_lexer": "ipython2", + "version": "2.7.12" + } + }, + "nbformat": 4, + "nbformat_minor": 0 +} diff --git a/README.md b/README.md index e40f6c2..726412c 100644 --- a/README.md +++ b/README.md @@ -1,4 +1,4 @@ -* Introduction +# Introduction This tutorial is a complete re-imagining of how one should teach users the matplotlib library. Hopefully, this tutorial may serve as inspiration for future restructuring of the matplotlib documentation. Plus, I have some @@ -7,18 +7,24 @@ ideas of how to improve this tutorial. Please fork and contribute back improvements! Feel free to use this tutorial for conferences and other opportunities for training. -The tutorial can be viewed on [nbviewer](http://nbviewer.ipython.org): -* [Part 0: Introduction To NumPy] -* [Part 1: PyPlot] -* [Part 2: How To Speak MPL] -* [Part 3: Artists] -* [Part 4: mpl_toolkits] +The tutorial can be viewed on [nbviewer](http://nbviewer.jupyter.org): +* [Part 0: Introduction To NumPy](http://nbviewer.jupyter.org/github/matplotlib/AnatomyOfMatplotlib/blob/master/AnatomyOfMatplotlib-Part0-Intro2NumPy.ipynb) +* [Part 1: Overview of Matplotlib](http://nbviewer.jupyter.org/github/matplotlib/AnatomyOfMatplotlib/blob/master/AnatomyOfMatplotlib-Part1-Figures_Subplots_and_layouts.ipynb) +* [Part 2: Plotting Methods](http://nbviewer.jupyter.org/github/matplotlib/AnatomyOfMatplotlib/blob/master/AnatomyOfMatplotlib-Part2-Plotting_Methods_Overview.ipynb) +* [Part 3: How To Speak MPL](http://nbviewer.jupyter.org/github/matplotlib/AnatomyOfMatplotlib/blob/master/AnatomyOfMatplotlib-Part3-HowToSpeakMPL.ipynb) +* [Part 4: Limits, Legends, and Layouts](http://nbviewer.jupyter.org/github/matplotlib/AnatomyOfMatplotlib/blob/master/AnatomyOfMatplotlib-Part4-Limits_Legends_and_Layouts.ipynb) +* [Part 5: Artists](http://nbviewer.jupyter.org/github/matplotlib/AnatomyOfMatplotlib/blob/master/AnatomyOfMatplotlib-Part5-Artists.ipynb) +* [Part 6: mpl_toolkits](http://nbviewer.jupyter.org/github/matplotlib/AnatomyOfMatplotlib/blob/master/AnatomyOfMatplotlib-Part6-mpl_toolkits.ipynb) -Cheers! +# Installation +All you need is matplotlib (v1.5 or greater) and jupyter installed. +You can use your favorite Python package installer for this: +```bash +conda install matplotlib jupyter +git clone https://github.com/matplotlib/AnatomyOfMatplotlib.git +cd AnatomyOfMatplotlib +jupyter notebook +``` +A browser window should appear and you can verify that everything works as expected by clicking on the `Test Install.ipynb` notebook. There, you will see a "code cell" that you can execute. Run it, and you should see a very simple line plot, indicating that all is well. -[Part 0: Introduction To NumPy]: http://nbviewer.ipython.org/github/WeatherGod/AnatomyOfMatplotlib/blob/master/AnatomyOfMatplotlib-Part0-Intro2NumPy.ipynb -[Part 1: PyPlot]: http://nbviewer.ipython.org/github/WeatherGod/AnatomyOfMatplotlib/blob/master/AnatomyOfMatplotlib-Part1-pyplot.ipynb -[Part 2: How To Speak MPL]: http://nbviewer.ipython.org/github/WeatherGod/AnatomyOfMatplotlib/blob/master/AnatomyOfMatplotlib-Part2-HowToSpeakMPL.ipynb -[Part 3: Artists]: http://nbviewer.ipython.org/github/WeatherGod/AnatomyOfMatplotlib/blob/master/AnatomyOfMatplotlib-Part3-Artists.ipynb -[Part 4: mpl_toolkits]: http://nbviewer.ipython.org/github/WeatherGod/AnatomyOfMatplotlib/blob/master/AnatomyOfMatplotlib-Part4-mpl_toolkits.ipynb diff --git a/Test Install.ipynb b/Test Install.ipynb new file mode 100644 index 0000000..62a6fd6 --- /dev/null +++ b/Test Install.ipynb @@ -0,0 +1,54 @@ +{ + "cells": [ + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "from __future__ import print_function\n", + "import matplotlib\n", + "matplotlib.use('nbagg')\n", + "from matplotlib import pyplot as plt\n", + "\n", + "if matplotlib.__version__ < '1.5':\n", + " print('Matplotlib needs to be updated')\n", + "\n", + "plt.plot([1, 2, 3, 2, 1])\n", + "plt.show()" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": true + }, + "outputs": [], + "source": [] + } + ], + "metadata": { + "kernelspec": { + "display_name": "Python 2", + "language": "python", + "name": "python2" + }, + "language_info": { + "codemirror_mode": { + "name": "ipython", + "version": 2 + }, + "file_extension": ".py", + "mimetype": "text/x-python", + "name": "python", + "nbconvert_exporter": "python", + "pygments_lexer": "ipython2", + "version": "2.7.12" + } + }, + "nbformat": 4, + "nbformat_minor": 0 +} diff --git a/assets/bivariate_normal.npy b/assets/bivariate_normal.npy new file mode 100644 index 0000000..b6b8dac Binary files /dev/null and b/assets/bivariate_normal.npy differ diff --git a/examples/bar_example.py b/examples/bar_example.py new file mode 100644 index 0000000..24688f7 --- /dev/null +++ b/examples/bar_example.py @@ -0,0 +1,45 @@ +import numpy as np +import matplotlib.pyplot as plt + +import example_utils + +def main(): + fig, axes = example_utils.setup_axes() + + basic_bar(axes[0]) + tornado(axes[1]) + general(axes[2]) + + example_utils.title(fig, '"ax.bar(...)": Plot rectangles') + fig.savefig('bar_example.png', facecolor='none') + plt.show() + +def basic_bar(ax): + y = [1, 3, 4, 5.5, 3, 2] + err = [0.2, 1, 2.5, 1, 1, 0.5] + x = np.arange(len(y)) + ax.bar(x, y, yerr=err, color='lightblue', ecolor='black') + ax.margins(0.05) + ax.set_ylim(bottom=0) + example_utils.label(ax, 'bar(x, y, yerr=e)') + +def tornado(ax): + y = np.arange(8) + x1 = y + np.random.random(8) + 1 + x2 = y + 3 * np.random.random(8) + 1 + ax.barh(y, x1, color='lightblue') + ax.barh(y, -x2, color='salmon') + ax.margins(0.15) + example_utils.label(ax, 'barh(x, y)') + +def general(ax): + num = 10 + left = np.random.randint(0, 10, num) + bottom = np.random.randint(0, 10, num) + width = np.random.random(num) + 0.5 + height = np.random.random(num) + 0.5 + ax.bar(left, height, width, bottom, color='salmon') + ax.margins(0.15) + example_utils.label(ax, 'bar(l, h, w, b)') + +main() diff --git a/examples/contour_example.py b/examples/contour_example.py new file mode 100644 index 0000000..c443407 --- /dev/null +++ b/examples/contour_example.py @@ -0,0 +1,26 @@ +import matplotlib.pyplot as plt +import numpy as np +from matplotlib.cbook import get_sample_data + +import example_utils + +z = np.load(get_sample_data('axes_grid/bivariate_normal.npy')) + +fig, axes = example_utils.setup_axes() + +axes[0].contour(z, cmap='gist_earth') +example_utils.label(axes[0], 'contour') + +axes[1].contourf(z, cmap='gist_earth') +example_utils.label(axes[1], 'contourf') + +axes[2].contourf(z, cmap='gist_earth') +cont = axes[2].contour(z, colors='black') +axes[2].clabel(cont, fontsize=6) +example_utils.label(axes[2], 'contourf + contour\n + clabel') + +example_utils.title(fig, '"contour, contourf, clabel": Contour/label 2D data', + y=0.96) +fig.savefig('contour_example.png', facecolor='none') + +plt.show() diff --git a/examples/example_utils.py b/examples/example_utils.py new file mode 100644 index 0000000..a6931cd --- /dev/null +++ b/examples/example_utils.py @@ -0,0 +1,23 @@ +""" +Just a few functions shared between all the examples. Ensures example plots are +all the same size, etc. +""" +import matplotlib.pyplot as plt + +def setup_axes(): + fig, axes = plt.subplots(ncols=3, figsize=(6.5,3)) + for ax in fig.axes: + ax.set(xticks=[], yticks=[]) + fig.subplots_adjust(wspace=0, left=0, right=0.93) + return fig, axes + +def title(fig, text, y=0.9): + fig.suptitle(text, size=14, y=y, weight='semibold', x=0.98, ha='right', + bbox=dict(boxstyle='round', fc='floralwhite', ec='#8B7E66', + lw=2)) + +def label(ax, text, y=0): + ax.annotate(text, xy=(0.5, 0.00), xycoords='axes fraction', ha='center', + style='italic', + bbox=dict(boxstyle='round', facecolor='floralwhite', + ec='#8B7E66')) diff --git a/examples/fill_example.py b/examples/fill_example.py new file mode 100644 index 0000000..207b650 --- /dev/null +++ b/examples/fill_example.py @@ -0,0 +1,77 @@ +""" +Illustrate different ways of using the various fill functions. +""" +import numpy as np +import matplotlib.pyplot as plt + +import example_utils + +def main(): + fig, axes = example_utils.setup_axes() + + fill_example(axes[0]) + fill_between_example(axes[1]) + stackplot_example(axes[2]) + + example_utils.title(fig, 'fill/fill_between/stackplot: Filled polygons', + y=0.95) + fig.savefig('fill_example.png', facecolor='none') + plt.show() + +def fill_example(ax): + # Use fill when you want a simple filled polygon between vertices + x, y = fill_data() + ax.fill(x, y, color='lightblue') + ax.margins(0.1) + example_utils.label(ax, 'fill') + +def fill_between_example(ax): + # Fill between fills between two curves or a curve and a constant value + # It can be used in several ways. We'll illustrate a few below. + x, y1, y2 = sin_data() + + # The most basic (and common) use of fill_between + err = np.random.rand(x.size)**2 + 0.1 + y = 0.7 * x + 2 + ax.fill_between(x, y + err, y - err, color='orange') + + # Filling between two curves with different colors when they cross in + # different directions + ax.fill_between(x, y1, y2, where=y1>y2, color='lightblue') + ax.fill_between(x, y1, y2, where=y10, color='red', alpha=0.5) + ax.fill_betweenx(x, -y1, where=y1<0, color='blue', alpha=0.5) + + ax.margins(0.15) + example_utils.label(ax, 'fill_between/x') + +def stackplot_example(ax): + # Stackplot is equivalent to a series of ax.fill_between calls + x, y = stackplot_data() + ax.stackplot(x, y.cumsum(axis=0), alpha=0.5) + example_utils.label(ax, 'stackplot') + +#-- Data generation ---------------------- + +def stackplot_data(): + x = np.linspace(0, 10, 100) + y = np.random.normal(0, 1, (5, 100)) + y = y.cumsum(axis=1) + y -= y.min(axis=0, keepdims=True) + return x, y + +def sin_data(): + x = np.linspace(0, 10, 100) + y = np.sin(x) + y2 = np.cos(x) + return x, y, y2 + +def fill_data(): + t = np.linspace(0, 2*np.pi, 100) + r = np.random.normal(0, 1, 100).cumsum() + r -= r.min() + return r * np.cos(t), r * np.sin(t) + +main() diff --git a/examples/imshow_example.py b/examples/imshow_example.py new file mode 100644 index 0000000..87f5561 --- /dev/null +++ b/examples/imshow_example.py @@ -0,0 +1,45 @@ +import matplotlib.pyplot as plt +import numpy as np +from matplotlib.cbook import get_sample_data +from mpl_toolkits import axes_grid1 + +import example_utils + +def main(): + fig, axes = setup_axes() + plot(axes, *load_data()) + example_utils.title(fig, '"ax.imshow(data, ...)": Colormapped or RGB arrays') + fig.savefig('imshow_example.png', facecolor='none') + plt.show() + +def plot(axes, img_data, scalar_data, ny): + # Note: I'm defining the extent so I can cheat a bit when using ImageGrid + # to make all of the axes the same height... + + # Default: Linear interpolation + axes[0].imshow(scalar_data, cmap='gist_earth', extent=[0, ny, ny, 0]) + + # Use nearest interpolation instead. + axes[1].imshow(scalar_data, cmap='gist_earth', interpolation='nearest', + extent=[0, ny, ny, 0]) + + # Show RGB/RGBA data instead of colormapping a scalar. + axes[2].imshow(img_data) + +def load_data(): + img_data = plt.imread(get_sample_data('grace_hopper.png')) + ny, nx, nbands = img_data.shape + scalar_data = np.load(get_sample_data('axes_grid/bivariate_normal.npy')) + return img_data, scalar_data, ny + +def setup_axes(): + # We'll set up the axes a bit differently here so that they'll all be the + # same height even though the aspect will be set and adjustable is "box". + fig = plt.figure(figsize=(6,3)) + axes = axes_grid1.ImageGrid(fig, [0, 0, .93, 1], (1, 3), axes_pad=0) + + for ax in axes: + ax.set(xticks=[], yticks=[]) + return fig, axes + +main() diff --git a/examples/pcolor_example.py b/examples/pcolor_example.py new file mode 100644 index 0000000..85468b2 --- /dev/null +++ b/examples/pcolor_example.py @@ -0,0 +1,42 @@ +""" +Shows the basics of pcolor/pcolormesh. +One note: Use imshow if your data is on a rectangular grid, as it's much +faster. This example shows a case that imshow can't handle. +""" +import matplotlib.pyplot as plt +import numpy as np +from matplotlib.cbook import get_sample_data + +import example_utils + +# Set up our data... +z = np.load(get_sample_data('axes_grid/bivariate_normal.npy')) +ny, nx = z.shape +y, x = np.mgrid[:ny, :nx] +y = (y - y.mean()) * (x + 10)**2 + +mask = (z > -0.1) & (z < 0.1) +z2 = np.ma.masked_where(mask, z) + +fig, axes = example_utils.setup_axes() + +# Either pcolor or pcolormesh would produce the same result here. +# pcolormesh is faster, however. +axes[0].pcolor(x, y, z, cmap='gist_earth') +example_utils.label(axes[0], 'either') + +# The difference between the two will become clear as we turn on edges: + +# pcolor will completely avoid drawing masked cells... +axes[1].pcolor(x, y, z2, cmap='gist_earth', edgecolor='black') +example_utils.label(axes[1], 'pcolor(x,y,z)') + +# While pcolormesh will draw them as empty (but still present) cells. +axes[2].pcolormesh(x, y, z2, cmap='gist_earth', edgecolor='black', lw=0.5, + antialiased=True) +example_utils.label(axes[2], 'pcolormesh(x,y,z)') + +example_utils.title(fig, 'pcolor/pcolormesh: Colormapped 2D arrays') +fig.savefig('pcolor_example.png', facecolor='none') + +plt.show() diff --git a/examples/plot_example.py b/examples/plot_example.py new file mode 100644 index 0000000..3a56ef3 --- /dev/null +++ b/examples/plot_example.py @@ -0,0 +1,27 @@ +import numpy as np +import matplotlib.pyplot as plt + +import example_utils + +x = np.linspace(0, 10, 100) + +fig, axes = example_utils.setup_axes() +for ax in axes: + ax.margins(y=0.10) + +# Default plotting, colors will be determined by the axes' color_cycle +for i in range(1, 6): + axes[0].plot(x, i * x) + +# Demonstrating different linestyles +for i, ls in enumerate(['-', '--', ':', '-.']): + axes[1].plot(x, np.cos(x) + i, linestyle=ls) + +# Using linestyles and markers +for i, (ls, mk) in enumerate(zip(['', '-', ':'], ['o', '^', 's'])): + axes[2].plot(x, np.cos(x) + i * x, linestyle=ls, marker=mk, markevery=10) + +example_utils.title(fig, '"ax.plot(x, y, ...)": Lines and/or markers', y=0.95) +fig.savefig('plot_example.png', facecolor='none') + +plt.show() diff --git a/examples/scatter_example.py b/examples/scatter_example.py new file mode 100644 index 0000000..33a4848 --- /dev/null +++ b/examples/scatter_example.py @@ -0,0 +1,30 @@ +""" +Illustrates the basics of using "scatter". +""" +import numpy as np +import matplotlib.pyplot as plt + +import example_utils + +# Generate some random data... +np.random.seed(1874) +x, y, z = np.random.normal(0, 1, (3, 100)) +t = np.arctan2(y, x) +size = 50 * np.cos(2 * t)**2 + 10 + +fig, axes = example_utils.setup_axes() + +axes[0].scatter(x, y, marker='o', facecolor='white', s=80) +example_utils.label(axes[0], 'scatter(x, y)') + +axes[1].scatter(x, y, s=size, marker='s', color='darkblue') +example_utils.label(axes[1], 'scatter(x, y, s)') + +axes[2].scatter(x, y, c=z, s=size, cmap='gist_ncar') +example_utils.label(axes[2], 'scatter(x, y, s, c)') + +example_utils.title(fig,'"ax.scatter(...)": Colored/scaled markers', + y=0.95) +fig.savefig('scatter_example.png', facecolor='none') + +plt.show() diff --git a/examples/statistical_example.py b/examples/statistical_example.py new file mode 100644 index 0000000..c98add8 --- /dev/null +++ b/examples/statistical_example.py @@ -0,0 +1,77 @@ +""" +Matplotlib has a handful of specalized statistical plotting methods. + +For many statistical plots, you may find that a specalized statistical plotting +package such as Seaborn (which uses matplotlib behind-the-scenes) is a better +fit to your needs. +""" +import numpy as np +import matplotlib.pyplot as plt + +import example_utils + +def main(): + colors = ['cyan', 'red', 'blue', 'green', 'purple'] + dists = generate_data() + + fig, axes = example_utils.setup_axes() + hist(axes[0], dists, colors) + boxplot(axes[1], dists, colors) + violinplot(axes[2], dists, colors) + + example_utils.title(fig, 'hist/boxplot/violinplot: Statistical plotting', + y=0.9) + fig.savefig('statistical_example.png', facecolor='none') + + plt.show() + +def generate_data(): + means = [0, -1, 2.5, 4.3, -3.6] + sigmas = [1.2, 5, 3, 1.5, 2] + # Each distribution has a different number of samples. + nums = [150, 1000, 100, 200, 500] + + dists = [np.random.normal(*args) for args in zip(means, sigmas, nums)] + return dists + +def hist(ax, dists, colors): + # We could call "ax.hist(dists, ...)" and skip the loop, but we'll plot + # each distribution separately so they'll overlap and turn on transparency + ax.set_color_cycle(colors) + for dist in dists: + ax.hist(dist, bins=20, density=True, edgecolor='none', alpha=0.5) + + ax.margins(y=0.05) + ax.set_ylim(bottom=0) + + example_utils.label(ax, 'ax.hist(dists)') + +def boxplot(ax, dists, colors): + result = ax.boxplot(dists, patch_artist=True, notch=True, vert=False) + + for box, color in zip(result['boxes'], colors): + box.set(facecolor=color, alpha=0.5) + for item in ['whiskers', 'caps', 'medians']: + plt.setp(result[item], color='gray', linewidth=1.5) + plt.setp(result['fliers'], markeredgecolor='gray', markeredgewidth=1.5) + plt.setp(result['medians'], color='black') + + ax.margins(0.05) + ax.set(yticks=[], ylim=[0, 6]) + + example_utils.label(ax, 'ax.boxplot(dists)') + +def violinplot(ax, dists, colors): + result = ax.violinplot(dists, vert=False, showmedians=True) + for body, color in zip(result['bodies'], colors): + body.set(facecolor=color, alpha=0.5) + for item in ['cbars', 'cmaxes', 'cmins', 'cmedians']: + plt.setp(result[item], edgecolor='gray', linewidth=1.5) + plt.setp(result['cmedians'], edgecolor='black') + + ax.margins(0.05) + ax.set(ylim=[0, 6]) + + example_utils.label(ax, 'ax.violinplot(dists)') + +main() diff --git a/examples/vector_example.py b/examples/vector_example.py new file mode 100644 index 0000000..05c3d53 --- /dev/null +++ b/examples/vector_example.py @@ -0,0 +1,39 @@ +import matplotlib.pyplot as plt +import numpy as np + +import example_utils + +# Generate data +n = 256 +x = np.linspace(-3, 3, n) +y = np.linspace(-3, 3, n) +xi, yi = np.meshgrid(x, y) +z = (1 - xi / 2 + xi**5 + yi**3) * np.exp(-xi**2 - yi**2) +dy, dx = np.gradient(z) +mag = np.hypot(dx, dy) + +fig, axes = example_utils.setup_axes() + +# Use ax.arrow to plot a single arrow on the axes. +axes[0].arrow(0, 0, -0.5, 0.5, width=0.005, color='black') +axes[0].axis([-1, 1, -1, 1]) +example_utils.label(axes[0], 'arrow(x, y, dx, dy)') + +# Plot a regularly-sampled vector field with ax.quiver +ds = np.s_[::16, ::16] # Downsample our array a bit... +axes[1].quiver(xi[ds], yi[ds], dx[ds], dy[ds], z[ds], cmap='gist_earth', + width=0.01, scale=0.25, pivot='middle') +axes[1].axis('tight') +example_utils.label(axes[1], 'quiver(x, y, dx, dy)') + +# Use ax.streamplot to show flowlines through our vector field +# We'll get fancy and vary their width and color +lw = 2 * (mag - mag.min()) / mag.ptp() + 0.2 +axes[2].streamplot(xi, yi, dx, dy, color=z, density=1.5, linewidth=lw, + cmap='gist_earth') +example_utils.label(axes[2], 'streamplot(x, y, dx, dy)') + +example_utils.title(fig, '"arrow/quiver/streamplot": Vector fields', y=0.96) +fig.savefig('vector_example.png', facecolor='none') + +plt.show() diff --git a/exercises/1.1-limits.py b/exercises/1.1-limits.py deleted file mode 100644 index 73d5015..0000000 --- a/exercises/1.1-limits.py +++ /dev/null @@ -1,3 +0,0 @@ -fig, ax = plt.subplots(1, 1) -ax.set_ylim( ) -plt.show() diff --git a/exercises/1.1-subplots_and_basic_plotting.py b/exercises/1.1-subplots_and_basic_plotting.py new file mode 100644 index 0000000..1ff79ca --- /dev/null +++ b/exercises/1.1-subplots_and_basic_plotting.py @@ -0,0 +1,11 @@ +import numpy as np +import matplotlib.pyplot as plt + +# Try to reproduce the figure shown in images/exercise_1-1.png + +# Our data... +x = np.linspace(0, 10, 100) +y1, y2, y3 = np.cos(x), np.cos(x + 1), np.cos(x + 2) +names = ['Signal 1', 'Signal 2', 'Signal 3'] + +# Can you figure out what to do next to plot x vs y1, y2, and y3 on one figure? diff --git a/exercises/1.2-spines.py b/exercises/1.2-spines.py deleted file mode 100644 index 6abdb53..0000000 --- a/exercises/1.2-spines.py +++ /dev/null @@ -1,23 +0,0 @@ -fig, ax = plt.subplots(1, 1) -ax.plot([-2, 2, 3, 4], [-10, 20, 25, 5]) -ax.spines['top'].set_visible(False) -ax.xaxis.set_ticks_position('bottom') # no ticklines at the top -ax.spines['right'].set_visible(False) -ax.yaxis.set_ticks_position('left') # no ticklines on the right - -# "outward" -# Move the two remaining spines "out" away from the plot by 10 points -ax.spines['bottom'].set_position(('outward', 10)) -ax.spines['left'].set_position(('outward', 10)) - -# "data" -# Have the spines stay intersected at (0,0) -#ax.spines['bottom'].set_position(('data', 0)) -#ax.spines['left'].set_position(('data', 0)) - -# "axes" -# Have the two remaining spines placed at a fraction of the axes -#ax.spines['bottom'].set_position(('axes', 0.75)) -#ax.spines['left'].set_position(('axes', 0.25)) - -plt.show() diff --git a/exercises/2.1-bar_and_fill_between.py b/exercises/2.1-bar_and_fill_between.py new file mode 100644 index 0000000..5ca04cd --- /dev/null +++ b/exercises/2.1-bar_and_fill_between.py @@ -0,0 +1,24 @@ +import numpy as np +import matplotlib.pyplot as plt +np.random.seed(1) + +# Generate data... +y_raw = np.random.randn(1000).cumsum() + 15 +x_raw = np.linspace(0, 24, y_raw.size) + +# Get averages of every 100 samples... +x_pos = x_raw.reshape(-1, 100).min(axis=1) +y_avg = y_raw.reshape(-1, 100).mean(axis=1) +y_err = y_raw.reshape(-1, 100).ptp(axis=1) + +bar_width = x_pos[1] - x_pos[0] + +# Make a made up future prediction with a fake confidence +x_pred = np.linspace(0, 30) +y_max_pred = y_avg[0] + y_err[0] + 2.3 * x_pred +y_min_pred = y_avg[0] - y_err[0] + 1.2 * x_pred + +# Just so you don't have to guess at the colors... +barcolor, linecolor, fillcolor = 'wheat', 'salmon', 'lightblue' + +# Now you're on your own! diff --git a/exercises/2.2-vmin_vmax_imshow_and_colorbars.py b/exercises/2.2-vmin_vmax_imshow_and_colorbars.py new file mode 100644 index 0000000..4922fb3 --- /dev/null +++ b/exercises/2.2-vmin_vmax_imshow_and_colorbars.py @@ -0,0 +1,15 @@ +import numpy as np +import matplotlib.pyplot as plt +np.random.seed(1) + +# Generate random data with different ranges... +data1 = np.random.random((10, 10)) +data2 = 2 * np.random.random((10, 10)) +data3 = 3 * np.random.random((10, 10)) + +# Set up our figure and axes... +fig, axes = plt.subplots(ncols=3, figsize=plt.figaspect(0.5)) +fig.tight_layout() # Make the subplots fill up the figure a bit more... +cax = fig.add_axes([0.25, 0.1, 0.55, 0.03]) # Add an axes for the colorbar + +# Now you're on your own! diff --git a/exercises/2.1-colors.py b/exercises/3.1-colors.py similarity index 100% rename from exercises/2.1-colors.py rename to exercises/3.1-colors.py diff --git a/exercises/2.2-markers.py b/exercises/3.2-markers.py similarity index 100% rename from exercises/2.2-markers.py rename to exercises/3.2-markers.py diff --git a/exercises/2.3-properties.py b/exercises/3.3-properties.py similarity index 100% rename from exercises/2.3-properties.py rename to exercises/3.3-properties.py diff --git a/exercises/2.4-arrows.py b/exercises/3.4-arrows.py similarity index 100% rename from exercises/2.4-arrows.py rename to exercises/3.4-arrows.py diff --git a/exercises/4.1-legends_and_scaling.py b/exercises/4.1-legends_and_scaling.py new file mode 100644 index 0000000..3f96e87 --- /dev/null +++ b/exercises/4.1-legends_and_scaling.py @@ -0,0 +1,17 @@ +import numpy as np +import matplotlib.pyplot as plt + +plt.style.use('classic') + +# Try to reproduce the figure shown in images/exercise_4-1.png +# Here's the data and colors used. + +t = np.linspace(0, 2 * np.pi, 150) +x1, y1 = np.cos(t), np.sin(t) +x2, y2 = 2 * x1, 2 * y1 + +colors = ['darkred', 'darkgreen'] + +# Try to plot the two circles, scale the axes as shown and add a legend +# Hint: it's easiest to combine `ax.axis(...)` and `ax.margins(...)` to scale +# the axes diff --git a/exercises/4.2-spines_ticks_and_subplot_spacing.py b/exercises/4.2-spines_ticks_and_subplot_spacing.py new file mode 100644 index 0000000..2f607c0 --- /dev/null +++ b/exercises/4.2-spines_ticks_and_subplot_spacing.py @@ -0,0 +1,9 @@ +import matplotlib.pyplot as plt +import numpy as np + +# Try to reproduce the figure shown in images/exercise_4.2.png +# This one is a bit trickier! + +# Here's the data... +data = [('dogs', 4, 4), ('frogs', -3, 1), ('cats', 1, 5), ('goldfish', -2, 2)] +animals, friendliness, popularity = zip(*data) diff --git a/exercises/3.1-goldstar.py b/exercises/5.1-goldstar.py similarity index 100% rename from exercises/3.1-goldstar.py rename to exercises/5.1-goldstar.py diff --git a/images/bar_example.png b/images/bar_example.png new file mode 100644 index 0000000..8aebe55 Binary files /dev/null and b/images/bar_example.png differ diff --git a/images/contour_example.png b/images/contour_example.png new file mode 100644 index 0000000..7e0ead7 Binary files /dev/null and b/images/contour_example.png differ diff --git a/images/exercise_1-1.png b/images/exercise_1-1.png new file mode 100644 index 0000000..b64ffea Binary files /dev/null and b/images/exercise_1-1.png differ diff --git a/images/exercise_2.1-bar_and_fill_between.png b/images/exercise_2.1-bar_and_fill_between.png new file mode 100644 index 0000000..37ef247 Binary files /dev/null and b/images/exercise_2.1-bar_and_fill_between.png differ diff --git a/images/exercise_2.2-vmin_vmax_imshow_and_colorbars.png b/images/exercise_2.2-vmin_vmax_imshow_and_colorbars.png new file mode 100644 index 0000000..45db4d9 Binary files /dev/null and b/images/exercise_2.2-vmin_vmax_imshow_and_colorbars.png differ diff --git a/images/exercise_4-1.png b/images/exercise_4-1.png new file mode 100644 index 0000000..a981f2c Binary files /dev/null and b/images/exercise_4-1.png differ diff --git a/images/exercise_4-2.png b/images/exercise_4-2.png new file mode 100644 index 0000000..e5fda91 Binary files /dev/null and b/images/exercise_4-2.png differ diff --git a/images/figure_axes_axis_labeled.png b/images/figure_axes_axis_labeled.png new file mode 100644 index 0000000..fc3a2f1 Binary files /dev/null and b/images/figure_axes_axis_labeled.png differ diff --git a/images/fill_example.png b/images/fill_example.png new file mode 100644 index 0000000..1d60c0c Binary files /dev/null and b/images/fill_example.png differ diff --git a/images/imshow_example.png b/images/imshow_example.png new file mode 100644 index 0000000..6306f36 Binary files /dev/null and b/images/imshow_example.png differ diff --git a/images/pcolor_example.png b/images/pcolor_example.png new file mode 100644 index 0000000..ab3a8f5 Binary files /dev/null and b/images/pcolor_example.png differ diff --git a/images/plot_example.png b/images/plot_example.png new file mode 100644 index 0000000..afbc85e Binary files /dev/null and b/images/plot_example.png differ diff --git a/images/scatter_example.png b/images/scatter_example.png new file mode 100644 index 0000000..1f38270 Binary files /dev/null and b/images/scatter_example.png differ diff --git a/images/statistical_example.png b/images/statistical_example.png new file mode 100644 index 0000000..cc398d6 Binary files /dev/null and b/images/statistical_example.png differ diff --git a/images/vector_example.png b/images/vector_example.png new file mode 100644 index 0000000..3b99d73 Binary files /dev/null and b/images/vector_example.png differ diff --git a/solutions/1.1-limits.py b/solutions/1.1-limits.py deleted file mode 100644 index 37bf892..0000000 --- a/solutions/1.1-limits.py +++ /dev/null @@ -1,3 +0,0 @@ -fig, ax = plt.subplots(1, 1) -ax.set_ylim(1000, 500) -plt.show() diff --git a/solutions/1.1-subplots_and_basic_plotting.py b/solutions/1.1-subplots_and_basic_plotting.py new file mode 100644 index 0000000..4a641d6 --- /dev/null +++ b/solutions/1.1-subplots_and_basic_plotting.py @@ -0,0 +1,14 @@ +import numpy as np +import matplotlib.pyplot as plt + +x = np.linspace(0, 10, 100) +y1, y2, y3 = np.cos(x), np.cos(x + 1), np.cos(x + 2) +names = ['Signal 1', 'Signal 2', 'Signal 3'] + +fig, axes = plt.subplots(nrows=3) + +for ax, y, name in zip(axes, [y1, y2, y3], names): + ax.plot(x, y, color='black') + ax.set(xticks=[], yticks=[], title=name) + +plt.show() diff --git a/solutions/1.2-spines.py b/solutions/1.2-spines.py deleted file mode 100644 index ae58e32..0000000 --- a/solutions/1.2-spines.py +++ /dev/null @@ -1,12 +0,0 @@ -fig, ax = plt.subplots(1, 1) -ax.plot([-2, 2, 3, 4], [-10, 20, 25, 5]) - -ax.spines['top'].set_position('center') -ax.spines['right'].set_position('center') -ax.tick_params(axis='both', direction='inout', length=10) - -# Move the two remaining spines "out" away from the plot by 10 points -ax.spines['bottom'].set_position(('outward', 10)) -ax.spines['left'].set_position(('outward', 10)) - -plt.show() diff --git a/solutions/2.1-bar_and_fill_between.py b/solutions/2.1-bar_and_fill_between.py new file mode 100644 index 0000000..125de02 --- /dev/null +++ b/solutions/2.1-bar_and_fill_between.py @@ -0,0 +1,37 @@ +import numpy as np +import matplotlib.pyplot as plt +np.random.seed(1) + +# Generate data... +y_raw = np.random.randn(1000).cumsum() + 15 +x_raw = np.linspace(0, 24, y_raw.size) + +# Get averages of every 100 samples... +x_pos = x_raw.reshape(-1, 100).min(axis=1) +y_avg = y_raw.reshape(-1, 100).mean(axis=1) +y_err = y_raw.reshape(-1, 100).ptp(axis=1) + +bar_width = x_pos[1] - x_pos[0] + +# Make a made up future prediction with a fake confidence +x_pred = np.linspace(0, 30) +y_max_pred = y_avg[0] + y_err[0] + 2.3 * x_pred +y_min_pred = y_avg[0] - y_err[0] + 1.2 * x_pred + +# Just so you don't have to guess at the colors... +barcolor, linecolor, fillcolor = 'wheat', 'salmon', 'lightblue' + +# Now you're on your own! + +fig, ax = plt.subplots() + +ax.plot(x_raw, y_raw, color=linecolor) +ax.bar(x_pos, y_avg, width=bar_width, color=barcolor, yerr=y_err, + ecolor='gray', edgecolor='gray') +ax.fill_between(x_pred, y_min_pred, y_max_pred, color=fillcolor) + +ax.set(title='Future Projection of Attitudes', + ylabel='Snarkiness (snark units)', + xlabel='Minutes since class began') + +plt.show() diff --git a/solutions/2.2-vmin_vmax_imshow_and_colorbars.py b/solutions/2.2-vmin_vmax_imshow_and_colorbars.py new file mode 100644 index 0000000..208e6ea --- /dev/null +++ b/solutions/2.2-vmin_vmax_imshow_and_colorbars.py @@ -0,0 +1,22 @@ +import numpy as np +import matplotlib.pyplot as plt +np.random.seed(1) + + +# Generate random data with different ranges... +data1 = np.random.random((10, 10)) +data2 = 2 * np.random.random((10, 10)) +data3 = 3 * np.random.random((10, 10)) + +# Set up our figure and axes... +fig, axes = plt.subplots(ncols=3, figsize=plt.figaspect(0.5)) +fig.tight_layout() # Make the subplots fill up the figure a bit more... +cax = fig.add_axes([0.25, 0.1, 0.55, 0.03]) # Add an axes for the colorbar + +# Now you're on your own! +for ax, data in zip(axes, [data1, data2, data3]): + # Display data, explicitly making the colormap cover values from 0 to 3 + im = ax.imshow(data, vmin=0, vmax=3, interpolation='nearest') + +fig.colorbar(im, cax=cax, orientation='horizontal') +plt.show() diff --git a/solutions/2.1-colors.py b/solutions/3.1-colors.py similarity index 100% rename from solutions/2.1-colors.py rename to solutions/3.1-colors.py diff --git a/solutions/2.2-markers.py b/solutions/3.2-markers.py similarity index 100% rename from solutions/2.2-markers.py rename to solutions/3.2-markers.py diff --git a/solutions/2.3-properties.py b/solutions/3.3-properties.py similarity index 64% rename from solutions/2.3-properties.py rename to solutions/3.3-properties.py index 340f787..7e0c9eb 100644 --- a/solutions/2.3-properties.py +++ b/solutions/3.3-properties.py @@ -1,4 +1,4 @@ t = np.arange(0.0, 5.0, 0.1) a = np.exp(-t) * np.cos(2*np.pi*t) -plt.plot(t, a, 'r:', marker='D', mfc='y') +plt.plot(t, a, 'r:D', mfc='y', mec='g') plt.show() diff --git a/solutions/2.4-arrows.py b/solutions/3.4-arrows.py similarity index 100% rename from solutions/2.4-arrows.py rename to solutions/3.4-arrows.py diff --git a/solutions/4.1-legends_and_scaling.py b/solutions/4.1-legends_and_scaling.py new file mode 100644 index 0000000..10e53b3 --- /dev/null +++ b/solutions/4.1-legends_and_scaling.py @@ -0,0 +1,20 @@ +import numpy as np +import matplotlib.pyplot as plt + +plt.style.use('classic') + +t = np.linspace(0, 2 * np.pi, 150) +x1, y1 = np.cos(t), np.sin(t) +x2, y2 = 2 * x1, 2 * y1 + +colors = ['darkred', 'darkgreen'] + +fig, ax = plt.subplots() +ax.plot(x1, y1, color=colors[0], label='Inner', linewidth=3) +ax.plot(x2, y2, color=colors[1], label='Outer', linewidth=3) +ax.legend() + +ax.axis('equal') +ax.margins(0.05) + +plt.show() diff --git a/solutions/4.2-spines_ticks_and_subplot_spacing.py b/solutions/4.2-spines_ticks_and_subplot_spacing.py new file mode 100644 index 0000000..088d47b --- /dev/null +++ b/solutions/4.2-spines_ticks_and_subplot_spacing.py @@ -0,0 +1,25 @@ +import matplotlib.pyplot as plt +import numpy as np + +data = [('dogs', 4, 4), ('frogs', -3, 1), ('cats', 1, 5), ('goldfish', -2, 2)] +animals, friendliness, popularity = zip(*data) + + +def plot_and_setup_spines(ax, animals, y, ylabel): + x = np.arange(len(animals)) + ax.bar(x, y, align='center', color='gray') + ax.set(xticks=x, xticklabels=animals, ylabel=ylabel) + + ax.xaxis.set_ticks_position('bottom') + ax.yaxis.set_ticks_position('left') + ax.spines['bottom'].set_position(('data', 0)) + ax.tick_params(axis='x', direction='inout', length=8) + ax.margins(0.05) + +fig, axes = plt.subplots(nrows=2) +fig.subplots_adjust(hspace=0.0) + +plot_and_setup_spines(axes[0], animals, friendliness, 'Friendliness') +plot_and_setup_spines(axes[1], animals, popularity, 'Popularity') + +plt.show() diff --git a/solutions/3.1-goldstar.py b/solutions/5.1-goldstar.py similarity index 70% rename from solutions/3.1-goldstar.py rename to solutions/5.1-goldstar.py index 4057d05..7a04d3e 100644 --- a/solutions/3.1-goldstar.py +++ b/solutions/5.1-goldstar.py @@ -3,11 +3,12 @@ fig, ax = plt.subplots(1, 1) -offsets = zip([0.2, 0.4, 0.6, 0.8], [0.5] * 4) +offsets = list(zip([0.2, 0.4, 0.6, 0.8], [0.5] * 4)) collection = StarPolygonCollection(5, offsets=offsets, transOffset=ax.transData, facecolors=['gold'], - sizes=[75]) + sizes=[175], + edgecolors=['k']) ax.add_collection(collection) plt.show() pFad - Phonifier reborn

Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.

Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.


Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy