The SpanSelector widget in Matplotlib provides an easy way to select a range within a plot by clicking and dragging.
This widget is particularly useful for selecting ranges on one of the axes (typically x-axis or y-axis) to zoom into data, highlight specific sections, or analyze specific intervals in time series or other continuous data.
In this tutorial, we’ll cover the basics of creating and using the SpanSelector widget in Matplotlib, along with examples demonstrating different applications, including zooming, data filtering, and interactive analysis.
1. Basic Setup for the SpanSelector
The SpanSelector widget allows you to select a range along a specified axis. It requires defining a callback function that handles the event after a range has been selected.
Basic Structure of SpanSelector
import numpy as np import matplotlib.pyplot as plt from matplotlib.widgets import SpanSelector # Sample data for a line plot x = np.linspace(0, 10, 100) y = np.sin(x) # Create a figure and plot fig, ax = plt.subplots() ax.plot(x, y) plt.xlabel("X-axis") plt.ylabel("Y-axis") # Callback function to handle the selection def onselect(xmin, xmax): print(f"Range selected from {xmin:.2f} to {xmax:.2f}") # Create the SpanSelector object span_selector = SpanSelector(ax, onselect, 'horizontal', useblit=True, rectprops=dict(alpha=0.5, facecolor='red')) plt.show()
In this example:
- SpanSelector(ax, onselect, ‘horizontal', useblit=True) creates a horizontal SpanSelector.
- The onselect callback function is called when a range is selected, printing the minimum and maximum values of the selected range.
- rectprops=dict(alpha=0.5, facecolor='red') customizes the appearance of the selection rectangle with 50% transparency and red color.
2. Highlighting Selected Range
You can use the SpanSelector to highlight a selected range by shading it or drawing a rectangle over the selection.
# Create figure and plot fig, ax = plt.subplots() ax.plot(x, y) plt.xlabel("X-axis") plt.ylabel("Y-axis") # Create an empty rectangle to show the selected range highlight = ax.axvspan(0, 0, color='yellow', alpha=0.3, visible=False) # Callback function to highlight the selected range def onselect(xmin, xmax): highlight.set_visible(True) highlight.set_xy([[xmin, ax.get_ylim()[0]], [xmin, ax.get_ylim()[1]], [xmax, ax.get_ylim()[1]], [xmax, ax.get_ylim()[0]], [xmin, ax.get_ylim()[0]]]) fig.canvas.draw_idle() # Create the SpanSelector span_selector = SpanSelector(ax, onselect, 'horizontal', useblit=True, rectprops=dict(alpha=0.5, facecolor='blue')) plt.show()
In this example:
- The highlight rectangle is initially invisible but becomes visible after the selection.
- The onselect function updates the rectangle’s coordinates to match the selected range, shading the selected region.
3. Using SpanSelector to Zoom into Selected Range
One of the most common applications of the SpanSelector is zooming into the selected range by setting the x-axis limits based on the selection.
# Create figure and plot fig, ax = plt.subplots() ax.plot(x, y) plt.xlabel("X-axis") plt.ylabel("Y-axis") # Callback function to zoom into selected range def onselect(xmin, xmax): ax.set_xlim(xmin, xmax) plt.draw() # Create the SpanSelector span_selector = SpanSelector(ax, onselect, 'horizontal', useblit=True, rectprops=dict(alpha=0.5, facecolor='green')) plt.show()
In this example:
- The onselect function updates the x-axis limits to zoom into the selected range.
- plt.draw() is called to refresh the plot immediately after changing the limits.
4. SpanSelector for Range Filtering
You can use SpanSelector to select a specific range and display only the data within that range, effectively filtering the data shown.
# Create figure and initial plot fig, ax = plt.subplots() sc = ax.scatter(x, y, label="Data") plt.xlabel("X-axis") plt.ylabel("Y-axis") # Callback function to filter data within selected range def onselect(xmin, xmax): mask = (x >= xmin) & (x <= xmax) sc.set_offsets(np.c_[x[mask], y[mask]]) # Update scatter plot with filtered data fig.canvas.draw_idle() # Create the SpanSelector span_selector = SpanSelector(ax, onselect, 'horizontal', useblit=True, rectprops=dict(alpha=0.3, facecolor='purple')) plt.show()
In this example:
- The onselect function creates a mask to filter x and y values within the selected range and updates the scatter plot accordingly.
5. Adjusting SpanSelector to Select on Y-Axis
The SpanSelector can also be used to select ranges vertically along the y-axis by setting the orientation to ‘vertical'.
# Create figure and plot fig, ax = plt.subplots() ax.plot(x, y) plt.xlabel("X-axis") plt.ylabel("Y-axis") # Callback function for vertical selection def onselect(ymin, ymax): print(f"Range selected from {ymin:.2f} to {ymax:.2f}") # Create the SpanSelector for vertical selection span_selector = SpanSelector(ax, onselect, 'vertical', useblit=True, rectprops=dict(alpha=0.3, facecolor='orange')) plt.show()
In this example:
- SpanSelector is set to vertical selection mode by setting ‘vertical' for the third parameter.
- The callback function onselect now receives ymin and ymax values from the selection.
6. Using SpanSelector to Adjust Plot Limits in Real-Time
You can use SpanSelector to dynamically adjust the plot limits in real-time, allowing users to set the limits interactively.
# Create figure and plot fig, ax = plt.subplots() ax.plot(x, y) plt.xlabel("X-axis") plt.ylabel("Y-axis") # Callback function to adjust x-axis limits based on selection def onselect(xmin, xmax): ax.set_xlim(xmin, xmax) plt.draw() # SpanSelector for adjusting plot limits span_selector = SpanSelector(ax, onselect, 'horizontal', useblit=True, rectprops=dict(alpha=0.5, facecolor='cyan')) plt.show()
In this example:
- The onselect function directly updates the plot’s x-axis limits.
- This interactive zoom effect allows users to focus on specific data ranges.
7. Selecting and Analyzing Time Series Data with SpanSelector
The SpanSelector is very useful for analyzing specific time intervals in time series data. This example uses SpanSelector to calculate and display the mean value within the selected range.
# Sample time series data time = np.linspace(0, 10, 100) signal = np.sin(time) + 0.5 * np.random.normal(size=time.shape) # Create figure and plot time series fig, ax = plt.subplots() ax.plot(time, signal, label="Signal") plt.xlabel("Time") plt.ylabel("Signal Value") # Callback function to calculate mean in the selected range def onselect(tmin, tmax): mask = (time >= tmin) & (time <= tmax) mean_val = signal[mask].mean() ax.set_title(f"Mean Value in Selected Range: {mean_val:.2f}") plt.draw() # SpanSelector for selecting time range span_selector = SpanSelector(ax, onselect, 'horizontal', useblit=True, rectprops=dict(alpha=0.5, facecolor='yellow')) plt.show()
In this example:
- The onselect function calculates the mean value of the signal within the selected range and displays it as the plot title.
- This approach is useful for time series analysis, allowing you to compute statistics over selected intervals.
8. SpanSelector with Multiple Axes (Subplots)
If you have multiple subplots, you can use SpanSelector to control multiple axes simultaneously. Here’s an example where the x-axis range is controlled across two subplots.
# Sample data for two subplots y1 = np.sin(x) y2 = np.cos(x) # Create figure with two subplots fig, (ax1, ax2) = plt.subplots(2, 1, sharex=True) ax1.plot(x, y1, label="sin(x)") ax2.plot(x, y2, label="cos(x)") plt.xlabel("X-axis") # Callback function to apply range selection across both subplots def onselect(xmin, xmax): ax1.set_xlim(xmin, xmax) ax2.set_xlim(xmin, xmax) plt.draw() # SpanSelector for both subplots span_selector = SpanSelector(ax1, onselect, 'horizontal', useblit=True, rectprops=dict(alpha=0.3, facecolor='lightblue')) plt.show()
In this example:
- The onselect function updates the x-axis limits of both subplots simultaneously, keeping them in sync.
- This approach is useful for exploring specific ranges across multiple views.
9. Dis
abling and Enabling SpanSelector with Keyboard Shortcuts
You can add keyboard controls to enable or disable the SpanSelector, adding flexibility to its use.
# Create figure and plot fig, ax = plt.subplots() ax.plot(x, y) plt.xlabel("X-axis") plt.ylabel("Y-axis") # Callback function for selection def onselect(xmin, xmax): print(f"Range selected from {xmin:.2f} to {xmax:.2f}") # Create SpanSelector span_selector = SpanSelector(ax, onselect, 'horizontal', useblit=True, rectprops=dict(alpha=0.5, facecolor='gray')) # Key event function to enable/disable SpanSelector def on_key(event): if event.key == 'e': # Enable SpanSelector span_selector.set_active(True) print("SpanSelector enabled") elif event.key == 'd': # Disable SpanSelector span_selector.set_active(False) print("SpanSelector disabled") # Connect the key press event to the handler fig.canvas.mpl_connect('key_press_event', on_key) plt.show()
In this example:
- Pressing ‘e' enables the SpanSelector.
- Pressing ‘d' disables the SpanSelector, allowing you to turn it on or off as needed.
Summary
In this tutorial, we covered several ways to use the SpanSelector widget in Matplotlib to interactively select ranges in your plots:
- Basic SpanSelector Setup with a callback function.
- Highlighting Selected Range within the plot.
- Zooming into Selected Range by adjusting plot limits.
- Filtering Data within Selected Range for scatter plots.
- Selecting on Y-Axis by setting SpanSelector to vertical mode.
- Adjusting Plot Limits in Real-Time for interactive zoom.
- Analyzing Time Series Data by calculating statistics within selected intervals.
- Controlling Multiple Subplots to select ranges across different axes.
- Enabling/Disabling SpanSelector using keyboard shortcuts.