From a131488e9397f847f13014799e30aed3ebc0ac36 Mon Sep 17 00:00:00 2001 From: Tim Hoffmann <2836374+timhoffm@users.noreply.github.com> Date: Wed, 6 Mar 2024 23:50:01 +0100 Subject: [PATCH] Simplify the LineCollection example Superseeds #27871. This example is much simpler, but conveys the same LineCollection aspects - except for not using masked arrays. But I argue that this the example should be simple and using masked arrays rather distracts from the core aspects of LineCollection. If there's concern of not showing masked array support, we should add a third plot for that. --- .../shapes_and_collections/line_collection.py | 85 ++++++++----------- 1 file changed, 37 insertions(+), 48 deletions(-) diff --git a/galleries/examples/shapes_and_collections/line_collection.py b/galleries/examples/shapes_and_collections/line_collection.py index d534913ad2b2..a27496f62e0e 100644 --- a/galleries/examples/shapes_and_collections/line_collection.py +++ b/galleries/examples/shapes_and_collections/line_collection.py @@ -3,8 +3,7 @@ Plotting multiple lines with a LineCollection ============================================= -Matplotlib can efficiently draw multiple lines at once using a -`~.LineCollection`, as showcased below. +Matplotlib can efficiently draw multiple lines at once using a `~.LineCollection`. """ import matplotlib.pyplot as plt @@ -12,60 +11,52 @@ from matplotlib.collections import LineCollection -x = np.arange(100) -# Here are many sets of y to plot vs. x -ys = x[:50, np.newaxis] + x[np.newaxis, :] +colors = ["indigo", "blue", "green", "yellow", "orange", "red"] -segs = np.zeros((50, 100, 2)) -segs[:, :, 1] = ys -segs[:, :, 0] = x +# create a list of half-circles with varying radii +theta = np.linspace(0, np.pi, 36) +radii = np.linspace(4, 5, num=len(colors)) +arcs = [np.column_stack([r * np.cos(theta), r * np.sin(theta)]) for r in radii] -# Mask some values to test masked array support: -segs = np.ma.masked_where((segs > 50) & (segs < 60), segs) +fig, ax = plt.subplots(figsize=(6.4, 3.2)) +# set axes limits manually because Collections do not take part in autoscaling +ax.set_xlim(-6, 6) +ax.set_ylim(0, 6) +ax.set_aspect("equal") # to make the arcs look circular -# We need to set the plot limits, they will not autoscale -fig, ax = plt.subplots() -ax.set_xlim(x.min(), x.max()) -ax.set_ylim(ys.min(), ys.max()) +# create a LineCollection with the half-circles +# its properties can be set per line by passing a sequence (here used for *colors*) +# or they can be set for all lines by passing a scalar (here used for *linewidths*) +line_collection = LineCollection(arcs, colors=colors, linewidths=4) +ax.add_collection(line_collection) -# *colors* is sequence of rgba tuples. -# *linestyle* is a string or dash tuple. Legal string values are -# solid|dashed|dashdot|dotted. The dash tuple is (offset, onoffseq) where -# onoffseq is an even length tuple of on and off ink in points. If linestyle -# is omitted, 'solid' is used. -# See `matplotlib.collections.LineCollection` for more information. -colors = plt.rcParams['axes.prop_cycle'].by_key()['color'] - -line_segments = LineCollection(segs, linewidths=(0.5, 1, 1.5, 2), - colors=colors, linestyle='solid') -ax.add_collection(line_segments) -ax.set_title('Line collection with masked arrays') plt.show() # %% -# In the following example, instead of passing a list of colors -# (``colors=colors``), we pass an array of values (``array=x``) that get -# colormapped. +# Instead of passing a list of colors (``colors=colors``), we can alternatively use +# colormapping. The lines are then color-coded based on an additional array of values +# passed to the *array* parameter. In the below example, we color the lines based on +# their radius by passing ``array=radii``. -N = 50 -x = np.arange(N) -ys = [x + i for i in x] # Many sets of y to plot vs. x -segs = [np.column_stack([x, y]) for y in ys] +num_arcs = 15 +theta = np.linspace(0, np.pi, 36) +radii = np.linspace(4, 5.5, num=num_arcs) +arcs = [np.column_stack([r * np.cos(theta), r * np.sin(theta)]) for r in radii] -fig, ax = plt.subplots() -ax.set_xlim(np.min(x), np.max(x)) -ax.set_ylim(np.min(ys), np.max(ys)) +fig, ax = plt.subplots(figsize=(6.4, 3)) +# set axes limits manually because Collections do not take part in autoscaling +ax.set_xlim(-6, 6) +ax.set_ylim(0, 6) +ax.set_aspect("equal") # to make the arcs look circular -line_segments = LineCollection(segs, array=x, - linewidths=(0.5, 1, 1.5, 2), - linestyles='solid') -ax.add_collection(line_segments) -axcb = fig.colorbar(line_segments) -axcb.set_label('Line Number') -ax.set_title('Line Collection with mapped colors') -plt.sci(line_segments) # This allows interactive changing of the colormap. -plt.show() +# create a LineCollection with the half-circles and color mapping +line_collection = LineCollection(arcs, array=radii, cmap="rainbow") +ax.add_collection(line_collection) +fig.colorbar(line_collection, label="Radius") +ax.set_title("Line Collection with mapped colors") + +plt.show() # %% # # .. admonition:: References @@ -73,9 +64,7 @@ # The use of the following functions, methods, classes and modules is shown # in this example: # -# - `matplotlib.collections` # - `matplotlib.collections.LineCollection` -# - `matplotlib.cm.ScalarMappable.set_array` +# - `matplotlib.collections.Collection.set_array` # - `matplotlib.axes.Axes.add_collection` # - `matplotlib.figure.Figure.colorbar` / `matplotlib.pyplot.colorbar` -# - `matplotlib.pyplot.sci`