def planContour(pltVar,pltVarLbl):
    
    fig,ax,grd,proj = plotContour(pltVar,lev,lon,lat,'map',pltVarLbl,
                                  figsize=(10,10),dT=dT,runId=runId,
                                  zoom=zoom,mapBnds=mapBnds,NB=noBorder,strmRel=strmRel)
    
    if pltFT:
        plotFLpath(proj,flLon,flLat,dubLine=True)

    if pltVec:
        plotVec(lon[1::5],lat[1::5],u[lev*2,1::5,1::5],
               v[lev*2,1::5,1::5],'map',proj=proj)
        
    if pltRAP:
            plotVec(gribData['lon'],gribData['lat'],gribData['u'][rapLevIx[ix],:,:],
                    gribData['v'][rapLevIx[ix],:,:],crds='map',proj=proj,color='white',
                    linewidth=1.5,edgecolor='white',quivKeyX=0.08)
            plotVec(gribData['lon'],gribData['lat'],gribData['u'][rapLevIx[ix],:,:],
                    gribData['v'][rapLevIx[ix],:,:],crds='map',proj=proj,color='blue',
                    edgecolor=None,quivKeyX=0.08)

    if pltGRlocs:
        plt.scatter(lonGR,latGR,marker='d',color='w',s=200,zorder=7,transform=proj)
        plt.scatter(lonGR,latGR,marker='d',color='k',s=100,zorder=8,transform=proj)

        for labelGR, c, d in zip(grTxt, lonGR, latGR):
            plt.annotate(labelGR, xy = (c, d), xytext = (-8, 5),zorder=10,
                         textcoords = 'offset points',fontsize=13,color='w',
                         bbox=dict(boxstyle="round", fc="b",alpha=0.6,pad=0.01),
                         transform=proj)
            
    if plotXSloc:
        if len(xsStrt) > 1:
            lbls = []
            for iz in range(0,len(xsStrt)):
                xsLat,xsLon,dRnd,hdng = xsCalc(xsStrt[iz][0],xsStrt[iz][1],xsEnd[iz][0],xsEnd[iz][1])
                ax.plot(xsLon,xsLat,transform=proj,linestyle='-',linewidth=2,color='k')
                if iz%2 == 0:
                    xyP = (xsStrt[iz][1],xsStrt[iz][0]) # Label the start of the cross section
                    xyT = (-25,-25)
                else:
                    xyP = (xsEnd[iz][1],xsEnd[iz][0]) # Label the end of the cross section
                    xyT = (-25,25)
                plt.annotate(str(iz+1),xy=xyP,xytext=xyT,zorder=10,transform=proj,
                            textcoords='offset points',fontsize=13,color='k',
                            bbox=dict(boxstyle="round", fc="w",alpha=0.7,pad=0.04),
                            arrowprops=dict(fc='w',ec='k',alpha=0.7,shrink=0.05,width=2,headwidth=8,headlength=8))
                if iz == len(xsStrt)-1:
                    lbls.append('{} - ({:.2f},{:.2f})-({:.2f},{:.2f})'.format(iz+1,xsStrt[iz][0],xsStrt[iz][1],
                                                                              xsEnd[iz][0],xsEnd[iz][1]))
                else:
                    lbls.append('{} - ({:.2f},{:.2f})-({:.2f},{:.2f})\n'.format(iz+1,xsStrt[iz][0],xsStrt[iz][1],
                                                                                xsEnd[iz][0],xsEnd[iz][1]))

            lblStr = ''.join(lbls)
            plt.text(0.99,0.99,lblStr,ha='right',va='top',transform=ax.transAxes,
                     bbox=dict(boxstyle='square',fc='w',ec='k',pad=0.15,alpha=0.75))
            xsStrng = 'multXS'
        else:
            xsLat,xsLon,dRnd,hdng = xsCalc(xsStrt[0][0],xsStrt[0][1],xsEnd[0][0],xsEnd[0][1])
            ax.plot(xsLon,xsLat,transform=proj,linestyle='-',linewidth=2,color='k')
            xsStrng = '{:.0f}{:.0f}-{:.0f}{:.0f}'.format(xsStrt[0][0]*10,xsStrt[0][1]*-10,
                                                       xsEnd[0][0]*10,xsEnd[0][1]*-10)
            
        if noBorder:
            if strmRel:
                saveStr = '{}NB_{}{}_{}_{}-SR_{:.1f}km_{}.{}'.format(savePath,dtSave,runIdSv,'map',pltVarLbl,lev,xsStrng,fType)
                fig.savefig(saveStr,bbox_inches='tight',pad_inches=0)
            if strmRel:
                saveStr = '{}NB_{}{}_{}_{}_{:.1f}km_{}.{}'.format(savePath,dtSave,runIdSv,'map',pltVarLbl,lev,xsStrng,fType)
                fig.savefig(saveStr,bbox_inches='tight',pad_inches=0)
        else:
            if strmRel:
                saveStr = '{}{}{}_{}_{}-SR_{:.1f}km_{}.{}'.format(savePath,dtSave,runIdSv,'map',pltVarLbl,lev,
                                                                                       xsStrng,fType)
            else:
                saveStr = '{}{}{}_{}_{}_{:.1f}km_{}.{}'.format(savePath,dtSave,runIdSv,'map',pltVarLbl,lev,
                                                                                       xsStrng,fType)
            fig.savefig(saveStr,bbox_inches='tight')
        
    else: 
        if noBorder:
            saveStr = '{}NB_{}{}_{}_{}_{:.1f}km.{}'.format(savePath,dtSave,runIdSv,'map',pltVarLbl,lev,fType)
            fig.savefig(saveStr,bbox_inches='tight',pad_inches=0)
    
        else:
            saveStr = '{}{}{}_{}_{}_{:.1f}km.{}'.format(savePath,dtSave,runIdSv,'map',pltVarLbl,lev,fType)
            fig.savefig(saveStr,bbox_inches='tight')
    
    
    if saveKML:
        kmlSaveStr = '{}NB_{}{}_{}_{}_{:.1f}km.kmz'.format(savePath,dtSave,runIdSv,'map',pltVarLbl,lev)
        makeKML(lon.min(),lat.min(),lon.max(),lat.max(),figs=[saveStr],kmzfile=kmlSaveStr)
        os.remove(saveStr)


    plt.close()

"""
Explanation: planContour
Takes a given variable and variable label and using other parameters defined in this notebook, creates plan view contour plots.
End of explanation
"""


def xsContour(pltVar,pltVarLbl,xsStrtTmp,xsEndTmp,xsIX):
    
    lonDiff = np.abs(xsEndTmp[1]-xsStrtTmp[1])
    latDiff = np.abs(xsEndTmp[0]-xsStrtTmp[0])
    
    if latDiff >= lonDiff:
        xCrd = 'lat'
    else:
        xCrd = 'lon'
    
    fig,ax = plotXS(pltVar,lon,lat,alt,u,v,w,xsStrtTmp,xsEndTmp,
                  pltFlag=pltVarLbl,dT=dT,leafSz=leafSz,runId=runId,
                  vecPlt=pltVecXS,figsize=(15,5),xCrd=xCrd,strmRel=strmRel)
    
    if strmRel:
        saveStr = '{}{}{}_{}-SR_{}-{}_{:.0f}{:.0f}-{:.0f}{:.0f}.{}'.format(savePath,dtSave,runIdSv,pltVarLbl,'XS',xsIX+1,
                                                                      xsStrtTmp[0]*10,xsStrtTmp[1]*-10,
                                                                      xsEndTmp[0]*10,xsEndTmp[1]*-10,
                                                                       fType)
    else:
        saveStr = '{}{}{}_{}_{}-{}_{:.0f}{:.0f}-{:.0f}{:.0f}.{}'.format(savePath,dtSave,runIdSv,pltVarLbl,'XS',xsIX+1,
                                                                      xsStrtTmp[0]*10,xsStrtTmp[1]*-10,
                                                                      xsEndTmp[0]*10,xsEndTmp[1]*-10,
                                                                       fType)
    fig.savefig(saveStr,bbox_inches='tight')
    plt.close()

"""
Explanation: xsContour
Takes a given variable, variable label, cross-section start/end points, and using other parameters defined in this notebook, creates cross-section contour plots.
End of explanation
"""


flight = '20150706'

# outPrefix = 'S3P6_D7D8_fsdabr'
# outPrefix = 'P3S1_fsdabr'

outPrefix = '0317_SR1-XP-D8-FSD'
# outPrefix = '0322_SR1-XP-D8-FSD'


strmRel = False
if 'P3S1' in outPrefix:
    strmU = 5.23
    strmV = -3.26
elif 'S3P6' in outPrefix:
    strmU = 6.235
    strmV = -3.6

fType = 'png'

samPrefix = '/Users/danstechman/GoogleDrive/PECAN-Data/samurai/' + flight + '/'
samFile = samPrefix + outPrefix + '/output/samurai_XYZ_analysis.nc'
flFile = '/Users/danstechman/GoogleDrive/PECAN-Data/FlightLevelData/Processed/' + flight + '_FltLvl_Processed.nc'
gribFile = '/Users/danstechman/GoogleDrive/PECAN-Data/model/RAP/20150706/rap_130_20150706_0400_000.nc'

dtDir = True # If True, create a directory named based on current date/time for figure output

if dtDir:
    dtNow = dt.strftime(dt.now(),'%Y%m%d_%H%M')
    savePath = samPrefix + outPrefix + '/figs/' + dtNow + '/'
else:
    savePath = samPrefix + outPrefix + '/figs/'


# Import SAMURAI data
samData = samImport(samFile)

"""
Explanation: Case Selection / File Locations
outPrefix is the name of the directory where the SAMURAI output is located
samFile is the full path pointing to the SAMURAI analysis file
flFile is the full path pointing to the flight-level data (if used)
End of explanation
"""


if 'S3P6' in outPrefix:
#     xsStrt = [(43.321,-97.841)]#,(43.2,-98.1),(43.317,-97.52) ]
#     xsEnd = [(44.214,-98.298)]#,(44.4,-98.1),(44.063,-97.949)]
#     xsEnd = [(44.143,-98.395)]
#     xsStrt = [(43.31,-97.92)]
    
    # Generate a number of parallel cross-sections spaced at a given interval
    # starting at some initial set of XS start/end points
    dists = np.arange(1,30)
    
    initLatStrt = 44.1
    initLonStrt = -98.576
    initLatEnd = 43.275
    initLonEnd = -98.051

    xsStrt = []
    xsEnd = []

    for d in dists:
        newLatStrt,newLonStrt = multXSCrdCalc(initLatStrt,initLonStrt,d,50.4)
        xsStrt.append((newLatStrt,newLonStrt))
        
        newLatEnd,newLonEnd = multXSCrdCalc(initLatEnd,initLonEnd,d,50.4)
        xsEnd.append((newLatEnd,newLonEnd))
    
elif 'P3S1' in outPrefix:
    xsStrt = [(44.86789,-97.50534)] #Mid of spiral
    xsEnd = [(44.35309,-96.9209)]

    # Generate a number of parallel cross-sections spaced at a given interval
    # starting at some initial set of XS start/end points
#     dists = np.arange(1,30)
    
#     initLatStrt = 44.782
#     initLonStrt = -97.652
#     initLatEnd = 44.2672
#     initLonEnd = -97.0663

#     xsStrt = []
#     xsEnd = []

#     for d in dists:
#         newLatStrt,newLonStrt = multXSCrdCalc(initLatStrt,initLonStrt,d,50.4)
#         xsStrt.append((newLatStrt,newLonStrt))
        
#         newLatEnd,newLonEnd = multXSCrdCalc(initLatEnd,initLonEnd,d,50.4)
#         xsEnd.append((newLatEnd,newLonEnd))

"""
Explanation: Cross-section location(s)
If specifying multiple cross-sections, format the xsStrt/xsEnd vars as lists of tuples (e.g., xsStrt = [(43.2,-97.9), (43.3,-97.8), ...])
Here, it is important to double check that the winds within the plane of the cross-section(s) match what is expected based on those seen in the PPI(s). If winds appear to be opposite of those expected, swap the initial and final XS points. (Still trying to find a way to implement automatic checks for this.)
End of explanation
"""


plotPlanViews = True

plotXSloc     = False
pltVec        = True
pltGRlocs     = True
pltFT         = False
pltRAP        = False

unifyBnds     = False

noBorder      = False
saveKML       = False

pltDBZ  = True
pltU    = True
pltV    = True
pltW    = True
pltVort = False
pltWndSpd = False

### Plan view plot settings ###
if plotPlanViews:
    pltLevs = samData['alt'][2::2]
#     pltLevs = [3]

    # These map boundaries will place all of the above runs within a unified map boundary
    if unifyBnds:
        unifiedMapBnds = [-99.3,-97.1,43.1,45.0]

    # Provide locations and label names for ground radars if plotting
    if pltGRlocs:
        # Ground-based radar names and locations
        if outPrefix == 'S3P6_D7D8_fsdabr':
            grTxt = ['FSD','ABR','D7','D8']
            latGR = [43.583,45.451,43.3864,43.1597]
            lonGR = [-96.724,-98.408,-97.7197,-97.6374]
        elif outPrefix == '0317_SR1-XP-D8-FSD':
            grTxt = ['S1','XP','D8','FSD']
            latGR = [43.5243,43.3284,43.1597,43.583]
            lonGR = [-98.0047,-97.3252,-97.6374,-96.724]
        else:
            print('No ground radar locations specified. Setting pltGRlocs to False')
            pltGRlocs = False

    # Get start/end times for flight tracks
    # For the data index of pddSprlTimes, use (leg/sprl # - 1).
    # Need to redo this section to better handle different cases
    if pltFT:
        pddSprlTimes = np.load('/Users/danstechman/GoogleDrive/School/Research/PECAN/Radar/code/samuraiAnalysis/pecan_PDD-Sprl_times/20150706_pddSprl_times.npy')[()]
        # PDD 6
        if 'P6' in outPrefix and 'S3P6' not in outPrefix:
            flS = pddSprlTimes['I20P_strtDT'][5]
            flE = pddSprlTimes['I20P_endDT'][5]

        # Spiral 3    
        elif 'S3' in outPrefix and not any(val in outPrefix for val in ('S3P6','prl')):# 'S3P6' not in outPrefix and 'prl':
            flS = pddSprlTimes['I20S_strtDT'][2]
            flE = pddSprlTimes['I20S_endDT'][2]

        # Spiral3/PDD6 combo
        elif 'S3P6' in outPrefix:
            flS = pddSprlTimes['I20P_strtDT'][5]
            flE = pddSprlTimes['I20S_endDT'][2]

        #Purl 1 from Spiral 3:
        elif 'prl1' in outPrefix:
            flS = dt.strptime('20150706-042710','%Y%m%d-%H%M%S')
            flE = dt.strptime('20150706-043152','%Y%m%d-%H%M%S')

        else:
            raise ValueError('Unknown FL path start/end datetimes')
        
        
        
        if 'P3S1' in outPrefix:
            # PDD3/Spiral1 combo
            flS = pddSprlTimes['I20P_strtDT'][2]
            flE = pddSprlTimes['I20S_endDT'][0]
        
        else:
            raise ValueError('FL path start/end datetimes undefined for chosen case')

"""
Explanation: Plan View Plot Controls
Specify whether you want plan view plots, and if so, which variables to plot, at what levels, and with which options enabled.
End of explanation
"""


plotXScts = False

pltDBZx  = True
pltUx    = False
pltVx    = False
pltWx    = False
pltVortX = False
pltWndSpdX = False

# How many points to average into the cross-section from both sides?
leafSz = 15

# Plot vectors?
pltVecXS = True

"""
Explanation: Cross-Section Plot Controls
Specify whether you want cross-section plots, and if so, which variables to plot, and with which options enabled.
End of explanation
"""


# Import data from SAMURAI file
dT = samData['time']
dbz = samData['dbz']
u = samData['u']
v = samData['v']
w = samData['w']
vort = samData['vort']
lat = samData['lat']
lon = samData['lon']
alt = samData['alt']

wndSpd = np.sqrt(np.square(u)+np.square(v))

if strmRel:
    u = u-strmU
    v = v-strmV

# Set map boundary settings
if unifyBnds:
    zoom = True
    mapBnds = unifiedMapBnds
else:
    zoom = False
    mapBnds = None
    
    
# Check to make sure we're creating borderless figures if saving KML files
if saveKML and not noBorder:
    print('\'No border\' must be True if saving KML. Setting noBorder equal to True...')
    noBorder = True


# Make the runID and datetime filename-friendly
if not pltRAP:
    runId = outPrefix
else:
    runId = outPrefix + '_rapOvr'
    
    # Import model (RAP) data if desired and match levels
    gribData = gribImport(gribFile)
    rapLevIx = gribLevs(pltLevs,gribData['geoHght'])

runIdSv = '_' + runId.replace('_','-')

if dT is not None:
    dtSave = dt.strftime(dT,'%Y%m%d_%H%M')
else:
    dtSave = 'unknownDT'


# Import FL data if plotting the flight track
if pltFT and plotPlanViews:
    flData = getFLpathData(flFile,pathStrt=flS,pathEnd=flE,crdsOnly=True)
    flLat = flData['lat']
    flLon = flData['lon']
    


# Make the output figure directory if it doesn't exist
if not os.path.exists(savePath):
    os.makedirs(savePath)

"""
Explanation: <font color='blue'>End of commonly modified code/variables</font>
Import Data / Initialize File Saving Parameters
End of explanation
"""


if plotPlanViews:

    for ix in range(0,len(pltLevs)):
        lev = pltLevs[ix]

        print('Now plotting plan views at {:.2f} km ({} of {})...'.format(lev,ix+1,len(pltLevs)))

        if pltDBZ:
            planContour(dbz,'dbz')
        if pltU:
            planContour(u,'u')
        if pltV:
            planContour(v,'v')
        if pltW:
            planContour(w,'w')
        if pltVort:
            planContour(vort,'vort')
        if pltWndSpd:
            planContour(wndSpd,'wind')

"""
Explanation: Generate all desired plan view plots
End of explanation
"""


if plotXScts:

    for ix in range(0,len(xsStrt)):

        xsStrtTmp = xsStrt[ix]
        xsEndTmp = xsEnd[ix]
        print('Now plotting cross-section between ({:.2f},{:.2f}) and ({:.2f},{:.2f}) ({} of {})...'.format(xsStrtTmp[0],xsStrtTmp[1],
                                                                                                            xsEndTmp[0],xsEndTmp[1],
                                                                                                            ix+1,len(xsStrt)))

        if pltDBZx:
            xsContour(dbz,'dbz',xsStrtTmp,xsEndTmp,ix)
        if pltUx:
            xsContour(u,'u',xsStrtTmp,xsEndTmp,ix)
        if pltVx:
            xsContour(v,'v',xsStrtTmp,xsEndTmp,ix)
        if pltWx:
            xsContour(w,'w',xsStrtTmp,xsEndTmp,ix)
        if pltVortX:
            xsContour(vort,'vort',xsStrtTmp,xsEndTmp,ix)
        if pltWndSpdX:
            xsContour(wndSpd,'wind',xsStrtTmp,xsEndTmp,ix)

"""
Explanation: Generate all desired cross-section plots
End of explanation
"""


