{
  "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\n.. redirect-from:: /gallery/lines_bars_and_markers/curve_error_band\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.14.6"
    }
  },
  "nbformat": 4,
  "nbformat_minor": 0
}