Beispiel #1
0
  def __call__(self, x, y, inverse=False, coords=None):
    from models import aacgm
    from copy import deepcopy
    import numpy as np
    import inspect

    if coords is not None and coords not in self._coordsDict:
      print 'Invalid coordinate system given in coords ({}): setting "{}"'.format(coords, self.coords)
      coords = None

    if coords and coords != self.coords:
      trans = coords+'-'+self.coords
      if trans in ['geo-mag','mag-geo']:
        flag = 0 if trans == 'geo-mag' else 1
        try:
          nx, ny = len(x), len(y)
          xt = np.array(x)
          yt = np.array(y)
          shape = xt.shape    
          y, x, _ = aacgm.aacgmConvArr(list(yt.flatten()), list(xt.flatten()), [0.]*nx, flag)
          x = np.array(x).reshape(shape)
          y = np.array(y).reshape(shape)
        except TypeError as e:
          y, x, _ = aacgm.aacgmConv(y, x, 0., flag)


    if self.coords is 'geo':
      return basemap.Basemap.__call__(self, x, y, inverse=inverse)

    elif self.coords is 'mag':
      try:
        callerFile, _, callerName = inspect.getouterframes(inspect.currentframe())[1][1:4]
      except: 
        return basemap.Basemap.__call__(self, x, y, inverse=inverse)
      if isinstance(y, float) and abs(y) == 90.:
        return basemap.Basemap.__call__(self, x, y, inverse=inverse)
      if 'mpl_toolkits' in callerFile and callerName is '_readboundarydata':
        if not inverse:
          try:
            nx, ny = len(x), len(y)
            x = np.array(x)
            y = np.array(y)
            shape = x.shape
            yout, xout, _ = aacgm.aacgmConvArr(list(y.flatten()), list(x.flatten()), [0.]*nx, 0)
            xout = np.array(xout).reshape(shape)
            yout = np.array(yout).reshape(shape)
          except TypeError:
            yout, xout, _ = aacgm.aacgmConv(y, x, 0., 0)
          return basemap.Basemap.__call__(self, xout, yout, inverse=inverse)
        else:
          return basemap.Basemap.__call__(self, x, y, inverse=inverse)
      else:
        return basemap.Basemap.__call__(self, x, y, inverse=inverse)

    elif self.coords is 'mlt':
      print 'Not implemented'
      callerFile, _, callerName = inspect.getouterframes(inspect.currentframe())[1][1:4]
Beispiel #2
0
  def __init__(self, datetime=None, coords='geo', 
    projection='stere', resolution='c', dateTime=None, 
    lat_0=None, lon_0=None, boundinglat=None, width=None, height=None, 
    fillContinents='.8', fillOceans='None', fillLakes=None, coastLineWidth=0., 
    grid=True, gridLabels=True, showCoords=True, **kwargs):
    """Create empty map 
    
    **Args**:    
      * **[width, height]**: width and height in m from the (lat_0, lon_0) center
      * **[lon_0]**: center meridian (default is -70E)    
      * **[lat_0]**: center latitude (default is -90E)
      * **[boundingLat]**: bounding latitude (default it +/-20)    
      * **[grid]**: show/hide parallels and meridians grid    
      * **[fill_continents]**: continent color. Default is 'grey'    
      * **[fill_water]**: water color. Default is 'None'    
      * **[coords]**: 'geo'
      * **[showCoords]**: display coordinate system name in upper right corner
      * **[dateTime]** (datetime.datetime): necessary for MLT plots if you want the continents to be plotted
      * **[kwargs]**: See <http://tinyurl.com/d4rzmfo> for more keywords
    **Returns**:
      * **map**: a Basemap object (<http://tinyurl.com/d4rzmfo>)
    **Example**:
      ::

        myMap = mapObj(lat_0=50, lon_0=-95, width=111e3*60, height=111e3*60)
        
    written by Sebastien, 2013-02
    """
    from models import aacgm
    import numpy as np
    from pylab import text
    import math
    from copy import deepcopy

    self._coordsDict = {'mag': 'AACGM',
              'geo': 'Geographic',
              'mlt': 'MLT'}

    if coords is 'mlt':             
      print 'MLT coordinates not implemented yet.'
      return

    # Add an extra member to the Basemap class
    if coords is not None and coords not in self._coordsDict:
      print 'Invalid coordinate system given in coords ({}): setting "geo"'.format(coords)
      coords = 'geo'
    self.coords = coords

    # Set map projection limits and center point depending on hemisphere selection
    if lat_0 is None: 
      lat_0 = 90.
      if boundinglat: lat_0 = math.copysign(lat_0, boundinglat)
    if lon_0 is None: 
      lon_0 = -100.
      if self.coords == 'mag': 
        _, lon_0, _ = aacgm.aacgmConv(0., lon_0, 0., 0)
    if boundinglat:
      width = height = 2*111e3*( abs(lat_0 - boundinglat) )

    # Initialize map
    super(mapObj, self).__init__(projection=projection, resolution=resolution, 
        lat_0=lat_0, lon_0=lon_0, width=width, height=height, **kwargs)

    # Add continents
    if coords is not 'mlt' or dateTime is not None:
      _ = self.drawcoastlines(linewidth=coastLineWidth)
      # self.drawmapboundary(fill_color=fillOceans)
      _ = self.fillcontinents(color=fillContinents, lake_color=fillLakes)

    # Add coordinate spec
    if showCoords:
      _ = text(self.urcrnrx, self.urcrnry, self._coordsDict[coords]+' coordinates', 
          rotation=-90., va='top', fontsize=8)

    # draw parallels and meridians.
    if grid:
      parallels = np.arange(-80.,81.,20.)
      out = self.drawparallels(parallels, color='.6', zorder=10)
      # label parallels on map
      if gridLabels: 
        lablon = int(self.llcrnrlon/10)*10
        rotate_label = lablon - lon_0 if lat_0 >= 0 else lon_0 - lablon + 180.
        x,y = basemap.Basemap.__call__(self, lablon*np.ones(parallels.shape), parallels)
        for ix,iy,ip in zip(x,y,parallels):
          if not self.xmin <= ix <= self.xmax: continue
          if not self.ymin <= iy <= self.ymax: continue
          _ = text(ix, iy, r"{:3.0f}$^\circ$".format(ip), 
              rotation=rotate_label, va='center', ha='center', zorder=10, color='.4')
      # label meridians on bottom and left
      meridians = np.arange(-180.,181.,20.)
      if gridLabels: 
        merLabels = [False,False,False,True]
      else: 
        merLabels = [False,False,False,False]
      # draw meridians
      out = self.drawmeridians(meridians, labels=merLabels, color='.6', zorder=10)
Beispiel #3
0
def plotFan(sTime,rad,interval=60,fileType='fitex',param='velocity',filtered=False ,\
        scale=[],channel='a',coords='geo',colors='lasse',gsct=False,fov=True,edgeColors='face',lowGray=False,fill=True,\
        velscl=1000.,legend=True,overlayPoes=False,poesparam='ted',poesMin=-3.,poesMax=0.5, \
        poesLabel=r"Total Log Energy Flux [ergs cm$^{-2}$ s$^{-1}$]",overlayBnd=False, \
        show=True,png=False,pdf=False,dpi=500,tFreqBands=[]):

    """A function to make a fan plot
    
    **Args**:
        * **sTime** (`datetime <http://tinyurl.com/bl352yx>`_): the start time you want to plot
        * **rad** (list): a list of 3 letter radar codes, e.g. ['bks'], e.g. ['bks','wal','gbr']
        * **[interval]** (int): the the time period to be plotted, in seconds.  default = 60
        * **[fileType]** (str): the file type to plot, valid inputs are 'fitex','fitacf', 'lmfit'.  default = 'fitex'
        * **[param]** (str): the parameter to be plotted, valid inputs are 'velocity', 'power', 'width', 'elevation', 'phi0'.  default = 'velocity'
        * **[filtered]** (boolean): a flag indicating whether the data should be boxcar filtered.  default = False
        * **[scale]** (list): the min and max values of the color scale, i.e. [min,max].  If this is set to [], then default values will be used
        * **[channel] (char)**: the channel for which to plot data.  default = 'a'
        * **[coords]** (str): the coordinate system to use, valid inputs are 'geo', 'mag'.  default = 'geo'
        * **[colors]** (str): the color map to use, valid inputs are 'lasse', 'aj'.  default = 'lasse'
        * **[gsct]** (boolean): a flag indicating whether to plot ground scatter as gray.  default = False
        * **[fov]**  (boolean): a flag indicating whether to overplot the radar fields of view.  default = True
        * **[edgeColors]** (str): edge colors of the polygons, default = 'face'
        * **[lowGray]** (boolean): a flag indicating whether to plot low velocities in gray.  default = False
        * **[fill]** (boolean): a flag indicating whether to plot filled or point RB cells.  default = True
        * **[velscl]** (float): the velocity to use as baseline for velocity vector length, only applicable if fill = 0.  default = 1000
        * **[legend]** (boolean): a flag indicating whether to plot the legend, only applicable if fill = 0.  default = True
        * **[overlayPoes]** (boolean): a flag indicating whether to overlay poes data.  default = False
        * **[poesparam]** (str): the poes parameter to plot.  default = 'ted'.  available params can be found in :class:`gme.sat.poes.poesRec`
        * **[poesMin]** (float): the min value for the poes data color scale.  default = -3.
        * **[poesMax]**  (float): the max value for the poes data color scale.  default = 0.5
        * **[poesLabel]** (str): the label for the poes color bar.  default = r"Total Log Energy Flux [ergs cm$^{-2}$ s$^{-1}$]"
        * **[overlayBnd]** (boolean): a flag indicating whether to plot an auroral boundary determined from fitting poes data.  default = False
        * **[show]** (boolean): a flag indicating whether to display the figure on the screen.  This can cause problems over ssh.  default = True
        * **[pdf]** (boolean): a flag indicating whether to output to a pdf file.  default = False.  WARNING: saving as pdf is slow
        * **[png]** (boolean): a flag indicating whether to output to a png file.  default = False
        * **[dpi]** (int): dots per inch if saving as png.  default = 300
        * **[tFreqBands]** (list): upper and lower bounds of frequency in kHz to be used.  Must be unset (or set to []) or have a pair for each radar, and for any band set to [] the default will be used.  default = [[8000,20000]], [[8000,20000],[8000,20000]], etc.
    **Returns**:
        * Nothing

    **Example**:
        ::
        
            import datetime as dt
            pydarn.plotting.fan.plotFan(dt.datetime(2013,3,16,16,30),['fhe','fhw'],param='power',gsct=True)
            pydarn.plotting.fan.plotFan(dt.datetime(2013,3,16,16,30),['fhe','fhw'],param='power',gsct=True,tFreqBands=[[10000,11000],[]])

    Written by AJ 20121004
    Modified by Matt W. 20130717
    """

    
    import datetime as dt, gme, pickle
    from matplotlib.backends.backend_pdf import PdfPages
    import models.aacgm as aacgm, os, copy
    tt = dt.datetime.now()
    
    #check the inputs
    assert(isinstance(sTime,dt.datetime)),'error, sTime must be a datetime object'
    assert(isinstance(rad,list)),"error, rad must be a list, eg ['bks'] or ['bks','fhe']"
    for r in rad:
        assert(isinstance(r,str) and len(r) == 3),'error, elements of rad list must be 3 letter strings'
    assert(coords == 'geo' or coords == 'mag'),"error, coords must be one of 'geo' or 'mag'"
    assert(param == 'velocity' or param == 'power' or param == 'width' or \
        param == 'elevation' or param == 'phi0'), \
        "error, allowable params are 'velocity','power','width','elevation','phi0'"
    assert(scale == [] or len(scale)==2), \
    'error, if present, scales must have 2 elements'
    assert(colors == 'lasse' or colors == 'aj'),"error, valid inputs for color are 'lasse' and 'aj'"
    
    #check freq band and set to default if needed
    assert(tFreqBands == [] or len(tFreqBands) == len(rad)),'error, if present, tFreqBands must have same number of elements as rad'
    tbands = []
    for i in range(len(rad)):
        if tFreqBands == [] or tFreqBands[i] == []: tbands.append([8000,20000])
        else: tbands.append(tFreqBands[i])

    for i in range(len(tbands)):
        assert(tbands[i][1] > tbands[i][0]),'error, frequency upper bound must be > lower bound'

    if(scale == []):
        if(param == 'velocity'): scale=[-200,200]
        elif(param == 'power'): scale=[0,30]
        elif(param == 'width'): scale=[0,150]
        elif(param == 'elevation'): scale=[0,50]
        elif(param == 'phi0'): scale=[-numpy.pi,numpy.pi]

        
    fbase = sTime.strftime("%Y%m%d")
        
    cmap,norm,bounds = utils.plotUtils.genCmap(param,scale,colors=colors,lowGray=lowGray)
    
    #open the data files
    myFiles = []
    myBands = []
    for i in range(len(rad)):
        f = radDataOpen(sTime,rad[i],sTime+datetime.timedelta(seconds=interval),fileType=fileType,filtered=filtered,channel=channel)
        if(f != None): 
            myFiles.append(f)
            myBands.append(tbands[i])


    assert(myFiles != []),'error, no data available for this period'

    xmin,ymin,xmax,ymax = 1e16,1e16,-1e16,-1e16

    allBeams = [''] * len(myFiles)
    sites,fovs,oldCpids,lonFull,latFull=[],[],[],[],[]
    lonC,latC = [],[]

    #go through all open files
    for i in range(len(myFiles)):
        #read until we reach start time
        allBeams[i] = radDataReadRec(myFiles[i])
        while (allBeams[i].time < sTime and allBeams[i] != None):
            allBeams[i] = radDataReadRec(myFiles[i])

        #check that the file has data in the target interval
        if(allBeams[i] == None): 
            myFiles[i].close()
            myFiles[i] = None
            continue

    
        #get to field of view coords in order to determine map limits
        t=allBeams[i].time
        site = pydarn.radar.site(radId=allBeams[i].stid,dt=t)
        sites.append(site)
        if(coords == 'geo'):           #make a list of site lats and lons
            latFull.append(site.geolat)
            lonFull.append(site.geolon)
            latC.append(site.geolat)     #latC and lonC are used for figuring out
            lonC.append(site.geolon)     #where the map should be centered.
        elif(coords == 'mag'):
            x = aacgm.aacgmConv(site.geolat,site.geolon,0.,t.year,0)
            latFull.append(x[0])
            lonFull.append(x[1])
            latC.append(x[0])
            lonC.append(x[1])
        myFov = pydarn.radar.radFov.fov(site=site,rsep=allBeams[i].prm.rsep,\
                        ngates=allBeams[i].prm.nrang+1,nbeams=site.maxbeam,coords=coords)
        fovs.append(myFov)
        for b in range(0,site.maxbeam+1):
            for k in range(0,allBeams[i].prm.nrang+1):
                lonFull.append(myFov.lonFull[b][k])
                latFull.append(myFov.latFull[b][k])
        oldCpids.append(allBeams[i].cp)
        
        k=allBeams[i].prm.nrang
        b=0
        latC.append(myFov.latFull[b][k])
        lonC.append(myFov.lonFull[b][k])
        b=site.maxbeam
        latC.append(myFov.latFull[b][k])
        lonC.append(myFov.lonFull[b][k])

    #Now that we have 3 points from the FOVs of the radars, calculate the lat,lon pair
    #to center the map on. We can simply do this by converting from Spherical coords
    #to Cartesian, taking the mean of each coordinate and then converting back
    #to get lat_0 and lon_0
    lonC,latC = (numpy.array(lonC)+360.)%360.0,numpy.array(latC)
    xs=numpy.cos(numpy.deg2rad(latC))*numpy.cos(numpy.deg2rad(lonC))
    ys=numpy.cos(numpy.deg2rad(latC))*numpy.sin(numpy.deg2rad(lonC))
    zs=numpy.sin(numpy.deg2rad(latC))
    xc=numpy.mean(xs)
    yc=numpy.mean(ys)
    zc=numpy.mean(zs)
    lon_0=numpy.rad2deg(numpy.arctan2(yc,xc))
    lat_0=numpy.rad2deg(numpy.arctan2(zc,numpy.sqrt(xc*xc+yc*yc)))

    #Now do some stuff in map projection coords to get necessary width and height of map
    #and also figure out the corners of the map
    t1=dt.datetime.now()
    lonFull,latFull = (numpy.array(lonFull)+360.)%360.0,numpy.array(latFull)

    tmpmap = utils.mapObj(coords=coords,projection='stere', width=10.0**3, 
                                                height=10.0**3, lat_0=lat_0, lon_0=lon_0)
    x,y = tmpmap(lonFull,latFull)
    minx = x.min()*1.05     #since we don't want the map to cut off labels or
    miny = y.min()*1.05     #FOVs of the radars we should alter the extrema a bit.
    maxx = x.max()*1.05
    maxy = y.max()*1.05
    width = (maxx-minx)
    height = (maxy-miny)
    llcrnrlon,llcrnrlat = tmpmap(minx,miny,inverse=True)
    urcrnrlon,urcrnrlat = tmpmap(maxx,maxy,inverse=True)

    dist = width/50.
    cTime = sTime

    myFig = plot.figure(figsize=(12,8))
    
    #draw the actual map we want
    myMap = utils.mapObj(coords=coords, projection='stere', lat_0=lat_0, lon_0=lon_0,
                                             llcrnrlon=llcrnrlon, llcrnrlat=llcrnrlat, urcrnrlon=urcrnrlon,
                                             urcrnrlat=urcrnrlat)
    myMap.drawparallels(numpy.arange(-80.,81.,10.),labels=[1,0,0,0])
    myMap.drawmeridians(numpy.arange(-180.,181.,20.),labels=[0,0,0,1])
    #if(coords == 'geo'):
    myMap.drawcoastlines(linewidth=0.5,color='k')
    myMap.drawmapboundary(fill_color='w')
    myMap.fillcontinents(color='w', lake_color='w')
    #overlay fields of view, if desired
    if(fov == 1):
        for i,r in enumerate(rad):
            pydarn.plotting.overlayRadar(myMap, codes=r, dateTime=sTime)
            #this was missing fovObj! We need to plot the fov for this particular sTime.
            pydarn.plotting.overlayFov(myMap, codes=r, dateTime=sTime, fovObj=fovs[i]) 
    
    print dt.datetime.now()-t1
    #manually draw the legend
    if((not fill) and legend):
        #draw the box
        y = [myMap.urcrnry*.82,myMap.urcrnry*.99]
        x = [myMap.urcrnrx*.86,myMap.urcrnrx*.99]
        verts = [x[0],y[0]],[x[0],y[1]],[x[1],y[1]],[x[1],y[0]]
        poly = patches.Polygon(verts,fc='w',ec='k',zorder=11)
        myFig.gca().add_patch(poly)
        labs = ['5 dB','15 dB','25 dB','35 dB','gs','1000 m/s']
        pts = [5,15,25,35]
        #plot the icons and labels
        for w in range(6):
            myFig.gca().text(x[0]+.35*(x[1]-x[0]),y[1]*(.98-w*.025),labs[w],zorder=15,color='k',size=8,va='center')
            xctr = x[0]+.175*(x[1]-x[0])
            if(w < 4):
                myFig.scatter(xctr,y[1]*(.98-w*.025),s=.1*pts[w],zorder=15,marker='o',linewidths=.5,\
                edgecolor='face',facecolor='k')
            elif(w == 4):
                myFig.scatter(xctr,y[1]*(.98-w*.025),s=.1*35.,zorder=15,marker='o',\
                linewidths=.5,edgecolor='k',facecolor='w')
            elif(w == 5):
                y=LineCollection(numpy.array([((xctr-dist/2.,y[1]*(.98-w*.025)),(xctr+dist/2.,y[1]*(.98-w*.025)))]),linewidths=.5,zorder=15,color='k')
                myFig.gca().add_collection(y)
                
    bbox = myFig.gca().get_axes().get_position()
    #now, loop through desired time interval

    tz = dt.datetime.now()
    cols = []
    bndTime = sTime + datetime.timedelta(seconds=interval)
    
    ft = 'None'
    #go though all files
    pcoll = None
    for i in range(len(myFiles)):
        scans = []
        #check that we have good data at this time
        if(myFiles[i] == None or allBeams[i] == None): continue
        ft = allBeams[i].fType
        #until we reach the end of the time window
        while(allBeams[i] != None and allBeams[i].time < bndTime):
            #filter on frequency
            if allBeams[i].prm.tfreq >= myBands[i][0] and allBeams[i].prm.tfreq <= myBands[i][1]: 
                scans.append(allBeams[i])
            #read the next record
            allBeams[i] = radDataReadRec(myFiles[i])
        #if there is no data in scans, overlayFan will object
        if scans == []: continue
        intensities, pcoll = overlayFan(scans,myMap,myFig,param,coords,gsct=gsct,site=sites[i],fov=fovs[i], fill=fill,velscl=velscl,dist=dist,cmap=cmap,norm=norm)

                                                                            
    #if no data has been found pcoll will not have been set, and the following code will object                                   
    if pcoll: 
        cbar = myFig.colorbar(pcoll,orientation='vertical',shrink=.65,fraction=.1,drawedges=True)
        
        l = []
        #define the colorbar labels
        for i in range(0,len(bounds)):
            if(param == 'phi0'):
                ln = 4
                if(bounds[i] == 0): ln = 3
                elif(bounds[i] < 0): ln = 5
                l.append(str(bounds[i])[:ln])
                continue
            if((i == 0 and param == 'velocity') or i == len(bounds)-1):
                l.append(' ')
                continue
            l.append(str(int(bounds[i])))
        cbar.ax.set_yticklabels(l)
        cbar.ax.tick_params(axis='y',direction='out')
        #set colorbar ticklabel size
        for ti in cbar.ax.get_yticklabels():
            ti.set_fontsize(12)
        if(param == 'velocity'): 
            cbar.set_label('Velocity [m/s]',size=14)
            cbar.extend='max'
            
        if(param == 'grid'): cbar.set_label('Velocity [m/s]',size=14)
        if(param == 'power'): cbar.set_label('Power [dB]',size=14)
        if(param == 'width'): cbar.set_label('Spec Wid [m/s]',size=14)
        if(param == 'elevation'): cbar.set_label('Elev [deg]',size=14)
        if(param == 'phi0'): cbar.set_label('Phi0 [rad]',size=14)
    
    #myFig.gca().set_rasterized(True)
    #label the plot
    tx1 = myFig.text((bbox.x0+bbox.x1)/2.,bbox.y1+.02,cTime.strftime('%Y/%m/%d'),ha='center',size=14,weight=550)
    tx2 = myFig.text(bbox.x1+.02,bbox.y1+.02,cTime.strftime('%H:%M - ')+\
                bndTime.strftime('%H:%M      '),ha='right',size=13,weight=550)
    tx3 = myFig.text(bbox.x0,bbox.y1+.02,'['+ft+']',ha='left',size=13,weight=550)
    #label with frequency bands
    tx4 = myFig.text(bbox.x1+.02,bbox.y1,'Frequency filters:',ha='right',size=8,weight=550)
    for i in range(len(rad)):
        myFig.text(bbox.x1+.02,bbox.y1-((i+1)*.015),rad[i]+': '+\
                str(tbands[i][0]/1e3)+' - '+str(tbands[i][1]/1e3)+\
                ' MHz',ha='right',size=8,weight=550)
    
    if(overlayPoes):
        pcols = gme.sat.poes.overlayPoesTed(myMap, myFig.gca(), cTime, param=poesparam, scMin=poesMin, scMax=poesMax)
        if(pcols != None):
            cols.append(pcols)
            pTicks = numpy.linspace(poesMin,poesMax,8)
            cbar = myFig.colorbar(pcols,ticks=pTicks,orientation='vertical',shrink=0.65,fraction=.1)
            cbar.ax.set_yticklabels(pTicks)
            cbar.set_label(poesLabel,size=14)
            cbar.ax.tick_params(axis='y',direction='out')
            #set colorbar ticklabel size
            for ti in cbar.ax.get_yticklabels():
                ti.set_fontsize(12)
            
    if(overlayBnd):
        gme.sat.poes.overlayPoesBnd(myMap, myFig.gca(), cTime)

    #handle the outputs
    if png == True:
        # if not show:
        #   canvas = FigureCanvasAgg(myFig)
        myFig.savefig(sTime.strftime("%Y%m%d.%H%M.")+str(interval)+'.fan.png',dpi=dpi)
    if pdf:
        # if not show:
        #   canvas = FigureCanvasAgg(myFig)
        myFig.savefig(sTime.strftime("%Y%m%d.%H%M.")+str(interval)+'.fan.pdf')
    if show:
        myFig.show()
Beispiel #4
0
def plotFan(sTime,rad,interval=60,fileType='fitex',param='velocity',filtered=False ,\
    scale=[],channel='a',coords='geo',colors='lasse',gsct=False,fov=True,edgeColors='face',lowGray=False,fill=True,\
    velscl=1000.,legend=True,overlayPoes=False,poesparam='ted',poesMin=-3.,poesMax=0.5, \
    poesLabel=r"Total Log Energy Flux [ergs cm$^{-2}$ s$^{-1}$]",overlayBnd=False, \
    show=True,png=False,pdf=False,dpi=500,tFreqBands=[]):

  """A function to make a fan plot
  
  **Args**:
    * **sTime** (`datetime <http://tinyurl.com/bl352yx>`_): the start time you want to plot
    * **rad** (list): a list of 3 letter radar codes, e.g. ['bks'], e.g. ['bks','wal','gbr']
    * **[interval]** (int): the the time period to be plotted, in seconds.  default = 60
    * **[fileType]** (str): the file type to plot, valid inputs are 'fitex','fitacf', 'lmfit'.  default = 'fitex'
    * **[param]** (str): the parameter to be plotted, valid inputs are 'velocity', 'power', 'width', 'elevation', 'phi0'.  default = 'velocity'
    * **[filtered]** (boolean): a flag indicating whether the data should be boxcar filtered.  default = False
    * **[scale]** (list): the min and max values of the color scale, i.e. [min,max].  If this is set to [], then default values will be used
    * **[channel] (char)**: the channel for which to plot data.  default = 'a'
    * **[coords]** (str): the coordinate system to use, valid inputs are 'geo', 'mag'.  default = 'geo'
    * **[colors]** (str): the color map to use, valid inputs are 'lasse', 'aj'.  default = 'lasse'
    * **[gsct]** (boolean): a flag indicating whether to plot ground scatter as gray.  default = False
    * **[fov]**  (boolean): a flag indicating whether to overplot the radar fields of view.  default = True
    * **[edgeColors]** (str): edge colors of the polygons, default = 'face'
    * **[lowGray]** (boolean): a flag indicating whether to plot low velocities in gray.  default = False
    * **[fill]** (boolean): a flag indicating whether to plot filled or point RB cells.  default = True
    * **[velscl]** (float): the velocity to use as baseline for velocity vector length, only applicable if fill = 0.  default = 1000
    * **[legend]** (boolean): a flag indicating whether to plot the legend, only applicable if fill = 0.  default = True
    * **[overlayPoes]** (boolean): a flag indicating whether to overlay poes data.  default = False
    * **[poesparam]** (str): the poes parameter to plot.  default = 'ted'.  available params can be found in :class:`gme.sat.poes.poesRec`
    * **[poesMin]** (float): the min value for the poes data color scale.  default = -3.
    * **[poesMax]**  (float): the max value for the poes data color scale.  default = 0.5
    * **[poesLabel]** (str): the label for the poes color bar.  default = r"Total Log Energy Flux [ergs cm$^{-2}$ s$^{-1}$]"
    * **[overlayBnd]** (boolean): a flag indicating whether to plot an auroral boundary determined from fitting poes data.  default = False
    * **[show]** (boolean): a flag indicating whether to display the figure on the screen.  This can cause problems over ssh.  default = True
    * **[pdf]** (boolean): a flag indicating whether to output to a pdf file.  default = False.  WARNING: saving as pdf is slow
    * **[png]** (boolean): a flag indicating whether to output to a png file.  default = False
    * **[dpi]** (int): dots per inch if saving as png.  default = 300
    * **[tFreqBands]** (list): upper and lower bounds of frequency in kHz to be used.  Must be unset (or set to []) or have a pair for each radar, and for any band set to [] the default will be used.  default = [[8000,20000]], [[8000,20000],[8000,20000]], etc.
  **Returns**:
    * Nothing

  **Example**:
    ::
    
      import datetime as dt
      pydarn.plotting.fan.plotFan(dt.datetime(2013,3,16,16,30),['fhe','fhw'],param='power',gsct=True)
      pydarn.plotting.fan.plotFan(dt.datetime(2013,3,16,16,30),['fhe','fhw'],param='power',gsct=True,tFreqBands=[[10000,11000],[]])

  Written by AJ 20121004
  Modified by Matt W. 20130717
  """

  
  import datetime as dt, gme, pickle
  from matplotlib.backends.backend_pdf import PdfPages
  import models.aacgm as aacgm, os, copy
  tt = dt.datetime.now()
  
  #check the inputs
  assert(isinstance(sTime,dt.datetime)),'error, sTime must be a datetime object'
  assert(isinstance(rad,list)),"error, rad must be a list, eg ['bks'] or ['bks','fhe']"
  for r in rad:
    assert(isinstance(r,str) and len(r) == 3),'error, elements of rad list must be 3 letter strings'
  assert(coords == 'geo' or coords == 'mag'),"error, coords must be one of 'geo' or 'mag'"
  assert(param == 'velocity' or param == 'power' or param == 'width' or \
    param == 'elevation' or param == 'phi0'), \
    "error, allowable params are 'velocity','power','width','elevation','phi0'"
  assert(scale == [] or len(scale)==2), \
  'error, if present, scales must have 2 elements'
  assert(colors == 'lasse' or colors == 'aj'),"error, valid inputs for color are 'lasse' and 'aj'"
  
  #check freq band and set to default if needed
  assert(tFreqBands == [] or len(tFreqBands) == len(rad)),'error, if present, tFreqBands must have same number of elements as rad'
  tbands = []
  for i in range(len(rad)):
    if tFreqBands == [] or tFreqBands[i] == []: tbands.append([8000,20000])
    else: tbands.append(tFreqBands[i])

  for i in range(len(tbands)):
    assert(tbands[i][1] > tbands[i][0]),'error, frequency upper bound must be > lower bound'

  if(scale == []):
    if(param == 'velocity'): scale=[-200,200]
    elif(param == 'power'): scale=[0,30]
    elif(param == 'width'): scale=[0,150]
    elif(param == 'elevation'): scale=[0,50]
    elif(param == 'phi0'): scale=[-numpy.pi,numpy.pi]

    
  fbase = sTime.strftime("%Y%m%d")
    
  cmap,norm,bounds = utils.plotUtils.genCmap(param,scale,colors=colors,lowGray=lowGray)
  
  #open the data files
  myFiles = []
  myBands = []
  for i in range(len(rad)):
    f = radDataOpen(sTime,rad[i],sTime+datetime.timedelta(seconds=interval),fileType=fileType,filtered=filtered,channel=channel)
    if(f != None): 
      myFiles.append(f)
      myBands.append(tbands[i])


  assert(myFiles != []),'error, no data available for this period'

  xmin,ymin,xmax,ymax = 1e16,1e16,-1e16,-1e16

  allBeams = [''] * len(myFiles)
  sites,fovs,oldCpids,lonFull,latFull=[],[],[],[],[]
  lonC,latC = [],[]

  #go through all open files
  for i in range(len(myFiles)):
    #read until we reach start time
    allBeams[i] = radDataReadRec(myFiles[i])
    while (allBeams[i].time < sTime and allBeams[i] != None):
      allBeams[i] = radDataReadRec(myFiles[i])

    #check that the file has data in the target interval
    if(allBeams[i] == None): 
      myFiles[i].close()
      myFiles[i] = None
      continue

  
    #get to field of view coords in order to determine map limits
    t=allBeams[i].time
    site = pydarn.radar.site(radId=allBeams[i].stid,dt=t)
    sites.append(site)
    if(coords == 'geo'):           #make a list of site lats and lons
      latFull.append(site.geolat)
      lonFull.append(site.geolon)
      latC.append(site.geolat)     #latC and lonC are used for figuring out
      lonC.append(site.geolon)     #where the map should be centered.
    elif(coords == 'mag'):
      x = aacgm.aacgmConv(site.geolat,site.geolon,0.,0)
      latFull.append(x[0])
      lonFull.append(x[1])
      latC.append(x[0])
      lonC.append(x[1])
    myFov = pydarn.radar.radFov.fov(site=site,rsep=allBeams[i].prm.rsep,\
            ngates=allBeams[i].prm.nrang+1,nbeams=site.maxbeam,coords=coords)
    fovs.append(myFov)
    for b in range(0,site.maxbeam+1):
      for k in range(0,allBeams[i].prm.nrang+1):
        lonFull.append(myFov.lonFull[b][k])
        latFull.append(myFov.latFull[b][k])
    oldCpids.append(allBeams[i].cp)
    
    k=allBeams[i].prm.nrang
    b=0
    latC.append(myFov.latFull[b][k])
    lonC.append(myFov.lonFull[b][k])
    b=site.maxbeam
    latC.append(myFov.latFull[b][k])
    lonC.append(myFov.lonFull[b][k])

  #Now that we have 3 points from the FOVs of the radars, calculate the lat,lon pair
  #to center the map on. We can simply do this by converting from Spherical coords
  #to Cartesian, taking the mean of each coordinate and then converting back
  #to get lat_0 and lon_0
  lonC,latC = (numpy.array(lonC)+360.)%360.0,numpy.array(latC)
  xs=numpy.cos(numpy.deg2rad(latC))*numpy.cos(numpy.deg2rad(lonC))
  ys=numpy.cos(numpy.deg2rad(latC))*numpy.sin(numpy.deg2rad(lonC))
  zs=numpy.sin(numpy.deg2rad(latC))
  xc=numpy.mean(xs)
  yc=numpy.mean(ys)
  zc=numpy.mean(zs)
  lon_0=numpy.rad2deg(numpy.arctan2(yc,xc))
  lat_0=numpy.rad2deg(numpy.arctan2(zc,numpy.sqrt(xc*xc+yc*yc)))

  #Now do some stuff in map projection coords to get necessary width and height of map
  #and also figure out the corners of the map
  t1=dt.datetime.now()
  lonFull,latFull = (numpy.array(lonFull)+360.)%360.0,numpy.array(latFull)

  tmpmap = utils.mapObj(coords=coords,projection='stere', width=10.0**3, 
                        height=10.0**3, lat_0=lat_0, lon_0=lon_0)
  x,y = tmpmap(lonFull,latFull)
  minx = x.min()*1.05     #since we don't want the map to cut off labels or
  miny = y.min()*1.05     #FOVs of the radars we should alter the extrema a bit.
  maxx = x.max()*1.05
  maxy = y.max()*1.05
  width = (maxx-minx)
  height = (maxy-miny)
  llcrnrlon,llcrnrlat = tmpmap(minx,miny,inverse=True)
  urcrnrlon,urcrnrlat = tmpmap(maxx,maxy,inverse=True)

  dist = width/50.
  cTime = sTime

  myFig = plot.figure(figsize=(12,8))
  
  #draw the actual map we want
  myMap = utils.mapObj(coords=coords, projection='stere', lat_0=lat_0, lon_0=lon_0,
                       llcrnrlon=llcrnrlon, llcrnrlat=llcrnrlat, urcrnrlon=urcrnrlon,
                       urcrnrlat=urcrnrlat)
  myMap.drawparallels(numpy.arange(-80.,81.,10.),labels=[1,0,0,0])
  myMap.drawmeridians(numpy.arange(-180.,181.,20.),labels=[0,0,0,1])
  #if(coords == 'geo'):
  myMap.drawcoastlines(linewidth=0.5,color='k')
  myMap.drawmapboundary(fill_color='w')
  myMap.fillcontinents(color='w', lake_color='w')
  #overlay fields of view, if desired
  if(fov == 1):
    for i,r in enumerate(rad):
      pydarn.plotting.overlayRadar(myMap, codes=r, dateTime=sTime)
      #this was missing fovObj! We need to plot the fov for this particular sTime.
      pydarn.plotting.overlayFov(myMap, codes=r, dateTime=sTime, fovObj=fovs[i]) 
  
  print dt.datetime.now()-t1
  #manually draw the legend
  if((not fill) and legend):
    #draw the box
    y = [myMap.urcrnry*.82,myMap.urcrnry*.99]
    x = [myMap.urcrnrx*.86,myMap.urcrnrx*.99]
    verts = [x[0],y[0]],[x[0],y[1]],[x[1],y[1]],[x[1],y[0]]
    poly = patches.Polygon(verts,fc='w',ec='k',zorder=11)
    myFig.gca().add_patch(poly)
    labs = ['5 dB','15 dB','25 dB','35 dB','gs','1000 m/s']
    pts = [5,15,25,35]
    #plot the icons and labels
    for w in range(6):
      myFig.gca().text(x[0]+.35*(x[1]-x[0]),y[1]*(.98-w*.025),labs[w],zorder=15,color='k',size=8,va='center')
      xctr = x[0]+.175*(x[1]-x[0])
      if(w < 4):
        myFig.scatter(xctr,y[1]*(.98-w*.025),s=.1*pts[w],zorder=15,marker='o',linewidths=.5,\
        edgecolor='face',facecolor='k')
      elif(w == 4):
        myFig.scatter(xctr,y[1]*(.98-w*.025),s=.1*35.,zorder=15,marker='o',\
        linewidths=.5,edgecolor='k',facecolor='w')
      elif(w == 5):
        y=LineCollection(numpy.array([((xctr-dist/2.,y[1]*(.98-w*.025)),(xctr+dist/2.,y[1]*(.98-w*.025)))]),linewidths=.5,zorder=15,color='k')
        myFig.gca().add_collection(y)
        
  bbox = myFig.gca().get_axes().get_position()
  #now, loop through desired time interval

  tz = dt.datetime.now()
  cols = []
  bndTime = sTime + datetime.timedelta(seconds=interval)
  
  ft = 'None'
  #go though all files
  pcoll = None
  for i in range(len(myFiles)):
    scans = []
    #check that we have good data at this time
    if(myFiles[i] == None or allBeams[i] == None): continue
    ft = allBeams[i].fType
    #until we reach the end of the time window
    while(allBeams[i] != None and allBeams[i].time < bndTime):
      #filter on frequency
      if allBeams[i].prm.tfreq >= myBands[i][0] and allBeams[i].prm.tfreq <= myBands[i][1]: 
        scans.append(allBeams[i])
      #read the next record
      allBeams[i] = radDataReadRec(myFiles[i])
    #if there is no data in scans, overlayFan will object
    if scans == []: continue
    intensities, pcoll = overlayFan(scans,myMap,myFig,param,coords,gsct=gsct,site=sites[i],fov=fovs[i], fill=fill,velscl=velscl,dist=dist,cmap=cmap,norm=norm)

                                      
  #if no data has been found pcoll will not have been set, and the following code will object                                   
  if pcoll: 
    cbar = myFig.colorbar(pcoll,orientation='vertical',shrink=.65,fraction=.1,drawedges=True)
    
    l = []
    #define the colorbar labels
    for i in range(0,len(bounds)):
      if(param == 'phi0'):
        ln = 4
        if(bounds[i] == 0): ln = 3
        elif(bounds[i] < 0): ln = 5
        l.append(str(bounds[i])[:ln])
        continue
      if((i == 0 and param == 'velocity') or i == len(bounds)-1):
        l.append(' ')
        continue
      l.append(str(int(bounds[i])))
    cbar.ax.set_yticklabels(l)
    cbar.ax.tick_params(axis='y',direction='out')
    #set colorbar ticklabel size
    for ti in cbar.ax.get_yticklabels():
      ti.set_fontsize(12)
    if(param == 'velocity'): 
      cbar.set_label('Velocity [m/s]',size=14)
      cbar.extend='max'
      
    if(param == 'grid'): cbar.set_label('Velocity [m/s]',size=14)
    if(param == 'power'): cbar.set_label('Power [dB]',size=14)
    if(param == 'width'): cbar.set_label('Spec Wid [m/s]',size=14)
    if(param == 'elevation'): cbar.set_label('Elev [deg]',size=14)
    if(param == 'phi0'): cbar.set_label('Phi0 [rad]',size=14)
  
  #myFig.gca().set_rasterized(True)
  #label the plot
  tx1 = myFig.text((bbox.x0+bbox.x1)/2.,bbox.y1+.02,cTime.strftime('%Y/%m/%d'),ha='center',size=14,weight=550)
  tx2 = myFig.text(bbox.x1+.02,bbox.y1+.02,cTime.strftime('%H:%M - ')+\
        bndTime.strftime('%H:%M      '),ha='right',size=13,weight=550)
  tx3 = myFig.text(bbox.x0,bbox.y1+.02,'['+ft+']',ha='left',size=13,weight=550)
  #label with frequency bands
  tx4 = myFig.text(bbox.x1+.02,bbox.y1,'Frequency filters:',ha='right',size=8,weight=550)
  for i in range(len(rad)):
    myFig.text(bbox.x1+.02,bbox.y1-((i+1)*.015),rad[i]+': '+\
        str(tbands[i][0]/1e3)+' - '+str(tbands[i][1]/1e3)+\
        ' MHz',ha='right',size=8,weight=550)
  
  if(overlayPoes):
    pcols = gme.sat.poes.overlayPoesTed(myMap, myFig.gca(), cTime, param=poesparam, scMin=poesMin, scMax=poesMax)
    if(pcols != None):
      cols.append(pcols)
      pTicks = numpy.linspace(poesMin,poesMax,8)
      cbar = myFig.colorbar(pcols,ticks=pTicks,orientation='vertical',shrink=0.65,fraction=.1)
      cbar.ax.set_yticklabels(pTicks)
      cbar.set_label(poesLabel,size=14)
      cbar.ax.tick_params(axis='y',direction='out')
      #set colorbar ticklabel size
      for ti in cbar.ax.get_yticklabels():
        ti.set_fontsize(12)
      
  if(overlayBnd):
    gme.sat.poes.overlayPoesBnd(myMap, myFig.gca(), cTime)

  #handle the outputs
  if png == True:
    # if not show:
    #   canvas = FigureCanvasAgg(myFig)
    myFig.savefig(sTime.strftime("%Y%m%d.%H%M.")+str(interval)+'.fan.png',dpi=dpi)
  if pdf:
    # if not show:
    #   canvas = FigureCanvasAgg(myFig)
    myFig.savefig(sTime.strftime("%Y%m%d.%H%M.")+str(interval)+'.fan.pdf')
  if show:
    myFig.show()
def read_data(sTime, eTime, rad):

    # remove the file
    #try:
    #    os.remove('data.mat')
    #except OSError:
    #    pass

    cp_list = [150, 153, 157, 9050, 3501]

    #####################################
    # start time
    # sTime = dt.datetime(2011,10,8,4,0)

    # rad list
    # rad = ['pgr']

    # end time
    # eTime = dt.datetime(2011,10,8,4,1)
    ####################################

    # specify channel as 'a'
    channel = 'a'

    # aacgm coord
    coords = 'mag'

    bmnum = None

    cp = None

    # complete
    fileType = 'fitacf'

    filtered = False

    # to be specified as local in the future
    src = None

    # starts main function
    myFiles = []
    # go through all the radars
    for i in range(len(rad)):
        f = radDataOpen(sTime,
                        rad[i],
                        eTime=eTime,
                        channel=channel,
                        bmnum=bmnum,
                        cp=cp,
                        fileType=fileType,
                        filtered=filtered,
                        src=src)
        if (f != None):
            myFiles.append(f)
    allBeams = [''] * len(myFiles)
    # explanation of parameters
    # vels records velocity
    # ts records time
    # latR, lonR record the location of radars (fixed for 'mag' coord)
    # latO, lonO record the location of observations in 'mag' coord
    # azm records azm angles (0, 360)
    # lonO_MLT is converted from lonO in MLT coord
    vels, ts, latR, lonR, latO, lonO, azm, lonO_MLT, vel_err = [], [], [], [], [], [], [], [], []
    data_dict = {}
    for i in range(len(myFiles)):
        allBeams[i] = radDataReadRec(myFiles[i])
        # only need to read it once since it is fixed w.r.t. time
        t = allBeams[i].time
        site = pydarn.radar.site(radId=allBeams[i].stid, dt=t)
        myFov = pydarn.radar.radFov.fov(site=site, rsep=allBeams[i].prm.rsep,\
                ngates=allBeams[i].prm.nrang+1, nbeams=site.maxbeam, coords=coords)
        # x records the location of radars (i-th)
        if (coords == 'mag'):
            x = aacgm.aacgmConv(site.geolat, site.geolon, 0., t.year, 0)
        # read in data until the end of file
        while (allBeams[i] != None):
            if (abs(allBeams[i].cp) in cp_list):
                t = allBeams[i].time
                # go through all the observations which are located along one particular beam
                # throw out the first 10 "range gates" of the data grid
                for k in range(10, len(allBeams[i].fit.slist)):
                    # gate number r
                    r = allBeams[i].fit.slist[k]
                    # throw away outliers
                    if (allBeams[i].fit.qflg[k] != 1):
                        continue
                    if (allBeams[i].fit.gflg[k] == 1):
                        continue
                    if (allBeams[i].fit.v_e[k] > 150):
                        continue
                    if (allBeams[i].fit.p_l[k] < 3):
                        continue
                    vels.append(allBeams[i].fit.v[k])
                    # calculate the measurement error
                    vel_err.append(allBeams[i].fit.w_l[k] /
                                   sqrt(allBeams[i].fit.nlag[k]))
                    ts.append(t)
                    latR.append(x[0])
                    lonR.append(x[1])
                    # allBeams[i].bmnum represents the beam number
                    latO_ele = myFov.latCenter[allBeams[i].bmnum, r]
                    lonO_ele = myFov.lonCenter[allBeams[i].bmnum, r]
                    latO.append(latO_ele)
                    lonO.append(lonO_ele)
                    # obtain the azm angle
                    azm.append(calc_azm(latO_ele, lonO_ele, x[0], x[1]))
                    # longitude coordinate conversion from aacgm to MLT
                    epoch = timeUtils.datetimeToEpoch(sTime)
                    mltDef = aacgm.mltFromEpoch(epoch, 0.0) * 15.
                    # mltDef is the rotation that needs to be applied, and lonO_ele is the AACGM longitude.
                    # use modulo so new longitude is between 0 & 360
                    lonO_MLT.append(np.mod((lonO_ele + mltDef), 360.))
            allBeams[i] = radDataReadRec(myFiles[i])
    # sio.savemat('data.mat', {'latO': latO, 'lonO_MLT': lonO_MLT, 'vels': vels, 'azm': azm, 'vel_err': vel_err})
    data_dict = {
        'latO': latO,
        'lonO_MLT': lonO_MLT,
        'vels': vels,
        'azm': azm,
        'vel_err': vel_err
    }

    return data_dict
Beispiel #6
0
    def __init__(self,
                 datetime=None,
                 coords='geo',
                 projection='stere',
                 resolution='c',
                 dateTime=None,
                 lat_0=None,
                 lon_0=None,
                 boundinglat=None,
                 width=None,
                 height=None,
                 fillContinents='.8',
                 fillOceans='None',
                 fillLakes=None,
                 coastLineWidth=0.,
                 grid=True,
                 gridLabels=True,
                 showCoords=True,
                 **kwargs):
        """Create empty map 
    
    **Args**:    
      * **[width, height]**: width and height in m from the (lat_0, lon_0) center
      * **[lon_0]**: center meridian (default is -70E)    
      * **[lat_0]**: center latitude (default is -90E)
      * **[boundingLat]**: bounding latitude (default it +/-20)    
      * **[grid]**: show/hide parallels and meridians grid    
      * **[fill_continents]**: continent color. Default is 'grey'    
      * **[fill_water]**: water color. Default is 'None'    
      * **[coords]**: 'geo'
      * **[showCoords]**: display coordinate system name in upper right corner
      * **[dateTime]** (datetime.datetime): necessary for MLT plots if you want the continents to be plotted
      * **[kwargs]**: See <http://tinyurl.com/d4rzmfo> for more keywords
    **Returns**:
      * **map**: a Basemap object (<http://tinyurl.com/d4rzmfo>)
    **Example**:
      ::

        myMap = mapObj(lat_0=50, lon_0=-95, width=111e3*60, height=111e3*60)
        
    written by Sebastien, 2013-02
    """
        from models import aacgm
        import numpy as np
        from pylab import text
        import math
        from copy import deepcopy
        import datetime as dt

        self._coordsDict = {'mag': 'AACGM', 'geo': 'Geographic', 'mlt': 'MLT'}

        if coords is 'mlt':
            print 'MLT coordinates not implemented yet.'
            return

        if datetime is None:
            datetime = dt.datetime.utcnow()
        self.datetime = datetime

        # Add an extra member to the Basemap class
        if coords is not None and coords not in self._coordsDict:
            print 'Invalid coordinate system given in coords ({}): setting "geo"'.format(
                coords)
            coords = 'geo'
        self.coords = coords

        # Set map projection limits and center point depending on hemisphere selection
        if lat_0 is None:
            lat_0 = 90.
            if boundinglat: lat_0 = math.copysign(lat_0, boundinglat)
        if lon_0 is None:
            lon_0 = -100.
            if self.coords == 'mag':
                _, lon_0, _ = aacgm.aacgmConv(0., lon_0, 0.,
                                              self.datetime.year, 0)
        if boundinglat:
            width = height = 2 * 111e3 * (abs(lat_0 - boundinglat))

        # Initialize map
        super(mapObj, self).__init__(projection=projection,
                                     resolution=resolution,
                                     lat_0=lat_0,
                                     lon_0=lon_0,
                                     width=width,
                                     height=height,
                                     **kwargs)

        # Add continents
        if coords is not 'mlt' or dateTime is not None:
            _ = self.drawcoastlines(linewidth=coastLineWidth)
            # self.drawmapboundary(fill_color=fillOceans)
            _ = self.fillcontinents(color=fillContinents, lake_color=fillLakes)

        # Add coordinate spec
        if showCoords:
            _ = text(self.urcrnrx,
                     self.urcrnry,
                     self._coordsDict[coords] + ' coordinates',
                     rotation=-90.,
                     va='top',
                     fontsize=8)

        # draw parallels and meridians.
        if grid:
            parallels = np.arange(-80., 81., 20.)
            out = self.drawparallels(parallels, color='.6', zorder=10)
            # label parallels on map
            if gridLabels:
                lablon = int(self.llcrnrlon / 10) * 10
                rotate_label = lablon - lon_0 if lat_0 >= 0 else lon_0 - lablon + 180.
                x, y = basemap.Basemap.__call__(
                    self, lablon * np.ones(parallels.shape), parallels)
                for ix, iy, ip in zip(x, y, parallels):
                    if not self.xmin <= ix <= self.xmax: continue
                    if not self.ymin <= iy <= self.ymax: continue
                    _ = text(ix,
                             iy,
                             r"{:3.0f}$^\circ$".format(ip),
                             rotation=rotate_label,
                             va='center',
                             ha='center',
                             zorder=10,
                             color='.4')
            # label meridians on bottom and left
            meridians = np.arange(-180., 181., 20.)
            if gridLabels:
                merLabels = [False, False, False, True]
            else:
                merLabels = [False, False, False, False]
            # draw meridians
            out = self.drawmeridians(meridians,
                                     labels=merLabels,
                                     color='.6',
                                     zorder=10)
Beispiel #7
0
    def __call__(self, x, y, inverse=False, coords=None):
        from models import aacgm
        from copy import deepcopy
        import numpy as np
        import inspect

        if coords is not None and coords not in self._coordsDict:
            print 'Invalid coordinate system given in coords ({}): setting "{}"'.format(
                coords, self.coords)
            coords = None

        if coords and coords != self.coords:
            trans = coords + '-' + self.coords
            if trans in ['geo-mag', 'mag-geo']:
                flag = 0 if trans == 'geo-mag' else 1
                try:
                    nx, ny = len(x), len(y)
                    xt = np.array(x)
                    yt = np.array(y)
                    shape = xt.shape
                    y, x, _ = aacgm.aacgmConvArr(list(yt.flatten()),
                                                 list(xt.flatten()), [0.] * nx,
                                                 self.datetime.year, flag)
                    x = np.array(x).reshape(shape)
                    y = np.array(y).reshape(shape)
                except TypeError as e:
                    y, x, _ = aacgm.aacgmConv(y, x, 0., self.datetime.year,
                                              flag)

        if self.coords is 'geo':
            return basemap.Basemap.__call__(self, x, y, inverse=inverse)

        elif self.coords is 'mag':
            try:
                callerFile, _, callerName = inspect.getouterframes(
                    inspect.currentframe())[1][1:4]
            except:
                return basemap.Basemap.__call__(self, x, y, inverse=inverse)
            if isinstance(y, float) and abs(y) == 90.:
                return basemap.Basemap.__call__(self, x, y, inverse=inverse)
            if 'mpl_toolkits' in callerFile and callerName is '_readboundarydata':
                if not inverse:
                    try:
                        nx, ny = len(x), len(y)
                        x = np.array(x)
                        y = np.array(y)
                        shape = x.shape
                        yout, xout, _ = aacgm.aacgmConvArr(
                            list(y.flatten()), list(x.flatten()), [0.] * nx,
                            self.datetime.year, 0)
                        xout = np.array(xout).reshape(shape)
                        yout = np.array(yout).reshape(shape)
                    except TypeError:
                        yout, xout, _ = aacgm.aacgmConv(
                            y, x, 0., self.datetime.year, 0)
                    return basemap.Basemap.__call__(self,
                                                    xout,
                                                    yout,
                                                    inverse=inverse)
                else:
                    return basemap.Basemap.__call__(self,
                                                    x,
                                                    y,
                                                    inverse=inverse)
            else:
                return basemap.Basemap.__call__(self, x, y, inverse=inverse)

        elif self.coords is 'mlt':
            print 'Not implemented'
            callerFile, _, callerName = inspect.getouterframes(
                inspect.currentframe())[1][1:4]
Beispiel #8
0
def plotFan(sTime,rad,eTime=None,interval=60,fileType='fitex',param='velocity',filtered=False ,\
    scale=[],channel='a',coords='geo',colors='lasse',gsct=0,fov=1,edgeColors='face',gflg=0,fill=True,\
    velscl=1000.,legend=1,overlayPoes=False,poesparam='ted',poesMin=-3.,poesMax=0.5, \
    poesLabel=r"Total Log Energy Flux [ergs cm$^{-2}$ s$^{-1}$]",overlayBnd=False,output='gui'):
  """A function to make fan plots
  
  **Args**:
    * **sTime** (`datetime <http://tinyurl.com/bl352yx>`_): the start time you want to plot
    * **rad** (str): a list of 3 letter radar codes
    * **[eTime]** (`datetime <http://tinyurl.com/bl352yx>`_): the last time you want to plot.  If this is None, it will be set equal to sTime.  default = None
    * **[interval]** (int): the interval between fan plots, in seconds
    * **[fileType]**: the file type to plot, valid inputs are 'fitex','fitacf',
      'lmfit'.  default = 'fitex'
    * **[param]**: the parameter to be plotted, valid inputs are 'velocity', 
      'power', 'width', 'elevation', 'phi0'.  default = 'velocity
    * **[filtered]**: a flag indicating whether the data should be boxcar filtered
      default = 0
    * **[scale]**: the min and max values of the color scale.  If this is set to []
      then default values will be used
    * **[channel]**: the channel for which to plot data.  default = 'a'
    * **[coords]**: the coordinate system to use, valid inputs are 'geo', 'mag'
      default = 'geo'
    * **[colors]**: the color map to use, valid inputs are 'lasse', 'aj'
      default = 'lasse'
    * **[gsct]**: a flag indicating whether to plot ground scatter as gray.
      default = 0
    * **[fov]**: a flag indicating whether to overplot the radar fields of view
      default = 0
    * **[edgeColors]**: edge colors of the polygons, default = 'face'
    * **[gflg]**: a flag indicating whether to plot low velocities in gray
      default = 0
    * **[fill]**: a flag indicating whether to plot filled or point RB cells
      default = True
    * **[velscl]**: the velocity to use as baseline for velocity vector length,
      only applicable if fill = 0.  default = 1000
    * **[legend]**: a flag indicating whether to plot the legend
      only applicable if fill = 0.  default = 1
  **Returns**:
    NONE

  **Example**:
    ::
    
      plotFan('20121001',['bks','fhw'],time=[0,24],interval=2,fileType='fitex',param='velocity',filtered=0 ,
                scale=[-400,400],channel='a',coords='geo',colors='lasse',gsct=0,pdf=0,fov=1,edgeColors='face',gflg=0)

  Written by AJ 20121004

  """

  
  import datetime as dt, gme, pickle
  from matplotlib.backends.backend_pdf import PdfPages
  import models.aacgm as aacgm, os, copy
  tt = dt.datetime.now()
  
  #check the inputs
  assert(isinstance(sTime,dt.datetime)),'error, sTime must be a datetime object'
  if(eTime == None): eTime = sTime
  assert(isinstance(eTime,dt.datetime)),'error, eTime must be a datetime object'
  assert(eTime >= sTime), 'error, eTime < sTime'
  assert(isinstance(rad,list)),"error, rad must be a list, eg ['bks'] or ['bks','fhe']"
  for r in rad:
    assert(isinstance(r,str) and len(r) == 3),'error, elements of rad list must be 3 letter strings'
  assert(coords == 'geo' or coords == 'mag'),"error, coords must be one of 'geo' or 'mag'"
  assert(param == 'velocity' or param == 'power' or param == 'width' or \
    param == 'elevation' or param == 'phi0'), \
    "error, allowable params are 'velocity','power','width','elevation','phi0'"
  assert(scale == [] or len(scale)==2), \
  'error, if present, scales must have 2 elements'
  assert(colors == 'lasse' or colors == 'aj'),"error, valid inputs for color are 'lasse' and 'aj'"
  
  if(scale == []):
    if(param == 'velocity'): scale=[-200,200]
    elif(param == 'power'): scale=[0,30]
    elif(param == 'width'): scale=[0,150]
    elif(param == 'elevation'): scale=[0,50]
    elif(param == 'phi0'): scale=[-numpy.pi,numpy.pi]
      
  #check for plotting directory, create if does not exist
  d = os.environ['PYPLOTS']+'/fan'
  if not os.path.exists(d):
    os.makedirs(d)
    
  fbase = d+'/'+sTime.strftime("%Y%m%d")+'.fan.'
    
  cmap,norm,bounds = utils.plotUtils.genCmap(param,scale,colors=colors,gflg=gflg)
  
  
  #open the data files
  myFiles = []
  for r in rad:
    f = radDataOpen(sTime,r,eTime+datetime.timedelta(seconds=interval),fileType=fileType,filtered=filtered,channel=channel)
    if(f != None): myFiles.append(f)

  assert(myFiles != []),'error, no data available for this period'

  xmin,ymin,xmax,ymax = 1e16,1e16,-1e16,-1e16

  allBeams = [''] * len(myFiles)
  sites,fovs,oldCpids,lonFull,latFull=[],[],[],[],[]
  #go through all open files
  for i in range(len(myFiles)):
    #read until we reach start time
    allBeams[i] = radDataReadRec(myFiles[i])
    while(allBeams[i].time < sTime and allBeams[i] != None):
      allBeams[i] = radDataReadRec(myFiles[i])
      
    #check that the file has data in the target interval
    if(allBeams[i] == None): 
      myFiles[i].close()
      myFiles[i] = None
      continue
  
    #get to field of view coords in order to determine map limits
    t=allBeams[i].time
    site = pydarn.radar.site(radId=allBeams[i].stid,dt=t)
    sites.append(site)
    if(coords == 'geo'):
      latFull.append(site.geolat)
      lonFull.append(site.geolon)
    elif(coords == 'mag'):
      x = aacgm.aacgmConv(site.geolat,site.geolon,0.,0)
      latFull.append(x[0])
      lonFull.append(x[1])
    myFov = pydarn.radar.radFov.fov(site=site,rsep=allBeams[i].prm.rsep,\
            ngates=allBeams[i].prm.nrang+1,nbeams=site.maxbeam,coords=coords)
    fovs.append(myFov)
    for b in range(0,site.maxbeam+1):
      for k in range(0,allBeams[i].prm.nrang+1):
        lonFull.append(myFov.lonFull[b][k])
        latFull.append(myFov.latFull[b][k])
    oldCpids.append(allBeams[i].cp)
      
  #do some stuff in map projection coords to get necessary width and height of map
  #lon_0 = (xmin+xmax)/2.
  #lat_0 = (ymin+ymax)/2.
  t1=dt.datetime.now()
  lonFull,latFull = (numpy.array(lonFull)+360.)%360.,numpy.array(latFull)
  tmpmap = Basemap(projection='npstere', boundinglat=20,lat_0=90, lon_0=numpy.mean(lonFull))
  x,y = tmpmap(lonFull,latFull)
  minx = x.min()
  miny = y.min()
  maxx = x.max()
  maxy = y.max()
  width = (maxx-minx)
  height = (maxy-miny)
  cx = minx + width/2.
  cy = miny + height/2.
  lon_0,lat_0 = tmpmap(cx, cy, inverse=True)
  dist = width/50.
  cTime = sTime
  
  myFig = plot.figure()

  #draw the actual map we want
  myMap = Basemap(projection='stere',width=width,height=height,lon_0=numpy.mean(lonFull),lat_0=lat_0)
  myMap.drawparallels(numpy.arange(-80.,81.,10.),labels=[1,0,0,0])
  myMap.drawmeridians(numpy.arange(-180.,181.,20.),labels=[0,0,0,1])
  if(coords == 'geo'):
    myMap.drawcoastlines(linewidth=0.5,color='k')
    myMap.drawmapboundary(fill_color='w')
    myMap.fillcontinents(color='w', lake_color='w')
  #overlay fields of view, if desired
  if(fov == 1):
    ty = dt.datetime.now()
    for r in rad:
      pydarn.plot.overlayRadar(myMap, codes=r, dateTime=sTime, coords=coords)
      pydarn.plot.overlayFov(myMap, codes=r, dateTime=sTime,coords=coords)
    print 'overlays',dt.datetime.now()-ty
  
  print dt.datetime.now()-t1
  #manually draw the legend
  if((not fill) and legend):
    #draw the box
    y = [myMap.urcrnry*.82,myMap.urcrnry*.99]
    x = [myMap.urcrnrx*.86,myMap.urcrnrx*.99]
    verts = [x[0],y[0]],[x[0],y[1]],[x[1],y[1]],[x[1],y[0]]
    poly = patches.Polygon(verts,fc='w',ec='k',zorder=11)
    myFig.gca().add_patch(poly)
    labs = ['5 dB','15 dB','25 dB','35 dB','gs','1000 m/s']
    pts = [5,15,25,35]
    #plot the icons and labels
    for w in range(6):
      myFig.gca().text(x[0]+.35*(x[1]-x[0]),y[1]*(.98-w*.025),labs[w],zorder=15,color='k',size=6,va='center')
      xctr = x[0]+.175*(x[1]-x[0])
      if(w < 4):
        plot.scatter(xctr,y[1]*(.98-w*.025),s=.1*pts[w],zorder=15,marker='o',linewidths=.5,\
        edgecolor='face',facecolor='k')
      elif(w == 4):
        plot.scatter(xctr,y[1]*(.98-w*.025),s=.1*35.,zorder=15,marker='o',\
        linewidths=.5,edgecolor='k',facecolor='w')
      elif(w == 5):
        y=LineCollection(numpy.array([((xctr-dist/2.,y[1]*(.98-w*.025)),(xctr+dist/2.,y[1]*(.98-w*.025)))]),linewidths=.5,zorder=15,color='k')
        myFig.gca().add_collection(y)
        
  pickle.dump(myFig,open('map.pickle','wb'),-1)
  
  bbox = myFig.gca().get_axes().get_position()
  first = True
  pnum,stot = 0,dt.timedelta(seconds=0)
  axes = AxesSequence()
  #now, loop through desired time interval
  while(cTime <= eTime):
    tz = dt.datetime.now()
    cols = []
    bndTime = cTime + datetime.timedelta(seconds=interval)
    
    ft = 'None'
    #go though all files
    for i in range(len(myFiles)):
      scans = [[] for j in range(len(myFiles))]
      #check that we have good data at this time
      if(myFiles[i] == None or allBeams[i] == None): continue
      ft = allBeams[i].fType
      #until we reach the end of the time window
      while(allBeams[i] != None and allBeams[i].time < bndTime):
        scans[i].append(allBeams[i])
        #read the next record
        allBeams[i] = radDataReadRec(myFiles[i])
      intensities, pcoll = overlayFan(scans[i],myMap,myFig,param,coords,gsct=gsct,site=sites[i],fov=fovs[i],\
                                        fill=fill,velscl=velscl,dist=dist,cmap=cmap,norm=norm)
                                        
                                        
    
    if(first):
      cbar = plot.colorbar(pcoll,orientation='vertical',shrink=.65,fraction=.1)
    
      l = []
      #define the colorbar labels
      for i in range(0,len(bounds)):
        if(param == 'phi0'):
          ln = 4
          if(bounds[i] == 0): ln = 3
          elif(bounds[i] < 0): ln = 5
          l.append(str(bounds[i])[:ln])
          continue
        if((i == 0 and param == 'velocity') or i == len(bounds)-1):
          l.append(' ')
          continue
        l.append(str(int(bounds[i])))
      cbar.ax.set_yticklabels(l)
      cbar.ax.tick_params(axis='y',direction='out')
      #set colorbar ticklabel size
      for ti in cbar.ax.get_yticklabels():
        ti.set_fontsize(7)
      if(param == 'velocity'): 
        cbar.set_label('Velocity [m/s]',size=10)
        cbar.extend='max'
        
      if(param == 'grid'): cbar.set_label('Velocity [m/s]',size=10)
      if(param == 'power'): cbar.set_label('Power [dB]',size=10)
      if(param == 'width'): cbar.set_label('Spec Wid [m/s]',size=10)
      if(param == 'elevation'): cbar.set_label('Elev [deg]',size=10)
      if(param == 'phi0'): cbar.set_label('Phi0 [rad]',size=10)
    
    #myFig.gca().set_rasterized(True)
    #label the plot
    tx1 = plot.figtext((bbox.x0+bbox.x1)/2.,bbox.y1+.02,cTime.strftime('%Y/%m/%d'),ha='center',size=14,weight=550)
    tx2 = plot.figtext(bbox.x1,bbox.y1+.02,cTime.strftime('%H:%M - ')+\
          bndTime.strftime('%H:%M      '),ha='right',size=13,weight=550)
    tx3 = plot.figtext(bbox.x0,bbox.y1+.02,'['+ft+']',ha='left',size=13,weight=550)
    
    if(overlayPoes):
      pcols = gme.poes.overlayPoesTed(myMap, myFig.gca(), cTime, param=poesparam, scMin=poesMin, scMax=poesMax)
      if(pcols != None and first):
        cols.append(pcols)
        pTicks = numpy.linspace(poesMin,poesMax,8)#[-3.0,-2.5,-2.0,-1.5,-1.0,-0.5,0.0,0.5]
        cbar = plot.colorbar(pcols,ticks=pTicks,orientation='vertical',shrink=0.65,fraction=.1)
        cbar.ax.set_yticklabels(pTicks)
        cbar.set_label(poesLabel,size=10)
        cbar.ax.tick_params(axis='y',direction='out')
        #set colorbar ticklabel size
        for ti in cbar.ax.get_yticklabels():
          ti.set_fontsize(7)
        
    if(overlayBnd):
      gme.poes.overlayPoesBnd(myMap, myFig.gca(), cTime)

    t1 = dt.datetime.now()
    #myFig.savefig(pp, format='pdf', dpi=300,orientation='landscape')
    if(output == 'gui'): axes.axes.append(myFig.gca())
    else: myFig.savefig(fbase+str(pnum)+'.svg', orientation='landscape')
    tsave=dt.datetime.now()-t1
    print 'save',tsave
    stot+=tsave
    #myFig.show()
    
    #try:
      ##if(fill == 1): 
        ##pcoll.remove()
      ##else: 
        ##ccoll.set_paths([])
        ##lcoll.remove()
      #for c in cols:
        #c.remove()
        #del c
      
      ##if(gsct == 1): x.remove()
    #except: pass
    
    #myFig.texts.remove(tx1)
    #myFig.texts.remove(tx2)
    #myFig.texts.remove(tx3)

    cTime = bndTime
    first = False
    pnum += 1
    myFig.clf()
    myFig = pickle.load(open('map.pickle','rb'))
    print 'plot loop',dt.datetime.now()-tz
    
  
  if(output != 'gui'): print 'file[s] is[are] at: '+d+'/'+sTime.strftime("%Y%m%d")+'.fan.%n.pdf'
  else: axes.show()
  print dt.datetime.now()-tt
  print stot/pnum
Beispiel #9
0
def makePygrid(sTime,rad,eTime=None,fileType='fitex',interval=60,vb=0,filtered=True, fileName=None):
  """a function to read in fitted radar data and put it into a geospatial grid
  
  **INPUTS**:
    * **sTime** (`datetime <http://tinyurl.com/bl352yx>`_): the start time do want to grid
    * **rad** (str): the 3 letter radar code, e.g. 'bks'
    * **[eTime]** (`datetime <http://tinyurl.com/bl352yx>`_): the last time that you want data for.  if this is set to None, it will be set to 1 day after sTime.  default = None
    * **[fileType]** (str): 'fitex', 'fitacf', or 'lmfit'; default = 'fitex'
    * **[interval]** (int): the time interval at which to do the gridding in seconds; default = 60
    * **[filtered] (bool)**: True to boxcar filter, False for normal data; default = True
    
  **Returns**:
    * Nothing.

  **Example**:
    ::
    
      import datetime as dt
      pydarn.proc.makePygrid(dt.datetime(2011,1,1),'bks')

    
  Written by AJ 20120807

  """
  import pydarn,math,datetime as dt,models.aacgm as aacgm,os

  
  if eTime == None: eTime = sTime+dt.timedelta(days=1)
  
  #read the radar data
  myFile = radDataOpen(sTime,rad,eTime=eTime,fileType=fileType,filtered=filtered,fileName=fileName)
  if myFile == None: 
    print 'could not find data requested, returning None'
    return None
  
  #get a radar site object
  site = pydarn.radar.network().getRadarByCode(rad).getSiteByDate(sTime)

  #a list for all the grid objects
  myGrids = []
  #create a pygrid object
  g = pygrid()
  #initialize start time
  cTime = sTime
  lastInd = 0
  

  
  oldCpid = -999999999999999
  myBeam = radDataReadRec(myFile)
  if myBeam == None:
    print 'no data available'
    return None

  d = os.environ['DATADIR']+'/pygrid/'+rad
  if not os.path.exists(d):
    os.makedirs(d)
  fileName = d+'/'+sTime.strftime("%Y%m%d")+'.'+rad+'.pygrid.hdf5'
  #open a pygrid file
  gFile = openPygrid(fileName,'w')
  
  #until we reach the designated end time
  while cTime < eTime:
    if myBeam == None : break
    
    #boundary time
    bndT = cTime+dt.timedelta(seconds=interval)
    #remove vectors from the grid object
    g.delVecs()
    #verbose option
    if(vb==1): print cTime
    #iterate through the radar data
    while(myBeam.time < bndT):
      
      #current time of radar data
      t = myBeam.time
      
      #check for a control program change
      if(myBeam.cp != oldCpid and myBeam.channel == 'a'):
        #get possibly new ngates
        ngates = max([site.maxgate,myBeam.prm.nrang])
        #gereate a new FOV
        myFov = pydarn.radar.radFov.fov(site=site,rsep=myBeam.prm.rsep,\
          ngates=ngates+1,nbeams=site.maxbeam)
        myFova = pydarn.radar.radFov.fov(site=site,rsep=myBeam.prm.rsep,\
          ngates=ngates+1, model=None, altitude=300.)

        #create a 2D list to hold coords of RB cells
        coordsList = [[None]*ngates for _ in range(site.maxbeam)]
        #generate new coordsList
        for ii in range(site.maxbeam):
          for jj in range(ngates):
            arr1=aacgm.aacgmConv(myFov.latCenter[ii][jj],myFov.lonCenter[ii][jj],300,0)
            arr2=aacgm.aacgmConv(myFov.latCenter[ii][jj+1],myFov.lonCenter[ii][jj+1],300,0)
            arr3=aacgm.aacgmConv(myFova.latCenter[ii][jj],myFova.lonCenter[ii][jj],300,0)
            arr4=aacgm.aacgmConv(myFova.latCenter[ii][jj+1],myFova.lonCenter[ii][jj+1],300,0)
            azm = greatCircleAzm(arr3[0],arr3[1],arr4[0],arr4[1])
            coordsList[ii][jj] = [arr1[0],arr1[1],azm]
        oldCpid = myBeam.cp
        
      #are we in the target time interval?
      if(cTime < t <= bndT): 
        #enter the radar data into the grid
        g.enterData(myBeam,coordsList)
        
      #read the next record
      myBeam = radDataReadRec(myFile)
      
      if(myBeam == None): break

    #if we have > 0 gridded vector
    if(g.nVecs > 0):
      #record some information
      g.sTime = cTime
      g.eTime = bndT
      #average is LOS vectors
      g.averageVecs()
      #write to the hdf5 file
      writePygridRec(gFile,g)
      
    #reassign the current time we are at
    cTime = bndT
    
    
  closePygrid(gFile)
  if(os.path.exists(fileName+'.bz2')): os.system('rm '+fileName+'.bz2')
  os.system('bzip2 '+fileName)