{ "cells": [ { "cell_type": "markdown", "metadata": {}, "source": [ "\n# ``fill_between`` with transparency\n\nThe `~matplotlib.axes.Axes.fill_between` function generates a shaded\nregion between a min and max boundary that is useful for illustrating ranges.\nIt has a very handy ``where`` argument to combine filling with logical ranges,\ne.g., to just fill in a curve over some threshold value.\n\nAt its most basic level, ``fill_between`` can be used to enhance a graph's\nvisual appearance. Let's compare two graphs of financial data with a simple\nline plot on the left and a filled line on the right.\n" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "collapsed": false }, "outputs": [], "source": [ "import matplotlib.pyplot as plt\nimport numpy as np\n\nimport matplotlib.cbook as cbook\n\n# load up some sample financial data\nr = cbook.get_sample_data('goog.npz')['price_data']\n# create two subplots with the shared x and y axes\nfig, (ax1, ax2) = plt.subplots(1, 2, sharex=True, sharey=True)\n\npricemin = r[\"close\"].min()\n\nax1.plot(r[\"date\"], r[\"close\"], lw=2)\nax2.fill_between(r[\"date\"], pricemin, r[\"close\"], alpha=0.7)\n\nfor ax in ax1, ax2:\n ax.grid(True)\n ax.label_outer()\n\nax1.set_ylabel('price')\n\nfig.suptitle('Google (GOOG) daily closing price')\nfig.autofmt_xdate()" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "The alpha channel is not necessary here, but it can be used to soften\ncolors for more visually appealing plots. In other examples, as we'll\nsee below, the alpha channel is functionally useful as the shaded\nregions can overlap and alpha allows you to see both. Note that the\npostscript format does not support alpha (this is a postscript\nlimitation, not a matplotlib limitation), so when using alpha save\nyour figures in PNG, PDF or SVG.\n\nOur next example computes two populations of random walkers with a\ndifferent mean and standard deviation of the normal distributions from\nwhich the steps are drawn. We use filled regions to plot +/- one\nstandard deviation of the mean position of the population. Here the\nalpha channel is useful, not just aesthetic.\n\n" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "collapsed": false }, "outputs": [], "source": [ "# Fixing random state for reproducibility\nnp.random.seed(19680801)\n\nNsteps, Nwalkers = 100, 250\nt = np.arange(Nsteps)\n\n# an (Nsteps x Nwalkers) array of random walk steps\nS1 = 0.004 + 0.02*np.random.randn(Nsteps, Nwalkers)\nS2 = 0.002 + 0.01*np.random.randn(Nsteps, Nwalkers)\n\n# an (Nsteps x Nwalkers) array of random walker positions\nX1 = S1.cumsum(axis=0)\nX2 = S2.cumsum(axis=0)\n\n\n# Nsteps length arrays empirical means and standard deviations of both\n# populations over time\nmu1 = X1.mean(axis=1)\nsigma1 = X1.std(axis=1)\nmu2 = X2.mean(axis=1)\nsigma2 = X2.std(axis=1)\n\n# plot it!\nfig, ax = plt.subplots(1)\nax.plot(t, mu1, lw=2, label='mean population 1')\nax.plot(t, mu2, lw=2, label='mean population 2')\nax.fill_between(t, mu1+sigma1, mu1-sigma1, facecolor='C0', alpha=0.4)\nax.fill_between(t, mu2+sigma2, mu2-sigma2, facecolor='C1', alpha=0.4)\nax.set_title(r'random walkers empirical $\\mu$ and $\\pm \\sigma$ interval')\nax.legend(loc='upper left')\nax.set_xlabel('num steps')\nax.set_ylabel('position')\nax.grid()" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "The ``where`` keyword argument is very handy for highlighting certain\nregions of the graph. ``where`` takes a boolean mask the same length\nas the x, ymin and ymax arguments, and only fills in the region where\nthe boolean mask is True. In the example below, we simulate a single\nrandom walker and compute the analytic mean and standard deviation of\nthe population positions. The population mean is shown as the dashed\nline, and the plus/minus one sigma deviation from the mean is shown\nas the filled region. We use the where mask ``X > upper_bound`` to\nfind the region where the walker is outside the one sigma boundary,\nand shade that region red.\n\n" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "collapsed": false }, "outputs": [], "source": [ "# Fixing random state for reproducibility\nnp.random.seed(1)\n\nNsteps = 500\nt = np.arange(Nsteps)\n\nmu = 0.002\nsigma = 0.01\n\n# the steps and position\nS = mu + sigma*np.random.randn(Nsteps)\nX = S.cumsum()\n\n# the 1 sigma upper and lower analytic population bounds\nlower_bound = mu*t - sigma*np.sqrt(t)\nupper_bound = mu*t + sigma*np.sqrt(t)\n\nfig, ax = plt.subplots(1)\nax.plot(t, X, lw=2, label='walker position')\nax.plot(t, mu*t, lw=1, label='population mean', color='C0', ls='--')\nax.fill_between(t, lower_bound, upper_bound, facecolor='C0', alpha=0.4,\n label='1 sigma range')\nax.legend(loc='upper left')\n\n# here we use the where argument to only fill the region where the\n# walker is above the population 1 sigma boundary\nax.fill_between(t, upper_bound, X, where=X > upper_bound, fc='red', alpha=0.4)\nax.fill_between(t, lower_bound, X, where=X < lower_bound, fc='red', alpha=0.4)\nax.set_xlabel('num steps')\nax.set_ylabel('position')\nax.grid()" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Another handy use of filled regions is to highlight horizontal or vertical\nspans of an Axes -- for that Matplotlib has the helper functions\n`~matplotlib.axes.Axes.axhspan` and `~matplotlib.axes.Axes.axvspan`. See\n:doc:`/gallery/subplots_axes_and_figures/axhspan_demo`.\n\n" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "collapsed": false }, "outputs": [], "source": [ "plt.show()" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ ".. tags::\n\n styling: alpha\n plot-type: fill_between\n level: intermediate\n purpose: showcase\n\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.13.2" } }, "nbformat": 4, "nbformat_minor": 0 }