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')
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')
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()
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)