|
10 | 10 | # sphinx_gallery_thumbnail_number = 2
|
11 | 11 |
|
12 | 12 | import numpy as np
|
13 |
| -from scipy.interpolate import splprep, splev |
14 | 13 |
|
15 | 14 | import matplotlib.pyplot as plt
|
16 | 15 | from matplotlib.path import Path
|
|
22 | 21 | x, y = r * np.cos(t), r * np.sin(t)
|
23 | 22 |
|
24 | 23 | fig, ax = plt.subplots()
|
25 |
| -ax.plot(x, y) |
26 |
| -plt.show() |
| 24 | +ax.plot(x, y, "k") |
| 25 | +ax.set(aspect=1) |
27 | 26 |
|
28 | 27 | #############################################################################
|
29 | 28 | # An error band can be used to indicate the uncertainty of the curve.
|
|
39 | 38 | # `~.Axes.fill_between` method (see also
|
40 | 39 | # :doc:`/gallery/lines_bars_and_markers/fill_between_demo`).
|
41 | 40 |
|
42 |
| -# Error amplitudes depending on the curve parameter *t* |
43 |
| -# (actual values are arbitrary and only for illustrative purposes): |
44 |
| -err = 0.05 * np.sin(2 * t) ** 2 + 0.04 + 0.02 * np.cos(9 * t + 2) |
45 | 41 |
|
46 |
| -# calculate normals via derivatives of splines |
47 |
| -tck, u = splprep([x, y], s=0) |
48 |
| -dx, dy = splev(u, tck, der=1) |
49 |
| -l = np.hypot(dx, dy) |
50 |
| -nx = dy / l |
51 |
| -ny = -dx / l |
| 42 | +def draw_error_band(ax, x, y, err, **kwargs): |
| 43 | + # Calculate normals via centered finite differences (except the first point |
| 44 | + # which uses a forward difference and the last point which uses a backward |
| 45 | + # difference). |
| 46 | + dx = np.concatenate([[x[1] - x[0]], x[2:] - x[:-2], [x[-1] - x[-2]]]) |
| 47 | + dy = np.concatenate([[y[1] - y[0]], y[2:] - y[:-2], [y[-1] - y[-2]]]) |
| 48 | + l = np.hypot(dx, dy) |
| 49 | + nx = dy / l |
| 50 | + ny = -dx / l |
52 | 51 |
|
53 |
| -# end points of errors |
54 |
| -xp = x + nx * err |
55 |
| -yp = y + ny * err |
56 |
| -xn = x - nx * err |
57 |
| -yn = y - ny * err |
| 52 | + # end points of errors |
| 53 | + xp = x + nx * err |
| 54 | + yp = y + ny * err |
| 55 | + xn = x - nx * err |
| 56 | + yn = y - ny * err |
58 | 57 |
|
59 |
| -vertices = np.block([[xp, xn[::-1]], |
60 |
| - [yp, yn[::-1]]]).T |
61 |
| -codes = Path.LINETO * np.ones(len(vertices), dtype=Path.code_type) |
62 |
| -codes[0] = codes[len(xp)] = Path.MOVETO |
63 |
| -path = Path(vertices, codes) |
| 58 | + vertices = np.block([[xp, xn[::-1]], |
| 59 | + [yp, yn[::-1]]]).T |
| 60 | + codes = np.full(len(vertices), Path.LINETO) |
| 61 | + codes[0] = codes[len(xp)] = Path.MOVETO |
| 62 | + path = Path(vertices, codes) |
| 63 | + ax.add_patch(PathPatch(path, **kwargs)) |
64 | 64 |
|
65 |
| -patch = PathPatch(path, facecolor='C0', edgecolor='none', alpha=0.3) |
66 | 65 |
|
67 |
| -fig, ax = plt.subplots() |
68 |
| -ax.plot(x, y) |
69 |
| -ax.add_patch(patch) |
| 66 | +axs = (plt.figure(constrained_layout=True) |
| 67 | + .subplots(1, 2, sharex=True, sharey=True)) |
| 68 | +errs = [ |
| 69 | + (axs[0], "constant error", 0.05), |
| 70 | + (axs[1], "variable error", 0.05 * np.sin(2 * t) ** 2 + 0.04), |
| 71 | +] |
| 72 | +for i, (ax, title, err) in enumerate(errs): |
| 73 | + ax.set(title=title, aspect=1, xticks=[], yticks=[]) |
| 74 | + ax.plot(x, y, "k") |
| 75 | + draw_error_band(ax, x, y, err=err, |
| 76 | + facecolor=f"C{i}", edgecolor="none", alpha=.3) |
| 77 | + |
70 | 78 | plt.show()
|
71 | 79 |
|
72 | 80 | #############################################################################
|
|
0 commit comments