{ "cells": [ { "cell_type": "markdown", "metadata": {}, "source": [ "\n# Curve with error band\n\nThis example illustrates how to draw an error band around a parametrized curve.\n\nA parametrized curve x(t), y(t) can directly be drawn using `~.Axes.plot`.\n" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "collapsed": false }, "outputs": [], "source": [ "import matplotlib.pyplot as plt\nimport numpy as np\n\nfrom matplotlib.patches import PathPatch\nfrom matplotlib.path import Path\n\nN = 400\nt = np.linspace(0, 2 * np.pi, N)\nr = 0.5 + np.cos(t)\nx, y = r * np.cos(t), r * np.sin(t)\n\nfig, ax = plt.subplots()\nax.plot(x, y, \"k\")\nax.set(aspect=1)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "An error band can be used to indicate the uncertainty of the curve.\nIn this example we assume that the error can be given as a scalar *err*\nthat describes the uncertainty perpendicular to the curve in every point.\n\nWe visualize this error as a colored band around the path using a\n`.PathPatch`. The patch is created from two path segments *(xp, yp)*, and\n*(xn, yn)* that are shifted by +/- *err* perpendicular to the curve *(x, y)*.\n\nNote: This method of using a `.PathPatch` is suited to arbitrary curves in\n2D. If you just have a standard y-vs.-x plot, you can use the simpler\n`~.Axes.fill_between` method (see also\n:doc:`/gallery/lines_bars_and_markers/fill_between_demo`).\n\n" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "collapsed": false }, "outputs": [], "source": [ "def draw_error_band(ax, x, y, err, **kwargs):\n # Calculate normals via centered finite differences (except the first point\n # which uses a forward difference and the last point which uses a backward\n # difference).\n dx = np.concatenate([[x[1] - x[0]], x[2:] - x[:-2], [x[-1] - x[-2]]])\n dy = np.concatenate([[y[1] - y[0]], y[2:] - y[:-2], [y[-1] - y[-2]]])\n l = np.hypot(dx, dy)\n nx = dy / l\n ny = -dx / l\n\n # end points of errors\n xp = x + nx * err\n yp = y + ny * err\n xn = x - nx * err\n yn = y - ny * err\n\n vertices = np.block([[xp, xn[::-1]],\n [yp, yn[::-1]]]).T\n codes = np.full(len(vertices), Path.LINETO)\n codes[0] = codes[len(xp)] = Path.MOVETO\n path = Path(vertices, codes)\n ax.add_patch(PathPatch(path, **kwargs))\n\n\n_, axs = plt.subplots(1, 2, layout='constrained', sharex=True, sharey=True)\nerrs = [\n (axs[0], \"constant error\", 0.05),\n (axs[1], \"variable error\", 0.05 * np.sin(2 * t) ** 2 + 0.04),\n]\nfor i, (ax, title, err) in enumerate(errs):\n ax.set(title=title, aspect=1, xticks=[], yticks=[])\n ax.plot(x, y, \"k\")\n draw_error_band(ax, x, y, err=err,\n facecolor=f\"C{i}\", edgecolor=\"none\", alpha=.3)\n\nplt.show()" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ ".. admonition:: References\n\n The use of the following functions, methods, classes and modules is shown\n in this example:\n\n - `matplotlib.patches.PathPatch`\n - `matplotlib.path.Path`\n\n.. tags::\n\n component: error\n plot-type: line\n level: intermediate\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.5" } }, "nbformat": 4, "nbformat_minor": 0 }