Note
Go to the endto download the full example code.
Time Series Histogram#
This example demonstrates how to efficiently visualize large numbers of timeseries in a way that could potentially reveal hidden substructure and patternsthat are not immediately obvious, and display them in a visually appealing way.
In this example, we generate multiple sinusoidal "signal" series that areburied under a larger number of random walk "noise/background" series. For anunbiased Gaussian random walk with standard deviation of σ, the RMS deviationfrom the origin after n steps is σ*sqrt(n). So in order to keep the sinusoidsvisible on the same scale as the random walks, we scale the amplitude by therandom walk RMS. In addition, we also introduce a small random offsetphito shift the sines left/right, and some additive random noise to shiftindividual data points up/down to make the signal a bit more "realistic" (youwouldn't expect a perfect sine wave to appear in your data).
The first plot shows the typical way of visualizing multiple time series byoverlaying them on top of each other withplt.plot and a small value ofalpha. The second and third plots show how to reinterpret the data as a 2dhistogram, with optional interpolation between data points, by usingnp.histogram2d andplt.pcolormesh.
importtimeimportmatplotlib.pyplotaspltimportnumpyasnpfig,axes=plt.subplots(nrows=3,figsize=(6,8),layout='constrained')# Fix random state for reproducibilitynp.random.seed(19680801)# Make some data; a 1D random walk + small fraction of sine wavesnum_series=1000num_points=100SNR=0.10# Signal to Noise Ratiox=np.linspace(0,4*np.pi,num_points)# Generate unbiased Gaussian random walksY=np.cumsum(np.random.randn(num_series,num_points),axis=-1)# Generate sinusoidal signalsnum_signal=round(SNR*num_series)phi=(np.pi/8)*np.random.randn(num_signal,1)# small random offsetY[-num_signal:]=(np.sqrt(np.arange(num_points))# random walk RMS scaling factor*(np.sin(x-phi)+0.05*np.random.randn(num_signal,num_points))# small random noise)# Plot series using `plot` and a small value of `alpha`. With this view it is# very difficult to observe the sinusoidal behavior because of how many# overlapping series there are. It also takes a bit of time to run because so# many individual artists need to be generated.tic=time.time()axes[0].plot(x,Y.T,color="C0",alpha=0.1)toc=time.time()axes[0].set_title("Line plot with alpha")print(f"{toc-tic:.3f} sec. elapsed")# Now we will convert the multiple time series into a histogram. Not only will# the hidden signal be more visible, but it is also a much quicker procedure.tic=time.time()# Linearly interpolate between the points in each time seriesnum_fine=800x_fine=np.linspace(x.min(),x.max(),num_fine)y_fine=np.concatenate([np.interp(x_fine,x,y_row)fory_rowinY])x_fine=np.broadcast_to(x_fine,(num_series,num_fine)).ravel()# Plot (x, y) points in 2d histogram with log colorscale# It is pretty evident that there is some kind of structure under the noise# You can tune vmax to make signal more visiblecmap=plt.colormaps["plasma"]cmap=cmap.with_extremes(bad=cmap(0))h,xedges,yedges=np.histogram2d(x_fine,y_fine,bins=[400,100])pcm=axes[1].pcolormesh(xedges,yedges,h.T,cmap=cmap,norm="log",vmax=1.5e2,rasterized=True)fig.colorbar(pcm,ax=axes[1],label="# points",pad=0)axes[1].set_title("2d histogram and log color scale")# Same data but on linear color scalepcm=axes[2].pcolormesh(xedges,yedges,h.T,cmap=cmap,vmax=1.5e2,rasterized=True)fig.colorbar(pcm,ax=axes[2],label="# points",pad=0)axes[2].set_title("2d histogram and linear color scale")toc=time.time()print(f"{toc-tic:.3f} sec. elapsed")plt.show()

0.227 sec. elapsed0.091 sec. elapsed
Tags:plot-type: histogram2dplot-type: pcolormeshpurpose: storytellingstyling: colorstyling: colormap
References
The use of the following functions, methods, classes and modules is shownin this example:
Total running time of the script: (0 minutes 2.763 seconds)