{ "cells": [ { "cell_type": "markdown", "metadata": {}, "source": [ "\n# Resampling Data\n\nDownsampling lowers the sample rate or sample size of a signal. In\nthis tutorial, the signal is downsampled when the plot is adjusted\nthrough dragging and zooming.\n\n

Note

\n\nThis example exercises the interactive capabilities of Matplotlib, and this\nwill not appear in the static documentation. Please run this code on your\nmachine to see the interactivity.\n\nYou can copy and paste individual parts, or download the entire example\nusing the link at the bottom of the page.\n\n
\n" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "collapsed": false }, "outputs": [], "source": [ "import matplotlib.pyplot as plt\nimport numpy as np\n\n\n# A class that will downsample the data and recompute when zoomed.\nclass DataDisplayDownsampler:\n def __init__(self, xdata, y1data, y2data):\n self.origY1Data = y1data\n self.origY2Data = y2data\n self.origXData = xdata\n self.max_points = 50\n self.delta = xdata[-1] - xdata[0]\n\n def plot(self, ax):\n x, y1, y2 = self._downsample(self.origXData.min(), self.origXData.max())\n (self.line,) = ax.plot(x, y1, 'o-')\n self.poly_collection = ax.fill_between(x, y1, y2, step=\"pre\", color=\"r\")\n\n def _downsample(self, xstart, xend):\n # get the points in the view range\n mask = (self.origXData > xstart) & (self.origXData < xend)\n # dilate the mask by one to catch the points just outside\n # of the view range to not truncate the line\n mask = np.convolve([1, 1, 1], mask, mode='same').astype(bool)\n # sort out how many points to drop\n ratio = max(np.sum(mask) // self.max_points, 1)\n\n # mask data\n xdata = self.origXData[mask]\n y1data = self.origY1Data[mask]\n y2data = self.origY2Data[mask]\n\n # downsample data\n xdata = xdata[::ratio]\n y1data = y1data[::ratio]\n y2data = y2data[::ratio]\n\n print(f\"using {len(y1data)} of {np.sum(mask)} visible points\")\n\n return xdata, y1data, y2data\n\n def update(self, ax):\n # Update the artists\n lims = ax.viewLim\n if abs(lims.width - self.delta) > 1e-8:\n self.delta = lims.width\n xstart, xend = lims.intervalx\n x, y1, y2 = self._downsample(xstart, xend)\n self.line.set_data(x, y1)\n self.poly_collection.set_data(x, y1, y2, step=\"pre\")\n ax.figure.canvas.draw_idle()\n\n\n# Create a signal\nxdata = np.linspace(16, 365, (365-16)*4)\ny1data = np.sin(2*np.pi*xdata/153) + np.cos(2*np.pi*xdata/127)\ny2data = y1data + .2\n\nd = DataDisplayDownsampler(xdata, y1data, y2data)\n\nfig, ax = plt.subplots()\n\n# Hook up the line\nd.plot(ax)\nax.set_autoscale_on(False) # Otherwise, infinite loop\n\n# Connect for changing the view limits\nax.callbacks.connect('xlim_changed', d.update)\nax.set_xlim(16, 365)\nplt.show()" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ ".. tags:: interactivity: zoom, interactivity: event-handling\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.12.15" } }, "nbformat": 4, "nbformat_minor": 0 }