예제 #1
0
def cli():
    parser = argparse.ArgumentParser()
    parser.add_argument('--data', action='store_true',
                        help='Plot the recorded data. (Default)')
    parser.add_argument('--testfunc', action='store_true',
                        help='Plot the simulated test functions.')
    parser.add_argument('--tu', type=str,
                        help='Specify the time units (e.g., \'s\' or \'ms\').')
    parser.add_argument('--au', type=str,
                        help='Specify the amplitude units (e.g., \'m\' or \'mm\').')
    parser.add_argument('--pclip', type=float,
                        help='''Specify the percentage (0-1) of the peak amplitude to display. This
                        parameter is used for pcolormesh plots only. Default is set to 1.''')
    parser.add_argument('--title', type=str,
                        help='''Specify a title for the wiggle plot. Default title is
                        \'Data\' if \'--data\' is passed and 'Test Function' if \'--testfunc\'
                        is passed.''')
    parser.add_argument('--format', '-f', type=str, default='pdf', choices=['png', 'pdf', 'ps', 'eps', 'svg'],
                        help='''Specify the image format of the saved file. Accepted formats are png, pdf,
                        ps, eps, and svg. Default format is set to pdf.''')
    parser.add_argument('--map', action='store_true',
                        help='''Plot a map of the receiver and source/sampling point locations. The current
                        source/sampling point will be highlighted. The boundary of the scatterer will also
                        be shown if available.''')
    parser.add_argument('--mode', type=str, choices=['light', 'dark'], required=False,
                        help='''Specify whether to view plots in light mode for daytime viewing
                        or dark mode for nighttime viewing.
                        Mode must be either \'light\' or \'dark\'.''')
    
    args = parser.parse_args()
    #==============================================================================
    # if a plotParams.pkl file already exists, load relevant parameters
    if Path('plotParams.pkl').exists():
        plotParams = pickle.load(open('plotParams.pkl', 'rb'))
        
        # update parameters for wiggle plots based on passed arguments
        if args.mode is not None:
            plotParams['view_mode'] = args.mode
        
        if args.tu is not None:
            plotParams['tu'] = args.tu
        
        if args.au is not None:
            plotParams['au'] = args.au
            
        if args.pclip is not None:
            if args.pclip >= 0 and args.pclip <= 1:
                plotParams['pclip'] = args.pclip
            else:
                print(textwrap.dedent(
                      '''
                      Warning: Invalid value passed to argument \'--pclip\'. Value must be
                      between 0 and 1.
                      '''))
            
        if args.title is not None:
            if args.data:
                plotParams['data_title'] = args.title
            elif args.testfunc:
                plotParams['tf_title'] = args.title
    
    else: # create a plotParams dictionary file with default values
        plotParams = default_params()
        
        # update parameters for wiggle plots based on passed arguments
        if args.mode is not None:
            plotParams['view_mode'] = args.mode
        
        if args.tu is not None:
            plotParams['tu'] = args.tu
        
        if args.au is not None:
            plotParams['au'] = args.au
        
        if args.title is not None:
            if args.data:
                plotParams['data_title'] = args.title
            elif args.testfunc:
                plotParams['tf_title'] = args.title
    
    pickle.dump(plotParams, open('plotParams.pkl', 'wb'), pickle.HIGHEST_PROTOCOL)

    #==============================================================================
    # Load the relevant data to plot
    datadir = np.load('datadir.npz')
    receiverPoints = np.load(str(datadir['receivers']))
    time = np.load(str(datadir['recordingTimes']))
    
    # Apply any user-specified windows
    rinterval, tinterval, tstep, dt, sinterval = get_user_windows()
    receiverPoints = receiverPoints[rinterval, :]
    time = time[tinterval]
    
    # Load the scatterer boundary, if it exists
    if 'scatterer' in datadir:
        scatterer = np.load(str(datadir['scatterer']))
    else:
        scatterer = None    
    
    if all(v is True for v in [args.data, args.testfunc]):
        # User specified both data and testfuncs for plotting
        # Send error message and exit.
        sys.exit(textwrap.dedent(
                '''
                Error: Cannot plot both recorded data and simulated test functions. Use
                
                    vzwiggles --data
                    
                to plot the recorded data or
                
                    vzwiggles --testfuncs
                    
                to plot the simulated test functions.
                '''))
    
    elif all(v is not True for v in [args.data, args.testfunc]):
        # User did not specify which wiggles to plot.
        # Plot recorded data by default.
        # load the 3D data array into variable 'X'
        # X[receiver, time, source]
        wiggleType = 'data'
        X = load_data(domain='time', verbose=True)
        
        if 'sources' in datadir:
            sourcePoints = np.load(str(datadir['sources']))
            sourcePoints = sourcePoints[sinterval, :]
        else:
            sourcePoints = None
    
    elif args.data:
        # load the 3D data array into variable 'X'
        # X[receiver, time, source]
        wiggleType = 'data'
        X = load_data(domain='time', verbose=True)
        
        if 'sources' in datadir:
            sourcePoints = np.load(str(datadir['sources']))
            sourcePoints = sourcePoints[sinterval, :]
        else:
            sourcePoints = None
        
    elif args.testfunc:
        wiggleType = 'testfunc'
        
        # Update time to convolution times
        T = time[-1] - time[0]
        time = np.linspace(-T, T, 2 * len(time) - 1)
        
        if 'testFuncs' not in datadir and not Path('VZTestFuncs.npz').exists():
            X, sourcePoints = load_test_funcs(domain='time', medium='constant',
                                              verbose=True, return_sampling_points=True)
            
        if 'testFuncs' in datadir and not Path('VZTestFuncs.npz').exists():
            X, sourcePoints = load_test_funcs(domain='time', medium='variable',
                                              verbose=True, return_sampling_points=True)
            
            # Pad time axis with zeros to length of convolution 2Nt-1
            npad = ((0, 0), (X.shape[1] - 1, 0), (0, 0))
            X = np.pad(X, pad_width=npad, mode='constant', constant_values=0)
            
        elif not 'testFuncs' in datadir and Path('VZTestFuncs.npz').exists():
            X, sourcePoints = load_test_funcs(domain='time', medium='constant',
                                              verbose=True, return_sampling_points=True)
                    
        elif 'testFuncs' in datadir and Path('VZTestFuncs.npz').exists():
            userResponded = False
            print(textwrap.dedent(
                 '''
                 Two files are available containing simulated test functions.
                 
                 Enter '1' to view the user-provided test functions. (Default)
                 Enter '2' to view the test functions computed by Vezda.
                 Enter 'q/quit' to exit.
                 '''))
            while userResponded == False:
                answer = input('Action: ')
                
                if answer == '' or answer == '1':
                    X, sourcePoints = load_test_funcs(domain='time', medium='variable',
                                                      verbose=True, return_sampling_points=True)
            
                    # Pad time axis with zeros to length of convolution 2Nt-1
                    npad = ((0, 0), (X.shape[1] - 1, 0), (0, 0))
                    X = np.pad(X, pad_width=npad, mode='constant', constant_values=0)
                    
                    userResponded = True
                    break
                
                elif answer == '2':
                    X, sourcePoints = load_test_funcs(domain='time', medium='constant',
                                                      verbose=True, return_sampling_points=True)
                    
                    userResponded = True
                    break
                
                elif answer == 'q' or answer == 'quit':
                    sys.exit('Exiting program.')
                
                else:
                    print('Invalid response. Please enter \'1\', \'2\', or \'q/quit\'.')
            
    
    #==============================================================================        
    # increment source/recording interval and receiver interval to be consistent
    # with one-based indexing (i.e., count from one instead of zero)
    sinterval += 1
    rinterval += 1
    
    Ns = X.shape[2]
    
    remove_keymap_conflicts({'left', 'right', 'up', 'down', 'save'})
    if args.map:
        fig, ax1, ax2 = setFigure(num_axes=2, mode=plotParams['view_mode'],
                                  ax2_dim=receiverPoints.shape[1])
            
        ax1.volume = X
        ax1.index = Ns // 2
        title = wave_title(ax1.index, sinterval, sourcePoints, wiggleType, plotParams)
        plotWiggles(ax1, X[:, :, ax1.index], time, rinterval, receiverPoints, title, wiggleType, plotParams)
        
        ax2.index = ax1.index
        plotMap(ax2, ax2.index, receiverPoints, sourcePoints, scatterer, wiggleType, plotParams)
        plt.tight_layout()
        fig.canvas.mpl_connect('key_press_event', lambda event: process_key_waves(event, time, rinterval, sinterval,
                                                                                  receiverPoints, sourcePoints, Ns, scatterer,
                                                                                  args.map, wiggleType, plotParams))
    
    else:
        fig, ax = setFigure(num_axes=1, mode=plotParams['view_mode'])
            
        ax.volume = X
        ax.index = Ns // 2
        title = wave_title(ax.index, sinterval, sourcePoints, wiggleType, plotParams)
        plotWiggles(ax, X[:, :, ax.index], time, rinterval, receiverPoints, title, wiggleType, plotParams)
        plt.tight_layout()
        fig.canvas.mpl_connect('key_press_event', lambda event: process_key_waves(event, time, rinterval, sinterval,
                                                                                  receiverPoints, sourcePoints, Ns, scatterer,
                                                                                  args.map, wiggleType, plotParams))
    
    plt.show()
예제 #2
0
import sys
import numpy as np
from vezda.data_utils import get_user_windows, fft_and_window
from vezda.math_utils import nextPow2
from vezda.sampling_utils import sampleSpace
from vezda.plot_utils import setFigure
from vezda.LinearOperators import asConvolutionalOperator
import matplotlib.pyplot as plt
import matplotlib.animation as animation

import textwrap

sys.path.append(os.getcwd())
import pulseFun

rinterval, tinterval, tstep, dt, sinterval = get_user_windows()

datadir = np.load('datadir.npz')
recordingTimes = np.load(str(datadir['recordingTimes']))
recordingTimes = recordingTimes[tinterval]

Nt = len(recordingTimes)
T = recordingTimes[-1] - recordingTimes[0]
convolutionTimes = np.linspace(-T, T, 2 * Nt - 1)

N = nextPow2(2 * Nt)
freqs = np.fft.rfftfreq(N, tstep * dt)
Nf = len(freqs)

if 'sources' in datadir:
    sourcePoints = np.load(str(datadir['sources']))
예제 #3
0
def cli():
    parser = argparse.ArgumentParser()
    parser.add_argument('--nfo', action='store_true',
                        help='''Plot the singular-value decomposition of the
                        near-field operator (NFO).''')
    parser.add_argument('--lso', action='store_true',
                        help='''Plot the singular-value decomposition of the
                        Lippmann-Schwinger operator (LSO).''')
    parser.add_argument('--format', '-f', type=str, default='pdf', choices=['png', 'pdf', 'ps', 'eps', 'svg'],
                        help='''Specify the image format of the saved file. Accepted formats are png, pdf,
                        ps, eps, and svg. Default format is set to pdf.''')
    parser.add_argument('--mode', type=str, choices=['light', 'dark'], required=False,
                        help='''Specify whether to view plots in light mode for daytime viewing
                        or dark mode for nighttime viewing.
                        Mode must be either \'light\' or \'dark\'.''')
    args = parser.parse_args()
    
    # See if an SVD already exists. If so, attempt to load it...
    if args.nfo and not args.lso:
        operatorName = 'near-field operator'
        filename = 'NFO_SVD.npz'
    
    elif not args.nfo and args.lso:
        operatorName = 'Lippmann-Schwinger operator'
        filename = 'LSO_SVD.npz'
            
    elif args.nfo and args.lso:
        sys.exit(textwrap.dedent(
                '''
                UsageError: Please specify only one of the arguments \'--nfo\' or \'--lso\'.
                '''))
    
    else:
        sys.exit(textwrap.dedent(
                '''
                For which operator would you like to plot a singular-value decomposition?
                Enter:
                    
                    vzsvd --nfo
                
                for the near-field operator or
                
                    vzsvd --lso
                    
                for the Lippmann-Schwinger operator.
                '''))
            
    try:
        U, s, Vh = load_svd(filename)
    except IOError:
        sys.exit(textwrap.dedent(
                '''
                A singular-value decomposition of the {s} does not exist.
                '''.format(s=operatorName)))

    #==============================================================================
    # Read in data files 
    #==============================================================================
    datadir = np.load('datadir.npz')
    receiverPoints = np.load(str(datadir['receivers']))
    recordingTimes = np.load(str(datadir['recordingTimes']))
    
    # Apply user-specified windows
    rinterval, tinterval, tstep, dt, sinterval = get_user_windows()
    receiverPoints = receiverPoints[rinterval, :]
    recordingTimes = recordingTimes[tinterval]
    
    # Load appropriate source points and source window
    if args.nfo:    # Near-field operator                
        if 'sources' in datadir:
            sourcePoints = np.load(str(datadir['sources']))
            sourcePoints = sourcePoints[sinterval, :]
        else:
            sourcePoints = None
            
    else:
        # if args.lso (Lippmann-Schwinger operator)
            
        # in the case of the Lippmann-Schwinger operator, 'sourcePoints'
        # correspond to sampling points, which should always exist.
        if 'testFuncs' in datadir:
            sourcePoints = np.load(str(datadir['samplingPoints']))
                
        elif Path('VZTestFuncs.npz').exists():
            TFDict = np.load('VZTestFuncs.npz')
            sourcePoints = TFDict['samplingPoints']
        
        else:
            sys.exit(textwrap.dedent(
                    '''
                    Error: A sampling grid must exist and test functions computed
                    before a singular-value decomposition of the Lippmann-Schwinger
                    operator can be computed or plotted.
                    '''))
    
        # update sinterval for test functions
        sinterval = np.arange(0, sourcePoints.shape[0], 1)   
        
    # increment receiver/source intervals to be consistent with
    # one-based indexing (i.e., count from one instead of zero)
    rinterval += 1
    sinterval += 1
    
    #==============================================================================
    # Determine whether to plot SVD in time domain or frequency domain 
    #==============================================================================
    if np.issubdtype(U.dtype, np.complexfloating):
        domain = 'freq'
    else:
        domain = 'time'
    
    # Load plot parameters
    if Path('plotParams.pkl').exists():
        plotParams = pickle.load(open('plotParams.pkl', 'rb'))
    else:
        plotParams = default_params()
        
    Nr = receiverPoints.shape[0]
    Nt = len(recordingTimes)
    k = len(s)
                
    if domain == 'freq':
        # plot singular vectors in frequency domain 
        N = nextPow2(2 * Nt)
        freqs = np.fft.rfftfreq(N, tstep * dt)
            
        if plotParams['fmax'] is None:
            plotParams['fmax'] = np.max(freqs)
            
        # Apply the frequency window
        fmin = plotParams['fmin']
        fmax = plotParams['fmax']
        df = 1.0 / (N * tstep * dt)
            
        startIndex = int(round(fmin / df))
        stopIndex = int(round(fmax / df))
        finterval = np.arange(startIndex, stopIndex, 1)
        freqs = freqs[finterval]
        
        M = len(freqs)         
        Ns = int(Vh.shape[1] / M)
        U = U.toarray().reshape((Nr, M, k))
        V = Vh.getH().toarray().reshape((Ns, M, k))
            
    else: # domain == 'time'
        M = 2 * Nt - 1
        Ns = int(Vh.shape[1] / M)
        U = U.reshape((Nr, M, k))
        V = Vh.T.reshape((Ns, M, k))
        T = recordingTimes[-1] - recordingTimes[0]
        times = np.linspace(-T, T, M)
        
    if args.mode is not None:
        plotParams['view_mode'] = args.mode
        
    pickle.dump(plotParams, open('plotParams.pkl', 'wb'), pickle.HIGHEST_PROTOCOL)
        
    remove_keymap_conflicts({'left', 'right', 'up', 'down', 'save'})
    if domain == 'freq':
            
        # plot the left singular vectors
        fig_lvec, ax_lvec_r, ax_lvec_i = setFigure(num_axes=2, mode=plotParams['view_mode'])
        ax_lvec_r.volume = U.real
        ax_lvec_i.volume = U.imag
        ax_lvec_r.index = 0
        ax_lvec_i.index = 0
        fig_lvec.suptitle('Left-Singular Vector', color=ax_lvec_r.titlecolor, fontsize=16)
        fig_lvec.subplots_adjust(bottom=0.27, top=0.86)
        leftTitle_r = vector_title('left', ax_lvec_r.index + 1, 'real')
        leftTitle_i = vector_title('left', ax_lvec_i.index + 1, 'imag')
        for ax, title in zip([ax_lvec_r, ax_lvec_i], [leftTitle_r, leftTitle_i]):
            left_im = plotFreqVectors(ax, ax.volume[:, :, ax.index], freqs, rinterval,
                                      receiverPoints, title, 'left', plotParams)
                
        lp0 = ax_lvec_r.get_position().get_points().flatten()
        lp1 = ax_lvec_i.get_position().get_points().flatten()
        left_cax = fig_lvec.add_axes([lp0[0], 0.12, lp1[2]-lp0[0], 0.03])
        lcbar = fig_lvec.colorbar(left_im, left_cax, orientation='horizontal')
        lcbar.outline.set_edgecolor(ax_lvec_r.cbaredgecolor)
        lcbar.ax.tick_params(axis='x', colors=ax_lvec_r.labelcolor)              
        lcbar.ax.yaxis.set_major_formatter(FormatStrFormatter('%.1f'))
        lcbar.set_label('Amplitude',
                        labelpad=5, rotation=0, fontsize=12, color=ax_lvec_r.labelcolor)
        fig_lvec.canvas.mpl_connect('key_press_event', lambda event: process_key_vectors(event, freqs, rinterval, sinterval,
                                                                                         receiverPoints, sourcePoints, plotParams,
                                                                                         'cmplx_left'))
            
        # plot the right singular vectors
        fig_rvec, ax_rvec_r, ax_rvec_i = setFigure(num_axes=2, mode=plotParams['view_mode'])
        ax_rvec_r.volume = V.real
        ax_rvec_i.volume = V.imag
        ax_rvec_r.index = 0
        ax_rvec_i.index = 0
        fig_rvec.suptitle('Right-Singular Vector', color=ax_rvec_r.titlecolor, fontsize=16)
        fig_rvec.subplots_adjust(bottom=0.27, top=0.86)
        rightTitle_r = vector_title('right', ax_rvec_r.index + 1, 'real')
        rightTitle_i = vector_title('right', ax_rvec_i.index + 1, 'imag')
        for ax, title in zip([ax_rvec_r, ax_rvec_i], [rightTitle_r, rightTitle_i]):
            right_im = plotFreqVectors(ax, ax.volume[:, :, ax.index], freqs, sinterval,
                                       sourcePoints, title, 'right', plotParams)
            
        rp0 = ax_rvec_r.get_position().get_points().flatten()
        rp1 = ax_rvec_i.get_position().get_points().flatten()
        right_cax = fig_rvec.add_axes([rp0[0], 0.12, rp1[2]-rp0[0], 0.03])
        rcbar = fig_rvec.colorbar(right_im, right_cax, orientation='horizontal')  
        rcbar.outline.set_edgecolor(ax_rvec_r.cbaredgecolor)
        rcbar.ax.tick_params(axis='x', colors=ax_rvec_r.labelcolor)
        rcbar.ax.yaxis.set_major_formatter(FormatStrFormatter('%.1f'))
        rcbar.set_label('Amplitude',
                        labelpad=5, rotation=0, fontsize=12, color=ax_lvec_r.labelcolor)
        fig_rvec.canvas.mpl_connect('key_press_event', lambda event: process_key_vectors(event, freqs, rinterval, sinterval,
                                                                                         receiverPoints, sourcePoints, plotParams,
                                                                                         'cmplx_right'))
            
    else:
        # domain == 'time'   
        fig_vec, ax_lvec, ax_rvec = setFigure(num_axes=2, mode=plotParams['view_mode'])
            
        ax_lvec.volume = U
        ax_lvec.index = 0
        leftTitle = vector_title('left', ax_lvec.index + 1)
        plotWiggles(ax_lvec, ax_lvec.volume[:, :, ax_lvec.index], times, rinterval,
                    receiverPoints, leftTitle, 'left', plotParams)
      
        ax_rvec.volume = V
        ax_rvec.index = 0
        rightTitle = vector_title('right', ax_rvec.index + 1)
        plotWiggles(ax_rvec, ax_rvec.volume[:, :, ax_rvec.index], times, sinterval,
                    sourcePoints, rightTitle, 'right', plotParams)
        fig_vec.tight_layout()
        fig_vec.canvas.mpl_connect('key_press_event', lambda event: process_key_vectors(event, times, rinterval, sinterval,
                                                                                        receiverPoints, sourcePoints, plotParams))
    #==============================================================================
    # plot the singular values
    # figure and axis for singular values
    fig_vals, ax_vals = setFigure(num_axes=1, mode=plotParams['view_mode'])
        
    n = np.arange(1, k + 1, 1)
    kappa = s[0] / s[-1]    # condition number = max(s) / min(s)
    ax_vals.plot(n, s, '.', clip_on=False, markersize=9, label=r'Condition Number: %0.1e' %(kappa), color=ax_vals.pointcolor)
    ax_vals.set_xlabel('n', color=ax_vals.labelcolor)
    ax_vals.set_ylabel('$\sigma_n$', color=ax_vals.labelcolor)
    legend = ax_vals.legend(title='Singular Values', loc='upper center', bbox_to_anchor=(0.5, 1.25),
                            markerscale=0, handlelength=0, handletextpad=0, fancybox=True, shadow=True,
                            fontsize='large')
    legend.get_title().set_fontsize('large')
    ax_vals.set_xlim([1, k])
    ax_vals.set_ylim(bottom=0)
    ax_vals.locator_params(axis='y', nticks=6)
    ax_vals.ticklabel_format(style='sci', axis='y', scilimits=(0,0))
    fig_vals.tight_layout()
    fig_vals.savefig('singularValues.' + args.format, format=args.format, bbox_inches='tight', facecolor=fig_vals.get_facecolor())
    
    plt.show()
예제 #4
0
def cli():
    parser = argparse.ArgumentParser()
    parser.add_argument('--data', action='store_true',
                        help='Plot the frequency spectrum of the recorded data. (Default)')
    parser.add_argument('--testfunc', action='store_true',
                        help='Plot the frequency spectrum of the simulated test functions.')
    parser.add_argument('--power', action='store_true',
                        help='''Plot the mean power spectrum of the input signals. Default is to plot the
                        mean amplitude spectrum of the Fourier transform.''')
    parser.add_argument('--fmin', type=float,
                        help='Specify the minimum frequency of the amplitude/power spectrum plot. Default is set to 0.')
    parser.add_argument('--fmax', type=float,
                        help='''Specify the maximum frequency of the amplitude/power spectrum plot. Default is set to the
                        maximum frequency bin based on the length of the time signal.''')
    parser.add_argument('--fu', type=str,
                        help='Specify the frequency units (e.g., Hz)')
    parser.add_argument('--format', '-f', type=str, default='pdf', choices=['png', 'pdf', 'ps', 'eps', 'svg'],
                        help='''specify the image format of the saved file. Accepted formats are png, pdf,
                        ps, eps, and svg. Default format is set to pdf.''')
    parser.add_argument('--mode', type=str, choices=['light', 'dark'], required=False,
                        help='''Specify whether to view plots in light mode for daytime viewing
                        or dark mode for nighttime viewing.
                        Mode must be either \'light\' or \'dark\'.''')
    args = parser.parse_args()
    
    #==============================================================================        
    # Get time window parameters
    tinterval, tstep, dt = get_user_windows()[1:4]
    datadir = np.load('datadir.npz')
    recordingTimes = np.load(str(datadir['recordingTimes']))
    recordingTimes = recordingTimes[tinterval]
    
    # Used for getting time and frequency units
    if Path('plotParams.pkl').exists():
        plotParams = pickle.load(open('plotParams.pkl', 'rb'))
    else:
        plotParams = default_params()
    
    if all(v is True for v in [args.data, args.testfunc]):
        sys.exit(textwrap.dedent(
                '''
                Error: Cannot plot frequency spectrum of both recorded data and
                simulated test functions. Use
                
                    vzspectra --data
                    
                to plot the frequency spectrum of the recorded data or
                
                    vzspectra --testfuncs
                    
                to plot the frequency spectrum of the simulated test functions.
                '''))
    
    elif (args.data and not args.testfunc) or all(v is not True for v in [args.data, args.testfunc]):
        # default is to plot spectra of data if user does not specify either args.data or args.testfunc
        X = load_data(domain='time', verbose=True)
        
    elif not args.data and args.testfunc:
        if 'testFuncs' not in datadir and not Path('VZTestFuncs.npz').exists():
            X = load_test_funcs(domain='time', medium='constant', verbose=True)
        
        elif 'testFuncs' in datadir and not Path('VZTestFuncs.npz').exists():
            X = load_test_funcs(domain='time', medium='variable', verbose=True)
            
        elif not 'testFuncs' in datadir and Path('VZTestFuncs.npz').exists():
            X = load_test_funcs(domain='time', medium='constant', verbose=True)
                    
        elif 'testFuncs' in datadir and Path('VZTestFuncs.npz').exists():
            userResponded = False
            print(textwrap.dedent(
                 '''
                 Two files are available containing simulated test functions.
                 
                 Enter '1' to view the user-provided test functions. (Default)
                 Enter '2' to view the test functions computed by Vezda.
                 Enter 'q/quit' to exit.
                 '''))
            while userResponded == False:
                answer = input('Action: ')
                
                if answer == '' or answer == '1':
                    X = load_test_funcs(domain='time', medium='variable', verbose=True)
                    userResponded = True
                    break
                
                elif answer == '2':
                    X = load_test_funcs(domain='time', medium='constant', verbose=True)
                    userResponded = True
                    break
                
                elif answer == 'q' or answer == 'quit':
                    sys.exit('Exiting program.')
                
                else:
                    print('Invalid response. Please enter \'1\', \'2\', or \'q/quit\'.')
        
    #==============================================================================
    # compute spectra
    freqs, amplitudes = compute_spectrum(X, tstep * dt, args.power)
        
    if args.power:
        plotLabel = 'power'
        plotParams['freq_title'] = 'Mean Power Spectrum'
        plotParams['freq_ylabel'] = 'Power'
    else:
        plotLabel = 'amplitude'
        plotParams['freq_title'] = 'Mean Amplitude Spectrum'
        plotParams['freq_ylabel'] = 'Amplitude'
            
    if args.data or all(v is not True for v in [args.data, args.testfunc]):
        plotParams['freq_title'] += ' [' + plotParams['data_title'] + ']'
    elif args.testfunc:
        plotParams['freq_title'] += ' [' + plotParams['tf_title'] + 's]'
        
    if args.fmin is not None: 
        if args.fmin >= 0:
            if args.fmax is not None:
                if args.fmax > args.fmin:
                    plotParams['fmin'] = args.fmin
                    plotParams['fmax'] = args.fmax
                else:
                    sys.exit(textwrap.dedent(
                            '''
                            RelationError: The maximum frequency of the %s spectrum plot must
                            be greater than the mininum frequency.
                            ''' %(plotLabel)))   
            else:
                fmax = plotParams['fmax']
                if fmax > args.fmin:
                    plotParams['fmin'] = args.fmin
                else:
                    sys.exit(textwrap.dedent(
                            '''
                            RelationError: The specified minimum frequency of the %s spectrum 
                            plot must be less than the maximum frequency.
                            ''' %(plotLabel)))                                        
        else:
            sys.exit(textwrap.dedent(
                    '''
                    ValueError: The specified minimum frequency of the %s spectrum 
                    plot must be nonnegative.
                    ''' %(plotLabel)))
            
    #===============================================================================
    if args.fmax is not None:
        if args.fmin is not None:
            if args.fmin >= 0:
                if args.fmax > args.fmin:
                    plotParams['fmin'] = args.fmin
                    plotParams['fmax'] = args.fmax
                else:
                    sys.exit(textwrap.dedent(
                            '''
                            RelationError: The maximum frequency of the %s spectrum plot must
                            be greater than the mininum frequency.
                            ''' %(plotLabel)))
            else:
                sys.exit(textwrap.dedent(
                        '''
                        ValueError: The specified minimum frequency of the %s spectrum 
                        plot must be nonnegative.
                        ''' %(plotLabel)))
        else:
            fmin = plotParams['fmin']
            if args.fmax > fmin:
                plotParams['fmax'] = args.fmax
            else:
                sys.exit(textwrap.dedent(
                        '''
                        RelationError: The specified maximum frequency of the %s spectrum 
                        plot must be greater than the minimum frequency.
                        ''' %(plotLabel)))
    elif plotParams['fmax'] is None:
        plotParams['fmax'] = np.max(freqs)
                
    #===================================================================================
    if args.fu is not None:
        plotParams['fu'] = args.fu
            
    if args.mode is not None:
        plotParams['view_mode'] = args.mode
    
    pickle.dump(plotParams, open('plotParams.pkl', 'wb'), pickle.HIGHEST_PROTOCOL)
    
    fig, ax = setFigure(num_axes=1, mode=plotParams['view_mode'])
    ax.plot(freqs, amplitudes, color=ax.linecolor, linewidth=ax.linewidth)
    ax.set_title(plotParams['freq_title'], color=ax.titlecolor)
    
    # get frequency units from plotParams
    fu = plotParams['fu']
    fmin = plotParams['fmin']
    fmax = plotParams['fmax']
    if fu != '':
        ax.set_xlabel('Frequency (%s)' %(fu), color=ax.labelcolor)
    else:
        ax.set_xlabel('Frequency', color=ax.labelcolor)
    ax.set_ylabel(plotParams['freq_ylabel'], color=ax.labelcolor)
    ax.set_xlim([fmin, fmax])
    ax.set_ylim(bottom=0)
    ax.fill_between(freqs, 0, amplitudes, where=(amplitudes > 0), color='m', alpha=ax.alpha)
    ax.locator_params(axis='y', nticks=6)
    ax.ticklabel_format(style='sci', axis='y', scilimits=(0,0))
    plt.tight_layout()
    fig.savefig(plotLabel + 'Spectrum.' + args.format, format=args.format, bbox_inches='tight', facecolor=fig.get_facecolor())
    plt.show()
    
예제 #5
0
def cli():
    parser = argparse.ArgumentParser()
    parser.add_argument('--data', action='store_true',
                        help='Plot the recorded data. (Default)')
    parser.add_argument('--impulse', action='store_true',
                        help='Plot the simulated impulse responses.')
    parser.add_argument('--medium', type=str, default='constant', choices=['constant', 'variable'],
                        help='''Specify whether the background medium is constant or variable
                        (inhomogeneous). If argument is set to 'constant', the velocity defined in
                        the required 'pulsesFun.py' file is used. Default is set to 'constant'.''')
    parser.add_argument('--tu', type=str,
                        help='Specify the time units (e.g., \'s\' or \'ms\').')
    parser.add_argument('--au', type=str,
                        help='Specify the amplitude units (e.g., \'m\' or \'mm\').')
    parser.add_argument('--colormap', type=str, default=None, choices=['grays', 'seismic', 'native'],
                        help='specify a colormap for wiggle plots. Default is \'grays\'.')
    parser.add_argument('--pclip', type=float,
                        help='''Specify the percentage (0-1) of the peak amplitude to display. This
                        parameter is used for pcolormesh plots only. Default is set to 1.''')
    parser.add_argument('--title', type=str,
                        help='''Specify a title for the wiggle plot. Default title is
                        \'Data\' if \'--data\' is passed and 'Impulse Response' if \'--impulse\'
                        is passed.''')
    parser.add_argument('--format', '-f', type=str, default='pdf', choices=['png', 'pdf', 'ps', 'eps', 'svg'],
                        help='''Specify the image format of the saved file. Accepted formats are png, pdf,
                        ps, eps, and svg. Default format is set to pdf.''')
    parser.add_argument('--map', action='store_true',
                        help='''Plot a map of the receiver and source/search point locations. The current
                        source/search point will be highlighted. The boundary of the scatterer will also
                        be shown if available.''')
    parser.add_argument('--mode', type=str, choices=['light', 'dark'], required=False,
                        help='''Specify whether to view plots in light mode for daytime viewing
                        or dark mode for nighttime viewing.
                        Mode must be either \'light\' or \'dark\'.''')
    
    args = parser.parse_args()
    #==============================================================================
    # if a plotParams.pkl file already exists, load relevant parameters
    if Path('plotParams.pkl').exists():
        plotParams = pickle.load(open('plotParams.pkl', 'rb'))
        
        # update parameters for wiggle plots based on passed arguments
        if args.mode is not None:
            plotParams['view_mode'] = args.mode
        
        if args.tu is not None:
            plotParams['tu'] = args.tu
        
        if args.au is not None:
            plotParams['au'] = args.au
            
        if args.colormap is not None:
            plotParams['wiggle_colormap'] = args.colormap
            
        if args.pclip is not None:
            if args.pclip >= 0 and args.pclip <= 1:
                plotParams['pclip'] = args.pclip
            else:
                print(textwrap.dedent(
                      '''
                      Warning: Invalid value passed to argument \'--pclip\'. Value must be
                      between 0 and 1.
                      '''))
            
        if args.title is not None:
            if args.data:
                plotParams['data_title'] = args.title
            elif args.impulse:
                plotParams['tf_title'] = args.title
    
    else: # create a plotParams dictionary file with default values
        plotParams = default_params()
        
        # update parameters for wiggle plots based on passed arguments
        if args.mode is not None:
            plotParams['view_mode'] = args.mode
        
        if args.tu is not None:
            plotParams['tu'] = args.tu
        
        if args.au is not None:
            plotParams['au'] = args.au
            
        if args.colormap is not None:
            plotParams['wiggle_colormap'] = args.colormap
        
        if args.title is not None:
            if args.data:
                plotParams['data_title'] = args.title
            elif args.impulse:
                plotParams['tf_title'] = args.title
    
    pickle.dump(plotParams, open('plotParams.pkl', 'wb'), pickle.HIGHEST_PROTOCOL)

    #==============================================================================
    # Load the relevant data to plot
    datadir = np.load('datadir.npz')
    receiverPoints = np.load(str(datadir['receivers']))
    time = np.load(str(datadir['recordingTimes']))
    
    # Apply any user-specified windows
    receiverNumbers, tinterval, tstep, dt, sourceNumbers = get_user_windows()
    receiverPoints = receiverPoints[receiverNumbers, :]
    time = time[tinterval]
    
    if 'sources' in datadir:
        sourcePoints = np.load(str(datadir['sources']))
        sourcePoints = sourcePoints[sourceNumbers, :]
            
        # Check for source-receiver reciprocity
        reciprocalNumbers = get_unique_indices(sourcePoints, receiverPoints)
        reciprocalNumbers = np.asarray(reciprocalNumbers, dtype=np.int)
            
        if len(reciprocalNumbers) > 0:
            newReceivers = sourcePoints[reciprocalNumbers, :]
            reciprocity = True
        else:
            reciprocity = False
    else:
        reciprocity = False
        sourcePoints = None
    
    # Load the scatterer boundary, if it exists
    if 'scatterer' in datadir:
        scatterer = np.load(str(datadir['scatterer']))
    else:
        scatterer = None    
    
    if all(v is True for v in [args.data, args.impulse]):
        # User specified both data and impulse response for plotting
        # Send error message and exit.
        sys.exit(textwrap.dedent(
                '''
                Error: Cannot plot both recorded data and simulated impulse responses. Use
                
                    vzwiggles --data
                    
                to plot the recorded data or
                
                    vzwiggles --impulse
                    
                to plot the simulated impulse responses.
                '''))
    
    elif all(v is not True for v in [args.data, args.impulse]) or args.data:
        # If user did not specify which wiggles to plot, plot recorded data by default.
        # load the 3D data array into variable 'X'
        # X[receiver, time, source]
        wiggleType = 'data'
        X = load_data(domain='time', verbose=True)
        
        if reciprocity:
            Nr = len(receiverNumbers)
            Ns = len(sourceNumbers)
            M = len(reciprocalNumbers)
            
            XR = X[-M:, :, -Nr:]
            X = X[:Nr, :, :Ns]
            
            reciprocalNumbers += 1        
            ER = Experiment(XR, time, reciprocalNumbers, newReceivers,
                            receiverNumbers, receiverPoints, wiggleType)                        
        else:
            ER = None
        
    elif args.impulse:
        wiggleType = 'impulse'
        
        # Update time to convolution times
        T = time[-1] - time[0]
        time = np.linspace(-T, T, 2 * len(time) - 1)
        X, sourcePoints = load_impulse_responses(domain='time', medium=args.medium,
                                                 verbose=True, return_search_points=True)
        
        # Update sourceNumbers to match search points
        sourceNumbers = np.arange(sourcePoints.shape[0])
        
        if reciprocity:
            Nr = len(receiverNumbers)
            M = len(reciprocalNumbers)
            
            XR = X[-M:, :, :]
            X = X[:Nr, :, :]
            
            reciprocalNumbers += 1        
            ER = Experiment(XR, time, reciprocalNumbers, newReceivers,
                            sourceNumbers, sourcePoints, wiggleType)
        else:
            ER = None
    
    #==============================================================================        
    # increment source/receiver numbers to be consistent with
    # one-based indexing (i.e., count from one instead of zero)
    sourceNumbers += 1
    receiverNumbers += 1
    
    E = Experiment(X, time, receiverNumbers, receiverPoints,
                   sourceNumbers, sourcePoints, wiggleType)
        
    p = Plotter(E, ER)
    p.plot(scatterer, plotParams, args.map)
    plt.show()
예제 #6
0
def cli():
    parser = argparse.ArgumentParser()
    parser.add_argument('--data', action='store_true',
                        help='Plot the frequency spectra of the recorded data. (Default)')
    parser.add_argument('--impulse', action='store_true',
                        help='Plot the frequency spectra of the simulated impulse responses.')
    parser.add_argument('--scaling', '-s', type=str, default='amp', choices=['amp', 'pow', 'psd'],
                        help='''Specify the scaling of the spectrum. Choose from amplitude ('amp'), power ('pow'),
                        or power spectral density ('psd') using Welch's method. Default is set to 'amp'.''')
    parser.add_argument('--nseg', type=int,
                        help='''Specify the approximate number of segments into which the time signal will be partitioned.
                        Only used if scaling is set to 'psd'. Increasing the number of segments increases computational
                        cost and the accuracy of the PSD estimate, but decreases frequency resolution. Default is set to 20.''')
    parser.add_argument('--fmin', type=float,
                        help='Specify the minimum frequency of the amplitude/power spectrum plot. Default is set to 0.')
    parser.add_argument('--fmax', type=float,
                        help='''Specify the maximum frequency of the amplitude/power spectrum plot. Default is set to the
                        maximum frequency bin based on the length of the time signal.''')
    parser.add_argument('--au', type=str,
                        help='Specify the amplitude units (e.g., Pa)')    
    parser.add_argument('--fu', type=str,
                        help='Specify the frequency units (e.g., Hz)')
    parser.add_argument('--format', '-f', type=str, default='pdf', choices=['png', 'pdf', 'ps', 'eps', 'svg'],
                        help='''specify the image format of the saved file. Accepted formats are png, pdf,
                        ps, eps, and svg. Default format is set to pdf.''')
    parser.add_argument('--mode', type=str, choices=['light', 'dark'], required=False,
                        help='''Specify whether to view plots in light mode for daytime viewing
                        or dark mode for nighttime viewing.
                        Mode must be either \'light\' or \'dark\'.''')
    args = parser.parse_args()
    
    #==============================================================================        
    # Get time window parameters
    tinterval, tstep, dt = get_user_windows()[1:4]
    datadir = np.load('datadir.npz')
    recordingTimes = np.load(str(datadir['recordingTimes']))
    recordingTimes = recordingTimes[tinterval]
    
    # Used for getting time and frequency units
    if Path('plotParams.pkl').exists():
        plotParams = pickle.load(open('plotParams.pkl', 'rb'))
    else:
        plotParams = default_params()
    
    if all(v is True for v in [args.data, args.impulse]):
        X = load_data(domain='time', verbose=True)
        Xlabel = plotParams['data_title']
        Xcolor = 'm'
        
        if 'testFuncs' not in datadir and not Path('VZImpulseResponses.npz').exists():
            X2 = load_impulse_responses(domain='time', medium='constant', verbose=True)
            X2label = plotParams['impulse_title']
            X2color = 'c'
        
        elif 'testFuncs' in datadir and not Path('VZImpulseResponses.npz').exists():
            X2 = load_impulse_responses(domain='time', medium='variable', verbose=True)
            X2label = plotParams['impulse_title']
            X2color = 'c'
            
        elif not 'testFuncs' in datadir and Path('VZImpulseResponses.npz').exists():
            X2 = load_impulse_responses(domain='time', medium='constant', verbose=True)
            X2label = plotParams['impulse_title']
            X2color = 'c'
            
        elif 'testFuncs' in datadir and Path('VZImpulseResponses.npz').exists():
            userResponded = False
            print(textwrap.dedent(
                 '''
                 Two files are available containing simulated impulse responses.
                 
                 Enter '1' to view the user-provided impulse responses. (Default)
                 Enter '2' to view the impulse responses computed by Vezda.
                 Enter 'q/quit' to exit.
                 '''))
            while userResponded == False:
                answer = input('Action: ')
                
                if answer == '' or answer == '1':
                    X2 = load_impulse_responses(domain='time', medium='variable', verbose=True)
                    X2label = plotParams['impulse_title']
                    X2color = 'c'
                    userResponded = True
                    break
                
                elif answer == '2':
                    X2 = load_impulse_responses(domain='time', medium='constant', verbose=True)
                    X2label = plotParams['impulse_title']
                    X2color = 'c'
                    userResponded = True
                    break
                
                elif answer == 'q' or answer == 'quit':
                    sys.exit('Exiting program.')
                
                else:
                    print('Invalid response. Please enter \'1\', \'2\', or \'q/quit\'.')
    
    elif (args.data and not args.impulse) or all(v is not True for v in [args.data, args.impulse]):
        # default is to plot spectra of data if user does not specify either args.data or args.impulse
        X = load_data(domain='time', verbose=True)
        Xlabel = plotParams['data_title']
        Xcolor = 'm'
        X2 = None
        
    elif not args.data and args.impulse:
        if 'testFuncs' not in datadir and not Path('VZImpulseResponses.npz').exists():
            X = load_impulse_responses(domain='time', medium='constant', verbose=True)
            Xlabel = plotParams['impulse_title']
            Xcolor = 'c'
        
        elif 'testFuncs' in datadir and not Path('VZImpulseResponses.npz').exists():
            X = load_impulse_responses(domain='time', medium='variable', verbose=True)
            Xlabel = plotParams['impulse_title']
            Xcolor = 'c'
            
        elif not 'testFuncs' in datadir and Path('VZImpulseResponses.npz').exists():
            X = load_impulse_responses(domain='time', medium='constant', verbose=True)
            Xlabel = plotParams['impulse_title']
            Xcolor = 'c'
                    
        elif 'testFuncs' in datadir and Path('VZImpulseResponses.npz').exists():
            userResponded = False
            print(textwrap.dedent(
                 '''
                 Two files are available containing simulated impulse responses.
                 
                 Enter '1' to view the user-provided impulse responses. (Default)
                 Enter '2' to view the impulse responses computed by Vezda.
                 Enter 'q/quit' to exit.
                 '''))
            while userResponded == False:
                answer = input('Action: ')
                
                if answer == '' or answer == '1':
                    X = load_impulse_responses(domain='time', medium='variable', verbose=True)
                    Xlabel = plotParams['impulse_title']
                    Xcolor = 'c'
                    userResponded = True
                    break
                
                elif answer == '2':
                    X = load_impulse_responses(domain='time', medium='constant', verbose=True)
                    Xlabel = plotParams['impulse_title']
                    Xcolor = 'c'
                    userResponded = True
                    break
                
                elif answer == 'q' or answer == 'quit':
                    sys.exit('Exiting program.')
                
                else:
                    print('Invalid response. Please enter \'1\', \'2\', or \'q/quit\'.')
        
        X2 = None
        
    #==============================================================================
    # compute spectra
    if args.nseg is not None:
        if args.nseg >= 1:
            nseg = args.nseg
        else:
            sys.exit(textwrap.dedent(
                    '''
                    Error: Optional argument '--nseg' must be greater than or equal to one.
                    '''))
    else:
        # if args.nseg is None
        nseg = 1
    
    freqs, A = compute_spectra(X, tstep * dt, scaling=args.scaling, nseg=nseg)
    if X2 is not None:
        Nt = X.shape[1]
        X2 = X2[:, -Nt:, :]
        freqs2, A2 = compute_spectra(X2, tstep * dt, scaling=args.scaling, nseg=nseg)
    else:
        freqs2 = None
        A2 = None
        
    if args.au is not None:
        plotParams['au'] = args.au
    
    if args.fu is not None:
        plotParams['fu'] = args.fu

    au = plotParams['au']
    fu = plotParams['fu']
    
    if args.scaling == 'amp':
        plotLabel = 'amplitude'
        plotParams['freq_title'] = 'Mean Amplitude Spectrum'
        if au != '':
            plotParams['freq_ylabel'] = 'Amplitude (%s)' %(au)
        else:
            plotParams['freq_ylabel'] = 'Amplitude'
   
    elif args.scaling == 'pow':
        plotLabel = 'power'
        plotParams['freq_title'] = 'Mean Power Spectrum'
        if au != '':
            plotParams['freq_ylabel'] = 'Power (%s)' %(au + '$^2$')
        else:
            plotParams['freq_ylabel'] = 'Power'
    
    elif args.scaling == 'psd':
        plotLabel = 'psd'
        plotParams['freq_title'] = 'Mean Power Spectral Density'
        if au != '' and fu != '':
            plotParams['freq_ylabel'] = 'Power/Frequency (%s)' %(au + '$^2/$' + fu)
        else:
            plotParams['freq_ylabel'] = 'Power/Frequency'
        
    if args.fmin is not None: 
        if args.fmin >= 0:
            if args.fmax is not None:
                if args.fmax > args.fmin:
                    plotParams['fmin'] = args.fmin
                    plotParams['fmax'] = args.fmax
                else:
                    sys.exit(textwrap.dedent(
                            '''
                            RelationError: The maximum frequency of the %s spectrum plot must
                            be greater than the mininum frequency.
                            ''' %(plotLabel)))   
            else:
                fmax = plotParams['fmax']
                if fmax > args.fmin:
                    plotParams['fmin'] = args.fmin
                else:
                    sys.exit(textwrap.dedent(
                            '''
                            RelationError: The specified minimum frequency of the %s spectrum 
                            plot must be less than the maximum frequency.
                            ''' %(plotLabel)))                                        
        else:
            sys.exit(textwrap.dedent(
                    '''
                    ValueError: The specified minimum frequency of the %s spectrum 
                    plot must be nonnegative.
                    ''' %(plotLabel)))
            
    #===============================================================================
    if args.fmax is not None:
        if args.fmin is not None:
            if args.fmin >= 0:
                if args.fmax > args.fmin:
                    plotParams['fmin'] = args.fmin
                    plotParams['fmax'] = args.fmax
                else:
                    sys.exit(textwrap.dedent(
                            '''
                            RelationError: The maximum frequency of the %s spectrum plot must
                            be greater than the mininum frequency.
                            ''' %(plotLabel)))
            else:
                sys.exit(textwrap.dedent(
                        '''
                        ValueError: The specified minimum frequency of the %s spectrum 
                        plot must be nonnegative.
                        ''' %(plotLabel)))
        else:
            fmin = plotParams['fmin']
            if args.fmax > fmin:
                plotParams['fmax'] = args.fmax
            else:
                sys.exit(textwrap.dedent(
                        '''
                        RelationError: The specified maximum frequency of the %s spectrum 
                        plot must be greater than the minimum frequency.
                        ''' %(plotLabel)))
    elif plotParams['fmax'] is None:
        plotParams['fmax'] = np.max(freqs)
                
    #===================================================================================
    if args.mode is not None:
        plotParams['view_mode'] = args.mode
    
    pickle.dump(plotParams, open('plotParams.pkl', 'wb'), pickle.HIGHEST_PROTOCOL)
    
    fig, ax = setFigure(num_axes=1, mode=plotParams['view_mode'])
    
    if args.scaling == 'psd':
        plotscale = 'log'
    else:
        plotscale = 'linear'
    
    gradient_fill(freqs, A, fill_color=Xcolor, ax=ax, scale=plotscale, zorder=2)
    handles, labels = [], []
    handles.append(Line2D([0], [0], color=Xcolor, lw=4))
    labels.append(Xlabel)
    if all(v is not None for v in [freqs2, A2]):
        gradient_fill(freqs2, A2, fill_color=X2color, ax=ax, scale=plotscale, zorder=1)
        handles.append(Line2D([0], [0], color=X2color, lw=4))
        labels.append(X2label)
        
    ax.legend(handles, labels, fancybox=True, framealpha=1, shadow=True, loc='upper right')
    ax.set_title(plotParams['freq_title'], color=ax.titlecolor)
    
    fmin = plotParams['fmin']
    fmax = plotParams['fmax']
    if fu != '':
        ax.set_xlabel('Frequency (%s)' %(fu), color=ax.labelcolor)
    else:
        ax.set_xlabel('Frequency', color=ax.labelcolor)
    ax.set_ylabel(plotParams['freq_ylabel'], color=ax.labelcolor)
    ax.set_xlim([fmin, fmax])
    if args.scaling != 'psd':
        ax.set_ylim(bottom=0)
        ax.ticklabel_format(style='sci', axis='y', scilimits=(0,0))
    
    plt.tight_layout()
    fig.savefig(plotLabel + 'Spectrum.' + args.format, format=args.format, bbox_inches='tight', facecolor=fig.get_facecolor())
    plt.show()