Example #1
0
def plot_signals(input_data, filename=None, downsamplefactor=1,n_columns=1, hspace=None, sharey=False, sharex=True,ylim=None, xlim=None, marker='None', decimate=0, markersize=2,linestyle=True,labelfmt="{short_name} {units}", filldown=True, suptitle='shot {shot}',raw_names=False,labeleg='False',color='b', fun=myiden, fun2=None, **kwargs):
    """ 
    Plot a figure full of signals using n_columns[1], 
        sharey [=1]  "gangs" y axes  - sim for sharex - sharex=None stops this
        sharey: 2 gangs all but first (top) axis
        x axes are ganged by default: see Note:

    fun, fun2: optionally plot a function of the signal.  fun= refers
    to a function of one variable.  fun2 is a function (t,x), such as
    one that returns a different timebase (diff should do this)
    if fun2 is given (a function of t and sig), then fun is ignored 

        labelfmt["{short_name} {units}"] controls the channel labels.  
            The default ignores the shot and uses an abbreviated form of the channel name.  
            If the short form is very short, it becomes a y label.
            A full version is "{name} {units}" and if > 8 chars, will become the x label.
            Even longer is "Shot={shot}, k_h={kh}, {name}"
        labeleg: If 'True' put label in legend - else use this str as a legend lab
        linestyle: default of True means use '-' if no marker, and nothing if a 
            marker is given      
            e.g. marker of '.' and markersize<1 will produce "shaded" waveforms, 
            good to see harmonic structure even without zooming in (need to 
            adjust markersize or plot size for best results.
        raw_names uses "digitiser" names, otherwise use names from the config file
        Note = sharex that to allow implicit overlay by using the same subplot
        specs the sharex must be the same between main and overlay - hence the 
        use of explicit sharex = None
        
        suptitle by default refers to the shot number
    """
    if pyfusion.VERBOSE > 0: print(fun, fun2)
    import pylab as pl
    n_rows = input_data.signal.n_channels()
    n_rows = int(round(0.49+(n_rows/float(n_columns))))
    if (n_rows > 3) and (hspace is None): 
        hspace = 0.001 # should be 0, but some plots omitted if 
                       #exactly zero - fixed in matplotlib 1
    if pyfusion.VERBOSE > 3: print(str(n_rows) + ' ' + str(n_columns))

    if labelfmt != None:
        if len(make_title(labelfmt, input_data, 0, raw_names=raw_names)) > 11: 
            mylabel = pl.xlabel
        else:
            mylabel = pl.ylabel
    fontkwargs = {'fontsize': 'small'}        
    # True is the only sensible indicator I can think of that we want intelligient defaults
    # If linestyle == True, we default to '-' UNLESS marker is set, in which case default to '' (no line)
    if linestyle == True:
        if marker == 'None': linestyle = '-'
        else: linestyle = ''
        
    axcount = -1  # so the first will be 0
    for row in range(n_rows):
        for col in range(n_columns):
            axcount += 1
            # natural sequence for subplot is to fillacross l-r, then top-down 
            subplot_num = row*n_columns+col

            # we often want to fill downwards for simple arrays - especially if comparing with a 3x16 array
            if filldown: chan_num = col*n_rows+row
            else:        chan_num = row*n_columns+col

            if chan_num >= input_data.signal.n_channels(): break
            if pyfusion.VERBOSE>3: print(subplot_num+1,chan_num)
            if axcount == 0:
                # note - sharex=None is required fo that overlays can be done
                if n_rows * n_columns == 1:
                    axlead = pl.gca()  # this allows plotting on existing axis for a single plot
                else:
                    axlead = pl.subplot(n_rows, n_columns, subplot_num+1, sharex = None)
                axn = axlead
                axlead_x = axlead if sharex else None
            else:
                if axcount >= sharey: 
                    axn = pl.subplot(n_rows, n_columns, subplot_num+1, sharex = axlead_x, sharey=axlead)
                else: # another noshare y, but sharex
                    axn = pl.subplot(n_rows, n_columns, subplot_num+1,
                                     sharex = axlead_x)
                    axlead = axn

            #  Clumsy addition to put labels in the legend
            #  To do better, should be one or the other, but the
            #  original code is after the plot - need to move it
            # back to here, before the plot
                
            if labeleg == 'False':
                lab = ''
            elif labeleg == 'True':
                sht = str(input_data.meta['shot'])
                lab = make_title(sht + ' ' + labelfmt, input_data, chan_num)
            else:
                lab = labeleg

            KWargs = dict(marker=marker, markersize=markersize, 
                          linestyle=linestyle, label = lab, color=color)
            KWargs.update(kwargs)

            if fun2 is not None:
                pl.plot(*fun2(input_data.timebase[::downsamplefactor], 
                              input_data.signal.get_channel(
                                  chan_num)[::downsamplefactor]),**KWargs)
            else:
                pl.plot(input_data.timebase[::downsamplefactor], 
                        fun(input_data.signal.get_channel(
                            chan_num)[::downsamplefactor]),**KWargs)

# this old code was no faster
#           #   if downsamplefactor==1:
#            pl.plot(input_data.timebase, 
#                    input_data.signal.get_channel(chan_num),
#                    **kwargs)
#            else:
#                plotdata=input_data.signal.get_channel(chan_num)
#                timedata=input_data.timebase
#                pl.plot(timedata[0:len(timedata):downsamplefactor], 
#                        plotdata[0:len(timedata):downsamplefactor], 
#                        **kwargs)
#                pl.axis([-0.01,0.1,-5,5])

            pl.xticks(**fontkwargs)
            pl.yticks(**fontkwargs)

            if labelfmt != None:    
                if mylabel == pl.ylabel and np.mod(row,2): displace='\n'
                else: displace = ''  # use \n to make two line label to displace every second one

                lab = make_title(labelfmt+displace, input_data, chan_num)
                mylabel(lab,**fontkwargs)

            if n_rows>3: 
                #print('locator_params',int(25/np.sqrt(n_rows)))
                axn.locator_params(prune='both', axis = 'y',
                                   nbins=min(5,int(25/np.sqrt(n_rows))))
                # this gets rid of the x labels at either end until wee 
                # can suppress xlabels on all but the lowest

                if n_rows>1: axn.locator_params(prune='both', axis = 'x')

            if ylim != None: pl.ylim(ylim)
            if xlim != None: pl.xlim(xlim)
    if suptitle is not None:
        try:
            suptitlestr = (suptitle.format(**input_data.meta))
        except:
            suptitlestr = ''
            debug_(pyfusion.DEBUG, 1, 
                   msg=' input metadata [{m}] does not have  a '
                   'key for suptitle [{s}]'
                   .format(m=input_data.meta, s=suptitle))

    if hspace != None:  # adjust vertical spacing between plots
        pl.gcf().subplotpars.hspace = hspace
        pl.gcf().subplotpars.bottom = 0.04 + hspace
        extratop = 0.01
        if suptitlestr != '': extratop += 0.04
        pl.gcf().subplots_adjust(top = 1-(hspace+extratop)) # allow a little room for title

    # suptitle can have references to show number etc in metadata
    if suptitlestr != '': pl.suptitle(suptitlestr)
    if filename != None:
        pl.savefig(filename)
    else:
        pl.show(block=0)
    debug_(pyfusion.DEBUG, 4, key='plot_signals')
Example #2
0
def plot_signals(input_data,
                 filename=None,
                 downsamplefactor=1,
                 n_columns=1,
                 hspace=None,
                 sharey=False,
                 sharex=True,
                 ylim=None,
                 xlim=None,
                 marker='None',
                 markersize=2,
                 linestyle=True,
                 labelfmt="{short_name} {units}",
                 filldown=True,
                 suptitle='shot {shot}',
                 raw_names=False,
                 labeleg='False',
                 color='b',
                 t0=0,
                 fun=myiden,
                 scale=1,
                 offset=0,
                 fun2=None,
                 **kwargs):
    """ 
    Plot a figure full of signals using n_columns[1], or just one signal
        sharey [=1 or 'all']  "gangs" y axes  - sim. for sharex - sharex=None stops this
        sharey: 2 gangs all but first (top) axis
        x axes are ganged by default: see Note:

    downsamplefactor = 1 # 10 plots 1/10th of the data.
    color
    marker
    linestyle
    markersize
    n_columns = 1
    scale = 1  # only works if fun2 is None
    offset = 0  # plots offset + scale * sig
    fun, fun2: optionally plot a function of the signal.  fun= refers
    to a function of one variable.  fun2 is a function (t,x), such as
    one that returns a different timebase (diff should do this)
    if fun2 is given (a function of t and sig), then fun is ignored 


        labelfmt["{short_name} {units}"] controls the channel labels.  
            The default ignores the shot and uses an abbreviated form of the channel name.  
            If the short form is very short, it becomes a y label.
            A full version is "{name} {units}" and if > 8 chars, will become the x label.
            Even longer is "Shot={shot}, k_h={kh}, {name}"
        labeleg: If 'True' put label in legend - else use this str as a legend lab
        linestyle: default of True means use '-' if no marker, and nothing if a 
            marker is given      
            e.g. marker of '.' and markersize<1 will produce "shaded" waveforms, 
            good to see harmonic structure even without zooming in (need to 
            adjust markersize or plot size for best results.
        raw_names uses "digitiser" names, otherwise use names from the config file
        Note = sharex that to allow implicit overlay by using the same subplot
        specs the sharex must be the same between main and overlay - hence the 
        use of explicit sharex = None
        
        suptitle by default refers to the shot number
    """
    if isinstance(sharey, str) and sharey.lower() == 'all':
        sharey = 1
    elif isinstance(sharey, type(
            max)):  # really want isinstance(sharey, function) but not defined
        raise ValueError(
            '''sharey was set to the function all()! - use sharey=1 or "sharey='all'"'''
        )

    if pyfusion.NSAMPLES > 0 and downsamplefactor != 1:
        print('Ignoring downsample on already decimated signal')
        downsamplefactor = 1

    if pyfusion.VERBOSE > 1: print(fun, fun2)
    if ((scale != 1) or (offset != 0)) and fun2 is not None:
        raise ValueError('need fun2 to be None so that scale/offset works')
    import pylab as pl
    n_rows = input_data.signal.n_channels(
    )  # didn't work with fftd data - because fft doesn't invoke timeseries class?  - but seems to work now! (2020)
    n_rows = int(round(0.49 + (n_rows / float(n_columns))))
    if (n_rows > 3) and (hspace is None):
        hspace = 0.001  # should be 0, but some plots omitted if
        #exactly zero - fixed in matplotlib 1
    if pyfusion.VERBOSE > 3: print(str(n_rows) + ' ' + str(n_columns))

    if labelfmt != None:
        if len(make_title(labelfmt, input_data, 0, raw_names=raw_names)) > 11:
            mylabel = pl.xlabel
        else:
            mylabel = pl.ylabel
    fontkwargs = {'fontsize': 'small'}
    # True is the only sensible indicator I can think of that we want intelligient defaults
    # If linestyle == True, we default to '-' UNLESS marker is set, in which case default to '' (no line)
    if linestyle == True:
        if marker == 'None': linestyle = '-'
        else: linestyle = ''

    axcount = -1  # so the first will be 0
    for row in range(n_rows):
        for col in range(n_columns):
            axcount += 1
            # natural sequence for subplot is to fillacross l-r, then top-down
            subplot_num = row * n_columns + col

            # we often want to fill downwards for simple arrays - especially if comparing with a 3x16 array
            if filldown: chan_num = col * n_rows + row
            else: chan_num = row * n_columns + col

            if chan_num >= input_data.signal.n_channels(): break
            if pyfusion.VERBOSE > 3: print(subplot_num + 1, chan_num)
            if axcount == 0:
                # note - sharex=None is required so that overlays can be done
                if n_rows * n_columns == 1:
                    axlead = pl.gca(
                    )  # this allows plotting on existing axis for a single plot
                else:
                    axlead = pl.subplot(n_rows,
                                        n_columns,
                                        subplot_num + 1,
                                        sharex=None)
                axn = axlead
                axlead_x = axlead if sharex else None
            else:
                if axcount >= sharey:
                    axn = pl.subplot(n_rows,
                                     n_columns,
                                     subplot_num + 1,
                                     sharex=axlead_x,
                                     sharey=axlead)
                else:  # another noshare y, but sharex
                    axn = pl.subplot(n_rows,
                                     n_columns,
                                     subplot_num + 1,
                                     sharex=axlead_x)
                    axlead = axn

            #  Clumsy addition to put labels in the legend
            #  To do better, should be one or the other, but the
            #  original code is after the plot - need to move it
            # back to here, before the plot
            ##### No! should use text(0.5,1,'foo',verticalalignment='top',transform=gca().transAxes)

            if labeleg == 'False':
                lab = ''
            elif labeleg == 'True':
                sht = str(input_data.meta['shot'])
                lab = make_title(sht + ' ' + labelfmt, input_data, chan_num)
            else:
                lab = labeleg

            KWargs = dict(marker=marker,
                          markersize=markersize,
                          linestyle=linestyle,
                          label=lab,
                          color=color)
            KWargs.update(kwargs)

            if fun2 is not None:  # can't easily accommodate 'scale/offset' here
                pl.plot(
                    *fun2(
                        input_data.timebase[::downsamplefactor] - t0,
                        input_data.signal.get_channel(chan_num)
                        [::downsamplefactor]), **KWargs)
            else:
                pl.plot(
                    input_data.timebase[::downsamplefactor] - t0,
                    offset + scale * fun(
                        input_data.signal.get_channel(chan_num)
                        [::downsamplefactor]), **KWargs)


# this old code was no faster
#           #   if downsamplefactor==1:
#            pl.plot(input_data.timebase,
#                    input_data.signal.get_channel(chan_num),
#                    **kwargs)
#            else:
#                plotdata=input_data.signal.get_channel(chan_num)
#                timedata=input_data.timebase
#                pl.plot(timedata[0:len(timedata):downsamplefactor],
#                        plotdata[0:len(timedata):downsamplefactor],
#                        **kwargs)
#                pl.axis([-0.01,0.1,-5,5])

            pl.xticks(**fontkwargs)
            pl.yticks(**fontkwargs)

            if labelfmt != None:
                if mylabel == pl.ylabel and np.mod(row, 2): displace = '\n'
                else:
                    displace = ''  # use \n to make two line label to displace every second one

                lab = make_title(labelfmt + displace, input_data, chan_num)
                mylabel(lab, **fontkwargs)

            if n_rows > 3:
                #print('locator_params',int(25/np.sqrt(n_rows)))
                axn.locator_params(prune='both',
                                   axis='y',
                                   nbins=min(5, int(25 / np.sqrt(n_rows))))
                # this gets rid of the x labels at either end until we
                # can suppress xlabels on all but the lowest

                if n_rows > 1: axn.locator_params(prune='both', axis='x')

            if ylim != None: pl.ylim(ylim)
            if xlim != None: pl.xlim(xlim)
    if suptitle is not None:
        try:
            suptitlestr = (suptitle.format(**input_data.meta))
        except:
            suptitlestr = ''
            debug_(pyfusion.DEBUG,
                   1,
                   key='plot_signal_suptitle',
                   msg=' input metadata [{m}] does not have  a '
                   'key for suptitle [{s}]'.format(m=input_data.meta,
                                                   s=suptitle))

    if hspace is not None:  # adjust vertical spacing between plots
        pl.gcf().subplotpars.hspace = hspace
        pl.gcf().subplotpars.bottom = hspace + 0.08  # was 0.04
        extratop = 0.01
        if suptitlestr != '': extratop += 0.04
        pl.gcf().subplots_adjust(
            top=1 - (hspace + extratop))  # allow a little room for title

    # suptitle can have references to show number etc in metadata
    if suptitlestr != '': pl.suptitle(suptitlestr)
    if filename != None:
        pl.savefig(filename)
    else:
        pl.show(block=0)
    debug_(pyfusion.DEBUG, 2, key='plot_signals')
Example #3
0
def plot_signals(input_data, filename=None,downsamplefactor=1,n_columns=1, hspace=None, sharey=False, sharex=True,ylim=None, xlim=None, marker='None', markersize=0.3,linestyle=True,labelfmt="%(short_name)s", filldown=True):
    """ 
    Plot a figure full of signals using n_columns[1], 
        sharey [=1]  "gangs" y axes  - sim for sharex - sharex=None stops this
        x axes are ganged by default: see Note:

        labelfmt["%(short_name)s"] controls the channel labels.  
            The default ignores the shot and uses an abbreviated form of the channel name.  
            If the short form is very short, it becomes a y label.
            A full version is "%(name)s" and if > 8 chars, will become the x label.
            Even longer is "Shot=%(shot), k_h=%(kh)s, %(name)s"
        linestyle: default of True means use '-' if no marker, and nothing if a 
            marker is given      
            e.g. marker of '.' and markersize<1 will produce "shaded" waveforms, 
            good to see harmonic structure even without zooming in (need to 
            adjust markersize or plot size for best results.
        Note = sharex that to allow implicit overlay by using the same subplot
        specs the sharex must be the same between main and overlay - hence the 
        use of explicit sharex = None

    """
    import pylab as pl
    n_rows = input_data.signal.n_channels()
    n_rows = int(round(0.49+(n_rows/float(n_columns))))
    if (n_rows > 3) and (hspace == None): 
        hspace = 0.001 # should be 0, but some plots omitted if 
                       #exactly zero - fixed in matplotlib 1
    if pyfusion.VERBOSE>3: print str(n_rows) + ' ' + str(n_columns)

    if labelfmt != None:
        if len(make_title(labelfmt, input_data, 0)) > 8: 
            mylabel = pl.xlabel
        else:
            mylabel = pl.ylabel
    fontkwargs = {'fontsize': 'small'}        
    # True is the only sensible indicator I can think of that we want intelligient defaults
    # If linestyle == True, we default to '-' UNLESS marker is set, in which case default to '' (no line)
    if linestyle == True:
        if marker == 'None': linestyle = '-'
        else: linestyle = ''
        
    for row in range(n_rows):
        for col in range(n_columns):

            # natural sequence for subplot is to fillacross l-r, then top-down 
            subplot_num = row*n_columns+col

            # we often want to fill downwards for simple arrays - especially if comparing with a 3x16 array
            if filldown: chan_num = col*n_rows+row
            else:        chan_num = row*n_columns+col

            if chan_num >= input_data.signal.n_channels(): break
            if pyfusion.VERBOSE>3: print (subplot_num+1,chan_num),
            if (row==0) and (col==0):
                # note - sharex=None is required fo that overlays can be done
                ax1 = pl.subplot(n_rows, n_columns, subplot_num+1, sharex = None)
                axn = ax1
            else:
                if sharex == True: sharex = ax1
                if sharey: axn = pl.subplot(n_rows, n_columns, subplot_num+1, sharex = sharex, sharey=ax1)
                else: axn = pl.subplot(n_rows, n_columns, subplot_num+1, sharex = sharex)

            if downsamplefactor==1:
                pl.plot(input_data.timebase, input_data.signal.get_channel(chan_num),
                        marker=marker, markersize=markersize, linestyle=linestyle)
            else:
                plotdata=input_data.signal.get_channel(chan_num)
                timedata=input_data.timebase
                pl.plot(timedata[0:len(timedata):downsamplefactor], plotdata[0:len(timedata):downsamplefactor], 
                        marker=marker, markersize=markersize, linestyle=linestyle)
#                pl.axis([-0.01,0.1,-5,5])

            pl.xticks(**fontkwargs)
            pl.yticks(**fontkwargs)

            if labelfmt != None:    
                if mylabel == pl.ylabel and np.mod(row,2): displace='\n'
                else: displace = ''  # use \n to make two line label to displace every second one

                mylabel(make_title(labelfmt+displace, input_data, chan_num),**fontkwargs)

            if n_rows>3: 
                #print('locator_params',int(25/np.sqrt(n_rows)))
                axn.locator_params(prune='both', axis = 'y',
                                   nbins=min(5,int(25/np.sqrt(n_rows))))
                # this gets rid of the x labels at either end until wee 
                # can suppress xlabels on all but the lowest

                if n_rows>1: axn.locator_params(prune='both', axis = 'x')

            if ylim != None: pl.ylim(ylim)
            if xlim != None: pl.xlim(xlim)
    if hspace != None:  # adjust vertical spacing between plots
        pl.gcf().subplotpars.hspace = hspace
        pl.gcf().subplotpars.bottom = 0.04 + hspace
        pl.gcf().subplots_adjust(top = 1-(hspace+0.01))

    if filename != None:
        pl.savefig(filename)
    else:
        pl.show()
Example #4
0
def plot_spectrogram(input_data,
                     windowfn=None,
                     units='kHz',
                     channel_number=0,
                     filename=None,
                     coloraxis='now is clim!',
                     clim=None,
                     xlim=None,
                     ylim=None,
                     noverlap=0,
                     NFFT=None,
                     suptitle='shot {shot}',
                     title=None,
                     sharey=True,
                     sharex=True,
                     n_columns=None,
                     raw_names=False,
                     hspace=None,
                     labelfmt="{short_name} {units}",
                     filldown=False,
                     hold=None,
                     **kwargs):
    """    Plot a spectrogram 
      NFFTs
      noverlap  (integer - number of samples overlapped, float - 1.0 -> half nFFT)
      windowfn (p.window.hanning)
      coloraxis - gets from pyfusion.conf.get('Plots')

    Accepts multi or single channel data (I think?)
    Title will be auto generated: if supplied, include '+' to include the auto-generated part
    To suppress, use title=' ' (one space)
    clim:  [None] auto clim, 'show' - label each graph with clims
    Returns ax_list which can be used for clims or other manipulations
    """
    import pylab as pl

    # can't recurse as this is a signal   input_data[chan.name].plot_specgram()

    if hold is not None and hold == 0:
        pl.figure()
    if windowfn is None: windowfn = pl.window_hanning

    # look in the config file section Plots for NFFT = 1234
    # Dave - how about a method to allow this in one line
    # e.g. pyfusion.config.numgetdef('Plots','NFFT', 2048)
    # usage:
    # if (NFFT is None): NFFT = pyfusion.config.numgetdef('Plots','NFFT', 2048)
    #
    # also nice to have pyfusion.config.re-read()
    if NFFT is None:
        try:
            NFFT = (int(pyfusion.config.get('Plots', 'NFFT')))
        except:
            NFFT = 2048

    print(NFFT)
    if units.lower() == 'khz': ffact = 1000.
    else: ffact = 1.
    xextent = (min(input_data.timebase), max(input_data.timebase))

    n_pics = input_data.signal.n_channels()  # doesn't work with fftd data
    if n_columns is None:
        n_columns = int(0.8 + np.sqrt(n_pics))
    n_rows = int(round(0.49 + (n_columns / float(n_pics))))
    while n_rows * n_columns < n_pics:
        n_rows += 1

    if (n_rows > 3) and (hspace is None):
        hspace = 0.001  # should be 0, but some plots omitted if
        #exactly zero - fixed in matplotlib 1
    if pyfusion.VERBOSE > 3: print(str(n_rows) + ' ' + str(n_columns))

    fontkwargs = {'fontsize': 'small'}
    # True is the only sensible indicator I can think of that we want intelligient defaults
    displace = ''  # doens't make send for spectra, as they are usually squarish

    axcount = -1  # so the first will be 0
    ax_list = []  #  We don't use subplots(), because we want control of sharey
    for row in range(n_rows):
        for col in range(n_columns):
            axcount += 1
            # natural sequence for subplot is to fillacross l-r, then top-down
            subplot_num = row * n_columns + col

            # we often want to fill downwards for simple arrays - especially if comparing with a 3x16 array
            if filldown: chan_num = col * n_rows + row
            else: chan_num = row * n_columns + col

            #print(chan_num, subplot_num, col, row)
            if chan_num >= input_data.signal.n_channels(): break
            if pyfusion.VERBOSE > 3: print(subplot_num + 1, chan_num)

            if pyfusion.VERBOSE > 3: print(subplot_num + 1, chan_num)
            if axcount == 0:
                # note - sharex=None is required so that overlays can be done
                if n_rows * n_columns == 1:
                    axlead = pl.gca(
                    )  # this allows plotting on existing axis for a single plot
                else:
                    axlead = pl.subplot(n_rows,
                                        n_columns,
                                        subplot_num + 1,
                                        sharex=None)
                axn = axlead
                axlead_x = axlead if sharex else None
            else:
                if axcount >= sharey:
                    axn = pl.subplot(n_rows,
                                     n_columns,
                                     subplot_num + 1,
                                     sharex=axlead_x,
                                     sharey=axlead)
                else:  # another noshare y, but sharex
                    axn = pl.subplot(n_rows,
                                     n_columns,
                                     subplot_num + 1,
                                     sharex=axlead_x)
                    axlead = axn

            noverlap = noverlap if isinstance(noverlap, int) else int(
                round(NFFT / (1 + 1. / (1e-6 + noverlap))))

            (specarr, freqs, t, im) = \
                axn.specgram(input_data.signal.get_channel(chan_num),
                             NFFT=NFFT, noverlap=noverlap,
                             Fs=input_data.timebase.sample_freq/ffact,
                             window=windowfn, xextent=xextent, **kwargs)
            ax_list.append(axn)
            # Used be (incorrectly coloraxis)
            if pyfusion.VERBOSE > 2:
                print(
                    'data/plot_spectrogram: noverlap={no}, {nt} time segs, {nf} freqs'
                    .format(no=noverlap, nt=len(t), nf=len(freqs)))
            if xlim is not None:
                axn.set_xlim(xlim)
            if ylim is not None:
                axn.set_ylim(ylim)
            if clim is not None and clim != 'show': im.set_clim(clim)
            else:
                try:
                    pl.clim(eval(pyfusion.config.get('Plots', 'coloraxis')))
                except:
                    pass

            if labelfmt != None:
                if len(make_title(labelfmt, input_data, 0,
                                  raw_names=raw_names)) > 11:
                    mylabel = pl.xlabel
                else:
                    mylabel = pl.ylabel

            lab = make_title(labelfmt + displace, input_data, chan_num)
            mylabel(lab, **fontkwargs)

            # look in the config file section Plots for a string like
            # FT_Axis = [0,0.08,0,500e3]   don't quote
            exceptions_to_hide = Exception if pyfusion.DBG() < 3 else None
            try:
                #pl.axis(eval(pyfusion.config.get('Plots','FT_Axis')))
                # this is clumsier now we need to consider freq units.
                axt = eval(pyfusion.config.get('Plots', 'FT_Axis'))
                set_axis_if_OK(pl.gca(), axt[0:2], np.array(axt[2:]) / ffact)
            except exceptions_to_hide:
                pass
            # but override X if we have zoomed in bdb
            if 'reduce_time' in input_data.history:
                pl.xlim(np.min(input_data.timebase), max(input_data.timebase))

            try:
                tit = str("{s}, {c}".format(
                    s=input_data.meta['shot'],
                    c=input_data.channels[chan_num].config_name))
            except:
                tit = str("{s}, {c}".format(s=input_data.meta['shot'],
                                            c=input_data.channels.name))
            if title is None or title == '':  # get the default title
                pass  # tit is the default
            else:
                tit = title.replace('+', tit)
            # No titles for rows >= 3 - maybe better to have no titles at all
            #   and use the legend (without frame) to show the channel number
            # instead of the ytitle.
            if n_rows <= 3:  # keep consistent with n_rows > 3 above
                pl.title(tit)
            if clim == 'show':
                axn.legend([], [],
                           frameon=0,
                           title=str(
                               np.round(axn.get_images()[0].get_clim(), 1)))

    # ======== end of plot loop
    if suptitle is not None:
        try:
            suptitlestr = (suptitle.format(**input_data.meta))
        except:
            suptitlestr = ''
            debug_(pyfusion.DEBUG,
                   1,
                   key='plot_signal_suptitle',
                   msg=' input metadata [{m}] does not have  a '
                   'key for suptitle [{s}]'.format(m=input_data.meta,
                                                   s=suptitle))

    if suptitle != '': pl.suptitle(suptitlestr)
    if hspace is not None:  # adjust vertical spacing between plots
        pl.gcf().subplotpars.hspace = hspace
        pl.gcf().subplotpars.bottom = hspace + 0.08  # was 0.04
        extratop = 0.01
        if suptitle != '': extratop += 0.04
        pl.gcf().subplots_adjust(
            top=1 - (hspace + extratop))  # allow a little room for title

    if filename != None:
        pl.savefig(filename)
    else:
        pl.show(block=0)

    return (ax_list)