Multi-panel time series of lines and filled outlines using matplotlib?

If I wanted to create a combined image like the one shown below ( source here ) Could you tell me the matplotlib objects that I need to collect? I'm trying to work with AxesImage objects and I also downloaded the SciKits Timeseries - but do I need it or can it be as easy to use strptime, mktime and strftime from a time module and roll my own axes? Thanks ~

alt text

+4
source share
1 answer

You do not need any custom axes. The Timeseries Scikit is great, but you don't have to work with dates in matplotlib at all ...

You probably want to use various functions in matplotlib.dates , plot_date to display your values, imshow (and / or pcolor in some cases) to build your specgrams of different sorts, and matplotlib.mlab.specgram to calculate them.

For your subplots, you will want to use sharex kwarg when creating them, so that they all have the same x axis. To disable the x-axis labels on some axes when using the x-axis sharing between graphs, you need to use something like matplotlib.pyplot.setp(ax1.get_xticklabels(), visible=False) . (It's a bit rude to hack, but this is the only way to display only the X-axis labels on the lower subtitle when sharing the same x axis between all subsets). To adjust the distance between subheadings, see subplots_adjust .

Hope this all makes sense ... I'll add a quick example of using all of this when I have time later ...

Edit: So, here is an example of an idea. Some things (like the labels of the multi-color axis) shown in your example are pretty hard to do in matplotlib. (Not impossible, but I missed them here ...)

 import datetime import numpy as np import matplotlib as mpl import matplotlib.pyplot as plt from matplotlib import mlab from mpl_toolkits.axes_grid1 import make_axes_locatable def main(): #-- Make a series of dates start = datetime.datetime(2010,9,15,8,0) end = datetime.datetime(2010,9,15,18,0) delta = datetime.timedelta(seconds=1) # Note: "time" is now an array of floats, where 1.0 corresponds # to one day, and 0.0 corresponds to 1900 (I think...) # It _not_ an array of datetime objects! time = mpl.dates.drange(start, end, delta) num = time.size #-- Generate some data x = brownian_noise(num) y = brownian_noise(num) z = brownian_noise(num) plot(x, y, z, time) plt.show() def plot(x, y, z, time): fig = plt.figure() #-- Panel 1 ax1 = fig.add_subplot(311) im, cbar = specgram(x, time, ax1, fig) ax1.set_ylabel('X Freq. (Hz)') ax1.set_title('Fake Analysis of Something') #-- Panel 2 ax2 = fig.add_subplot(312, sharex=ax1) im, cbar = specgram(y, time, ax2, fig) ax2.set_ylabel('Y Freq. (Hz)') #-- Panel 3 ax3 = fig.add_subplot(313, sharex=ax1) # Plot the 3 source datasets xline = ax3.plot_date(time, x, 'r-') yline = ax3.plot_date(time, y, 'b-') zline = ax3.plot_date(time, z, 'g-') ax3.set_ylabel(r'Units $(\mu \phi)$') # Make an invisible spacer... cax = make_legend_axes(ax3) plt.setp(cax, visible=False) # Make a legend ax3.legend((xline, yline, zline), ('X', 'Y', 'Z'), loc='center left', bbox_to_anchor=(1.0, 0.5), frameon=False) # Set the labels to be rotated at 20 deg and aligned left to use less space plt.setp(ax3.get_xticklabels(), rotation=-20, horizontalalignment='left') # Remove space between subplots plt.subplots_adjust(hspace=0.0) def specgram(x, time, ax, fig): """Make and plot a log-scaled spectrogram""" dt = np.diff(time)[0] # In days... fs = dt * (3600 * 24) # Samples per second spec_img, freq, _ = mlab.specgram(x, Fs=fs, noverlap=200) t = np.linspace(time.min(), time.max(), spec_img.shape[1]) # Log scaling for amplitude values spec_img = np.log10(spec_img) # Log scaling for frequency values (y-axis) ax.set_yscale('log') # Plot amplitudes im = ax.pcolormesh(t, freq, spec_img) # Add the colorbar in a seperate axis cax = make_legend_axes(ax) cbar = fig.colorbar(im, cax=cax, format=r'$10^{%0.1f}$') cbar.set_label('Amplitude', rotation=-90) ax.set_ylim([freq[1], freq.max()]) # Hide x-axis tick labels plt.setp(ax.get_xticklabels(), visible=False) return im, cbar def make_legend_axes(ax): divider = make_axes_locatable(ax) legend_ax = divider.append_axes('right', 0.4, pad=0.2) return legend_ax def brownian_noise(num): x = np.random.random(num) - 0.5 x = np.cumsum(x) return x if __name__ == '__main__': main() 

alt text

+10
source

All Articles