Obspy: colorbar for spectrograms

Created on 30 Jun 2015  路  10Comments  路  Source: obspy/obspy

I'm not sure if it is just me, but I just had a big struggle with the obspy.imaging.spectrogram script trying to add a colorbar to the figure. I would therefore like to suggest two permanent changes for the obspy.imaging.spectrogram script:

img = ax.imshow(specgram, interpolation="nearest", extent=extent, norm=norm, **kwargs)

instead of

ax.imshow(specgram, interpolation="nearest", extent=extent, **kwargs)

and

    if axes:
        return ax, img

instead of

    if axes:
        return ax

I'm under the impression that clipping is at the moment only applied in the log case. The first suggestion would change that for log and non-log frequency axes. To me it would also make sense to assign it permanently to img and return img along with ax so that a colobar can be easily created with sth like this:

ax, img = spectrogram(...) 
fig.colorbar(img)
question

Most helpful comment

Sorry for not answering earlier, this got lost in our flood of tickets, I guess..

It's pretty straightforward to access any lines, images, collections, you-name-it, directly from the Figure or Axes objects for further tweaking with matplotlib:

import matplotlib.pyplot as plt 
from obspy import read

tr = read()[0]

fig = tr.spectrogram(show=False)
ax = fig.axes[0]
mappable = ax.images[0]
plt.colorbar(mappable=mappable, ax=ax)

fig = tr.spectrogram(show=False, log=True)
ax = fig.axes[0]
mappable = ax.collections[0]
plt.colorbar(mappable=mappable, ax=ax)

plt.show()

The type of matplotlib object to look up depends on whether it's a logarithmic plot (matplotlib.collections.QuadMesh object) or not (matplotlib.image.AxesImage object).

All 10 comments

I am experiencing the same problem. May I ask how you solve it with the current version of obspy.imaging.spectrogram?

Thanks

How did you get a colorbar to work? I'm struggling with this right now too.

Hello EvaMuc and mat2py , I have been trying to get the above working but have had no luck. Any chance please you could provide details of the solution you ended up doing to get this to work. Many thanks in advance.

Hey wf215 - sorry, I never managed to get this to work! I've just left it and moved onto other things for the moment.

Hey mat2py, no worries. Thanks for replying.

Sorry for not answering earlier, this got lost in our flood of tickets, I guess..

It's pretty straightforward to access any lines, images, collections, you-name-it, directly from the Figure or Axes objects for further tweaking with matplotlib:

import matplotlib.pyplot as plt 
from obspy import read

tr = read()[0]

fig = tr.spectrogram(show=False)
ax = fig.axes[0]
mappable = ax.images[0]
plt.colorbar(mappable=mappable, ax=ax)

fig = tr.spectrogram(show=False, log=True)
ax = fig.axes[0]
mappable = ax.collections[0]
plt.colorbar(mappable=mappable, ax=ax)

plt.show()

The type of matplotlib object to look up depends on whether it's a logarithmic plot (matplotlib.collections.QuadMesh object) or not (matplotlib.image.AxesImage object).

Many thanks megies for your answer. Really appreciated

Hey megie, thanks for the answer! First time I've got the colorbar() working so a big thanks for that.

Got a follow up question, if that's okay, as you seem good with this stuff. I want to do this but I already have the figure as subplots and so this code doesn't seem to quite work for that situation:

def plotwaveyspec(spl1,fmin=0.1,fmax=20):
    from obspy.imaging.spectrogram import spectrogram

    #info
    beg = spl1[0].stats.starttime    
    end = spl1[0].stats.endtime

    #setup figure
    fig = plt.figure()

    #example code
    ax1 = fig.add_axes([0.1, 0.75, 0.7, 0.2]) #[left bottom width height]
    ax2 = fig.add_axes([0.1, 0.1, 0.7, 0.60], sharex=ax1)
    ax3 = fig.add_axes([0.83, 0.1, 0.03, 0.6])

    #make time vector
    t = np.arange(spl1[0].stats.npts) / spl1[0].stats.sampling_rate

    #plot waveform (top subfigure)    
    ax1.plot(t, spl1[0].data, 'k')

    #plot spectrogram (bottom subfigure)
    spl2 = spl1[0]
    fig = spl2.spectrogram(show=False, axes=ax2)
    ax = fig.axes[0]
    mappable = ax.images[0]
    plt.colorbar(mappable=mappable,ax=ax)

    ax2.set_ylim(fmin, fmax)

    plt.show()
    #print some info
    print('Figure starttime = %s'%beg)
    print('Figure endtime   = %s'%end)

note: spl1 is just a slice of a trace (quicker to plot and test than the whole trace)

The plt.colorbar() line only has one input and I thought that the ax= input referred to where you wanted to put the colorbar (in the same way as the spectrogram ax= input), but you seem to be using it as a data input?

I have an axis set up for the colorbar already (ax3) and so I would think I would need the plt.colorbar() line to be:

plt.colorbar(mappable=mappable, cax=ax3)

instead but that isn't working either. Both options come out with the figure below and shows the error after the figure

spec_attempt

Traceback (most recent call last):

  File "<ipython-input-30-aaa2b403062f>", line 1, in <module>
    plotwaveyspec(spl1)

  File "<ipython-input-29-0a93f39d1abf>", line 25, in plotwaveyspec
    ax = fig.axes[0]

TypeError: 'Axes' object does not support indexing

Many thanks for your help if you can see the mistake/fix!
Cheers

I actually just managed to solve it. If anyone else has the problem, replace the spectrogram plot section with:

    #plot spectrogram (bottom subfigure)
    spl2 = spl1[0]
    fig = spl2.spectrogram(show=False, axes=ax2)
    #ax = fig.axes[1]
    mappable = ax2.images[0]
    plt.colorbar(mappable=mappable, cax=ax3)

    ax2.set_ylim(fmin, fmax)

    plt.show()

spec_attempt2

Thanks again for the help megies

You should consider using a different colormap.. :-) https://www.youtube.com/watch?v=xAoljeRJ3lU

Was this page helpful?
0 / 5 - 0 ratings