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