madrigal.ui.madrigalPlot module
madrigalPlot is the module that produces plots of Madrigal data.
Presently based on madplotlib: http://matplotlib.sourceforge.net/
$Id: madrigalPlot.py 6609 2018-10-16 20:01:56Z brideout $
"""madrigalPlot is the module that produces plots of Madrigal data. Presently based on madplotlib: http://matplotlib.sourceforge.net/ $Id: madrigalPlot.py 6609 2018-10-16 20:01:56Z brideout $ """ import sys,os import os.path import traceback import types import datetime import bisect import math import colorsys import subprocess import numpy import madrigal.metadata import madrigal._derive def defineHomeEnvVariable(): """defineHomeEnvVariable makes sure HOME env variable is defined, as required by matplotlib. If not defined, sets HOME to MADROOT/metadata/userdata """ try: os.environ['HOME'] return except KeyError: import madrigal.metadata madDB = madrigal.metadata.MadrigalDB() os.environ['HOME'] = os.path.join(madDB.getMadroot(), 'metadata/userdata') defineHomeEnvVariable() import matplotlib # set rendering matplotlib.use('Agg') import matplotlib.pylab import matplotlib.colors import matplotlib.cm import numpy.ma import numpy def convertToAbsoluteTimeStr(xticks, noTime=False, noDate=False, timezone=0): """convertToAbsoluteTimeStr converts a list of strings containing seconds since 1/1/1950 to datetime string. Input: xticks - a list of strings containing seconds since 1/1/1950 Returns: a list of strings formated as YYYY-MM-DD HH-MM-SS. If noTime, format as YYYY-MM-DD """ datetime1950 = datetime.datetime(1950,1,1,0,0,0) newList = [] seconds = long(xticks[0]) - timezone iniDoy = datetime1950 + datetime.timedelta(0, seconds) iniDoy = int(iniDoy.strftime('%j')) for item in xticks: seconds = long(item) - timezone newDatetime = datetime1950 + datetime.timedelta(0, seconds) if noTime: newList.append(newDatetime.strftime('%Y-%m-%d')) elif noDate: curDoy = int(newDatetime.strftime('%j')) currHour = newDatetime.hour currMin = newDatetime.minute currHour += (curDoy - iniDoy)*24 newList.append('%02d:%02d' %(currHour,currMin)) else: newList.append(newDatetime.strftime('%Y-%m-%d %H:%M:%S')) return newList def get_vo_cmap(): """get_vo_cmap is a function to return a colormap optimized to show sign changes in the middle of the range. """ LUTSIZE = matplotlib.rcParams['image.lut'] _vo_cm_data = {'red': ((0, 0.75, 0.75), (0.4, 0.0, 0.0), (0.5, 0.0, 0.0), (0.6, 1.0, 1.0), (1.0, 1.0, 1.0)), 'green': ((0, 1.0, 1.0), (0.4, 0.5, 0.5), (0.5, 0.25, 0.25), (0.6, 0.25, 0.25), (1.0, 1.0, 1.0)), 'blue': ((0, 1.0, 1.0), (0.4, 1.0, 1.0), (0.5, 0.5, 0.5), (0.6, 0.0, 0.0), (1.0, 0.5, 0.5))} vo_cm = matplotlib.colors.LinearSegmentedColormap('vo_cm',_vo_cm_data, LUTSIZE) return vo_cm def getIsprintString(filename, parms, filterStr): """getIsprintString returns the output of isprint given inputs Inputs: filename - Madrigal filename parms - comma-delimited parameters filterStr - arguments to pass to isprint cmd """ madDB = madrigal.metadata.MadrigalDB() cmd = '%s/bin/isprint file=%s ' % (madDB.getMadroot(), filename) for parm in parms.split(','): cmd += '%s ' % (parm) cmd += filterStr cmd += ' header=f summary=f ' pipe = subprocess.Popen(cmd, shell=True, stdout=subprocess.PIPE).stdout result = pipe.read() delimiter = '\n' lines = result.split(delimiter) return(delimiter.join(lines[1:]).strip()) class madScatterPlot: """madScatterPlot is the class the produces two dimensional scatter plots of x versus y. """ def __init__(self, isprintText, titleStr, xLabelStr, yLabelStr, fullFilename, size = 'small', useAbsoluteTime = False, startTime = None, endTime = None, maxNumPoints = None, noTime = False, noDate = False, yMinimum = None, yMaximum = None, timezone = 0): """__init__ writes a madScatter plot to a file. Inputs: isprintText - a string giving isprint output without headers. First parameter must be UTH or UT1, depending on whether time scale should be relative to the experiment beginning (UTH) or absolute (UT1). The second must be the parameter to be plotted. Any missing data should be written as "missing" or other string that cannot be converted to a float. titleStr - plot title (string) - should describe parameter being plotted xLabelStr - x label string yLabelStr - ylabel string fullFilename - full path of file containing pcolor plot to be saved. Extension must be jpeg or png, or exception thrown. size - size of plot to save. Must be "small", "wide", or "large". Defaults to small. useAbsoluteTime - if true, print time as YYYY-MM-DD HH:MM:SS. If false (default), print time as hour since beginning of experiment (UTH). If useAbsoluteTime is true, first parameter in isprintText must be UT1, if false, it must be UTH. startTime - start plot at given time. If useAbsoluteTime == True, then startTime must be in units of seconds since 1/1/1950. If useAbsoluteTime == False, then startTime must be in units of UTH (hours since midnight UT of first day of experiment). Default is None, which means start at lowest time found. endTime - end plot at given time. If useAbsoluteTime == True, then endTime must be in units of seconds since 1/1/1950. If useAbsoluteTime == False, then endTime must be in units of UTH (hours since midnight UT of first day of experiment). Default is None, which means end at largest time found. maxNumPoints - maximum number of points to plot. If not None, truncate isprintText if needed to have at most maxNumPoints lines. noTime - if True and useAbsoluteTime True, then dates without times printed on x axis. noDate - if True and useAbsoluteTime True, then times without dates printed on x axis. yMinimum - set y minimum. If default=None, use data minimum yMaximum - set y maximum. If default=None, use data maximum timezone - The offset of the local (non-DST) timezone, in seconds west of UTC (negative in most of Western Europe, positive in the US, zero in the UK). Returns: void Affects: None """ self.__missing = 1.0E30 # special value, since numpy doesn't handle NaN self.__parameter_count = 2 # verify input if size not in ('small', 'wide', 'large'): raise ValueError, 'size must be "small", "wide", or "large", not %s' % (str(size)) if size in ('small', 'wide'): fontSize = 12 elif size in ('large'): fontSize = 18 if maxNumPoints != None: isprintText = self.__truncateIsprint(isprintText, maxNumPoints) # convert the input data into numeric arrays of float assuming no headers and filter the missing values. try: split_data = isprintText.split() float_data = map(self.__filter_missing, split_data) array_data = numpy.asarray(float_data) array_data = numpy.reshape(array_data,(-1,self.__parameter_count)) except: traceback.print_exc() raise ValueError, 'input text is not parseable' # find min, max of x (time) if startTime == None: xMin = array_data[0,0] else: xMin = startTime if endTime == None: xMax = array_data[-1,0] else: xMax = endTime # find min, max of y, not including missing yMin = None yMax = None for y in array_data[:,1]: if y == self.__missing: continue if yMin == None: yMin = y elif yMin > y: yMin = y if yMax == None: yMax = y elif yMax < y: yMax = y if yMin == None: raise ValueError, 'No valid y data found' # select the plot size if size == 'small': matplotlib.pylab.figure(1, figsize=(9,3), facecolor = 'w') elif size == 'wide': matplotlib.pylab.figure(1, figsize=(10,4), facecolor = 'w') elif size == 'large': matplotlib.pylab.figure(1, figsize=(10,6), facecolor = 'w') if useAbsoluteTime: # leave room for rotated datetime string if size == 'large': matplotlib.pylab.axes([0.1, 0.2, 0.8, 0.7]) elif size == 'wide': matplotlib.pylab.axes([0.07, 0.2, 0.66, 0.7]) elif size == 'small': matplotlib.pylab.axes([0.14, 0.18, 0.83, 0.7]) matplotlib.pylab.scatter(array_data[:,0],array_data[:,1]) thisFont = {'size': fontSize} matplotlib.pylab.rc('font', **thisFont) # pass in the font dict as kwargs matplotlib.pylab.xlabel(xLabelStr, fontsize=fontSize) matplotlib.pylab.ylabel(yLabelStr, fontsize=fontSize) matplotlib.pylab.yticks(fontsize=fontSize) matplotlib.pylab.xlim(xMin, xMax) matplotlib.pylab.title(titleStr, fontsize=fontSize) matplotlib.pylab.grid(True) if useAbsoluteTime: # if plot is less than 24 hours, force ticks to be every 4 hours xmin, xmax = matplotlib.pylab.xlim() xmin = xmin / (60*60) xmax = xmax / (60*60) if noDate == True: if xmax % 4 != 0: newXmax = 4 * (int(xmax/4.0) + 1) else: newXmax = xmax newXLocs = [] newXLabels = [] step = int((xmax-xmin-1)/6)+1 xRange = range(0,int(newXmax-xmin),step) for i in xRange: tmp = (xmin + i)*60*60 newXLocs.append(tmp) if (xmax - xmin) < 1: newXLocs.append(xmax*60*60) newXLabels = convertToAbsoluteTimeStr(newXLocs, noDate=noDate, timezone=timezone) matplotlib.pylab.xticks(newXLocs, newXLabels) else: locs, labels = matplotlib.pylab.xticks() if len(locs) > 5: # truncate by len(locs) / 5 scale = 1 + int(len(locs) / 5) new_locs = [] for i in range(len(locs)): if i % scale == 0: new_locs.append(locs[i]) locs = new_locs newXTicks = convertToAbsoluteTimeStr(locs) matplotlib.pylab.xticks(locs, newXTicks, rotation=15) matplotlib.pylab.xticks(fontsize=fontSize) if yMinimum != None and yMaximum != None: matplotlib.pylab.ylim(yMinimum, yMaximum) elif yMinimum != None and yMaximum == None: matplotlib.pylab.ylim(yMin=yMinimum) elif yMinimum == None and yMaximum != None: matplotlib.pylab.ylim(yMax=yMaximum) # get the handle to the figure now that it has been created so we can manipulate on subsequent calls. #self.__figure = matplotlib.pylab.gcf() matplotlib.pylab.savefig(fullFilename) #matplotlib.pylab.show() matplotlib.pylab.clf() def __truncateIsprint(self, isprintText, maxLines): """__truncateIsprint truncates isprintText to have maxLines at most. """ isprintList = isprintText.split('\n') if len(isprintList) < maxLines: return isprintText else: dropNumber = int(1 + len(isprintList)/maxLines) newline = '\n' newIsprintText = newline.join(isprintList[::dropNumber]) return newIsprintText def __filter_missing(self,x): try: return float(x) except: return self.__missing class madLineTimePlot: """madLineTimePlot is the class the produces line plots of one or more parameters versus time. """ def __init__(self, isprintText, yParmList, titleStr, xLabelStr, yLabelStr, fullFilename, size = 'small', useAbsoluteTime = False, startTime = None, endTime = None, maxNumPoints = None, noTime = False, yMinimum = None, yMaximum = None, noDate = False, timezone = 0): """__init__ writes a madLineTimePlot plot to a file. Inputs: isprintText - a string giving isprint output without headers. First parameter must be UTH or UT1, depending on whether time scale should be relative to the experiment beginning (UTH) or absolute (UT1). The the following must be the parameters to be plotted. Any missing data should be written as "missing" or other string that cannot be converted to a float. yParmList - a list of y parameters (strings). Length must == num columns in isprintText - 1 titleStr - plot title (string) - should describe parameter being plotted xLabelStr - x label string yLabelStr - ylabel string fullFilename - full path of file containing pcolor plot to be saved. Extension must be jpeg or png, or exception thrown. size - size of plot to save. Must be "small", "wide", or "large". Defaults to small. useAbsoluteTime - if true, print time as YYYY-MM-DD HH:MM:SS. If false (default), print time as hour since beginning of experiment (UTH). If useAbsoluteTime is true, first parameter in isprintText must be UT1, if false, it must be UTH. startTime - start plot at given time. If useAbsoluteTime == True, then startTime must be in units of seconds since 1/1/1950. If useAbsoluteTime == False, then startTime must be in units of UTH (hours since midnight UT of first day of experiment). Default is None, which means start at lowest time found. endTime - end plot at given time. If useAbsoluteTime == True, then endTime must be in units of seconds since 1/1/1950. If useAbsoluteTime == False, then endTime must be in units of UTH (hours since midnight UT of first day of experiment). Default is None, which means end at largest time found. maxNumPoints - maximum number of points to plot. If not None, truncate isprintText if needed to have at most maxNumPoints lines. noTime - if True and useAbsoluteTime True, then dates without times printed on x axis. noDate - if True and useAbsoluteTime True, then times without dates printed on x axis. yMinimum - set y minimum. If default=None, use data minimum yMaximum - set y maximum. If default=None, use data maximum timezone - The offset of the local (non-DST) timezone, in seconds west of UTC (negative in most of Western Europe, positive in the US, zero in the UK). Returns: void Affects: None """ self.__missing = 1.0E30 # special value, since numpy doesn't handle NaN self.__parameter_count = 1 + len(yParmList) self.__colorList = 'gbrcmykw' # a list of colors for the lines # verify input if size not in ('small', 'wide', 'large'): raise ValueError, 'size must be "small", "wide", or "large", not %s' % (str(size)) if size in ('small', 'wide'): fontSize = 12 elif size in ('large'): fontSize = 18 if maxNumPoints != None: isprintText = self.__truncateIsprint(isprintText, maxNumPoints) # convert the input data into numeric arrays of float assuming no headers and filter the missing values. try: split_data = isprintText.split() float_data = map(self.__filter_missing, split_data) array_data = numpy.asarray(float_data) array_data = numpy.reshape(array_data,(-1,self.__parameter_count)) threshold = self.__missing*0.9999 array_data = numpy.ma.masked_where(array_data > threshold, array_data) except: traceback.print_exc() raise ValueError, 'input text is not parseable' # find min, max of x (time) if startTime == None: xMin = array_data[0,0] else: xMin = startTime if endTime == None: xMax = array_data[-1,0] else: xMax = endTime # find yMin just to ensure there is data yMin = None for column in range(len(yParmList)): for y in array_data[:,1+column]: if y == self.__missing: continue if yMin == None: yMin = y elif yMin > y: yMin = y if yMin == None: raise ValueError, 'No valid y data found' # select the plot size if size == 'small': matplotlib.pylab.figure(1, figsize=(8,3), facecolor = 'w') elif size == 'wide': matplotlib.pylab.figure(1, figsize=(10,4), facecolor = 'w') elif size == 'large': matplotlib.pylab.figure(1, figsize=(12,6), facecolor = 'w') if useAbsoluteTime: # leave room for rotated datetime string if size == 'large': matplotlib.pylab.axes([0.1, 0.2, 0.8, 0.7]) elif size == 'wide': matplotlib.pylab.axes([0.07, 0.2, 0.9, 0.7]) elif size == 'small': matplotlib.pylab.axes([0.1, 0.18, 0.87, 0.7]) else: if size == 'large': matplotlib.pylab.axes([0.1, 0.15, 0.71, 0.73]) for column in range(len(yParmList)): color = self.__colorList[column % len(self.__colorList)] matplotlib.pylab.plot(array_data[:,0],array_data[:,1 + column], '%so-' % (color), ms=5, mew=0.5) thisFont = {'size': fontSize} matplotlib.pylab.rc('font', **thisFont) # pass in the font dict as kwargs matplotlib.pylab.xlabel(xLabelStr, fontsize=fontSize) matplotlib.pylab.ylabel(yLabelStr, fontsize=fontSize) matplotlib.pylab.yticks(fontsize=fontSize) matplotlib.pylab.xlim(xMin, xMax) matplotlib.pylab.grid(True) if useAbsoluteTime: # if plot is less than 24 hours, force ticks to be every 4 hours xmin, xmax = matplotlib.pylab.xlim() xmin = xmin / (60*60) xmax = xmax / (60*60) if noDate == True: if xmax % 4 != 0: newXmax = 4 * (int(xmax/4.0) + 1) else: newXmax = xmax newXLocs = [] newXLabels = [] step = int((xmax-xmin-1)/6)+1 xRange = range(0,int(newXmax-xmin),step) for i in xRange: tmp = (xmin + i)*60*60 newXLocs.append(tmp) if (xmax - xmin) < 1: newXLocs.append(xmax*60*60) newXLabels = convertToAbsoluteTimeStr(newXLocs, noDate=noDate, timezone=timezone) matplotlib.pylab.xticks(newXLocs, newXLabels) else: locs, labels = matplotlib.pylab.xticks() if len(locs) > 5: # truncate by len(locs) / 5 scale = 1 + int(len(locs) / 5) new_locs = [] for i in range(len(locs)): if i % scale == 0: new_locs.append(locs[i]) locs = new_locs newXTicks = convertToAbsoluteTimeStr(locs, noTime) matplotlib.pylab.xticks(locs, newXTicks, rotation=15) else: # if plot is less than 48 hours, force ticks to be every 4 hours xmin, xmax = matplotlib.pylab.xlim() if xmax < 49: if xmax % 4 != 0: newXmax = 4 * (int(xmax/4.0) + 1) else: newXmax = xmax newXLocs = [] newXLabels = [] for i in range(0,int(4+newXmax),4): newXLocs.append(i) newXLabels.append(str(i)) matplotlib.pylab.xticks(newXLocs, newXLabels) matplotlib.pylab.xticks(fontsize=fontSize) if yMinimum != None and yMaximum != None: matplotlib.pylab.ylim(yMinimum, yMaximum) elif yMinimum != None and yMaximum == None: matplotlib.pylab.ylim(yMin=yMinimum) elif yMinimum == None and yMaximum != None: matplotlib.pylab.ylim(yMax=yMaximum) matplotlib.pylab.title(titleStr, fontsize=fontSize) matplotlib.pylab.legend(yParmList, numpoints=1, handlelength=0.05) matplotlib.pylab.savefig(fullFilename) matplotlib.pylab.clf() def __truncateIsprint(self, isprintText, maxLines): """__truncateIsprint truncates isprintText to have maxLines at most. """ isprintList = isprintText.split('\n') if len(isprintList) < maxLines: return isprintText else: dropNumber = int(1 + len(isprintList)/maxLines) newline = '\n' newIsprintText = newline.join(isprintList[::dropNumber]) return newIsprintText def __filter_missing(self,x): try: return float(x) except: return self.__missing def writeToFile(self, fullFilename): pass def displayToScreen(self): pass def getFigureHandle(self): pass class madXYScatterPlot: """madXYScatterPlot is the class the produces XY scatter plots. Change History: Written by "Brandon Scott Fines":mailto:bfines@haystack.mit.edu Aug 2, 2006 Written by "Bill Rideout":mailto:brideout@haystack.mit.edu Aug 2, 2006 """ def __init__(self,inputText, titleStr, xLabelStr, yLabelStr, fullFilename, size='small', lowBound=None, highBound=None, maxNumPoints=None, yLegend=None): """ Inputs: inputText - string of values to be plotted. The formatting is as follows: xval yval xval yval xval yval titleStr - title of the Plot xLabelStr - label for the x axis yLabelStr - label for the y axis fullFilename - full file path to save the resulting picture to size - size of plot to be saved. Must be 'small','wide', or 'large'. defaults to 'small'. lowBound - lower bound on the x-axis value. If no bound is specified, the lowest value found in inputText will be used. highBound - upper bound on the x-axis value. If no bound is specified, the highest value found in inputText will be used. maxNumPoints - maximum number of points to be plotted. Outputs: None Affects: Creates a scatter plot using matplotlib and writes that to the file designated by the variable 'fullFilename' Exceptions: ValueError if lowBound or highBound cannot be converted to a float value Non-standard python modules used: matplotlib """ #verify input if size not in ('small','wide','large'): raise ValueError, 'size must be "small","wide", or "large", not %s'%(str(size)) if size in ('small','wide'): fontSize = 12 elif size in 'large': fontSize = 18 if maxNumPoints !=None: inputText = self.__truncateInput(inputText, maxNumPoints) if lowBound !=None: #check that it is a number try: lowBound = float(lowBound) except ValueError: raise ValueError, 'lowBound not a number' try: highBound = float(highBound) except: raise ValueError, 'lowBound not a number' #convert the input data into numeric arrays x=[] y=[] split_data = inputText.split() #send x-values to x, y-values to y i=0 while i <len(split_data)-1: try: newX = float(split_data[i]) newY = float(split_data[i+1]) x.append(newX) y.append(newY) except: pass i=i+2 xlow =None xhigh = None # set min and max in x if specified if lowBound !=None and highBound !=None: xlow = lowBound xhigh = highBound elif lowBound !=None and highBound==None: #find the upper bound in x for i in x: if xhigh==None: xhigh = i if i>xhigh: xhigh = i xlow = lowBound elif lowBound==None and highBound !=None: #find the lower bound in x for i in x: if xlow==None: xlow = i if i<xlow: xlow = i xhigh=highBound else: #find lower and upper bounds for i in x: if xlow==None: xlow = i elif i<xlow: xlow = i if xhigh==None: xhigh = i elif i>xhigh: xhigh = i #find upper and lower bounds in y ylow = None yhigh = None for i in y: if ylow==None: ylow = i elif i<ylow: ylow = i if yhigh==None: yhigh = i elif i>yhigh: yhigh = i #check for good numbers if ylow == None: raise ValueError, 'no valid y data found' #select plot sizes if size=='small': matplotlib.pylab.figure(1,figsize=(6,4),facecolor='w') elif size=='wide': matplotlib.pylab.figure(1,figsize=(10,4),facecolor='w') elif size=='large': matplotlib.pylab.figure(1,figsize=(12,6),facecolor='w') #draw scatter plot #matplotlib.pylab.scatter(x,y) matplotlib.pylab.plot(x,y, 'gd',ms=5,mew=0.5) thisFont = {'size' : fontSize} matplotlib.pylab.rc('font', **thisFont) #pass in font dict as kwargs matplotlib.pylab.xlabel(xLabelStr,fontsize=fontSize) matplotlib.pylab.ylabel(yLabelStr,fontsize=fontSize) matplotlib.pylab.yticks(fontsize=fontSize) matplotlib.pylab.xticks(fontsize=fontSize) matplotlib.pylab.xlim(xlow,xhigh) matplotlib.pylab.title(titleStr,fontsize=fontSize) matplotlib.pylab.grid(True) if yLegend != None: matplotlib.pylab.legend(yLegend,numpoints=1,handlelength = 0.05) #save the figure matplotlib.pylab.savefig(fullFilename) matplotlib.pylab.clf() class madXYwithErrorPlot: """madXYwithErrorPlot is the class the produces two dimensional scatter plots of x versus y more its error. Written by "Miguel Urco":mailto:murco@jro.igp.gob.pe Jul 2, 2009 """ def __init__(self, isprintText, titleStr, xLabelStr, yLabelStr, fullFilename, size = 'small', useAbsoluteTime = False, startTime = None, endTime = None, maxNumPoints = None, noTime = False, noDate = False, yMinimum = None, yMaximum = None, timezone = 0): """__init__ writes a madScatter plot to a file. Inputs: isprintText - a string giving isprint output without headers. First of three parameters must be UTH or UT1, depending on whether time scale should be relative to the experiment beginning (UTH) or absolute (UT1). The second must be the parameter to be plotted. Any missing data should be written as "missing" or other string that cannot be converted to a float. titleStr - plot title (string) - should describe parameter being plotted xLabelStr - x label string yLabelStr - y label string fullFilename - full path of file containing pcolor plot to be saved. Extension must be jpeg or png, or exception thrown. size - size of plot to save. Must be "small", "wide", or "large". Defaults to small. useAbsoluteTime - if true, print time as YYYY-MM-DD HH:MM:SS. If false (default), print time as hour since beginning of experiment (UTH). If useAbsoluteTime is true, first parameter in isprintText must be UT1, if false, it must be UTH. startTime - start plot at given time. If useAbsoluteTime == True, then startTime must be in units of seconds since 1/1/1950. If useAbsoluteTime == False, then startTime must be in units of UTH (hours since midnight UT of first day of experiment). Default is None, which means start at lowest time found. endTime - end plot at given time. If useAbsoluteTime == True, then endTime must be in units of seconds since 1/1/1950. If useAbsoluteTime == False, then endTime must be in units of UTH (hours since midnight UT of first day of experiment). Default is None, which means end at largest time found. maxNumPoints - maximum number of points to plot. If not None, truncate isprintText if needed to have at most maxNumPoints lines. noDate - if True and useAbsoluteTime True, then times without dates printed on x axis. yMinimum - set y minimum. If default=None, use data minimum yMaximum - set y maximum. If default=None, use data maximum timezone - The offset of the local (non-DST) timezone, in seconds west of UTC (negative in most of Western Europe, positive in the US, zero in the UK). Returns: void Affects: None Now removes all lines with missing """ self.__missing = 1.0E30 # special value, since numpy doesn't handle NaN self.__parameter_count = 3 # verify input if size not in ('small', 'wide', 'large'): raise ValueError, 'size must be "small", "wide", or "large", not %s' % (str(size)) if size in ('small', 'wide'): fontSize = 12 elif size in ('large'): fontSize = 18 # filter out missing lines newIsprint = '' lines = isprintText.split('\n') for line in lines: try: items = line.split() float(items[0]) float(items[1]) float(items[2]) newIsprint += line + ' ' except: continue isprintText = newIsprint if maxNumPoints != None: isprintText = self.__truncateIsprint(isprintText, maxNumPoints) # convert the input data into numeric arrays of float assuming no headers and filter the missing values. try: split_data = isprintText.split() float_data = map(self.__filter_missing, split_data) array_data = numpy.asarray(float_data) array_data = numpy.reshape(array_data,(-1,self.__parameter_count)) except: traceback.print_exc() raise ValueError, 'input text is not parseable' # find min, max of x (time) if startTime == None: xMin = array_data[0,0] else: xMin = startTime if endTime == None: xMax = array_data[-1,0] else: xMax = endTime # find min, max of y, not including missing yMin = None yMax = None for y in array_data[:,1]: if y == self.__missing: continue if yMin == None: yMin = y elif yMin > y: yMin = y if yMax == None: yMax = y elif yMax < y: yMax = y if yMin == None: raise ValueError, 'No valid y data found' # select the plot size if size == 'small': matplotlib.pylab.figure(1, figsize=(8,3), facecolor = 'w') matplotlib.pylab.axes([0.11, 0.18, 0.78, 0.7]) elif size == 'wide': matplotlib.pylab.figure(1, figsize=(10,4), facecolor = 'w') elif size == 'large': matplotlib.pylab.figure(1, figsize=(10,6), facecolor = 'w') if useAbsoluteTime: # leave room for rotated datetime string if size == 'large': matplotlib.pylab.axes([0.1, 0.2, 0.8, 0.7]) elif size == 'wide': matplotlib.pylab.axes([0.07, 0.2, 0.66, 0.7]) elif size == 'small': matplotlib.pylab.axes([0.1, 0.18, 0.87, 0.7]) matplotlib.pylab.errorbar(array_data[:,0],array_data[:,2],array_data[:,1],ecolor='red',fmt='s',mfc='red',mec='green',ms=1,mew=1) thisFont = {'size': fontSize} matplotlib.pylab.rc('font', **thisFont) # pass in the font dict as kwargs matplotlib.pylab.xlabel(xLabelStr, fontsize=fontSize) matplotlib.pylab.ylabel(yLabelStr, fontsize=fontSize) matplotlib.pylab.yticks(fontsize=fontSize) matplotlib.pylab.xlim(xMin, xMax) matplotlib.pylab.title(titleStr, fontsize=fontSize) matplotlib.pylab.grid(True) if yMinimum != None and yMaximum != None: matplotlib.pylab.ylim(yMinimum, yMaximum) elif yMinimum != None and yMaximum == None: matplotlib.pylab.ylim(yMin=yMinimum) elif yMinimum == None and yMaximum != None: matplotlib.pylab.ylim(yMax=yMaximum) if useAbsoluteTime: # if plot is less than 24 hours, force ticks to be every 4 hours xmin, xmax = matplotlib.pylab.xlim() xmin = xmin / (60*60) xmax = xmax / (60*60) if noDate == True: if xmax % 4 != 0: newXmax = 4 * (int(xmax/4.0)+1) else: newXmax = xmax newXLocs = [] newXLabels = [] step = int((xmax-xmin-1)/6)+1 xRange = range(0,int(newXmax-xmin),step) for i in xRange: tmp = (xmin + i)*60*60 newXLocs.append(tmp) if (xmax - xmin) < 1: newXLocs.append(xmax*60*60) newXLabels = convertToAbsoluteTimeStr(newXLocs, noDate=noDate, timezone=timezone) matplotlib.pylab.xticks(newXLocs, newXLabels) else: locs, labels = matplotlib.pylab.xticks() if len(locs) > 5: # truncate by len(locs) / 5 scale = 1 + int(len(locs) / 5) new_locs = [] for i in range(len(locs)): if i % scale == 0: new_locs.append(locs[i]) locs = new_locs newXTicks = convertToAbsoluteTimeStr(locs) matplotlib.pylab.xticks(locs, newXTicks, rotation=15) matplotlib.pylab.xticks(fontsize=fontSize) # get the handle to the figure now that it has been created so we can manipulate on subsequent calls. #self.__figure = matplotlib.pylab.gcf() matplotlib.pylab.savefig(fullFilename) #matplotlib.pylab.show() matplotlib.pylab.clf() def __truncateInput(self,inputStr,maxLines): """__truncateInput truncates inputStr to have maxLines at most """ inputList = inputStr.split('\n') if len(inputList)<maxLines: return inputStr else: dropNumber = int(len(inputList)/maxLines) newline = '\n' newInputText = newline.join(inputList[::dropNumber]) return newInputText def __filter_missing(self,x): try: return float(x) except: return self.__missing class madPcolorPlot: """madPcolorPlot is the class that produces pcolor plots of x versus y with z intensity. Assumes the x axis is time. Usage example:: obj = madPcolorPlot(isprintText, 'Nel (log(m^-3)) - Millstone Hill - Oct. 30, 2003 - Alt code', 'Hours since midnight UT Oct. 30, 2003', 'Altitude (km)', './isprint.png', size = 'large', minColormap = 9, maxColormap = 12, smoothAltitude = False) Non-standard Python modules used: matplotlib Change history: Written by "Bill Rideout":mailto:wrideout@haystack.mit.edu Mar. 31, 2005 """ def __init__(self, isprintText, titleStr, xLabelStr, yLabelStr, fullFilename, size = 'small', minColormap = None, maxColormap = None, smoothAltitude = True, insertDataGap = 5, useAbsoluteTime = False, startTime = None, endTime = None, sortTimeFlag = False, maxNumTimes = None, maxNumAlt = None, truncateIsprint = False, colorMap = matplotlib.cm.jet, yMinimum = None, yMaximum = None, altYTitle = None, altYLabels = None, noTime = False, noDate = False, timezone = 0, background = 'w', peakAltStr = None): """__init__ writes a madPColorPlot to a file. Inputs: isprintText - a string giving isprint output without headers. First parameter must be UTH or UT1, depending on whether time scale should be relative to the experiment beginning (UTH) or absolute (UT1). The second must be gdalt, and third parameter to be plotted. Any missing data should be written as "missing" or other string that cannot be converted to a float. titleStr - plot title (string) - should describe parameter being plotted xLabelStr - x label string yLabelStr - ylabel string fullFilename - full path of file containing pcolor plot to be saved. Extension must be jpeg or png, or exception thrown. size - size of plot to save. Must be "small", "wide", or "large". Defaults to small. minColormap - minimum parameter value (defaults to lowest parameter value) maxColormap - maximum parameter value (defaults to highest parameter value). However, if both minColormap and maxColormap == None, autoscaling applied. smoothAltitude - if True, extrapolate between existing data between altitudes to fill in missing data; if False, leave missing insertDataGap - this parameter sets the threshold for inserting a data gap. The time intervals being plotted are ordered, and the time gap larger than 90% of the rest is determined. Any time interval more than insertDataGap times bigger is then considered missing data. Defaults to five. If None, no gaps are ever inserted. For data with close to uniform time intervals, no gaps will be inserted. useAbsoluteTime - if true, print time as YYYY-MM-DD HH:MM:SS. If false (default), print time as hour since beginning of experiment (UTH). If useAbsoluteTime is true, first parameter in isprintText must be UT1, if false, it must be UTH. startTime - start plot at given time. If useAbsoluteTime == True, then startTime must be in units of seconds since 1/1/1950. If useAbsoluteTime == False, then startTime must be in units of UTH (hours since midnight UT of first day of experiment). Default is None, which means start at lowest time found. endTime - end plot at given time. If useAbsoluteTime == True, then endTime must be in units of seconds since 1/1/1950. If useAbsoluteTime == False, then endTime must be in units of UTH (hours since midnight UT of first day of experiment). Default is None, which means end at largest time found. sortTimeFlag - if true, check that time is correctly sorted. If false (the default), assume time already sorted maxNumTimes - if not None, decimate the number of times in the isprint string to maxNumTimes. If None (the default), plot all times. maxNumAlt - if not None, reduce the number of altitudes to maxNumAlt. If None (the default), plot all altitudes. truncateIsprint - if True, and both maxNumTimes and maxNumAlt not = None, then truncate the number of isprint lines to be maxNumTimes * maxNumAlt colorMap - sets colormap. It not given, defaults to matplotlib.cm.jet yMinimum - minumum y value. If None (default), set by data y minimum. yMaximum - maximum y value. If None (default), set by data y maximum. altYTitle - title of right (second) y axis. If None (the default), no Y axis on the right side. altYLabels - a list of Y labels (strings) for the right axis. If None (the default), no Y labels on the right axis. noDate - if True and useAbsoluteTime True, then times without dates printed on x axis. timezone - The offset of the local (non-DST) timezone, in seconds west of UTC (negative in most of Western Europe, positive in the US, zero in the UK). peakAltStr - if not None (the default), plot the peak altitude with x. Format is a str with each line (time in same format as data, peak altitude) Returns: void Affects: None """ self.__missing = 1.0E30 # special value, used to create a masked array self.__parameter_count = 3 # verify input if size not in ('small', 'wide', 'large'): raise ValueError, 'size must be "small", "wide", or "large", not %s' % (str(size)) if size in ('small'): fontSize = 10 elif size in ('wide'): fontSize = 12 elif size in ('large'): fontSize = 18 if truncateIsprint and maxNumTimes != None and maxNumAlt != None: isprintText = self.__truncateIsprint(isprintText, maxNumTimes * maxNumAlt) # since matplotlib pcolor wants a regular grid, we create a grid with all altitudes # convert the input data into numeric arrays of float assuming no headers and filter the missing values. try: split_data = isprintText.split() float_data = map(self.__filter_missing, split_data) array_data = numpy.asarray(float_data) array_data = numpy.reshape(array_data,(-1,self.__parameter_count)) except: traceback.print_exc() raise ValueError, 'input text is not parseable' if sortTimeFlag: array_data = self.sortArrayInTime(array_data) if maxNumTimes != None and maxNumTimes != 0 and not truncateIsprint: array_data = self.decimateTimes(array_data, int(maxNumTimes), insertDataGap) # The first pass through is to obtain the number and range of the x and y variables xList = [] yList = [] zList = [] zMin = None zMax = None # loop over all the lines of data in the array for j in range(len(array_data)): try: x = array_data[j][0] y = array_data[j][1] z = array_data[j][2] if x not in xList: xList.append(x) if y not in yList: yList.append(y) if z != self.__missing: zList.append(z) if zMin != None: if z < zMin and z != self.__missing: zMin = z elif z != self.__missing: zMin = z if zMax != None: if z > zMax and z != self.__missing: zMax = z elif z != self.__missing: zMax = z except: continue if zMin == None: raise ValueError, 'No valid z data found' # if both minColormap and maxColormap == None, use autoscaling if minColormap == None and maxColormap == None: zList.sort() d10 = zList[int(len(zList)*0.10)] d90 = zList[int(len(zList)*0.90)] zMin = d10 - (d90-d10) * 0.75 zMax = d90 + (d90-d10) * 0.75 # now sort the X and Y axis lists and pull their length xList.sort() if startTime == None: xMin = xList[0] else: xMin = startTime if endTime == None: xMax = xList[-1] else: xMax = endTime yList.sort() max_x_dimension = len(xList) max_y_dimension = len(yList) if yMinimum == None: yMinimum = yList[0] if yMaximum == None: yMaximum = yList[-1] self.truncateAlt = False if maxNumAlt != None: if max_y_dimension > maxNumAlt: self.truncateAlt = True # build dictonary of indexes into xList self.xListDict = {} for i in range(len(xList)): self.xListDict[xList[i]] = i # if self.truncateAlt == False, build dictonary of indexes into yList, # else truncate y values by builing a list of maxNumAlt ranges if self.truncateAlt == False: self.yListDict = {} for i in range(len(yList)): self.yListDict[yList[i]] = i else: self.yListRanges = [] for i in range(maxNumAlt): self.yListRanges.append(yList[int(i*(len(yList)/maxNumAlt))]) max_y_dimension = maxNumAlt # now build arrays to handle the X axis label, Y axis label, and the Z data X = numpy.zeros((max_x_dimension, max_y_dimension), numpy.float32) Y = numpy.zeros((max_x_dimension, max_y_dimension), numpy.float32) Z = numpy.ones((max_x_dimension, max_y_dimension), numpy.float32) # all parameter values default to missing Z = Z * self.__missing # fill the X and Y arrays for i in range(max_x_dimension): for j in range(max_y_dimension): X[i][j] = float(xList[i]) if self.truncateAlt: Y[i][j] = float(yList[int(j*(len(yList)/maxNumAlt))]) else: Y[i][j] = float(yList[j]) # Now load up the data array Z with the array_data measurements as a function of x and y previousIndex = None previousValue = None presentTime = None newTimeFound = True for k in range(len(array_data)): try: xdata = array_data[k][0] ydata = array_data[k][1] zdata = array_data[k][2] if zdata == self.__missing: continue if xdata != presentTime: newTimeFound = True else: newTimeFound = False presentTime = xdata # now find the right place in the array for this data point i = self.xListDict[xdata] j = self.__getYIndex(ydata) Z[i][j] = zdata # now see if we need to fill in any gaps if (not newTimeFound) and smoothAltitude: if previousIndex < j - 1: # fill in all missing points for l in range(previousIndex + 1, j): # simply average between the points based on index thisValue = previousValue + (zdata - previousValue)*(float(l-previousIndex)/float(j-previousIndex)) Z[i][l] = thisValue previousIndex = j previousValue = zdata except: continue # insert missing data to represent gaps if needed if insertDataGap != None: # first find the time interval greater than 90% of others timeIntervalList = [] for i in range(len(xList) - 1): timeIntervalList.append(xList[i+1] - xList[i]) timeIntervalList.sort() index = int(len(timeIntervalList)*0.9) maxInterval = timeIntervalList[index] for i in range(len(xList) - 1): if xList[i+1] - xList[i] > maxInterval * insertDataGap: Z[i,:] = self.__missing # insert missing data to represent gaps if needed in Altitude if insertDataGap != None and not smoothAltitude: # first find the time interval greater than 90% of others altitudeIntervalList = [] for i in range(len(yList) - 1): altitudeIntervalList.append(yList[i+1] - yList[i]) altitudeIntervalList.sort() index = int(len(altitudeIntervalList)*0.9) maxInterval = altitudeIntervalList[index] for j in range(len(yList) - 1): if yList[j+1] - yList[j] > maxInterval * insertDataGap and j < max_y_dimension: Z[:,j] = self.__missing # make Z a masked array Znew = numpy.ma.masked_inside(Z, 0.99*self.__missing, 1.01*self.__missing) # set up plotting parameters if minColormap == None: minColormap = zMin if maxColormap == None: maxColormap = zMax # select the plot size if size == 'small': matplotlib.pylab.figure(1, figsize=(8,3), facecolor = 'w') elif size == 'wide': matplotlib.pylab.figure(1, figsize=(10,4), facecolor = 'w') elif size == 'large': matplotlib.pylab.figure(1, figsize=(14,5), facecolor = 'w') if useAbsoluteTime: # leave room for rotated datetime string if size == 'large': matplotlib.pylab.axes([0.1, 0.1, 0.85, 0.7]) elif size == 'wide': matplotlib.pylab.axes([0.07, 0.2, 0.97, 0.7]) elif size == 'small': matplotlib.pylab.axes([0.1, 0.18, 0.97, 0.7]) else: if size == 'small': matplotlib.pylab.axes([0.1, 0.18, 0.97, 0.7]) elif size == 'large': matplotlib.pylab.axes([0.1, 0.2, 0.9, 0.73]) matplotlib.pylab.pcolor(X,Y,Znew, edgecolors='none', vmin=minColormap, vmax=maxColormap, cmap = colorMap, norm = matplotlib.pylab.Normalize(), edgecolor='face') matplotlib.pylab.colorbar() thisFont = {'size': fontSize} matplotlib.pylab.rc('font', **thisFont) # pass in the font dict as kwargs matplotlib.pylab.xlabel(xLabelStr, fontsize=fontSize) matplotlib.pylab.ylabel(yLabelStr, fontsize=fontSize) matplotlib.pylab.xlim(xMin, xMax) matplotlib.pylab.ylim(yMinimum, yMaximum) matplotlib.pylab.yticks(fontsize=fontSize) matplotlib.pylab.title(titleStr, fontsize=fontSize) if useAbsoluteTime: # if plot is less than 49 hours xmin, xmax = matplotlib.pylab.xlim() xmin = numpy.floor(xmin / (60*60)) xmax = numpy.ceil(xmax / (60*60)) if noDate == True: newXLabels = [] if (xmax - xmin) <= 1: newXLocs = [] xRange = numpy.arange(0,1,0.25) for i in xRange: tmp=(xmin+i)*60*60 newXLocs.append(tmp) elif (xmax - xmin) <= 2: newXLocs = [] xRange = numpy.arange(0,2,0.5) for i in xRange: tmp=(xmin+i)*60*60 newXLocs.append(tmp) else: newXLocs = [] step = int((xmax-xmin-1)/6)+1 xRange = range(0,int(xmax-xmin),step) for i in xRange: tmp = (xmin + i)*60*60 newXLocs.append(tmp) #newXLocs.append(xmax*60*60) newXLabels = convertToAbsoluteTimeStr(newXLocs, noDate=noDate, timezone=timezone) matplotlib.pylab.xticks(newXLocs, newXLabels) else: locs, labels = matplotlib.pylab.xticks() if len(locs) > 5: # truncate by len(locs) / 5 scale = 1 + int(len(locs) / 5) new_locs = [] for i in range(len(locs)): if i % scale == 0: new_locs.append(locs[i]) locs = new_locs newXTicks = convertToAbsoluteTimeStr(locs) matplotlib.pylab.xticks(locs, newXTicks, rotation=15) else: # if plot is less than 48 hours, force ticks to be every 4 hours xmin, xmax = matplotlib.pylab.xlim() if xmax < 49: if xmax % 4 != 0: newXmax = 4 * (int(xmax/4.0) + 1) else: newXmax = xmax newXLocs = [] newXLabels = [] for i in range(0,int(4+newXmax),4): newXLocs.append(i) newXLabels.append(str(i)) matplotlib.pylab.xticks(newXLocs, newXLabels) matplotlib.pylab.xticks(fontsize=fontSize) # add second y-axis if desired if altYTitle != None and altYLabels != None: ax2 = matplotlib.pylab.twinx() matplotlib.pylab.ylabel(altYTitle) ax2.yaxis.tick_right() matplotlib.pylab.yticks(range(len(altYLabels)), altYLabels) matplotlib.pylab.yticks(fontsize=fontSize) # get the handle to the figure now that it has been created so we can manipulate on subsequent calls. #self.__figure = matplotlib.pylab.gcf() if peakAltStr: # plot peak altitudes data = peakAltStr.split() xdata = [float(item) for i, item in enumerate(data) if i % 2 == 0] ydata = [float(item) for i, item in enumerate(data) if i % 2 == 1] matplotlib.pylab.plot(xdata, ydata, 'b+') matplotlib.pylab.savefig(fullFilename) #matplotlib.pylab.show() matplotlib.pylab.clf() def __filter_missing(self,x): try: return float(x) except: return self.__missing def __getYIndex(self, yvalue): """__getYIndex returns the correct index into the y dimension for a given y value. Input: yvalue - value of y parameter Returns: the correct index into the y dimension Algorithm: if self.truncateAlt == False, simple use the dictionary self.yListDict. Else loop through self.yListRanges and return the first greater than the requested value """ if self.truncateAlt == False: return self.yListDict[yvalue] else: i = bisect.bisect_left(self.yListRanges, yvalue) if i >= len(self.yListRanges): i = len(self.yListRanges) - 1 return i def __truncateIsprint(self, isprintText, maxLines): """__truncateIsprint truncates isprintText to have maxLines at most. """ isprintList = isprintText.split('\n') if len(isprintList) < maxLines: return isprintText else: dropNumber = int(1 + len(isprintList)/maxLines) newIsprintText = '' for i in range(0,len(isprintList),dropNumber): newIsprintText += isprintList[i] + '\n' return newIsprintText def displayToScreen(self): " to implement this takes a reworking away from pylab to use the underlying matplotlib code " pass def getFigureHandle(self): return self.__figure def getAverage(self, X): """returns the average of items in a float array. Does not including missing data. If all data missing, returns self.__missing """ count = 0 total = 0.0 for i in range(X.shape[0]): if X[i] != self.__missing: count += 1 total += X[i] if count == 0: return self.__missing else: return total / float(count) def sortArrayInTime(self, array_data): """sortArrayInTime sorts a two-dimensional array so that the first element in each row (time) is in ascending order. Input: array_data - two-dimensional array to be sorted by rearranging rows so that the first element in each row (time) is in ascending order Returns: new_array """ sortIndex = numpy.argsort(array_data[:,0])[0] # if already sorted, just return original array if sortIndex == numpy.sort(sortIndex): return array_data new_array = numpy.zeros(array_data.shape, array_data.dtype) for i in range(len(sortIndex)): new_array[sortIndex[i],:] = array_data[i,:] return new_array def decimateTimes(self, array_data, maxNumTimes, insertDataGap): """decimateTimes decimates array_data to have at most maxNumTimes times. Input: array_data - two-dimensional array to be decimated by deleting times and missing data. maxNumTimes: int representing the maximum number of times to keep in array_data insertDataGap - this parameter sets the threshold for inserting a data gap. The time intervals being plotted are ordered, and the time gap larger than 90% of the rest is determined. Note that this parameter is used here to stop the truncation of isprint lines that will eventually be considered edge lines. Returns: new array built from decimated array_data """ # get the number of times in array_data, and make a list of all unique times numTimes = 0 uniqueTimes = [] time_array = array_data[:, 0] for i in range(len(time_array)): if i == 0: numTimes = 1 uniqueTimes.append(time_array[i]) elif time_array[i-1] != time_array[i]: uniqueTimes.append(time_array[i]) numTimes += 1 if numTimes <= maxNumTimes: return array_data # insert missing data to represent gaps if needed gapTimes = [] if insertDataGap != None: # first find the time interval greater than 90% of others timeIntervalList = [] for i in range(len(time_array) - 1): if time_array[i+1] == time_array[i]: continue timeIntervalList.append(time_array[i+1] - time_array[i]) timeIntervalList.sort() index = int(len(timeIntervalList)*0.9) maxInterval = timeIntervalList[index] for i in range(len(time_array) - 1): if time_array[i+1] - time_array[i] > maxInterval * insertDataGap: gapTimes.append(time_array[i+1]) gapTimes.append(time_array[i]) # get the number of times to skip each time numSkip = numTimes/maxNumTimes # get the number of rows in the new_array numRows = 0 numTimes = 0 useThisTime = False for i in range(len(time_array)): if i == 0: numTimes = 1 elif time_array[i-1] != time_array[i]: numTimes += 1 if numTimes % (numSkip + 1) == 0 or time_array[i] in gapTimes: useThisTime = True if array_data[i, -1] != self.__missing: numRows += 1 else: useThisTime = False else: if useThisTime: if array_data[i, -1] != self.__missing: numRows += 1 # create new_array new_array = numpy.zeros((numRows, array_data.shape[1]), array_data.dtype) # copy selected rows to new_array numRows = 0 numTimes = 0 useThisTime = False for i in range(len(time_array)): if i == 0: numTimes = 1 elif time_array[i-1] != time_array[i]: numTimes += 1 if numTimes % (numSkip + 1) == 0 or time_array[i] in gapTimes: useThisTime = True if array_data[i, -1] != self.__missing: new_array[numRows,:] = array_data[i,:] numRows += 1 else: useThisTime = False else: if useThisTime: if array_data[i, -1] != self.__missing: new_array[numRows,:] = array_data[i,:] numRows += 1 return new_array class madPcolorScan: """madPcolorScan is the class that produces pcolor scans. Usage example:: obj = madPcolorScan(isprintText, 'Nel (log(m^-3)) - 26 June 2006 13:49:43-14:07:36', 'Longitude', 'Latitude', './isprint.png', size = 'large', minColormap = 9, maxColormap = 12) Non-standard Python modules used: matplotlib Change history: Written by "Bill Rideout":mailto:wrideout@haystack.mit.edu Jul. 20, 2006 """ def __init__(self, isprintText, xGridSize, yGridSize, titleStr, xLabelStr, yLabelStr, fullFilename, size = 'small', xMinimum = None, xMaximum = None, yMinimum = None, yMaximum = None, minColormap = None, maxColormap = None, colorMap = matplotlib.cm.jet, maxNumLines = None): """__init__ writes a madPcolorScan to a file. Inputs: isprintText - a string giving isprint output without headers. First parameter must be the X axis value, and the second must be the Y axis value. The third column is the value (intensity). Any missing data should be written as "missing" or other string that cannot be converted to a float. xGridSize - grid size for x data (for example 0.1 for 0.1 degree longitude grid) yGridSize - grid size for x data (for example 0.1 for 0.1 degree latitude grid) titleStr - plot title (string) - should describe parameter being plotted xLabelStr - x label string yLabelStr - ylabel string fullFilename - full path of file containing pcolor plot to be saved. Extension must be jpeg or png, or exception thrown. size - size of plot to save. Must be "small", "wide", or "large". Defaults to small. xMinimum = minumum x value. If None (default), uses lowest x value found. xMaximum = maximum x value. If None (default), uses highest x value found. yMinimum = minumum y value. If None (default), uses lowest y value found. yMaximum = maximum y value. If None (default), uses highest y value found. minColormap - minimum parameter value (defaults to lowest parameter value) maxColormap - maximum parameter value (defaults to highest parameter value). However, if both minColormap and maxColormap == None, autoscaling applied. colorMap - sets colormap. It not given, defaults to matplotlib.cm.jet maxNumLine - max number of lines in isprintText before truncating. If None, no truncation Returns: void Affects: None """ self.__missing = 1.0E30 # special value, used to create a masked array self.__parameter_count = 3 self.__xGridSize = int(xGridSize) self.__yGridSize = int(yGridSize) self.__parseCount = 0 # used to tell which column self.__filter_input is working on # verify input if size not in ('small', 'wide', 'large'): raise ValueError, 'size must be "small", "wide", or "large", not %s' % (str(size)) if size in ('small', 'wide'): fontSize = 12 elif size in ('large'): fontSize = 18 if maxNumLines != None: isprintText = self.__truncateIsprint(isprintText, maxNumLines) # since matplotlib pcolor wants a regular grid, we create a grid with all altitudes # convert the input data into numeric arrays of float assuming no headers and filter the missing values. try: split_data = isprintText.split() float_data = map(self.__filter_input, split_data) array_data = numpy.asarray(float_data) array_data = numpy.reshape(array_data,(-1,self.__parameter_count)) except: traceback.print_exc() raise ValueError, 'input text is not parseable' array_data = self.sortArrayInX(array_data) # The first pass through is to obtain the number and range of the x and y variables xList = [] yList = [] zList = [] zMin = None zMax = None # loop over all the lines of data in the array for j in range(len(array_data)): try: x = array_data[j][0] y = array_data[j][1] z = array_data[j][2] if x not in xList: xList.append(x) if y not in yList: yList.append(y) if z != self.__missing: zList.append(z) if zMin != None: if z < zMin and z != self.__missing: zMin = z elif z != self.__missing: zMin = z if zMax != None: if z > zMax and z != self.__missing: zMax = z elif z != self.__missing: zMax = z except: continue if zMin == None: raise ValueError, 'No valid z data found' # if both minColormap and maxColormap == None, use autoscaling if minColormap == None and maxColormap == None: zList.sort() d10 = zList[int(len(zList)*0.10)] d90 = zList[int(len(zList)*0.90)] zMin = d10 - (d90-d10) * 0.75 zMax = d90 + (d90-d10) * 0.75 # now sort the X and Y axis lists and pull their length xList.sort() xMin = xList[0] xMax = xList[-1] yList.sort() yMin = yList[0] yMax = yList[-1] max_x_dimension = len(xList) max_y_dimension = len(yList) # build dictonary of indexes into xList self.xListDict = {} for i in range(len(xList)): self.xListDict[xList[i]] = i # build dictonary of indexes into yList, self.yListDict = {} for i in range(len(yList)): self.yListDict[yList[i]] = i # now build arrays to handle the X axis label, Y axis label, and the Z data X = numpy.zeros((max_x_dimension, max_y_dimension), numpy.float32) Y = numpy.zeros((max_x_dimension, max_y_dimension), numpy.float32) Z = numpy.ones((max_x_dimension, max_y_dimension), numpy.float32) # all parameter values default to missing Z = Z * self.__missing # fill the X and Y arrays for i in range(max_x_dimension): for j in range(max_y_dimension): X[i][j] = float(xList[i]) Y[i][j] = float(yList[j]) # Now load up the data array Z with the array_data measurements as a function of x and y previousIndex = None previousValue = None presentTime = None newTimeFound = True for k in range(len(array_data)): try: xdata = self.__round(array_data[k][0], self.__xGridSize) ydata = self.__round(array_data[k][1], self.__yGridSize) zdata = array_data[k][2] if zdata == self.__missing: continue if xdata != presentTime: newTimeFound = True else: newTimeFound = False presentTime = xdata # now find the right place in the array for this data point i = self.xListDict[xdata] j = self.yListDict[ydata] Z[i][j] = zdata previousIndex = j previousValue = zdata except: continue # make Z a masked array Znew = numpy.ma.masked_inside(Z, 0.99*self.__missing, 1.01*self.__missing) # set up plotting parameters if xMinimum == None: xMinimum = xMin if xMaximum == None: xMaximum = xMax if yMinimum == None: yMinimum = yMin if yMaximum == None: yMaximum = yMax if minColormap == None: minColormap = zMin if maxColormap == None: maxColormap = zMax # select the plot size if size == 'small': matplotlib.pylab.figure(1, figsize=(6,4), facecolor = 'w') elif size == 'wide': matplotlib.pylab.figure(1, figsize=(10,4), facecolor = 'w') elif size == 'large': matplotlib.pylab.figure(1, figsize=(12,6), facecolor = 'w') matplotlib.pylab.pcolor(X,Y,Znew, edgecolors='none', vmin=minColormap, vmax=maxColormap, cmap = colorMap, norm = matplotlib.pylab.Normalize()) matplotlib.pylab.colorbar() thisFont = {'size': fontSize} matplotlib.pylab.rc('font', **thisFont) # pass in the font dict as kwargs matplotlib.pylab.xlabel(xLabelStr, fontsize=fontSize) matplotlib.pylab.ylabel(yLabelStr, fontsize=fontSize) matplotlib.pylab.xlim(xMinimum, xMaximum) matplotlib.pylab.ylim(yMinimum, yMaximum) matplotlib.pylab.yticks(fontsize=fontSize) matplotlib.pylab.title(titleStr, fontsize=fontSize) # get the handle to the figure now that it has been created so we can manipulate on subsequent calls. #self.__figure = matplotlib.pylab.gcf() try: matplotlib.pylab.savefig(fullFilename) except: matplotlib.pylab.clf() raise #matplotlib.pylab.show() matplotlib.pylab.clf() def __round(self, value, increment): """__round returns a value to the nearest increment """ return value - math.fmod(value, increment) def __filter_input(self,x): """__filter_input is called in map to convert missing strings to self.__missing, and to round x and y vales to the nearest xGridSize or yGridSize """ try: value = float(x) if self.__parseCount % 3 == 0: # x value value = self.__round(value, self.__xGridSize) elif self.__parseCount % 3 == 1: # y value value = self.__round(value, self.__yGridSize) except: value = self.__missing self.__parseCount += 1 return value def __truncateIsprint(self, isprintText, maxLines): """__truncateIsprint truncates isprintText to have maxLines at most. """ isprintList = isprintText.split('\n') if len(isprintList) < maxLines: return isprintText else: dropNumber = int(1 + len(isprintList)/maxLines) newIsprintText = '' for i in range(0,len(isprintList),dropNumber): newIsprintText += isprintList[i] + '\n' return newIsprintText def displayToScreen(self): " to implement this takes a reworking away from pylab to use the underlying matplotlib code " pass def getFigureHandle(self): return self.__figure def getAverage(self, X): """returns the average of items in a float array. Does not including missing data. If all data missing, returns self.__missing """ count = 0 total = 0.0 for i in range(X.shape[0]): if X[i] != self.__missing: count += 1 total += X[i] if count == 0: return self.__missing else: return total / float(count) def sortArrayInX(self, array_data): """sortArrayInX sorts a two-dimensional array so that the first element in each row (x) is in ascending order. Input: array_data - two-dimensional array to be sorted by rearranging rows so that the first element in each row (x) is in ascending order Returns: new_array """ sortIndex = numpy.argsort(array_data[:,0])[0] # if already sorted, just return original array if sortIndex == numpy.sort(sortIndex): return array_data new_array = numpy.zeros(array_data.shape, array_data.dtype) for i in range(len(sortIndex)): new_array[sortIndex[i],:] = array_data[i,:] return new_array class madPcolorWedgeScan: """madPcolorWedgeScan is the class that produces pcolor scans where data is drawn as wedge shapes. Usage example:: obj = madPcolorScan(isprintText, 'Nel (log(m^-3)) - 26 June 2006 13:49:43-14:07:36', 'Longitude', 'Latitude', './isprint.png', size = 'large', minColormap = 9, maxColormap = 12) Non-standard Python modules used: matplotlib Change history: Written by "Bill Rideout":mailto:wrideout@haystack.mit.edu Jul. 20, 2006 """ def __init__(self, isprintText, scanType, titleStr, xLabelStr, yLabelStr, fullFilename, size = 'small', xMinimum = None, xMaximum = None, yMinimum = None, yMaximum = None, minColormap = None, maxColormap = None, colorMap = matplotlib.cm.jet): """__init__ writes a madPcolorWedgeScan to a file. Inputs: isprintText - a string giving isprint output without headers. The 9 parameters are (gdlatr, gdlonr, galtr, range, az1, az2, el1, el2, <parameter value>). Any missing data should be written as "missing" or other string that cannot be converted to a float. gdlatr, gdlonr, galtr are the station location scanType - must be 'az' or 'el_lat' (for north or south el scans), 'el_lon' (for east or west el scans) or 'el_gcdist' (for all other el scans. For az - x is long, y is lat for el_* y is always alt, and x is either lat, lon, or great circle distance titleStr - plot title (string) - should describe parameter being plotted xLabelStr - x label string yLabelStr - ylabel string fullFilename - full path of file containing pcolor plot to be saved. Extension must be jpeg or png, or exception thrown. size - size of plot to save. Must be "small", "wide", or "large". Defaults to small. xMinimum = minumum x value. If None (default), uses lowest value found. xMaximum = maximum x value. If None (default), uses highest value found. yMinimum = minumum y value. If None (default), uses lowest value found. yMaximum = maximum y value. If None (default), uses highest value found. minColormap - minimum parameter value (defaults to lowest parameter value) maxColormap - maximum parameter value (defaults to highest parameter value). However, if both minColormap and maxColormap == None, autoscaling applied. colorMap - sets colormap. It not given, defaults to matplotlib.cm.jet Returns: void Affects: Writes fullFilename to disk """ # verify input if scanType not in ('az', 'el_lat', 'el_lon', 'el_gcdist'): raise ValueError, 'scanType must be "az", "el_lat", "el_lon", "el_gcdist", not %s' % (str(scanType)) if size not in ('small', 'wide', 'large'): raise ValueError, 'size must be "small", "wide", or "large", not %s' % (str(size)) if size in ('small', 'wide'): fontSize = 12 elif size in ('large'): fontSize = 18 isprintLines = isprintText.split('\n') if xMaximum == None or xMinimum == None or yMaximum == None or yMinimum or maxColormap == None or minColormap == None: newLonMax, newLonMin, newLatMax, newLatMin, newAltMax, newGreatCDist, newParmMax, newParmMin = self._getLimits(isprintLines) # set values xMaximum, xMinimum, yMaximum, yMinimum = self._setLimits(scanType, xMaximum, xMinimum, yMaximum, yMinimum, newLonMax, newLonMin, newLatMax, newLatMin, newAltMax, newGreatCDist, newParmMax, newParmMin) if maxColormap == None: maxColormap = newParmMax if minColormap == None: minColormap = newParmMin # set up wedge generator dataGen = self._generateWedges(isprintLines, scanType) # select the plot size if size == 'small': matplotlib.pylab.figure(1, figsize=(6,5), facecolor = 'w') elif size == 'wide': matplotlib.pylab.figure(1, figsize=(10,4), facecolor = 'w') elif size == 'large': matplotlib.pylab.figure(1, figsize=(12,6), facecolor = 'w') matplotlib.pylab.hold(True) try: while True: data = dataGen.next() x = [data[1][0], data[2][0], data[3][0], data[4][0]] y = [data[1][1], data[2][1], data[3][1], data[4][1]] dataRatio = (data[0] - minColormap) / (maxColormap - minColormap) colorStr = matplotlib.colors.rgb2hex(colorMap(dataRatio)[:3]) thisPlot = matplotlib.pyplot.fill(x, y, colorStr, edgecolor='none') except StopIteration: pass thisFont = {'size': fontSize} matplotlib.pylab.rc('font', **thisFont) # pass in the font dict as kwargs scalableMappable = matplotlib.cm.ScalarMappable(cmap=colorMap) scalableMappable.set_array(numpy.array([minColormap, maxColormap])) scalableMappable.set_clim(minColormap, maxColormap) def get_alpha(*args, **kw): return(1.0) scalableMappable.get_alpha = get_alpha matplotlib.pylab.xlabel(xLabelStr, fontsize=fontSize) matplotlib.pylab.ylabel(yLabelStr, fontsize=fontSize) matplotlib.pylab.xlim(xMinimum, xMaximum) matplotlib.pylab.ylim(yMinimum, yMaximum) matplotlib.pylab.yticks(fontsize=fontSize) matplotlib.pylab.title(titleStr, fontsize=fontSize) matplotlib.pylab.colorbar(mappable=scalableMappable) matplotlib.pylab.gcf().subplots_adjust(bottom=0.15) try: matplotlib.pylab.savefig(fullFilename) except: matplotlib.pylab.clf() raise matplotlib.pylab.clf() def getGreatCircleDist(self, gdlatr, glonr, gdlat, glon): """getGreatCircleDist return the great circle distance in. Taken from madDeriveMethods c code. Inputs: gdlatr, glonr: reference point on earth's surface gdlat, glon: second point on earth's surface """ dlon = glonr/57.2958 - glon/57.2958 dlat = gdlatr/57.2958 - gdlat/57.2958; a = math.sin(dlat/2.0)*math.sin(dlat/2.0) + math.cos(gdlatr/57.2958)*math.cos(gdlat/57.2958) * math.sin(dlon/2.0)*math.sin(dlon/2.0) if math.sqrt(a) < 1.0: c = 2.0 * math.asin(math.sqrt(a)) else: c = 2.0 * math.asin(1.0) return(c * 6371.2) def _getLimits(self, isprintLines): """returns (newLonMax, newLonMin, newLatMax, newLatMin, newAltMax, newGreatCDist, newParmMax, newParmMin) given isprint lines with parameters (gdlatr, gdlonr, galtr, range, az1, az2, el1, el2, <parameter value>) We only look at the end points of ranges and the station location """ # set initial values to station location items = isprintLines[1].split() slat = float(items[0]) slon = float(items[1]) if slon > 180.0: slon -= 360.0 salt = float(items[2]) maxLon = slon minLon = slon maxLat = slat minLat = slat maxAlt = salt maxGreatCDist = 0.0 maxParm = -1.0e-30 minParm = 1.0e30 lastAz = None lastEl = None lastRange = None for i, isprintLine in enumerate(isprintLines): items = isprintLine.split() if len(items) < 9: continue range = float(items[3]) az1 = float(items[4]) az2 = float(items[5]) thisAz = (az1 + az2)/2 el1 = float(items[6]) el2 = float(items[7]) thisEl = (el1 + el2)/2 try: parm = float(items[8]) if parm > maxParm: maxParm = parm if parm < minParm: minParm = parm except ValueError: continue # see if we're at an end point if lastAz != None: if abs(lastAz - thisAz) > 0.001 or abs(lastEl - thisEl) > 0.001: # the last point was an end point gdlat,glon,gdalt = madrigal._derive.radarToGeodetic(slat,slon,salt,lastAz,lastEl,lastRange) if gdlat > maxLat: maxLat = gdlat if gdlat < minLat: minLat = gdlat if glon > maxLon: maxLon = glon if glon < minLon: minLon = glon if gdalt > maxAlt: maxAlt = gdalt greatCDist = self.getGreatCircleDist(slat, slon, gdlat, glon) if greatCDist > maxGreatCDist: maxGreatCDist = greatCDist lastAz = thisAz lastEl = thisEl lastRange = range # check last point gdlat,glon,gdalt = madrigal._derive.radarToGeodetic(slat,slon,slat,lastAz,lastEl,lastRange) if gdlat > maxLat: maxLat = gdlat if gdlat < minLat: minLat = gdlat if glon > maxLon: maxLon = glon if glon < minLon: minLon = glon if gdalt > maxAlt: maxAlt = gdalt greatCDist = self.getGreatCircleDist(slat, slon, gdlat, glon) if greatCDist > maxGreatCDist: maxGreatCDist = greatCDist return((maxLon, minLon, maxLat, minLat, maxAlt, maxGreatCDist, maxParm, minParm)) def _setLimits(self, scanType, xMaximum, xMinimum, yMaximum, yMinimum, newLonMax, newLonMin, newLatMax, newLatMin, newAltMax, newGreatCDist, newParmMax, newParmMin): """ _setLimits sets xMaximum, xMinimum, yMaximum, yMinimum based on values found in self._getLimits and scanType. If any value in (xMaximum, xMinimum, yMaximum, yMinimum) is not None, it will not be changed. """ newXMax = xMaximum newXMin = xMinimum newYMax = yMaximum newYMin = yMinimum if scanType == 'az': if xMaximum == None: newXMax = newLonMax if xMinimum == None: newXMin = newLonMin if yMaximum == None: newYMax = newLatMax if yMinimum == None: newYMin = newLatMin elif scanType == 'el_lat': if xMaximum == None: newXMax = newLatMax if xMinimum == None: newXMin = newLatMin if yMaximum == None: newYMax = newAltMax if yMinimum == None: newYMin = 0.0 elif scanType == 'el_lon': if xMaximum == None: newXMax = newLonMax if xMinimum == None: newXMin = newLonMin if yMaximum == None: newYMax = newAltMax if yMinimum == None: newYMin = 0.0 elif scanType == 'el_gcdist': if xMaximum == None: newXMax = newGreatCDist if xMinimum == None: newXMin = 0.0 if yMaximum == None: newYMax = newAltMax if yMinimum == None: newYMin = 0.0 return((newXMax, newXMin, newYMax, newYMin)) def _generateWedges(self, isprintLines, scanType): """_generateWedges is a python generator that return a data wedge in the form (dataValue, (point1_x, point1_y), (point2_x, point2_y), (point3_x, point3_y), (point4_x, point4_y)) Inputs: isprintLines - a list of line with 9 parameters that are (gdlatr, gdlonr, galtr, range, az1, az2, el1, el2, <parameter value>). Any missing data should be written as "missing" or other string that cannot be converted to a float. gdlatr, gdlonr, galtr are the station location. No wedge is returned for a missing data line scanType - must be 'az' or 'el_lat' (for north or south el scans), 'el_lon' (for east or west el scans) or 'el_gcdist' (for all other el scans. For az - x is long, y is lat for el_* y is always alt, and x is either lat, lon, or great circle distance """ # state variables lastAz1 = None lastAz2 = None lastEl1 = None lastEl2 = None lastRange = None lastDiffRangeLow = None lastValue = None for isprintLine in isprintLines: items = isprintLine.split() if len(items) < 9: continue gdlatr = float(items[0]) gdlonr = float(items[1]) galtr = float(items[2]) range = float(items[3]) az1 = float(items[4]) az2 = float(items[5]) el1 = float(items[6]) el2 = float(items[7]) valueStr = items[8] if lastAz1 != None and ( abs(lastAz1-az1) > 0.001 or abs(lastEl1-el1) > 0.001 ): # new radar line found, send last point if needed if lastValue != None: dataWedge = self._getWedge(gdlatr, gdlonr, galtr, lastRange, lastDiffRangeLow, lastDiffRangeLow, lastAz1, lastAz2, lastEl1, lastEl2, lastValue, scanType) yield(dataWedge) # this is the first point in the line, so no lastDiffRangeLow lastDiffRangeLow = None elif lastAz1 != None and ( abs(lastAz1-az1) < 0.001 and abs(lastEl1-el1) < 0.001 ): # continuing radar line if lastValue != None: lastDiffRangeLow = (range - lastRange)/2.0 dataWedge = self._getWedge(gdlatr, gdlonr, galtr, lastRange, lastDiffRangeLow, (range-lastRange)/2.0, lastAz1, lastAz2, lastEl1, lastEl2, lastValue, scanType) yield(dataWedge) else: lastDiffRangeLow = (range - lastRange)/2.0 # reset state variables lastAz1 = az1 lastAz2 = az2 lastEl1 = el1 lastEl2 = el2 lastRange = range try: lastValue = float(valueStr) except: lastValue = None # finally, send last wedge if needed if lastValue != None: dataWedge = self._getWedge(gdlatr, gdlonr, galtr, lastRange, lastDiffRangeLow, lastDiffRangeLow, lastAz1, lastAz2, lastEl1, lastEl2, lastValue, scanType) yield(dataWedge) def _getWedge(self, gdlatr, gdlonr, galtr, range, diffRange1, diffRange2, az1, az2, el1, el2, value, scanType): """_getWedge returns return a data wedge in the form (dataValue, (point1_x, point1_y), (point2_x, point2_y), (point3_x, point3_y), (point4_x, point4_y)). The x and y dimensions depend on scanType: az: x: lon, y: lat el_lat: x: lat, y: alt el_lon: x: lon, y: alt el_gcdist: x: great circle distance, y: alt Inputs: gdlatr, gdlonr, galtr - location of radar range, diffRange1, diffRange2 - range of center of wedge, and distance in and out from there az1, az2, el1, el2 - start and end aximuth and elevation. Which is used depends on scanType value - float data value scanType - az, el_lat, el_lon, el_gcdist """ if scanType == 'az': point1_y,point1_x,gdalt = madrigal._derive.radarToGeodetic(gdlatr, gdlonr, galtr,az1,el1,range-diffRange1) point2_y,point2_x,gdalt = madrigal._derive.radarToGeodetic(gdlatr, gdlonr, galtr,az2,el1,range-diffRange1) point3_y,point3_x,gdalt = madrigal._derive.radarToGeodetic(gdlatr, gdlonr, galtr,az2,el1,range+diffRange2) point4_y,point4_x,gdalt = madrigal._derive.radarToGeodetic(gdlatr, gdlonr, galtr,az1,el1,range+diffRange2) elif scanType == 'el_lat': point1_x,glon,point1_y = madrigal._derive.radarToGeodetic(gdlatr, gdlonr, galtr,az1,el1,range-diffRange1) point2_x,glon,point2_y = madrigal._derive.radarToGeodetic(gdlatr, gdlonr, galtr,az1,el2,range-diffRange1) point3_x,glon,point3_y = madrigal._derive.radarToGeodetic(gdlatr, gdlonr, galtr,az1,el2,range+diffRange2) point4_x,glon,point4_y = madrigal._derive.radarToGeodetic(gdlatr, gdlonr, galtr,az1,el1,range+diffRange2) elif scanType == 'el_lon': gdlat,point1_x,point1_y = madrigal._derive.radarToGeodetic(gdlatr, gdlonr, galtr,az1,el1,range-diffRange1) gdlat,point2_x,point2_y = madrigal._derive.radarToGeodetic(gdlatr, gdlonr, galtr,az1,el2,range-diffRange1) gdlat,point3_x,point3_y = madrigal._derive.radarToGeodetic(gdlatr, gdlonr, galtr,az1,el2,range+diffRange2) gdlat,point4_x,point4_y = madrigal._derive.radarToGeodetic(gdlatr, gdlonr, galtr,az1,el1,range+diffRange2) elif scanType == 'el_gcdist': gdlat,glon,point1_y = madrigal._derive.radarToGeodetic(gdlatr, gdlonr, galtr,az1,el1,range-diffRange1) point1_x = self.getGreatCircleDist(gdlatr, gdlonr, gdlat, glon) gdlat,glon,point2_y = madrigal._derive.radarToGeodetic(gdlatr, gdlonr, galtr,az1,el2,range-diffRange1) point2_x = self.getGreatCircleDist(gdlatr, gdlonr, gdlat, glon) gdlat,glon,point3_y = madrigal._derive.radarToGeodetic(gdlatr, gdlonr, galtr,az1,el2,range+diffRange2) point3_x = self.getGreatCircleDist(gdlatr, gdlonr, gdlat, glon) gdlat,glon,point4_y = madrigal._derive.radarToGeodetic(gdlatr, gdlonr, galtr,az1,el1,range+diffRange2) point4_x = self.getGreatCircleDist(gdlatr, gdlonr, gdlat, glon) return((value, (point1_x, point1_y), (point2_x, point2_y), (point3_x, point3_y), (point4_x, point4_y))) class madPcolorWedgeKmlScan: """madPcolorWedgeKmlScan is the class that produces pcolor scan kml files where data is drawn as wedge shapes. Usage example:: obj = madPcolorWedgeKmlScan(isprintText, 'az', './isprint.kml', minColormap = 9, maxColormap = 12) Non-standard Python modules used: matplotlib Change history: Written by "Bill Rideout":mailto:wrideout@haystack.mit.edu Dec 15, 2010 """ def __init__(self, isprintText, scanType, fullFilename, minColormap = None, maxColormap = None, instName = None, instDesc = None, instLat = None, instLon = None, instAlt = None, colorMap = None): """__init__ writes a madPcolorWedgeKmlScan to a file. Inputs: isprintText - a string giving isprint output without headers. The 9 parameters are (gdlatr, gdlonr, galtr, range, az1, az2, el1, el2, <parameter value>). Any missing data should be written as "missing" or other string that cannot be converted to a float. gdlatr, gdlonr, galtr are the station location scanType - must be 'az' or 'el_lat' (for north or south el scans), 'el_lon' (for east or west el scans) or 'el_gcdist' (for all other el scans. For az - x is long, y is lat for el_* y is always alt, and x is either lat, lon, or great circle distance fullFilename - full path of file containing kml file to be saved. Extension must be kml, or exception thrown. minColormap - minimum parameter value (defaults to lowest parameter value) maxColormap - maximum parameter value (defaults to highest parameter value). However, if both minColormap and maxColormap == None, autoscaling applied. instName, instDesc, instLat, instLon, instAlt - used to create a placemark for the radar. If instLat or instLon missing, no placemark added. colorMap - A matplotlib colormap to use to create colors. If None, then blue minimum and red maximum Returns: void Affects: Writes fullFilename to disk """ # verify input if scanType not in ('az', 'el_lat', 'el_lon', 'el_gcdist'): raise ValueError, 'scanType must be "az", "el_lat", "el_lon", "el_gcdist", not %s' % (str(scanType)) isprintLines = isprintText.split('\n') newLonMax, newLonMin, newLatMax, newLatMin, newAltMax, newGreatCDist, newParmMax, newParmMin = self._getLimits(isprintLines) # get look point lookLat = (newLatMax + newLatMin)/2.0 lookLon = (newLonMax + newLonMin)/2.0 lookAlt = newAltMax * 10.0 if maxColormap == None: maxColormap = newParmMax if minColormap == None: minColormap = newParmMin # set up wedge generator dataGen = self._generateWedges(isprintLines, scanType) text = self._createKmlText(dataGen, maxColormap, minColormap, lookLat, lookLon, lookAlt, scanType, instName, instDesc, instLat, instLon, instAlt, colorMap) f = open(fullFilename, 'w') f.write(text) f.close() def getGreatCircleDist(self, gdlatr, glonr, gdlat, glon): """getGreatCircleDist return the great circle distance in. Taken from madDeriveMethods c code. Inputs: gdlatr, glonr: reference point on earth's surface gdlat, glon: second point on earth's surface """ dlon = glonr/57.2958 - glon/57.2958 dlat = gdlatr/57.2958 - gdlat/57.2958; a = math.sin(dlat/2.0)*math.sin(dlat/2.0) + math.cos(gdlatr/57.2958)*math.cos(gdlat/57.2958) * math.sin(dlon/2.0)*math.sin(dlon/2.0) if math.sqrt(a) < 1.0: c = 2.0 * math.asin(math.sqrt(a)) else: c = 2.0 * math.asin(1.0) return(c * 6371.2) def _getLimits(self, isprintLines): """returns (newLonMax, newLonMin, newLatMax, newLatMin, newAltMax, newGreatCDist, newParmMax, newParmMin) given isprint lines with parameters (gdlatr, gdlonr, galtr, range, az1, az2, el1, el2, <parameter value>) We only look at the end points of ranges and the station location """ # set initial values to station location items = isprintLines[1].split() slat = float(items[0]) slon = float(items[1]) if slon > 180.0: slon -= 360.0 salt = float(items[2]) maxLon = slon minLon = slon maxLat = slat minLat = slat maxAlt = salt maxGreatCDist = 0.0 maxParm = -1.0e-30 minParm = 1.0e30 lastAz = None lastEl = None lastRange = None for i, isprintLine in enumerate(isprintLines): items = isprintLine.split() if len(items) < 9: continue range = float(items[3]) az1 = float(items[4]) az2 = float(items[5]) thisAz = (az1 + az2)/2 el1 = float(items[6]) el2 = float(items[7]) thisEl = (el1 + el2)/2 try: parm = float(items[8]) if parm > maxParm: maxParm = parm if parm < minParm: minParm = parm except ValueError: continue # see if we're at an end point if lastAz != None: if abs(lastAz - thisAz) > 0.001 or abs(lastEl - thisEl) > 0.001: # the last point was an end point gdlat,glon,gdalt = madrigal._derive.radarToGeodetic(slat,slon,salt,lastAz,lastEl,lastRange) if gdlat > maxLat: maxLat = gdlat if gdlat < minLat: minLat = gdlat if glon > maxLon: maxLon = glon if glon < minLon: minLon = glon if gdalt > maxAlt: maxAlt = gdalt greatCDist = self.getGreatCircleDist(slat, slon, gdlat, glon) if greatCDist > maxGreatCDist: maxGreatCDist = greatCDist lastAz = thisAz lastEl = thisEl lastRange = range # check last point gdlat,glon,gdalt = madrigal._derive.radarToGeodetic(slat,slon,slat,lastAz,lastEl,lastRange) if gdlat > maxLat: maxLat = gdlat if gdlat < minLat: minLat = gdlat if glon > maxLon: maxLon = glon if glon < minLon: minLon = glon if gdalt > maxAlt: maxAlt = gdalt greatCDist = self.getGreatCircleDist(slat, slon, gdlat, glon) if greatCDist > maxGreatCDist: maxGreatCDist = greatCDist return((maxLon, minLon, maxLat, minLat, maxAlt, maxGreatCDist, maxParm, minParm)) def _generateWedges(self, isprintLines, scanType): """_generateWedges is a python generator that return a data wedge in the form (dataValue, (point1_lat, point1_lon, point1_alt), (point2_lat, point2_lon, point2_alt), (point3_lat, point3_lon, point3_alt), (point4_lat, point4_lon, point4_alt)) Inputs: isprintLines - a list of line with 9 parameters that are (gdlatr, gdlonr, galtr, range, az1, az2, el1, el2, <parameter value>). Any missing data should be written as "missing" or other string that cannot be converted to a float. gdlatr, gdlonr, galtr are the station location. No wedge is returned for a missing data line scanType - must be 'az' or 'el_lat' (for north or south el scans), 'el_lon' (for east or west el scans) or 'el_gcdist' (for all other el scans. For az - x is long, y is lat for el_* y is always alt, and x is either lat, lon, or great circle distance """ # state variables lastAz1 = None lastAz2 = None lastEl1 = None lastEl2 = None lastRange = None lastDiffRangeLow = None lastValue = None for isprintLine in isprintLines: items = isprintLine.split() if len(items) < 9: continue gdlatr = float(items[0]) gdlonr = float(items[1]) galtr = float(items[2]) range = float(items[3]) az1 = float(items[4]) az2 = float(items[5]) el1 = float(items[6]) el2 = float(items[7]) valueStr = items[8] if lastAz1 != None and ( abs(lastAz1-az1) > 0.001 or abs(lastEl1-el1) > 0.001 ): # new radar line found, send last point if needed if lastValue != None: dataWedge = self._getWedge(gdlatr, gdlonr, galtr, lastRange, lastDiffRangeLow, lastDiffRangeLow, lastAz1, lastAz2, lastEl1, lastEl2, lastValue) yield(dataWedge) # this is the first point in the line, so no lastDiffRangeLow lastDiffRangeLow = None elif lastAz1 != None and ( abs(lastAz1-az1) < 0.001 and abs(lastEl1-el1) < 0.001 ): # continuing radar line if lastValue != None: lastDiffRangeLow = (range - lastRange)/2.0 dataWedge = self._getWedge(gdlatr, gdlonr, galtr, lastRange, lastDiffRangeLow, (range-lastRange)/2.0, lastAz1, lastAz2, lastEl1, lastEl2, lastValue) yield(dataWedge) else: lastDiffRangeLow = (range - lastRange)/2.0 # reset state variables lastAz1 = az1 lastAz2 = az2 lastEl1 = el1 lastEl2 = el2 lastRange = range try: lastValue = float(valueStr) except: lastValue = None # finally, send last wedge if needed if lastValue != None: dataWedge = self._getWedge(gdlatr, gdlonr, galtr, lastRange, lastDiffRangeLow, lastDiffRangeLow, lastAz1, lastAz2, lastEl1, lastEl2, lastValue) yield(dataWedge) def _getWedge(self, gdlatr, gdlonr, galtr, range, diffRange1, diffRange2, az1, az2, el1, el2, value): """_getWedge returns return a data wedge in the form (dataValue, (point1_lat, point1_lon, point1_alt), (point2_lat, point2_lon, point2_alt), (point3_lat, point3_lon, point3_alt), (point4_lat, point4_lon, point4_alt)). Inputs: gdlatr, gdlonr, galtr - location of radar range, diffRange1, diffRange2 - range of center of wedge, and distance in and out from there az1, az2, el1, el2 - start and end aximuth and elevation. Which is used depends on scanType value - float data value """ point1_lat,point1_lon,point1_alt = madrigal._derive.radarToGeodetic(gdlatr, gdlonr, galtr,az1,el1,range-diffRange1) point2_lat,point2_lon,point2_alt = madrigal._derive.radarToGeodetic(gdlatr, gdlonr, galtr,az2,el2,range-diffRange1) point3_lat,point3_lon,point3_alt = madrigal._derive.radarToGeodetic(gdlatr, gdlonr, galtr,az2,el2,range+diffRange2) point4_lat,point4_lon,point4_alt = madrigal._derive.radarToGeodetic(gdlatr, gdlonr, galtr,az1,el1,range+diffRange2) return((value, (point1_lat,point1_lon,point1_alt), (point2_lat,point2_lon,point2_alt), (point3_lat,point3_lon,point3_alt), (point4_lat,point4_lon,point4_alt))) def _createKmlText(self, dataGen, maxColormap, minColormap, lookLat, lookLon, lookAlt, scanType, instName, instDesc, instLat, instLon, instAlt, colorMap): """_createKmlText creates kml text Inputs: dataGen - list in form (dataValue, (point1_lat, point1_lon, point1_alt), (point2_lat, point2_lon, point2_alt), (point3_lat, point3_lon, point3_alt), (point4_lat, point4_lon, point4_alt)) maxColormap minColormap lookLat lookLon lookAlt scanType instName, instDesc, instLat, instLon, instAlt - - used to create a placemark for the radar. If instLat or instLon missing, no placemark added. colorMap - A matplotlib colormap to use to create colors. If None, then blue minimum and red maximum """ # need to fill in id and color styleTemplate = """ <Style id="p%i"> <PolyStyle> <color>%s</color> <fill>1</fill> <outline>0</outline> </PolyStyle> </Style> """ # need to fill in id and coordinates placemarkTemplate = """ <Placemark> <styleUrl>#%s</styleUrl> <Polygon> <altitudeMode>absolute</altitudeMode> <outerBoundaryIs> <LinearRing> <coordinates> %s </coordinates> </LinearRing> </outerBoundaryIs> </Polygon> </Placemark> """ instTemplate = """<Placemark> <name>%s</name> <description>%s</description> <Point> <coordinates>%f,%f,%f</coordinates> </Point> </Placemark> """ # need to fill in styles and placemarks documentTemplate = """<?xml version="1.0" encoding="UTF-8"?> <kml xmlns="http://www.opengis.net/kml/2.2" xmlns:gx="http://www.google.com/kml/ext/2.2" xmlns:kml="http://www.opengis.net/kml/2.2" xmlns:atom="http://www.w3.org/2005/Atom"> <Document> <name>ScanKmlFile</name> <LookAt> <longitude>%f</longitude> <latitude>%f</latitude> <altitude>%f</altitude> <heading>%f</heading> <tilt>50</tilt> <range>%f</range> <altitudeMode>relativeToGround</altitudeMode> </LookAt> %s %s %s </Document> </kml> """ retStr = '' styleStr = '' # create 100 colors for i in range(100): if not colorMap: colorStr = self._getKmlRGB(i/100.0) else: matLabColorStr = matplotlib.colors.rgb2hex(colorMap(i/100.0)[:3]) red = matLabColorStr[1:3] green = matLabColorStr[3:5] blue = matLabColorStr[5:7] colorStr = 'ff' + blue + green + red # this is the google earth standard for opaque color styleStr += styleTemplate % (i, colorStr) placemarkStr = '' # loop through data adding strings to placemark string while(True): try: p = dataGen.next() except StopIteration: break data = p[0] if data > maxColormap: styleIndex = 99 elif data < minColormap: styleIndex = 0 else: styleIndex = int(99.0 * ((data-minColormap)/(maxColormap-minColormap))) styleId = 'p%i' % (styleIndex) coordStr = ('%f,%f,%f %f,%f,%f %f,%f,%f %f,%f,%f %f,%f,%f' ) % \ (p[1][1], p[1][0], p[1][2]*1000.0, p[2][1], p[2][0], p[2][2]*1000.0, p[3][1], p[3][0], p[3][2]*1000.0, p[4][1], p[4][0], p[4][2]*1000.0, p[1][1], p[1][0], p[1][2]*1000.0) placemarkStr += placemarkTemplate % (styleId, coordStr) if scanType in ('el_lat'): heading = 90.0 distance = 200.0 elif scanType in ('el_lon', 'el_gcdist'): heading = 0.0 distance = 200.0 else: heading = 0.0 distance = 1000.0 # create instStr instStr = '' if instLat != None and instLon != None: if instAlt == None: instAlt = 0.0 if instName == None: instName = 'Radar' if instDesc == None: instDesc = 'This is the location of the radar that produced this scan.' instStr += instTemplate % (instName, instDesc, instLon, instLat, instAlt) retStr += documentTemplate % (lookLon, lookLat, lookAlt*100.0, heading, lookAlt*distance, styleStr, instStr, placemarkStr) return(retStr) def _getKmlRGB(self, value, transparent=False, wrap=False): """_getKmlRGB returns a Kml color string given a value between 0 qnd 1. If transparent == False, solid color. Otherwise transpanency set to 50% If wrap, colors at zero and 1 wrap. Otherwise, extremes red and blue If invert, use value = 1 - value """ if value < 0.0 or value > 1.0: raise ValueError, 'value must be between 0 and 1, not %f' % (value) if wrap: r,g,b = colorsys.hsv_to_rgb(value, 0.9, 0.9) else: r,g,b = colorsys.hsv_to_rgb(value*0.67, 0.9, 0.9) if not transparent: transStr = 'ff' else: transStr = '80' retStr = '%s%s%s%s' % (transStr, hex(int(r*255))[-2:], hex(int(g*255))[-2:], hex(int(b*255))[-2:]) return(retStr) class scanPlotter: """scanPlotter is the class that produces a series of scan plots for a single Madrigal file Non-standard Python modules used: matplotlib Change history: Written by "Bill Rideout":mailto:wrideout@haystack.mit.edu Jul. 26, 2006 """ def __init__(self, madFile, madDBObj=None): """__init__ initializes a scanPlotter object. Inputs: madFile - the Madrigal file to be analyzed. Must contain SCNTYP and CYCN parameters. madDBObj - a madrigal.metadata.MadrigalDB object. If None (default), one created Returns: void Affects: sets self.madFile, self.madDBObj """ if os.access(madFile, os.R_OK): self.madFile = madFile else: raise IOError, 'unable to read %s' % (str(madFile)) if madDBObj == None: self.madDBObj = madrigal.metadata.MadrigalDB() else: self.madDBObj = madDBObj def plotAllScans(self, scanType, fullFilenameTemplate, plotParm, size = 'small', xMinimum = None, xMaximum = None, yMinimum = None, yMaximum = None, xGridSize = None, yGridSize = None, minColormap = None, maxColormap = None, colorMap = matplotlib.cm.jet, maxNumLines = None, filterStr = ''): """plotAllScans creates a series of az or el scans. Inputs: scanType - must be 'az' or 'el' fullFilename - full path of file containing pcolor plot to be saved. Each image created will have _#.png appended, with # starting at 0 plotParm - mnemonic of parameter to be plotted. size - size of plot to save. Must be "small", "wide", or "large". Defaults to small. xMinimum = minumum x value. If None (default), uses lowest x value found for each scan. xMaximum = maximum x value. If None (default), uses highest x value found for each scan. yMinimum = minumum y value. If None (default), uses lowest y value found for each scan. yMaximum = maximum y value. If None (default), uses highest y value found for each scan. minColormap - minimum parameter value (defaults to lowest parameter value) maxColormap - maximum parameter value (defaults to highest parameter value). However, if both minColormap and maxColormap == None, autoscaling applied. colorMap - sets colormap. It not given, defaults to matplotlib.cm.jet maxNumLine - max number of lines in isprintText before truncating. If None, no truncation filterStr - a filter string to pass to isprint. Defaults to no filtering Returns - a list of tuples, where each tuple has two items: 1. time string, 2. metadata string in form for scanTab.txt. List length = number of plots created """ if scanType not in ('az', 'el'): raise ValueError, 'scantype must be az or el, not %s' % (str(scanType)) self.scanType = scanType retList = [] # handle ion velocity if plotParm.lower() == 'vo': cmap = madrigal.ui.madrigalPlot.get_vo_cmap() else: cmap = matplotlib.cm.jet # create isprint string parms = 'ut1,scntyp,cycn,%s,gdalt,gdlat,glon,azm,elm,gcdist' % (plotParm.strip()) isprintStr = getIsprintString(self.madFile, parms, filterStr) try: scanList = self.createScanInfoList(isprintStr) except: traceback.print_exc() return (retList) # loop through each scan scanFailureCount = 0 # keep track of how many scans fail for i in range(len(scanList)): scanCount = i - scanFailureCount scanInfo = scanList[i] try: startDateStr = self.getDateStrFromUT(scanInfo[1]) except: # no scans may have been found continue endDateStr = self.getTimeStrFromUT(scanInfo[4]) # create title if scanType == 'el': if scanInfo[3] > scanInfo[6]: ind = 'down' direction = 1 else: ind = 'up' direction = 0 titleStr = 'El %s scan (%s) %s-%s, az=%i' % (plotParm, ind, startDateStr, endDateStr, int(scanInfo[2])) timeStr = '%s-%s' % (startDateStr, endDateStr) metaStr = 'El scan: startTime %i el %f az %f stopTime %i el %f az %f dir %i' % (scanInfo[1], scanInfo[3], scanInfo[2], scanInfo[4], scanInfo[6], scanInfo[5], direction) retList.append((timeStr,metaStr)) if scanInfo[7] == 'Gdlat': xLabelStr = 'Geodetic latitude' xGridSize = 1.0 elif scanInfo[7] == 'Glon': xLabelStr = 'Longitude' xGridSize = 1.0 elif scanInfo[7] == 'Gcdist': xLabelStr = 'Ground distance in km' xGridSize = 100.0 xLabelStr = '' yLabelStr = 'Altitude (km)' if xGridSize == None: xGridSize = 1.0 if yGridSize == None: yGridSize = 20.0 else: if scanInfo[2] > scanInfo[5]: ind = 'ccw' direction = 1 else: ind = 'cw' direction = 0 titleStr = 'Az %s scan (%s) %s-%s, el=%i' % (plotParm, ind, startDateStr, endDateStr, int(scanInfo[3])) timeStr = '%s-%s' % (startDateStr, endDateStr) metaStr = 'Az scan: startTime %i az %f el %f stopTime %i az %f el %f dir %i' % (scanInfo[1], scanInfo[2], scanInfo[3], scanInfo[4], scanInfo[5], scanInfo[6], direction) retList.append((timeStr,metaStr)) xLabelStr = 'Longitude' yLabelStr = 'Geodetic latitude' xGridSize = 1.0 yGridSize = 1.0 name = '%s_%06i.png' % (fullFilenameTemplate, scanCount) try: madPcolorScan(scanInfo[0], xGridSize, yGridSize, titleStr, xLabelStr, yLabelStr, name, minColormap = minColormap, maxColormap = maxColormap, colorMap = cmap) except: print 'Problem creating scan %s' % (str(retList[-1])) traceback.print_exc() scanFailureCount += 1 retList.remove(retList[-1]) return (retList) def plotAllWedgeScans(self, scanType, fullFilenameTemplate, plotParm, size = 'small', xMinimum = None, xMaximum = None, yMinimum = None, yMaximum = None, minColormap = None, maxColormap = None, colorMap = matplotlib.cm.jet, maxNumLines = None, filterStr = '', addTitle = '', includeKml = False, radarName = None, radarDesc = None): """plotAllWedgeScans creates a series of az or el scans. Similar to plotAllScans, except produces fancier wedge plots with uniform scalling. Inputs: scanType - must be 'az' or 'el' fullFilename - full path of file containing pcolor plot to be saved. Each image created will have _#.png appended, with # starting at 0 plotParm - mnemonic of parameter to be plotted. size - size of plot to save. Must be "small", "wide", or "large". Defaults to small. xMinimum = minumum x value. If None (default), uses lowest x value found for each scan. xMaximum = maximum x value. If None (default), uses highest x value found for each scan. yMinimum = minumum y value. If None (default), uses lowest y value found for each scan. yMaximum = maximum y value. If None (default), uses highest y value found for each scan. minColormap - minimum parameter value (defaults to lowest parameter value) maxColormap - maximum parameter value (defaults to highest parameter value). However, if both minColormap and maxColormap == None, autoscaling applied. colorMap - sets colormap. It not given, defaults to matplotlib.cm.jet maxNumLine - max number of lines in isprintText before truncating. If None, no truncation filterStr - a filter string to pass to isprint. Defaults to no filtering addTitle - a string with additional title. If empty string (the default), no additional title string. includeKml - if True, create a corresponding kml file for every png file. Same names as png files, except extension = .kml. If False, do not. radarName - name to label radar placemark if kml generated. radarDesc - description text for radar placemark if kml generated Returns - a list of tuples, where each tuple has two items: 1. time string, 2. metadata string in form for scanTab.txt. List length = number of plots created """ if scanType not in ('az', 'el'): raise ValueError, 'scantype must be az or el, not %s' % (str(scanType)) self.scanType = scanType if scanType == 'az': wedgeScanType = 'az' retList = [] # handle ion velocity if plotParm.lower() == 'vo': cmap = madrigal.ui.madrigalPlot.get_vo_cmap() else: cmap = matplotlib.cm.jet # create isprint string parms = 'ut1,scntyp,cycn,%s,gdalt,gdlat,glon,azm,elm,gcdist,gdlatr,gdlonr,galtr,range,az1,az2,el1,el2' % (plotParm.strip()) filterStr += ' filter=%s,, ' % (plotParm.strip()) isprintStr = getIsprintString(self.madFile, parms, filterStr) try: scanList = self.createWedgeScanInfoList(isprintStr) except: traceback.print_exc() return (retList) gdlatr, gdlonr, galtr = self._getInstLocation(isprintStr) # create limit dictionary used to keep all scans of the same type with the same limits limitDict = self._getLimits(scanList, xMinimum, xMaximum, yMinimum, yMaximum) # loop through each scan scanFailureCount = 0 # keep track of how many scans fail for i in range(len(scanList)): scanCount = i - scanFailureCount scanInfo = scanList[i] try: startDateStr = self.getDateStrFromUT(scanInfo[1]) except: # no scans may have been found continue endDateStr = self.getTimeStrFromUT(scanInfo[4]) # create title if scanType == 'el': if scanInfo[3] > scanInfo[6]: ind = 'down' direction = 1 else: ind = 'up' direction = 0 if int(scanInfo[2]) == int(scanInfo[5]): # no change in az titleStr = 'El %s scan (%s) %s-%s, az=%i %s' % (plotParm, ind, startDateStr, endDateStr, int(scanInfo[2]), addTitle) else: # az changed titleStr = 'El (%i-%i) %s scan %s-%s, az=%i-%i %s' % (int(scanInfo[3]), int(scanInfo[6]), plotParm, startDateStr, endDateStr, int(scanInfo[2]), int(scanInfo[5]), addTitle) timeStr = '%s-%s' % (startDateStr, endDateStr) metaStr = 'El scan: startTime %i el %f az %f stopTime %i el %f az %f dir %i' % (scanInfo[1], scanInfo[3], scanInfo[2], scanInfo[4], scanInfo[6], scanInfo[5], direction) retList.append((timeStr,metaStr)) if scanInfo[7] == 'Gdlat': xLabelStr = 'Geodetic latitude' wedgeScanType = 'el_lat' elif scanInfo[7] == 'Glon': xLabelStr = 'Longitude' wedgeScanType = 'el_lon' elif scanInfo[7] == 'Gcdist': xLabelStr = 'Ground distance in km' wedgeScanType = 'el_gcdist' xLabelStr = '' yLabelStr = 'Altitude (km)' else: if scanInfo[2] > scanInfo[5]: ind = 'ccw' direction = 1 else: ind = 'cw' direction = 0 titleStr = 'Az %s scan (%s) %s-%s, el=%i %s' % (plotParm, ind, startDateStr, endDateStr, int(scanInfo[3]), addTitle) timeStr = '%s-%s' % (startDateStr, endDateStr) metaStr = 'Az scan: startTime %i az %f el %f stopTime %i az %f el %f dir %i' % (scanInfo[1], scanInfo[2], scanInfo[3], scanInfo[4], scanInfo[5], scanInfo[6], direction) retList.append((timeStr,metaStr)) xLabelStr = 'Longitude' yLabelStr = 'Geodetic latitude' name = '%s_%06i.png' % (fullFilenameTemplate, scanCount) try: madPcolorWedgeScan(scanInfo[0], wedgeScanType, titleStr, xLabelStr, yLabelStr, name, xMinimum = limitDict[wedgeScanType][0], xMaximum = limitDict[wedgeScanType][1], yMinimum = limitDict[wedgeScanType][2], yMaximum = limitDict[wedgeScanType][3], minColormap = minColormap, maxColormap = maxColormap, colorMap = cmap) success = True except: print 'Problem creating scan %s' % (str(retList[-1])) traceback.print_exc() scanFailureCount += 1 retList.remove(retList[-1]) success = False if includeKml and success: kmlName = name[:-3] + 'kml' try: madPcolorWedgeKmlScan(scanInfo[0], wedgeScanType, kmlName, minColormap = minColormap, maxColormap = maxColormap, instName = radarName, instDesc = radarDesc, instLat = gdlatr, instLon = gdlonr, instAlt = galtr, colorMap = cmap) except: print 'Problem creating kml scan' traceback.print_exc() return (retList) def getDateStrFromUT(self, ut): """getDateStrFromUT returns a date string formated as YYYY-MM-DD HH:MM:SS from a ut time (seconds since 1/1/1950) """ timeList = madrigal._derive.getDateFromUt(float(ut)) return '%04i-%02i-%02i %02i:%02i:%02i' % (timeList[0], timeList[1], timeList[2], timeList[3], timeList[4], timeList[5]) def getTimeStrFromUT(self, ut): """getTimeStrFromUT returns a time string formated as HH:MM:SS from a ut time (seconds since 1/1/1950) """ timeList = madrigal._derive.getDateFromUt(float(ut)) return '%02i:%02i:%02i' % (timeList[3], timeList[4], timeList[5]) def createScanInfoList(self, isprintStr): """createScanInfoList creates a list of tuples, which each tuple representing a single scan, and values of: (isprintString, startUT, startAz, startEl, endUT, endAz, endEl, type, minGdlat, maxGdlat,minGlon, maxGdlon,minGdalt, maxGdalt, minGcdist, maxGcdist). Isprint string has values (x,y,plotParm), where for az scan x=lon, y=lat, and for el scan y=alt, x=lat if starting az within 15 degrees of north or south, x=lon if starting az within 15 degrees of east or west, of x=gcdist if other az. Type is Gdlat or Glon or Gcdist for el scans, None for az scans. Input isprint string has parameters ut1,scntyp,cycn,<parm>,gdalt,gdlat,glon,azm,elm,gcdist Azimuth scans are split whenever direction or elevation changes. For elevation scans, there will be zero or one north-south scans, zero or one east-west scans, and zero or more off azimuth scans. An off azimuth scan is not within 15 degrees of north, south, east or west. Off azimuth scans are not combined with scans 180 degrees in the other direction, because the x axis is ground distance, which does not reverse sign. """ isprintItems = isprintStr.split() retList = [] # loop variables thisIsprintStr = [] cycNum = None startUT = [] startAz = [] startEl = [] endUT = [] endAz = [] endEl = [] elScan = [] minGdlat = [] maxGdlat = [] minGlon = [] maxGlon = [] minGdalt = [] maxGdalt = [] minGcdist = [] maxGcdist = [] thisAzDirection = None # used to detect new azimuth scans lastAzDirection = None # used to detect new azimuth scans lastEl = None # used to detect new azimuth scans thisAz = None lastUt = None # keep track of new ut isNewUt = None # true only when ut changes inAzScan = False for i in range(len(isprintItems)): item = isprintItems[i] mod = i % 10 if mod == 0: thisUt = float(item) if lastUt == None: lastUt = thisUt elif mod == 1: thisScntyp = int(item) elif mod == 2: thisCycn = int(float(item)) if cycNum == None: cycNum = thisCycn elif mod == 3: thisParm = item elif mod == 4: thisGdalt = float(item) elif mod == 5: thisGdlat = float(item) elif mod == 6: thisGlon = float(item) elif mod == 7: if thisAz != None and lastUt < thisUt and inAzScan: if thisAz > float(item): thisAzDirection = 'cw' elif thisAz < float(item): thisAzDirection = 'ccw' thisAz = float(item) elif mod == 8: thisEl = float(item) elif mod == 9: thisGcdist = float(item) # check whether this is a new time if lastUt < thisUt: isNewUt = True lastUt = thisUt else: isNewUt = False # if new cycle, close out value if data exists if thisCycn != cycNum: for i in range(len(thisIsprintStr)): if len(thisIsprintStr[i]) == 0: continue retList.append((thisIsprintStr[i], startUT[i], startAz[i], startEl[i], endUT[i], endAz[i], endEl[i], elScan[i], minGdlat[i], maxGdlat[i], minGlon[i], maxGlon[i], minGdalt[i], maxGdalt[i], minGcdist[i], maxGcdist[i])) thisIsprintStr = [] cycNum = None startUT = [] startAz = [] startEl = [] endUT = [] endAz = [] endEl = [] elScan = [] minGdlat = [] maxGdlat = [] minGlon = [] maxGlon = [] minGdalt = [] maxGdalt = [] minGcdist = [] maxGcdist = [] thisAzDirection = None lastAzDirection = None lastEl = None inAzScan = False # end of line - process it if self.scanType == 'el' and thisScntyp == 3: # add this elevation scan point # check type of el scan inAzScan = False if -15.0 <= thisAz <= 15.0 or -165.0 >= thisAz or thisAz >= 165.0: thisElScan = 'Gdlat' elif 75.0 <= thisAz <= 105.0 or -105.0 <= thisAz <= -75.0: thisElScan = 'Glon' else: thisElScan = 'Gcdist' # get index of this scan, None if a new scan index = None for i, item in enumerate(elScan): if item == 'Gdlat' and thisElScan == 'Gdlat': index = i break elif item == 'Glon' and thisElScan == 'Glon': index = i break elif item == 'Gcdist' and thisElScan == 'Gcdist' and int(thisAz) == int(startAz[i]): index = i break if index == None: # a new scan has been found thisIsprintStr.append('') startUT.append(thisUt) startAz.append(thisAz) startEl.append(thisEl) endUT.append(None) endAz.append(None) endEl.append(None) elScan.append(thisElScan) minGdlat.append(None) maxGdlat.append(None) minGlon.append(None) maxGlon.append(None) minGdalt.append(None) maxGdalt.append(None) minGcdist.append(None) maxGcdist.append(None) index = len(thisIsprintStr) - 1 endUT[index] = thisUt endAz[index] = thisAz endEl[index] = thisEl if thisElScan == 'Gdlat': thisIsprintStr[index] += '%f %f %s\n' % (thisGdlat, thisGdalt, thisParm) elif thisElScan == 'Glon': thisIsprintStr[index] += '%f %f %s\n' % (thisGlon, thisGdalt, thisParm) else: thisIsprintStr[index] += '%f %f %s\n' % (thisGcdist, thisGdalt, thisParm) elif self.scanType == 'az' and thisScntyp == 2: # az scan inAzScan = True # add this azimuth scan point # check if this is a new scan newAzScan = False if lastEl == None: newAzScan = True # check for elevation change elif abs(lastEl - int(thisEl)) > 3: newAzScan = True # check for direction change if lastAzDirection != None: if lastAzDirection != thisAzDirection: newAzScan = True thisAzDirection = None if newAzScan: # a new azimuth scan has been found thisIsprintStr.append('') startUT.append(thisUt) startAz.append(thisAz) startEl.append(thisEl) endUT.append(None) endAz.append(None) endEl.append(None) elScan.append(None) minGdlat.append(None) maxGdlat.append(None) minGlon.append(None) maxGlon.append(None) minGdalt.append(None) maxGdalt.append(None) minGcdist.append(None) maxGcdist.append(None) index = len(thisIsprintStr) - 1 lastEl = int(thisEl) lastAzDirection = None else: # this is at least the second line of the scan if not thisAzDirection is None: lastAzDirection = thisAzDirection endUT[-1] = thisUt endAz[-1] = thisAz endEl[-1] = thisEl thisIsprintStr[-1] += '%f %f %s\n' % (thisGlon, thisGdlat, thisParm) else: # not a scan line inAzScan = False continue if minGdlat[index] == None: minGdlat[index] = thisGdlat maxGdlat[index] = thisGdlat minGlon[index] = thisGlon maxGlon[index] = thisGlon minGdalt[index] = thisGdalt maxGdalt[index] = thisGdalt minGcdist[index] = thisGcdist maxGcdist[index] = thisGcdist else: if minGdlat[index] > thisGdlat: minGdlat[index] = thisGdlat if maxGdlat[index] < thisGdlat: maxGdlat[index] = thisGdlat if minGlon[index] > thisGlon: minGlon[index] = thisGlon if maxGlon[index] < thisGlon: maxGlon[index] = thisGlon if minGdalt[index] > thisGdalt: minGdalt[index] = thisGdalt if maxGdalt[index] < thisGdalt: maxGdalt[index] = thisGdalt if minGcdist[index] > thisGcdist: minGcdist[index] = thisGcdist if maxGcdist[index] < thisGcdist: maxGcdist[index] = thisGcdist # end, close out last cycle for i in range(len(thisIsprintStr)): if len(thisIsprintStr[i]) == 0: continue retList.append((thisIsprintStr[i], startUT[i], startAz[i], startEl[i], endUT[i], endAz[i], endEl[i], elScan[i], minGdlat[i], maxGdlat[i], minGlon[i], maxGlon[i], minGdalt[i], maxGdalt[i], minGcdist[i], maxGcdist[i])) return(retList) def createWedgeScanInfoList(self, isprintStr): """createWedgeScanInfoList creates a list of tuples, which each tuple representing a single scan, and values of: (isprintString, startUT, startAz, startEl, endUT, endAz, endEl, type, minGdlat, maxGdlat,minGlon, maxGdlon,minGdalt, maxGdalt, minGcdist, maxGcdist). Input isprint string has parameters ut1,scntyp,cycn,<parm>,gdalt,gdlat,glon,azm,elm,gcdist, gdlatr,gdlonr,galtr,range,az1,az2,el1,el2 Azimuth scans are split whenever direction or elevation changes. For elevation scans, there will be zero or more north-south scans, zero or more east-west scans, and zero or more off azimuth scans. A south to north elevation scan or a west to east elevation scan is called clockwise, and a switch from clockwise to counterclockwise will create a new elevation scan. An off azimuth scan is not within 15 degrees of north, south, east or west. Off azimuth scans are not combined with scans 180 degrees in the other direction, because the x axis is ground distance, which does not reverse sign. """ isprintItems = isprintStr.split() retList = [] # loop variables thisIsprintStr = [] cycNum = None startUT = [] startAz = [] startEl = [] endUT = [] endAz = [] endEl = [] elScan = [] minGdlat = [] maxGdlat = [] minGlon = [] maxGlon = [] minGdalt = [] maxGdalt = [] minGcdist = [] maxGcdist = [] thisAzDirection = None # used to detect new azimuth scans lastAzDirection = None # used to detect new azimuth scans thisElDirection = None # used to detect new elevation scans (cw or ccw) lastElDirection = None # used to detect new elevation scans (cw or ccw) lastEl = None # used to detect new azimuth scans thisAz = None thisEl = None lastUt = None # keep track of new ut isNewUt = None # true only when ut changes inAzScan = False inElScan = False for i in range(len(isprintItems)): item = isprintItems[i] mod = i % 18 if mod == 0: thisUt = float(item) if lastUt == None: lastUt = thisUt elif mod == 1: thisScntyp = int(item) elif mod == 2: thisCycn = int(float(item)) if cycNum == None: cycNum = thisCycn elif mod == 3: thisParm = item elif mod == 4: thisGdalt = float(item) elif mod == 5: thisGdlat = float(item) elif mod == 6: thisGlon = float(item) elif mod == 7: if thisAz != None and lastUt < thisUt and inAzScan: if thisAz > float(item): thisAzDirection = 'cw' elif thisAz < float(item): thisAzDirection = 'ccw' thisAz = float(item) elif mod == 8: if thisEl != None and inElScan: if abs(float(item) - thisEl) > 1.0: if thisElScan == 'Gdlat': if -165.0 >= thisAz or thisAz >= 165.0: # southern scan if float(item) > thisEl: thisElDirection = 'cw' else: thisElDirection = 'ccw' else: # northern scan if float(item) < thisEl: thisElDirection = 'cw' else: thisElDirection = 'ccw' elif thisElScan == 'Glon': if -105.0 <= thisAz <= -75.0: # western scan if float(item) > thisEl: thisElDirection = 'cw' else: thisElDirection = 'ccw' else: # eastern scan if float(item) < thisEl: thisElDirection = 'cw' else: thisElDirection = 'ccw' elif thisElScan == 'Gcdist': if float(item) > thisEl: thisElDirection = 'up' else: thisElDirection = 'down' thisEl = float(item) elif mod == 9: thisGcdist = float(item) elif mod == 10: thisGdlatr = float(item) elif mod == 11: thisGdlonr = float(item) elif mod == 12: thisGaltr = float(item) elif mod == 13: thisRange = float(item) elif mod == 14: thisAz1 = float(item) elif mod == 15: thisAz2 = float(item) elif mod == 16: thisEl1 = float(item) elif mod == 17: thisEl2 = float(item) # check whether this is a new time if lastUt < thisUt: isNewUt = True lastUt = thisUt else: isNewUt = False # if new cycle or elevation issue, close out value if data exists if (thisCycn != cycNum) or \ (thisElDirection == 'cw' and lastElDirection == 'ccw') or \ (thisElDirection == 'ccw' and lastElDirection == 'cw') or \ (thisElDirection == 'down' and lastElDirection == 'up') or \ (thisElDirection == 'up' and lastElDirection == 'down') or \ (thisElDirection != None and not inElScan) or \ (thisAzDirection != None and not inAzScan): for i in range(len(thisIsprintStr)): if len(thisIsprintStr[i]) == 0: continue retList.append((thisIsprintStr[i], startUT[i], startAz[i], startEl[i], endUT[i], endAz[i], endEl[i], elScan[i], minGdlat[i], maxGdlat[i], minGlon[i], maxGlon[i], minGdalt[i], maxGdalt[i], minGcdist[i], maxGcdist[i])) thisIsprintStr = [] cycNum = None startUT = [] startAz = [] startEl = [] endUT = [] endAz = [] endEl = [] elScan = [] minGdlat = [] maxGdlat = [] minGlon = [] maxGlon = [] minGdalt = [] maxGdalt = [] minGcdist = [] maxGcdist = [] thisAzDirection = None lastAzDirection = None thisElDirection = None # used to detect new elevation scans (cw or ccw) lastElDirection = None lastEl = None inAzScan = False inElScan = False # end of line - process it if self.scanType == 'el' and thisScntyp == 3: # add this elevation scan point # check type of el scan inAzScan = False inElScan = True if (-15.0 <= thisAz <= 15.0 or -165.0 >= thisAz or thisAz >= 165.0) and \ abs(thisAz1 - thisAz2) < 0.5: thisElScan = 'Gdlat' elif (75.0 <= thisAz <= 105.0 or -105.0 <= thisAz <= -75.0) and \ abs(thisAz1 - thisAz2) < 0.5: thisElScan = 'Glon' else: thisElScan = 'Gcdist' # get index of this scan, None if a new scan index = None for i, item in enumerate(elScan): if item == 'Gdlat' and thisElScan == 'Gdlat': index = i break elif item == 'Glon' and thisElScan == 'Glon': index = i break elif item == 'Gcdist' and thisElScan == 'Gcdist' and int(thisAz) == int(startAz[i]): index = i break elif item == 'Gcdist' and thisElScan == 'Gcdist' and i == len(elScan)-1: index = i break if index == None: # a new scan has been found thisIsprintStr.append('') startUT.append(thisUt) startAz.append(thisAz) startEl.append(thisEl) endUT.append(None) endAz.append(None) endEl.append(None) elScan.append(thisElScan) minGdlat.append(None) maxGdlat.append(None) minGlon.append(None) maxGlon.append(None) minGdalt.append(None) maxGdalt.append(None) minGcdist.append(None) maxGcdist.append(None) index = len(thisIsprintStr) - 1 lastElDirection = thisElDirection endUT[index] = thisUt endAz[index] = thisAz endEl[index] = thisEl # gdlatr, gdlonr, galtr, range, az1, az2, el1, el2,plotParm thisIsprintStr[index] += '%f %f %f %f %f %f %f %f %s\n' % (thisGdlatr, thisGdlonr, thisGaltr, thisRange, thisAz1, thisAz2, thisEl1, thisEl2, thisParm) elif self.scanType == 'az' and thisScntyp == 2: # az scan inAzScan = True inElScan = False # add this azimuth scan point # check if this is a new scan newAzScan = False if lastEl == None: newAzScan = True # check for elevation change elif abs(lastEl - int(thisEl)) > 3: newAzScan = True # check for direction change if lastAzDirection != None: if lastAzDirection != thisAzDirection: newAzScan = True thisAzDirection = None if newAzScan: # a new azimuth scan has been found thisIsprintStr.append('') startUT.append(thisUt) startAz.append(thisAz) startEl.append(thisEl) endUT.append(None) endAz.append(None) endEl.append(None) elScan.append(None) minGdlat.append(None) maxGdlat.append(None) minGlon.append(None) maxGlon.append(None) minGdalt.append(None) maxGdalt.append(None) minGcdist.append(None) maxGcdist.append(None) index = len(thisIsprintStr) - 1 lastEl = int(thisEl) lastAzDirection = None else: # this is at least the second line of the scan if not thisAzDirection is None: lastAzDirection = thisAzDirection endUT[-1] = thisUt endAz[-1] = thisAz endEl[-1] = thisEl thisIsprintStr[-1] += '%f %f %f %f %f %f %f %f %s\n' % (thisGdlatr, thisGdlonr, thisGaltr, thisRange, thisAz1, thisAz2, thisEl1, thisEl2, thisParm) else: # not a scan line inAzScan = False inElScan = False continue if minGdlat[index] == None: minGdlat[index] = thisGdlat maxGdlat[index] = thisGdlat minGlon[index] = thisGlon maxGlon[index] = thisGlon minGdalt[index] = thisGdalt maxGdalt[index] = thisGdalt minGcdist[index] = thisGcdist maxGcdist[index] = thisGcdist else: if minGdlat[index] > thisGdlat: minGdlat[index] = thisGdlat if maxGdlat[index] < thisGdlat: maxGdlat[index] = thisGdlat if minGlon[index] > thisGlon: minGlon[index] = thisGlon if maxGlon[index] < thisGlon: maxGlon[index] = thisGlon if minGdalt[index] > thisGdalt: minGdalt[index] = thisGdalt if maxGdalt[index] < thisGdalt: maxGdalt[index] = thisGdalt if minGcdist[index] > thisGcdist: minGcdist[index] = thisGcdist if maxGcdist[index] < thisGcdist: maxGcdist[index] = thisGcdist # end, close out last cycle for i in range(len(thisIsprintStr)): if len(thisIsprintStr[i]) == 0: continue retList.append((thisIsprintStr[i], startUT[i], startAz[i], startEl[i], endUT[i], endAz[i], endEl[i], elScan[i], minGdlat[i], maxGdlat[i], minGlon[i], maxGlon[i], minGdalt[i], maxGdalt[i], minGcdist[i], maxGcdist[i])) return(retList) def _getLimits(self, scanList, xMinimum, xMaximum, yMinimum, yMaximum): """_getLimits returns a dictionary with keys that may include ('az', 'el_lat', 'el_lon', 'el_gcdist'), though not all will neccessarily be there. Values are overall tuple of (xMinimum, xMaximum, yMinimum, yMaximum). These values are set by the input arguments unless it is None, in which case the scanList limits set the values. Inputs: scanList: a list of tuples, which each tuple representing a single scan, and has values of: (isprintString, startUT, startAz, startEl, endUT, endAz, endEl, type, minGdlat, maxGdlat,minGlon, maxGdlon,minGdalt, maxGdalt, minGcdist, maxGcdist). Isprint string has values (gdlatr, gdlonr, galtr, range, az1, az2, el1, el2,plotParm),. Type is Gdlat or Glon or Gcdist for el scans, None for az scans. xMinimum, xMaximum, yMinimum, yMaximum - as passed into scanPlotter """ retDict = {} xMinAz = None xMaxAz = None yMinAz = None yMaxAz = None xMinElLat = None xMaxElLat = None yMinElLat = None yMaxElLat = None xMinElLon = None xMaxElLon = None yMinElLon = None yMaxElLon = None xMinElGcdist = None xMaxElGcdist = None yMinElGcdist = None yMaxElGcdist = None minValue = None maxValue = None for scanItem in scanList: if scanItem[7] == None: # az scan if xMinAz == None: xMinAz = scanItem[10] elif xMinAz > scanItem[10]: xMinAz = scanItem[10] if xMaxAz == None: xMaxAz = scanItem[11] elif xMaxAz < scanItem[11]: xMaxAz = scanItem[11] if yMinAz == None: yMinAz = scanItem[8] elif yMinAz > scanItem[8]: yMinAz = scanItem[8] if yMaxAz == None: yMaxAz = scanItem[9] elif yMaxAz < scanItem[9]: yMaxAz = scanItem[9] elif scanItem[7] == 'Gdlat': # el_lat scan if xMinElLat == None: xMinElLat = scanItem[8] elif xMinElLat > scanItem[8]: xMinElLat = scanItem[8] if xMaxElLat == None: xMaxElLat = scanItem[9] elif xMaxElLat < scanItem[9]: xMaxElLat = scanItem[9] if yMinElLat == None: yMinElLat = scanItem[12] elif yMinElLat > scanItem[12]: yMinElLat = scanItem[12] if yMaxElLat == None: yMaxElLat = scanItem[13] elif yMaxElLat < scanItem[13]: yMaxElLat = scanItem[13] elif scanItem[7] == 'Glon': # el_lon scan if xMinElLon == None: xMinElLon = scanItem[10] elif xMinElLon > scanItem[10]: xMinElLon = scanItem[10] if xMaxElLon == None: xMaxElLon = scanItem[11] elif xMaxElLon < scanItem[11]: xMaxElLon = scanItem[11] if yMinElLon == None: yMinElLon = scanItem[12] elif yMinElLon > scanItem[12]: yMinElLon = scanItem[12] if yMaxElLon == None: yMaxElLon = scanItem[13] elif yMaxElLon < scanItem[13]: yMaxElLon = scanItem[13] elif scanItem[7] == 'Gcdist': # el_gcdist scan if xMinElGcdist == None: xMinElGcdist = scanItem[14] elif xMinElGcdist > scanItem[14]: xMinElGcdist = scanItem[14] if xMaxElGcdist == None: xMaxElGcdist = scanItem[15] elif xMaxElGcdist < scanItem[15]: xMaxElGcdist = scanItem[15] if yMinElGcdist == None: yMinElGcdist = scanItem[12] elif yMinElGcdist > scanItem[12]: yMinElGcdist = scanItem[12] if yMaxElGcdist == None: yMaxElGcdist = scanItem[13] elif yMaxElGcdist < scanItem[13]: yMaxElGcdist = scanItem[13] # fill out the dictionary if xMinAz != None: if xMinimum == None: xMin = xMinAz else: xMin = xMinimum if xMaximum == None: xMax = xMaxAz else: xMax = xMaximum if yMinimum == None: yMin = yMinAz else: yMin = yMinimum if yMaximum == None: yMax = yMaxAz else: yMax = yMaximum retDict['az'] = (xMin, xMax, yMin, yMax) if xMinElLat != None: if xMinimum == None: xMin = xMinElLat else: xMin = xMinimum if xMaximum == None: xMax = xMaxElLat else: xMax = xMaximum if yMinimum == None: yMin = yMinElLat else: yMin = yMinimum if yMaximum == None: yMax = yMaxElLat else: yMax = yMaximum retDict['el_lat'] = (xMin, xMax, yMin, yMax) if xMinElLon != None: if xMinimum == None: xMin = xMinElLon else: xMin = xMinimum if xMaximum == None: xMax = xMaxElLon else: xMax = xMaximum if yMinimum == None: yMin = yMinElLon else: yMin = yMinimum if yMaximum == None: yMax = yMaxElLon else: yMax = yMaximum retDict['el_lon'] = (xMin, xMax, yMin, yMax) if xMinElGcdist != None: if xMinimum == None: xMin = xMinElGcdist else: xMin = xMinimum if xMaximum == None: xMax = xMaxElGcdist else: xMax = xMaximum if yMinimum == None: yMin = yMinElGcdist else: yMin = yMinimum if yMaximum == None: yMax = yMaxElGcdist else: yMax = yMaximum retDict['el_gcdist'] = (xMin, xMax, yMin, yMax) return(retDict) def _getInstLocation(self, isprintStr): """_getInstLocation returns a tuple of instrument location (gdlatr, gdlonr, galtr) Input isprint string has parameters ut1,scntyp,cycn,<parm>,gdalt,gdlat,glon,azm,elm,gcdist, gdlatr,gdlonr,galtr,range,az1,az2,el1,el2 """ isprintItems = isprintStr.split() gdlatr = float(isprintItems[10]) gdlonr = float(isprintItems[11]) if gdlonr > 180.0: gdlonr -= 360.0 galtr = float(isprintItems[12]) return((gdlatr, gdlonr, galtr)) class madHistogram: """madHistogram is the class that produces Histogram plots of Madrigal Data. Usage example:: obj = madHistogram(isprintText, 'Nel (log(m^-3)) - Millstone Hill - Oct. 30, 2005 - Alt. code', 'Hours since midnight UT Oct. 30,2003' 'Altitude', './isprint.png' size = 'large') Inputs: isprintText - a string giving isprint output without headers. Any missing data should be written as 'missing' or other string that cannot be converted into a float. Only one column. TitleStr - plot title(string) - should describe the plot being made xLabelStr - Label for x axis fullFilename - full path of file containing histogram plot to be saved. Extension must be .jpeg or .png, or exception thrown size - size of plot to be saved. Must be 'small','wide', or 'large'. Defaults to small maxNumPoints - maximum number of points to be considered. Defaults to None, so all points in string shown numBins - number of bins to be used to store the data. More bins means closer resolution in Histogram. Default is 30 orientation - whether histogram shows horizontal or vertical. Must be written as 'horizontal' or 'vertical', or exception thrown--defaults to 'vertical' isNorm - whether histogram should be normalized or not. Default is 0, or False isBottom - If true, sets the lowest passed value as zero sdevs - number of standard deviations to take into account. When 0 is passed to it, this option is ignored and all data is included in the distribution; otherwise, the range of values accepted is sdevs*(standard deviation of sample) Outputs: A .png file is written to the fullFilename path given, resulting in a Histogram drawn by matplotlib Change History: Written by "Brandon Scott Fines":mailto:bfines@haystack.mit.edu Aug. 1,2006 Written by "Bill Rideout":mailto:brideout@haystack.mit.edu Aug. 1,2006 """ def __init__(self,isprintText, titleStr, xLabelStr, fullFilename, size = 'small', maxNumPoints = None, numBins = 30, Orientation='vertical', isNorm =0, isBottom=0, sdevs=0): """__init__ writes a madHistogram string to file """ self.__missing = 1.0E30 #special value, since numpy doesn't Handle NaN self.__parameter_count = 2 #verify input if not size in ('small','wide','large'): raise ValueError, 'size must be "small","wide" or "large", not %s'%(str(size)) if size in ('small','wide'): fontSize = 12 elif size in ('large'): fontSize = 18 # remove all non-float values items = isprintText.split() keptItems = [] for item in items: try: float(item) keptItems.append(item) except: continue delimiter = ' ' isprintText = delimiter.join(keptItems) if maxNumPoints !=None: isprintText = self._truncateIsprint(isprintText, maxNumPoints) #convert the input data into numeric arrays of floats assuming no headers and filter the missing values try: split_data = isprintText.split() float_data = map(self.__filter_missing,split_data) array_data = numpy.asarray(float_data) except: traceback.print_exc() raise ValueError, 'input text is not parseable' #if needed, throw away outliers if sdevs !=0: array_data = self.removeOutliers(sdevs,array_data) #select the plot size if size=='small': matplotlib.pylab.figure(1,figsize=(6,4), facecolor = 'w') elif size=='wide': matplotlib.pylab.figure(1,figsize=(10,4),facecolor='w') elif size=='large': matplotlib.pylab.figure(1,figsize=(12,6),facecolor='w') matplotlib.pylab.hist(array_data,bins = numBins,normed=isNorm,bottom=isBottom,orientation = Orientation) thisFont = {'size': fontSize} matplotlib.pylab.rc('font', **thisFont) #pass in the font dict as kwargs matplotlib.pylab.xlabel(xLabelStr, fontsize=fontSize) matplotlib.pylab.title(titleStr,fontsize=fontSize) #self.__figure = matplotlib.pylab.gcf() matplotlib.pylab.savefig(fullFilename) matplotlib.pylab.clf() def __truncateIsprintStr(self,isprintText, maxLines): """__truncateIsprintStr truncates isprintText to have maxLines at most. """ isprintList = isprintText.split('\n') if len(isprintList)<maxLines: return isprintText else: dropNumber = int(1+len(isprintList)/maxlines) newline = '\n' newIsprintText = newline.join(isprintList[::dropNumber]) return newIsprintText def __filter_missing(self,x): try: return float(x) except: return self.__missing def removeOutliers(self,ndevs,values=[]): #find the mean value in values sums = 0.0 count = 0 for i in values: sums = sums+i count = count+1 mean = sums/count #calculate a standard deviation innersum = 0 for i in values: innersum = innersum + math.pow((i-mean),2) sdev = math.sqrt((1.0/count)*innersum) #throw away all data points falling outside three standard deviations of the mean, then return the resulting list retArray = [] ndist = mean-ndevs*sdev pdist = mean+ndevs*sdev for i in values: if (i>=ndist) and (i<=pdist): retArray.append(i) return retArray #end eliminateOutliers() class madIsrRecordSummary: """madIsrRecordSummary is the class that produces a summary plot of a single ISR record. """ def __init__(self, TiData, TiError, TeData, TeError, VoData, VoError, NelData, NelError, isPopl, description, fullFilename, useRange = False, altResl = None): """__init__ writes a madIsrRecordSummary to a file. Inputs: TiData - an Nx2 numeric array of Ti (col 0) and altitude in km (col 1) TiError - an N length array of error in Ti TeData - an Nx2 numeric array of Te (col 0) and altitude in km (col 1) TeError - an N length array of error in Te VoData - an Nx2 numeric array of Vo (col 0) and altitude in km (col 1) VoError - an N length array of error in Vo NelData - an Nx2 numeric array of (Popl or Nel in m^-3) (col 0) and altitude in km (col 1) NelError - an 2xN length array of lower, upper error in Popl or Nel isPopl - true if Nel contains Popl data, false if Nel data description - text to put in fourth panel of plot - use carriage returns to separate lines fullFilename - full filename to save output png file. useRange - if False (the default), y axis = Altitude. If True, y axis = Range. altResl - altitude resolution in km. If not None, show altitude resolution on each graph. Returns: void Affects: None """ if useRange: yAxisStr = 'Range (km)' else: yAxisStr = 'Altitude (km)' # upper left - Ti and Te fig = matplotlib.pylab.figure(figsize=(10,10)) axis = matplotlib.pylab.subplot(2,2,1) if TiData.shape[0] > 0 and TeData.shape[0] > 0: axis.errorbar(TiData[:,0], TiData[:,1], xerr=TiError, fmt='bo-') axis.errorbar(TeData[:,0], TeData[:,1], xerr=TeError, fmt='rD-') matplotlib.pylab.text(0.65, 0.1, 'Ti: blue circle\nTe: red diamond', horizontalalignment='left', verticalalignment='top', transform = axis.transAxes, fontsize=10) matplotlib.pylab.text(0.5,0.5, 'Preliminary data\n\n\nfrom the\n\n\nMadrigal database', horizontalalignment='center', verticalalignment='center', fontsize=18, transform = axis.transAxes, alpha=0.2) matplotlib.pylab.xlabel('Temperature (K)') matplotlib.pylab.ylabel(yAxisStr) matplotlib.pylab.grid(True) # set limits based on data only tiMax = numpy.nanmax(TiData[:,0]) tiMin = numpy.nanmin(TiData[:,0]) teMax = numpy.nanmax(TeData[:,0]) teMin = numpy.nanmin(TeData[:,0]) lowerLimit = (int(min(tiMin, teMin)) / 1000) * 1000 upperLimit = (1+int(max(tiMax, teMax)) / 1000) * 1000 # alt resolution if altResl != None: altLabel = 'Alt res: \n%i km' % (int(altResl)) y_min, y_max = matplotlib.pylab.ylim() startX = lowerLimit + 0.8*(upperLimit - lowerLimit) startY = 0.15 reslPercentage = altResl/(y_max-y_min) matplotlib.pylab.axvline(x=startX, ymin=startY, ymax=reslPercentage + startY, linewidth=2, color='b') matplotlib.pylab.text(0.83, 0.2, altLabel, horizontalalignment='left', verticalalignment='top', transform = axis.transAxes, fontsize=10) matplotlib.pylab.xlim(lowerLimit, upperLimit) # upper right - Vo and 10*Vo axis = matplotlib.pylab.subplot(2,2,2) if VoData.shape[0] > 0: axis.errorbar(VoData[:,0], VoData[:,1], xerr=VoError, fmt='bo-') axis.errorbar(10.0*VoData[:,0], VoData[:,1], xerr=10.0*VoError, fmt='rD-') # set x limits to be even around 0 voMax = numpy.nanmax(10.0*VoData[:,0]) voMin = numpy.nanmin(10.0*VoData[:,0]) limit = max(abs(voMax), abs(voMin)) matplotlib.pylab.xlim(-1.0*limit, limit) matplotlib.pylab.text(0.58, 0.1, 'Vo: blue circle\n10*Vo: red diamond', horizontalalignment='left', verticalalignment='top', transform = axis.transAxes, fontsize=10) matplotlib.pylab.text(0.5,0.5, 'Preliminary data\n\n\nfrom the\n\n\nMadrigal database', horizontalalignment='center', verticalalignment='center', fontsize=18, transform = axis.transAxes, alpha=0.2) matplotlib.pylab.xlabel('Line of sight drift (m/s)') matplotlib.pylab.ylabel(yAxisStr) matplotlib.pylab.grid(True) # alt resolution if altResl != None: altLabel = 'Alt res: \n%i km' % (int(altResl)) y_min, y_max = matplotlib.pylab.ylim() startX = limit*0.6 startY = 0.15 reslPercentage = altResl/(y_max-y_min) matplotlib.pylab.axvline(x=startX, ymin=startY, ymax=reslPercentage + startY, linewidth=2, color='b') matplotlib.pylab.text(0.83, 0.2, altLabel, horizontalalignment='left', verticalalignment='top', transform = axis.transAxes, fontsize=10) matplotlib.pylab.xlim(-1.0*limit, limit) # lower left - Nel or Popl axis = matplotlib.pylab.subplot(2,2,3) if isPopl: labelStr = 'Log Power (m^-3)' else: labelStr = 'Log Electron density (m^-3)' if NelData.shape[0] > 0: # check that not every point equal if numpy.nanmax(NelData[:,0]) == numpy.nanmin(NelData[:,0]): pass else: axis.errorbar(NelData[:,0], NelData[:,1], xerr=NelError, fmt='bo-') matplotlib.pylab.xlabel(labelStr) matplotlib.pylab.ylabel(yAxisStr) matplotlib.pylab.grid(True) nelMax = numpy.nanmax(NelData[:,0]) nelMin = numpy.nanmin(NelData[:,0]) matplotlib.pylab.xlim(math.floor(nelMin), math.ceil(nelMax)) matplotlib.pylab.text(0.5,0.5, 'Preliminary data\n\n\nfrom the\n\n\nMadrigal database', horizontalalignment='center', verticalalignment='center', fontsize=18, transform = axis.transAxes, alpha=0.2) # alt resolution if altResl != None: altLabel = 'Alt res: \n%i km' % (int(altResl)) y_min, y_max = matplotlib.pylab.ylim() x_min, x_max = matplotlib.pylab.xlim() startX = x_min + 0.8*(x_max-x_min) startY = 0.15 reslPercentage = altResl/(y_max-y_min) matplotlib.pylab.axvline(x=startX, ymin=startY, ymax=reslPercentage + startY, linewidth=2, color='b') matplotlib.pylab.text(0.83, 0.2, altLabel, horizontalalignment='left', verticalalignment='top', transform = axis.transAxes, fontsize=10) matplotlib.pylab.xlim(math.floor(nelMin), math.ceil(nelMax)) # lower right - text axis = matplotlib.pylab.subplot(2,2,4) matplotlib.pylab.text(0.05, 0.9, description, horizontalalignment='left', verticalalignment='top', transform = axis.transAxes, fontsize=9) matplotlib.pylab.xticks([]) matplotlib.pylab.yticks([]) matplotlib.pylab.subplots_adjust(wspace = 0.25) matplotlib.pylab.savefig(fullFilename) #matplotlib.pylab.show() matplotlib.pylab.clf() matplotlib.pylab.close() if __name__ == '__main__': import time # test madPcolorScan # az scan f = open('testFiles/isprint_az_scan.txt') isprintText = f.read() f.close() print 'creating az scan at /tmp/isprint_az_scan.png' obj = madPcolorScan(isprintText, 1.0, 1.0, 'Az scan - NEL 2006-06-26 13:49:43-14:07:36', 'Longitude', 'Latitude', '/tmp/isprint_az_scan.png', 'small', -100,-50,40,60, 9,12) # el scan f = open('testFiles/isprint_el_scan.txt') isprintText = f.read() f.close() print 'creating el scan at /tmp/isprint_el_scan.png' obj = madPcolorScan(isprintText, 1.0, 40.0, 'El scan - NEL 2006-06-26 13:49:43-14:07:36', 'Latitude', 'Altitude (km)', '/tmp/isprint_el_scan.png', 'small') # test scanPlotter print 'creating az scan series using mlh060622a.000' scanObj = scanPlotter('/home/grail/brideout/madroot/experiments/2006/mlh/22jun06/mlh060622a.000') scanObj.plotAllScans('az','/tmp/junkAz', 'Nel', filterStr='filter=nel,,11.0') t = time.time() # test madIsrRecordSummary TiData = numpy.array([[800, 150],[900, 200],[910, 300], [945, 500], [980, 600]]) TiError = numpy.array([50,100,50,100,50]) TeData = numpy.array([[850, 150],[1000, 200],[1800, 300], [2000, 500], [2000, 600]]) TeError = numpy.array([50,100,50,100,50]) VoData = numpy.array([[-30, 150],[0, 200],[10, 300], [35, 500], [10, 600]]) VoError = numpy.array([5,10,5,10,5]) NelData = numpy.array([[11, 150],[11.5, 200],[11.3, 300], [11, 500], [10.5, 600]]) NelError = numpy.array(((2.0,0.5),(2.0,1.0), (2.0,0.5), (2.0,1.0), (2.0,0.5))) isPopl = True text = 'Kinst = Millstone Zenith Antenna\nMore stuff here\nand more\nand more' fullFilename = '/tmp/junk.png' madIsrRecordSummary(TiData,TiError,TeData,TeError,VoData,VoError,NelData,numpy.transpose(NelError),isPopl,text,fullFilename) f = open('testFiles/isprint_uth_fof2.txt') isprintText = f.read() f.close() print 'creating scatterplot at /tmp/isprint_fof2.png' obj = madScatterPlot(isprintText, 'Fof2 - Millstone Hill - Oct. 30, 2003', 'Hours since midnight UT Oct. 30, 2003', 'Fof2', '/tmp/isprint_fof2.png', size = 'large', useAbsoluteTime = False) f = open('testFiles/isprint_nel.txt') isprintText = f.read() f.close() print 'creating pcolor plot at /tmp/isprint_nel.png' obj = madPcolorPlot(isprintText, 'Nel (log(m^-3)) - Millstone Hill - Oct. 30, 2003 - Alt code', 'Hours since midnight UT Oct. 30, 2003', 'Altitude (km)', '/tmp/isprint_nel.png', size = 'large', minColormap = 9, maxColormap = 12, smoothAltitude = True, insertDataGap = 5, useAbsoluteTime = False, startTime = None, endTime = None, sortTimeFlag = False, maxNumTimes = None, maxNumAlt = 50, truncateIsprint = True, colorMap = matplotlib.cm.spring, altYTitle = 'Latitude', altYLabels = ('40', '41', '42', '43', '44', '45')) print 'took %i secs' % (time.time() - t)
Functions
def convertToAbsoluteTimeStr(
xticks, noTime=False, noDate=False, timezone=0)
convertToAbsoluteTimeStr converts a list of strings containing seconds since 1/1/1950 to datetime string.
Input: xticks - a list of strings containing seconds since 1/1/1950
Returns: a list of strings formated as YYYY-MM-DD HH-MM-SS. If noTime, format as YYYY-MM-DD
def convertToAbsoluteTimeStr(xticks, noTime=False, noDate=False, timezone=0): """convertToAbsoluteTimeStr converts a list of strings containing seconds since 1/1/1950 to datetime string. Input: xticks - a list of strings containing seconds since 1/1/1950 Returns: a list of strings formated as YYYY-MM-DD HH-MM-SS. If noTime, format as YYYY-MM-DD """ datetime1950 = datetime.datetime(1950,1,1,0,0,0) newList = [] seconds = long(xticks[0]) - timezone iniDoy = datetime1950 + datetime.timedelta(0, seconds) iniDoy = int(iniDoy.strftime('%j')) for item in xticks: seconds = long(item) - timezone newDatetime = datetime1950 + datetime.timedelta(0, seconds) if noTime: newList.append(newDatetime.strftime('%Y-%m-%d')) elif noDate: curDoy = int(newDatetime.strftime('%j')) currHour = newDatetime.hour currMin = newDatetime.minute currHour += (curDoy - iniDoy)*24 newList.append('%02d:%02d' %(currHour,currMin)) else: newList.append(newDatetime.strftime('%Y-%m-%d %H:%M:%S')) return newList
def defineHomeEnvVariable(
)
defineHomeEnvVariable makes sure HOME env variable is defined, as required by matplotlib.
If not defined, sets HOME to MADROOT/metadata/userdata
def defineHomeEnvVariable(): """defineHomeEnvVariable makes sure HOME env variable is defined, as required by matplotlib. If not defined, sets HOME to MADROOT/metadata/userdata """ try: os.environ['HOME'] return except KeyError: import madrigal.metadata madDB = madrigal.metadata.MadrigalDB() os.environ['HOME'] = os.path.join(madDB.getMadroot(), 'metadata/userdata')
def getIsprintString(
filename, parms, filterStr)
getIsprintString returns the output of isprint given inputs
Inputs: filename - Madrigal filename parms - comma-delimited parameters filterStr - arguments to pass to isprint cmd
def getIsprintString(filename, parms, filterStr): """getIsprintString returns the output of isprint given inputs Inputs: filename - Madrigal filename parms - comma-delimited parameters filterStr - arguments to pass to isprint cmd """ madDB = madrigal.metadata.MadrigalDB() cmd = '%s/bin/isprint file=%s ' % (madDB.getMadroot(), filename) for parm in parms.split(','): cmd += '%s ' % (parm) cmd += filterStr cmd += ' header=f summary=f ' pipe = subprocess.Popen(cmd, shell=True, stdout=subprocess.PIPE).stdout result = pipe.read() delimiter = '\n' lines = result.split(delimiter) return(delimiter.join(lines[1:]).strip())
def get_vo_cmap(
)
get_vo_cmap is a function to return a colormap optimized to show sign changes in the middle of the range.
def get_vo_cmap(): """get_vo_cmap is a function to return a colormap optimized to show sign changes in the middle of the range. """ LUTSIZE = matplotlib.rcParams['image.lut'] _vo_cm_data = {'red': ((0, 0.75, 0.75), (0.4, 0.0, 0.0), (0.5, 0.0, 0.0), (0.6, 1.0, 1.0), (1.0, 1.0, 1.0)), 'green': ((0, 1.0, 1.0), (0.4, 0.5, 0.5), (0.5, 0.25, 0.25), (0.6, 0.25, 0.25), (1.0, 1.0, 1.0)), 'blue': ((0, 1.0, 1.0), (0.4, 1.0, 1.0), (0.5, 0.5, 0.5), (0.6, 0.0, 0.0), (1.0, 0.5, 0.5))} vo_cm = matplotlib.colors.LinearSegmentedColormap('vo_cm',_vo_cm_data, LUTSIZE) return vo_cm
Classes
class madHistogram
madHistogram is the class that produces Histogram plots of Madrigal Data.
Usage example::
obj = madHistogram(isprintText, 'Nel (log(m^-3)) - Millstone Hill - Oct. 30, 2005 - Alt. code', 'Hours since midnight UT Oct. 30,2003' 'Altitude', './isprint.png' size = 'large')
Inputs:
isprintText - a string giving isprint output without headers. Any missing data should be written as 'missing' or other string that cannot be converted into a float. Only one column. TitleStr - plot title(string) - should describe the plot being made xLabelStr - Label for x axis fullFilename - full path of file containing histogram plot to be saved. Extension must be .jpeg or .png, or exception thrown size - size of plot to be saved. Must be 'small','wide', or 'large'. Defaults to small maxNumPoints - maximum number of points to be considered. Defaults to None, so all points in string shown numBins - number of bins to be used to store the data. More bins means closer resolution in Histogram. Default is 30 orientation - whether histogram shows horizontal or vertical. Must be written as 'horizontal' or 'vertical', or exception thrown--defaults to 'vertical' isNorm - whether histogram should be normalized or not. Default is 0, or False isBottom - If true, sets the lowest passed value as zero sdevs - number of standard deviations to take into account. When 0 is passed to it, this option is ignored and all data is included in the distribution; otherwise, the range of values accepted is sdevs*(standard deviation of sample)
Outputs:
A .png file is written to the fullFilename path given, resulting in a Histogram drawn by matplotlib
Change History:
Written by "Brandon Scott Fines":mailto:bfines@haystack.mit.edu Aug. 1,2006 Written by "Bill Rideout":mailto:brideout@haystack.mit.edu Aug. 1,2006
class madHistogram: """madHistogram is the class that produces Histogram plots of Madrigal Data. Usage example:: obj = madHistogram(isprintText, 'Nel (log(m^-3)) - Millstone Hill - Oct. 30, 2005 - Alt. code', 'Hours since midnight UT Oct. 30,2003' 'Altitude', './isprint.png' size = 'large') Inputs: isprintText - a string giving isprint output without headers. Any missing data should be written as 'missing' or other string that cannot be converted into a float. Only one column. TitleStr - plot title(string) - should describe the plot being made xLabelStr - Label for x axis fullFilename - full path of file containing histogram plot to be saved. Extension must be .jpeg or .png, or exception thrown size - size of plot to be saved. Must be 'small','wide', or 'large'. Defaults to small maxNumPoints - maximum number of points to be considered. Defaults to None, so all points in string shown numBins - number of bins to be used to store the data. More bins means closer resolution in Histogram. Default is 30 orientation - whether histogram shows horizontal or vertical. Must be written as 'horizontal' or 'vertical', or exception thrown--defaults to 'vertical' isNorm - whether histogram should be normalized or not. Default is 0, or False isBottom - If true, sets the lowest passed value as zero sdevs - number of standard deviations to take into account. When 0 is passed to it, this option is ignored and all data is included in the distribution; otherwise, the range of values accepted is sdevs*(standard deviation of sample) Outputs: A .png file is written to the fullFilename path given, resulting in a Histogram drawn by matplotlib Change History: Written by "Brandon Scott Fines":mailto:bfines@haystack.mit.edu Aug. 1,2006 Written by "Bill Rideout":mailto:brideout@haystack.mit.edu Aug. 1,2006 """ def __init__(self,isprintText, titleStr, xLabelStr, fullFilename, size = 'small', maxNumPoints = None, numBins = 30, Orientation='vertical', isNorm =0, isBottom=0, sdevs=0): """__init__ writes a madHistogram string to file """ self.__missing = 1.0E30 #special value, since numpy doesn't Handle NaN self.__parameter_count = 2 #verify input if not size in ('small','wide','large'): raise ValueError, 'size must be "small","wide" or "large", not %s'%(str(size)) if size in ('small','wide'): fontSize = 12 elif size in ('large'): fontSize = 18 # remove all non-float values items = isprintText.split() keptItems = [] for item in items: try: float(item) keptItems.append(item) except: continue delimiter = ' ' isprintText = delimiter.join(keptItems) if maxNumPoints !=None: isprintText = self._truncateIsprint(isprintText, maxNumPoints) #convert the input data into numeric arrays of floats assuming no headers and filter the missing values try: split_data = isprintText.split() float_data = map(self.__filter_missing,split_data) array_data = numpy.asarray(float_data) except: traceback.print_exc() raise ValueError, 'input text is not parseable' #if needed, throw away outliers if sdevs !=0: array_data = self.removeOutliers(sdevs,array_data) #select the plot size if size=='small': matplotlib.pylab.figure(1,figsize=(6,4), facecolor = 'w') elif size=='wide': matplotlib.pylab.figure(1,figsize=(10,4),facecolor='w') elif size=='large': matplotlib.pylab.figure(1,figsize=(12,6),facecolor='w') matplotlib.pylab.hist(array_data,bins = numBins,normed=isNorm,bottom=isBottom,orientation = Orientation) thisFont = {'size': fontSize} matplotlib.pylab.rc('font', **thisFont) #pass in the font dict as kwargs matplotlib.pylab.xlabel(xLabelStr, fontsize=fontSize) matplotlib.pylab.title(titleStr,fontsize=fontSize) #self.__figure = matplotlib.pylab.gcf() matplotlib.pylab.savefig(fullFilename) matplotlib.pylab.clf() def __truncateIsprintStr(self,isprintText, maxLines): """__truncateIsprintStr truncates isprintText to have maxLines at most. """ isprintList = isprintText.split('\n') if len(isprintList)<maxLines: return isprintText else: dropNumber = int(1+len(isprintList)/maxlines) newline = '\n' newIsprintText = newline.join(isprintList[::dropNumber]) return newIsprintText def __filter_missing(self,x): try: return float(x) except: return self.__missing def removeOutliers(self,ndevs,values=[]): #find the mean value in values sums = 0.0 count = 0 for i in values: sums = sums+i count = count+1 mean = sums/count #calculate a standard deviation innersum = 0 for i in values: innersum = innersum + math.pow((i-mean),2) sdev = math.sqrt((1.0/count)*innersum) #throw away all data points falling outside three standard deviations of the mean, then return the resulting list retArray = [] ndist = mean-ndevs*sdev pdist = mean+ndevs*sdev for i in values: if (i>=ndist) and (i<=pdist): retArray.append(i) return retArray
Ancestors (in MRO)
Methods
def __init__(
self, isprintText, titleStr, xLabelStr, fullFilename, size='small', maxNumPoints=None, numBins=30, Orientation='vertical', isNorm=0, isBottom=0, sdevs=0)
init writes a madHistogram string to file
def __init__(self,isprintText, titleStr, xLabelStr, fullFilename, size = 'small', maxNumPoints = None, numBins = 30, Orientation='vertical', isNorm =0, isBottom=0, sdevs=0): """__init__ writes a madHistogram string to file """ self.__missing = 1.0E30 #special value, since numpy doesn't Handle NaN self.__parameter_count = 2 #verify input if not size in ('small','wide','large'): raise ValueError, 'size must be "small","wide" or "large", not %s'%(str(size)) if size in ('small','wide'): fontSize = 12 elif size in ('large'): fontSize = 18 # remove all non-float values items = isprintText.split() keptItems = [] for item in items: try: float(item) keptItems.append(item) except: continue delimiter = ' ' isprintText = delimiter.join(keptItems) if maxNumPoints !=None: isprintText = self._truncateIsprint(isprintText, maxNumPoints) #convert the input data into numeric arrays of floats assuming no headers and filter the missing values try: split_data = isprintText.split() float_data = map(self.__filter_missing,split_data) array_data = numpy.asarray(float_data) except: traceback.print_exc() raise ValueError, 'input text is not parseable' #if needed, throw away outliers if sdevs !=0: array_data = self.removeOutliers(sdevs,array_data) #select the plot size if size=='small': matplotlib.pylab.figure(1,figsize=(6,4), facecolor = 'w') elif size=='wide': matplotlib.pylab.figure(1,figsize=(10,4),facecolor='w') elif size=='large': matplotlib.pylab.figure(1,figsize=(12,6),facecolor='w') matplotlib.pylab.hist(array_data,bins = numBins,normed=isNorm,bottom=isBottom,orientation = Orientation) thisFont = {'size': fontSize} matplotlib.pylab.rc('font', **thisFont) #pass in the font dict as kwargs matplotlib.pylab.xlabel(xLabelStr, fontsize=fontSize) matplotlib.pylab.title(titleStr,fontsize=fontSize) #self.__figure = matplotlib.pylab.gcf() matplotlib.pylab.savefig(fullFilename) matplotlib.pylab.clf()
def removeOutliers(
self, ndevs, values=[])
def removeOutliers(self,ndevs,values=[]): #find the mean value in values sums = 0.0 count = 0 for i in values: sums = sums+i count = count+1 mean = sums/count #calculate a standard deviation innersum = 0 for i in values: innersum = innersum + math.pow((i-mean),2) sdev = math.sqrt((1.0/count)*innersum) #throw away all data points falling outside three standard deviations of the mean, then return the resulting list retArray = [] ndist = mean-ndevs*sdev pdist = mean+ndevs*sdev for i in values: if (i>=ndist) and (i<=pdist): retArray.append(i) return retArray
class madIsrRecordSummary
madIsrRecordSummary is the class that produces a summary plot of a single ISR record.
class madIsrRecordSummary: """madIsrRecordSummary is the class that produces a summary plot of a single ISR record. """ def __init__(self, TiData, TiError, TeData, TeError, VoData, VoError, NelData, NelError, isPopl, description, fullFilename, useRange = False, altResl = None): """__init__ writes a madIsrRecordSummary to a file. Inputs: TiData - an Nx2 numeric array of Ti (col 0) and altitude in km (col 1) TiError - an N length array of error in Ti TeData - an Nx2 numeric array of Te (col 0) and altitude in km (col 1) TeError - an N length array of error in Te VoData - an Nx2 numeric array of Vo (col 0) and altitude in km (col 1) VoError - an N length array of error in Vo NelData - an Nx2 numeric array of (Popl or Nel in m^-3) (col 0) and altitude in km (col 1) NelError - an 2xN length array of lower, upper error in Popl or Nel isPopl - true if Nel contains Popl data, false if Nel data description - text to put in fourth panel of plot - use carriage returns to separate lines fullFilename - full filename to save output png file. useRange - if False (the default), y axis = Altitude. If True, y axis = Range. altResl - altitude resolution in km. If not None, show altitude resolution on each graph. Returns: void Affects: None """ if useRange: yAxisStr = 'Range (km)' else: yAxisStr = 'Altitude (km)' # upper left - Ti and Te fig = matplotlib.pylab.figure(figsize=(10,10)) axis = matplotlib.pylab.subplot(2,2,1) if TiData.shape[0] > 0 and TeData.shape[0] > 0: axis.errorbar(TiData[:,0], TiData[:,1], xerr=TiError, fmt='bo-') axis.errorbar(TeData[:,0], TeData[:,1], xerr=TeError, fmt='rD-') matplotlib.pylab.text(0.65, 0.1, 'Ti: blue circle\nTe: red diamond', horizontalalignment='left', verticalalignment='top', transform = axis.transAxes, fontsize=10) matplotlib.pylab.text(0.5,0.5, 'Preliminary data\n\n\nfrom the\n\n\nMadrigal database', horizontalalignment='center', verticalalignment='center', fontsize=18, transform = axis.transAxes, alpha=0.2) matplotlib.pylab.xlabel('Temperature (K)') matplotlib.pylab.ylabel(yAxisStr) matplotlib.pylab.grid(True) # set limits based on data only tiMax = numpy.nanmax(TiData[:,0]) tiMin = numpy.nanmin(TiData[:,0]) teMax = numpy.nanmax(TeData[:,0]) teMin = numpy.nanmin(TeData[:,0]) lowerLimit = (int(min(tiMin, teMin)) / 1000) * 1000 upperLimit = (1+int(max(tiMax, teMax)) / 1000) * 1000 # alt resolution if altResl != None: altLabel = 'Alt res: \n%i km' % (int(altResl)) y_min, y_max = matplotlib.pylab.ylim() startX = lowerLimit + 0.8*(upperLimit - lowerLimit) startY = 0.15 reslPercentage = altResl/(y_max-y_min) matplotlib.pylab.axvline(x=startX, ymin=startY, ymax=reslPercentage + startY, linewidth=2, color='b') matplotlib.pylab.text(0.83, 0.2, altLabel, horizontalalignment='left', verticalalignment='top', transform = axis.transAxes, fontsize=10) matplotlib.pylab.xlim(lowerLimit, upperLimit) # upper right - Vo and 10*Vo axis = matplotlib.pylab.subplot(2,2,2) if VoData.shape[0] > 0: axis.errorbar(VoData[:,0], VoData[:,1], xerr=VoError, fmt='bo-') axis.errorbar(10.0*VoData[:,0], VoData[:,1], xerr=10.0*VoError, fmt='rD-') # set x limits to be even around 0 voMax = numpy.nanmax(10.0*VoData[:,0]) voMin = numpy.nanmin(10.0*VoData[:,0]) limit = max(abs(voMax), abs(voMin)) matplotlib.pylab.xlim(-1.0*limit, limit) matplotlib.pylab.text(0.58, 0.1, 'Vo: blue circle\n10*Vo: red diamond', horizontalalignment='left', verticalalignment='top', transform = axis.transAxes, fontsize=10) matplotlib.pylab.text(0.5,0.5, 'Preliminary data\n\n\nfrom the\n\n\nMadrigal database', horizontalalignment='center', verticalalignment='center', fontsize=18, transform = axis.transAxes, alpha=0.2) matplotlib.pylab.xlabel('Line of sight drift (m/s)') matplotlib.pylab.ylabel(yAxisStr) matplotlib.pylab.grid(True) # alt resolution if altResl != None: altLabel = 'Alt res: \n%i km' % (int(altResl)) y_min, y_max = matplotlib.pylab.ylim() startX = limit*0.6 startY = 0.15 reslPercentage = altResl/(y_max-y_min) matplotlib.pylab.axvline(x=startX, ymin=startY, ymax=reslPercentage + startY, linewidth=2, color='b') matplotlib.pylab.text(0.83, 0.2, altLabel, horizontalalignment='left', verticalalignment='top', transform = axis.transAxes, fontsize=10) matplotlib.pylab.xlim(-1.0*limit, limit) # lower left - Nel or Popl axis = matplotlib.pylab.subplot(2,2,3) if isPopl: labelStr = 'Log Power (m^-3)' else: labelStr = 'Log Electron density (m^-3)' if NelData.shape[0] > 0: # check that not every point equal if numpy.nanmax(NelData[:,0]) == numpy.nanmin(NelData[:,0]): pass else: axis.errorbar(NelData[:,0], NelData[:,1], xerr=NelError, fmt='bo-') matplotlib.pylab.xlabel(labelStr) matplotlib.pylab.ylabel(yAxisStr) matplotlib.pylab.grid(True) nelMax = numpy.nanmax(NelData[:,0]) nelMin = numpy.nanmin(NelData[:,0]) matplotlib.pylab.xlim(math.floor(nelMin), math.ceil(nelMax)) matplotlib.pylab.text(0.5,0.5, 'Preliminary data\n\n\nfrom the\n\n\nMadrigal database', horizontalalignment='center', verticalalignment='center', fontsize=18, transform = axis.transAxes, alpha=0.2) # alt resolution if altResl != None: altLabel = 'Alt res: \n%i km' % (int(altResl)) y_min, y_max = matplotlib.pylab.ylim() x_min, x_max = matplotlib.pylab.xlim() startX = x_min + 0.8*(x_max-x_min) startY = 0.15 reslPercentage = altResl/(y_max-y_min) matplotlib.pylab.axvline(x=startX, ymin=startY, ymax=reslPercentage + startY, linewidth=2, color='b') matplotlib.pylab.text(0.83, 0.2, altLabel, horizontalalignment='left', verticalalignment='top', transform = axis.transAxes, fontsize=10) matplotlib.pylab.xlim(math.floor(nelMin), math.ceil(nelMax)) # lower right - text axis = matplotlib.pylab.subplot(2,2,4) matplotlib.pylab.text(0.05, 0.9, description, horizontalalignment='left', verticalalignment='top', transform = axis.transAxes, fontsize=9) matplotlib.pylab.xticks([]) matplotlib.pylab.yticks([]) matplotlib.pylab.subplots_adjust(wspace = 0.25) matplotlib.pylab.savefig(fullFilename) #matplotlib.pylab.show() matplotlib.pylab.clf() matplotlib.pylab.close()
Ancestors (in MRO)
Methods
def __init__(
self, TiData, TiError, TeData, TeError, VoData, VoError, NelData, NelError, isPopl, description, fullFilename, useRange=False, altResl=None)
init writes a madIsrRecordSummary to a file.
Inputs:
TiData - an Nx2 numeric array of Ti (col 0) and altitude in km (col 1) TiError - an N length array of error in Ti TeData - an Nx2 numeric array of Te (col 0) and altitude in km (col 1) TeError - an N length array of error in Te VoData - an Nx2 numeric array of Vo (col 0) and altitude in km (col 1) VoError - an N length array of error in Vo NelData - an Nx2 numeric array of (Popl or Nel in m^-3) (col 0) and altitude in km (col 1) NelError - an 2xN length array of lower, upper error in Popl or Nel isPopl - true if Nel contains Popl data, false if Nel data description - text to put in fourth panel of plot - use carriage returns to separate lines fullFilename - full filename to save output png file. useRange - if False (the default), y axis = Altitude. If True, y axis = Range. altResl - altitude resolution in km. If not None, show altitude resolution on each graph.
Returns: void
Affects: None
def __init__(self, TiData, TiError, TeData, TeError, VoData, VoError, NelData, NelError, sPopl, description, fullFilename, useRange = False, altResl = None): """__init__ writes a madIsrRecordSummary to a file. Inputs: TiData - an Nx2 numeric array of Ti (col 0) and altitude in km (col 1) TiError - an N length array of error in Ti TeData - an Nx2 numeric array of Te (col 0) and altitude in km (col 1) TeError - an N length array of error in Te VoData - an Nx2 numeric array of Vo (col 0) and altitude in km (col 1) VoError - an N length array of error in Vo NelData - an Nx2 numeric array of (Popl or Nel in m^-3) (col 0) and altitude in km (col 1) NelError - an 2xN length array of lower, upper error in Popl or Nel isPopl - true if Nel contains Popl data, false if Nel data description - text to put in fourth panel of plot - use carriage returns to separate lines fullFilename - full filename to save output png file. useRange - if False (the default), y axis = Altitude. If True, y axis = Range. altResl - altitude resolution in km. If not None, show altitude resolution on each graph. Returns: void Affects: None """ if useRange: yAxisStr = 'Range (km)' else: yAxisStr = 'Altitude (km)' # upper left - Ti and Te fig = matplotlib.pylab.figure(figsize=(10,10)) axis = matplotlib.pylab.subplot(2,2,1) if TiData.shape[0] > 0 and TeData.shape[0] > 0: axis.errorbar(TiData[:,0], TiData[:,1], xerr=TiError, fmt='bo-') axis.errorbar(TeData[:,0], TeData[:,1], xerr=TeError, fmt='rD-') matplotlib.pylab.text(0.65, 0.1, 'Ti: blue circle\nTe: red diamond', horizontalalignment='left', verticalalignment='top', transform = axis.transAxes, fontsize=10) matplotlib.pylab.text(0.5,0.5, 'Preliminary data\n\n\nfrom the\n\n\nMadrigal database', horizontalalignment='center', verticalalignment='center', fontsize=18, transform = axis.transAxes, alpha=0.2) matplotlib.pylab.xlabel('Temperature (K)') matplotlib.pylab.ylabel(yAxisStr) matplotlib.pylab.grid(True) # set limits based on data only tiMax = numpy.nanmax(TiData[:,0]) tiMin = numpy.nanmin(TiData[:,0]) teMax = numpy.nanmax(TeData[:,0]) teMin = numpy.nanmin(TeData[:,0]) lowerLimit = (int(min(tiMin, teMin)) / 1000) * 1000 upperLimit = (1+int(max(tiMax, teMax)) / 1000) * 1000 # alt resolution if altResl != None: altLabel = 'Alt res: \n%i km' % (int(altResl)) y_min, y_max = matplotlib.pylab.ylim() startX = lowerLimit + 0.8*(upperLimit - lowerLimit) startY = 0.15 reslPercentage = altResl/(y_max-y_min) matplotlib.pylab.axvline(x=startX, ymin=startY, ymax=reslPercentage + startY, linewidth=2, color='b') matplotlib.pylab.text(0.83, 0.2, altLabel, horizontalalignment='left', verticalalignment='top', transform = axis.transAxes, fontsize=10) matplotlib.pylab.xlim(lowerLimit, upperLimit) # upper right - Vo and 10*Vo axis = matplotlib.pylab.subplot(2,2,2) if VoData.shape[0] > 0: axis.errorbar(VoData[:,0], VoData[:,1], xerr=VoError, fmt='bo-') axis.errorbar(10.0*VoData[:,0], VoData[:,1], xerr=10.0*VoError, fmt='rD-') # set x limits to be even around 0 voMax = numpy.nanmax(10.0*VoData[:,0]) voMin = numpy.nanmin(10.0*VoData[:,0]) limit = max(abs(voMax), abs(voMin)) matplotlib.pylab.xlim(-1.0*limit, limit) matplotlib.pylab.text(0.58, 0.1, 'Vo: blue circle\n10*Vo: red diamond', horizontalalignment='left', verticalalignment='top', transform = axis.transAxes, fontsize=10) matplotlib.pylab.text(0.5,0.5, 'Preliminary data\n\n\nfrom the\n\n\nMadrigal database', horizontalalignment='center', verticalalignment='center', fontsize=18, transform = axis.transAxes, alpha=0.2) matplotlib.pylab.xlabel('Line of sight drift (m/s)') matplotlib.pylab.ylabel(yAxisStr) matplotlib.pylab.grid(True) # alt resolution if altResl != None: altLabel = 'Alt res: \n%i km' % (int(altResl)) y_min, y_max = matplotlib.pylab.ylim() startX = limit*0.6 startY = 0.15 reslPercentage = altResl/(y_max-y_min) matplotlib.pylab.axvline(x=startX, ymin=startY, ymax=reslPercentage + startY, linewidth=2, color='b') matplotlib.pylab.text(0.83, 0.2, altLabel, horizontalalignment='left', verticalalignment='top', transform = axis.transAxes, fontsize=10) matplotlib.pylab.xlim(-1.0*limit, limit) # lower left - Nel or Popl axis = matplotlib.pylab.subplot(2,2,3) if isPopl: labelStr = 'Log Power (m^-3)' else: labelStr = 'Log Electron density (m^-3)' if NelData.shape[0] > 0: # check that not every point equal if numpy.nanmax(NelData[:,0]) == numpy.nanmin(NelData[:,0]): pass else: axis.errorbar(NelData[:,0], NelData[:,1], xerr=NelError, fmt='bo-') matplotlib.pylab.xlabel(labelStr) matplotlib.pylab.ylabel(yAxisStr) matplotlib.pylab.grid(True) nelMax = numpy.nanmax(NelData[:,0]) nelMin = numpy.nanmin(NelData[:,0]) matplotlib.pylab.xlim(math.floor(nelMin), math.ceil(nelMax)) matplotlib.pylab.text(0.5,0.5, 'Preliminary data\n\n\nfrom the\n\n\nMadrigal database', horizontalalignment='center', verticalalignment='center', fontsize=18, transform = axis.transAxes, alpha=0.2) # alt resolution if altResl != None: altLabel = 'Alt res: \n%i km' % (int(altResl)) y_min, y_max = matplotlib.pylab.ylim() x_min, x_max = matplotlib.pylab.xlim() startX = x_min + 0.8*(x_max-x_min) startY = 0.15 reslPercentage = altResl/(y_max-y_min) matplotlib.pylab.axvline(x=startX, ymin=startY, ymax=reslPercentage + startY, linewidth=2, color='b') matplotlib.pylab.text(0.83, 0.2, altLabel, horizontalalignment='left', verticalalignment='top', transform = axis.transAxes, fontsize=10) matplotlib.pylab.xlim(math.floor(nelMin), math.ceil(nelMax)) # lower right - text axis = matplotlib.pylab.subplot(2,2,4) matplotlib.pylab.text(0.05, 0.9, description, horizontalalignment='left', verticalalignment='top', transform = axis.transAxes, fontsize=9) matplotlib.pylab.xticks([]) matplotlib.pylab.yticks([]) matplotlib.pylab.subplots_adjust(wspace = 0.25) matplotlib.pylab.savefig(fullFilename) #matplotlib.pylab.show() matplotlib.pylab.clf() matplotlib.pylab.close()
class madLineTimePlot
madLineTimePlot is the class the produces line plots of one or more parameters versus time.
class madLineTimePlot: """madLineTimePlot is the class the produces line plots of one or more parameters versus time. """ def __init__(self, isprintText, yParmList, titleStr, xLabelStr, yLabelStr, fullFilename, size = 'small', useAbsoluteTime = False, startTime = None, endTime = None, maxNumPoints = None, noTime = False, yMinimum = None, yMaximum = None, noDate = False, timezone = 0): """__init__ writes a madLineTimePlot plot to a file. Inputs: isprintText - a string giving isprint output without headers. First parameter must be UTH or UT1, depending on whether time scale should be relative to the experiment beginning (UTH) or absolute (UT1). The the following must be the parameters to be plotted. Any missing data should be written as "missing" or other string that cannot be converted to a float. yParmList - a list of y parameters (strings). Length must == num columns in isprintText - 1 titleStr - plot title (string) - should describe parameter being plotted xLabelStr - x label string yLabelStr - ylabel string fullFilename - full path of file containing pcolor plot to be saved. Extension must be jpeg or png, or exception thrown. size - size of plot to save. Must be "small", "wide", or "large". Defaults to small. useAbsoluteTime - if true, print time as YYYY-MM-DD HH:MM:SS. If false (default), print time as hour since beginning of experiment (UTH). If useAbsoluteTime is true, first parameter in isprintText must be UT1, if false, it must be UTH. startTime - start plot at given time. If useAbsoluteTime == True, then startTime must be in units of seconds since 1/1/1950. If useAbsoluteTime == False, then startTime must be in units of UTH (hours since midnight UT of first day of experiment). Default is None, which means start at lowest time found. endTime - end plot at given time. If useAbsoluteTime == True, then endTime must be in units of seconds since 1/1/1950. If useAbsoluteTime == False, then endTime must be in units of UTH (hours since midnight UT of first day of experiment). Default is None, which means end at largest time found. maxNumPoints - maximum number of points to plot. If not None, truncate isprintText if needed to have at most maxNumPoints lines. noTime - if True and useAbsoluteTime True, then dates without times printed on x axis. noDate - if True and useAbsoluteTime True, then times without dates printed on x axis. yMinimum - set y minimum. If default=None, use data minimum yMaximum - set y maximum. If default=None, use data maximum timezone - The offset of the local (non-DST) timezone, in seconds west of UTC (negative in most of Western Europe, positive in the US, zero in the UK). Returns: void Affects: None """ self.__missing = 1.0E30 # special value, since numpy doesn't handle NaN self.__parameter_count = 1 + len(yParmList) self.__colorList = 'gbrcmykw' # a list of colors for the lines # verify input if size not in ('small', 'wide', 'large'): raise ValueError, 'size must be "small", "wide", or "large", not %s' % (str(size)) if size in ('small', 'wide'): fontSize = 12 elif size in ('large'): fontSize = 18 if maxNumPoints != None: isprintText = self.__truncateIsprint(isprintText, maxNumPoints) # convert the input data into numeric arrays of float assuming no headers and filter the missing values. try: split_data = isprintText.split() float_data = map(self.__filter_missing, split_data) array_data = numpy.asarray(float_data) array_data = numpy.reshape(array_data,(-1,self.__parameter_count)) threshold = self.__missing*0.9999 array_data = numpy.ma.masked_where(array_data > threshold, array_data) except: traceback.print_exc() raise ValueError, 'input text is not parseable' # find min, max of x (time) if startTime == None: xMin = array_data[0,0] else: xMin = startTime if endTime == None: xMax = array_data[-1,0] else: xMax = endTime # find yMin just to ensure there is data yMin = None for column in range(len(yParmList)): for y in array_data[:,1+column]: if y == self.__missing: continue if yMin == None: yMin = y elif yMin > y: yMin = y if yMin == None: raise ValueError, 'No valid y data found' # select the plot size if size == 'small': matplotlib.pylab.figure(1, figsize=(8,3), facecolor = 'w') elif size == 'wide': matplotlib.pylab.figure(1, figsize=(10,4), facecolor = 'w') elif size == 'large': matplotlib.pylab.figure(1, figsize=(12,6), facecolor = 'w') if useAbsoluteTime: # leave room for rotated datetime string if size == 'large': matplotlib.pylab.axes([0.1, 0.2, 0.8, 0.7]) elif size == 'wide': matplotlib.pylab.axes([0.07, 0.2, 0.9, 0.7]) elif size == 'small': matplotlib.pylab.axes([0.1, 0.18, 0.87, 0.7]) else: if size == 'large': matplotlib.pylab.axes([0.1, 0.15, 0.71, 0.73]) for column in range(len(yParmList)): color = self.__colorList[column % len(self.__colorList)] matplotlib.pylab.plot(array_data[:,0],array_data[:,1 + column], '%so-' % (color), ms=5, mew=0.5) thisFont = {'size': fontSize} matplotlib.pylab.rc('font', **thisFont) # pass in the font dict as kwargs matplotlib.pylab.xlabel(xLabelStr, fontsize=fontSize) matplotlib.pylab.ylabel(yLabelStr, fontsize=fontSize) matplotlib.pylab.yticks(fontsize=fontSize) matplotlib.pylab.xlim(xMin, xMax) matplotlib.pylab.grid(True) if useAbsoluteTime: # if plot is less than 24 hours, force ticks to be every 4 hours xmin, xmax = matplotlib.pylab.xlim() xmin = xmin / (60*60) xmax = xmax / (60*60) if noDate == True: if xmax % 4 != 0: newXmax = 4 * (int(xmax/4.0) + 1) else: newXmax = xmax newXLocs = [] newXLabels = [] step = int((xmax-xmin-1)/6)+1 xRange = range(0,int(newXmax-xmin),step) for i in xRange: tmp = (xmin + i)*60*60 newXLocs.append(tmp) if (xmax - xmin) < 1: newXLocs.append(xmax*60*60) newXLabels = convertToAbsoluteTimeStr(newXLocs, noDate=noDate, timezone=timezone) matplotlib.pylab.xticks(newXLocs, newXLabels) else: locs, labels = matplotlib.pylab.xticks() if len(locs) > 5: # truncate by len(locs) / 5 scale = 1 + int(len(locs) / 5) new_locs = [] for i in range(len(locs)): if i % scale == 0: new_locs.append(locs[i]) locs = new_locs newXTicks = convertToAbsoluteTimeStr(locs, noTime) matplotlib.pylab.xticks(locs, newXTicks, rotation=15) else: # if plot is less than 48 hours, force ticks to be every 4 hours xmin, xmax = matplotlib.pylab.xlim() if xmax < 49: if xmax % 4 != 0: newXmax = 4 * (int(xmax/4.0) + 1) else: newXmax = xmax newXLocs = [] newXLabels = [] for i in range(0,int(4+newXmax),4): newXLocs.append(i) newXLabels.append(str(i)) matplotlib.pylab.xticks(newXLocs, newXLabels) matplotlib.pylab.xticks(fontsize=fontSize) if yMinimum != None and yMaximum != None: matplotlib.pylab.ylim(yMinimum, yMaximum) elif yMinimum != None and yMaximum == None: matplotlib.pylab.ylim(yMin=yMinimum) elif yMinimum == None and yMaximum != None: matplotlib.pylab.ylim(yMax=yMaximum) matplotlib.pylab.title(titleStr, fontsize=fontSize) matplotlib.pylab.legend(yParmList, numpoints=1, handlelength=0.05) matplotlib.pylab.savefig(fullFilename) matplotlib.pylab.clf() def __truncateIsprint(self, isprintText, maxLines): """__truncateIsprint truncates isprintText to have maxLines at most. """ isprintList = isprintText.split('\n') if len(isprintList) < maxLines: return isprintText else: dropNumber = int(1 + len(isprintList)/maxLines) newline = '\n' newIsprintText = newline.join(isprintList[::dropNumber]) return newIsprintText def __filter_missing(self,x): try: return float(x) except: return self.__missing def writeToFile(self, fullFilename): pass def displayToScreen(self): pass def getFigureHandle(self): pass
Ancestors (in MRO)
Methods
def __init__(
self, isprintText, yParmList, titleStr, xLabelStr, yLabelStr, fullFilename, size='small', useAbsoluteTime=False, startTime=None, endTime=None, maxNumPoints=None, noTime=False, yMinimum=None, yMaximum=None, noDate=False, timezone=0)
init writes a madLineTimePlot plot to a file.
Inputs:
isprintText - a string giving isprint output without headers. First parameter must be UTH or UT1, depending on whether time scale should be relative to the experiment beginning (UTH) or absolute (UT1). The the following must be the parameters to be plotted. Any missing data should be written as "missing" or other string that cannot be converted to a float. yParmList - a list of y parameters (strings). Length must == num columns in isprintText - 1 titleStr - plot title (string) - should describe parameter being plotted xLabelStr - x label string yLabelStr - ylabel string fullFilename - full path of file containing pcolor plot to be saved. Extension must be jpeg or png, or exception thrown. size - size of plot to save. Must be "small", "wide", or "large". Defaults to small. useAbsoluteTime - if true, print time as YYYY-MM-DD HH:MM:SS. If false (default), print time as hour since beginning of experiment (UTH). If useAbsoluteTime is true, first parameter in isprintText must be UT1, if false, it must be UTH. startTime - start plot at given time. If useAbsoluteTime == True, then startTime must be in units of seconds since 1/1/1950. If useAbsoluteTime == False, then startTime must be in units of UTH (hours since midnight UT of first day of experiment). Default is None, which means start at lowest time found. endTime - end plot at given time. If useAbsoluteTime == True, then endTime must be in units of seconds since 1/1/1950. If useAbsoluteTime == False, then endTime must be in units of UTH (hours since midnight UT of first day of experiment). Default is None, which means end at largest time found. maxNumPoints - maximum number of points to plot. If not None, truncate isprintText if needed to have at most maxNumPoints lines. noTime - if True and useAbsoluteTime True, then dates without times printed on x axis. noDate - if True and useAbsoluteTime True, then times without dates printed on x axis. yMinimum - set y minimum. If default=None, use data minimum yMaximum - set y maximum. If default=None, use data maximum timezone - The offset of the local (non-DST) timezone, in seconds west of UTC (negative in most of Western Europe, positive in the US, zero in the UK).
Returns: void
Affects: None
def __init__(self, isprintText, yParmList, titleStr, xLabelStr, yLabelStr, fullFilename, size = 'small', useAbsoluteTime = False, startTime = None, endTime = None, maxNumPoints = None, noTime = False, yMinimum = None, yMaximum = None, noDate = False, timezone = 0): """__init__ writes a madLineTimePlot plot to a file. Inputs: isprintText - a string giving isprint output without headers. First parameter must be UTH or UT1, depending on whether time scale should be relative to the experiment beginning (UTH) or absolute (UT1). The the following must be the parameters to be plotted. Any missing data should be written as "missing" or other string that cannot be converted to a float. yParmList - a list of y parameters (strings). Length must == num columns in isprintText - 1 titleStr - plot title (string) - should describe parameter being plotted xLabelStr - x label string yLabelStr - ylabel string fullFilename - full path of file containing pcolor plot to be saved. Extension must be jpeg or png, or exception thrown. size - size of plot to save. Must be "small", "wide", or "large". Defaults to small. useAbsoluteTime - if true, print time as YYYY-MM-DD HH:MM:SS. If false (default), print time as hour since beginning of experiment (UTH). If useAbsoluteTime is true, first parameter in isprintText must be UT1, if false, it must be UTH. startTime - start plot at given time. If useAbsoluteTime == True, then startTime must be in units of seconds since 1/1/1950. If useAbsoluteTime == False, then startTime must be in units of UTH (hours since midnight UT of first day of experiment). Default is None, which means start at lowest time found. endTime - end plot at given time. If useAbsoluteTime == True, then endTime must be in units of seconds since 1/1/1950. If useAbsoluteTime == False, then endTime must be in units of UTH (hours since midnight UT of first day of experiment). Default is None, which means end at largest time found. maxNumPoints - maximum number of points to plot. If not None, truncate isprintText if needed to have at most maxNumPoints lines. noTime - if True and useAbsoluteTime True, then dates without times printed on x axis. noDate - if True and useAbsoluteTime True, then times without dates printed on x axis. yMinimum - set y minimum. If default=None, use data minimum yMaximum - set y maximum. If default=None, use data maximum timezone - The offset of the local (non-DST) timezone, in seconds west of UTC (negative in most of Western Europe, positive in the US, zero in the UK). Returns: void Affects: None """ self.__missing = 1.0E30 # special value, since numpy doesn't handle NaN self.__parameter_count = 1 + len(yParmList) self.__colorList = 'gbrcmykw' # a list of colors for the lines # verify input if size not in ('small', 'wide', 'large'): raise ValueError, 'size must be "small", "wide", or "large", not %s' % (str(size)) if size in ('small', 'wide'): fontSize = 12 elif size in ('large'): fontSize = 18 if maxNumPoints != None: isprintText = self.__truncateIsprint(isprintText, maxNumPoints) # convert the input data into numeric arrays of float assuming no headers and filter the missing values. try: split_data = isprintText.split() float_data = map(self.__filter_missing, split_data) array_data = numpy.asarray(float_data) array_data = numpy.reshape(array_data,(-1,self.__parameter_count)) threshold = self.__missing*0.9999 array_data = numpy.ma.masked_where(array_data > threshold, array_data) except: traceback.print_exc() raise ValueError, 'input text is not parseable' # find min, max of x (time) if startTime == None: xMin = array_data[0,0] else: xMin = startTime if endTime == None: xMax = array_data[-1,0] else: xMax = endTime # find yMin just to ensure there is data yMin = None for column in range(len(yParmList)): for y in array_data[:,1+column]: if y == self.__missing: continue if yMin == None: yMin = y elif yMin > y: yMin = y if yMin == None: raise ValueError, 'No valid y data found' # select the plot size if size == 'small': matplotlib.pylab.figure(1, figsize=(8,3), facecolor = 'w') elif size == 'wide': matplotlib.pylab.figure(1, figsize=(10,4), facecolor = 'w') elif size == 'large': matplotlib.pylab.figure(1, figsize=(12,6), facecolor = 'w') if useAbsoluteTime: # leave room for rotated datetime string if size == 'large': matplotlib.pylab.axes([0.1, 0.2, 0.8, 0.7]) elif size == 'wide': matplotlib.pylab.axes([0.07, 0.2, 0.9, 0.7]) elif size == 'small': matplotlib.pylab.axes([0.1, 0.18, 0.87, 0.7]) else: if size == 'large': matplotlib.pylab.axes([0.1, 0.15, 0.71, 0.73]) for column in range(len(yParmList)): color = self.__colorList[column % len(self.__colorList)] matplotlib.pylab.plot(array_data[:,0],array_data[:,1 + column], '%so-' % (color), ms=5, mew=0.5) thisFont = {'size': fontSize} matplotlib.pylab.rc('font', **thisFont) # pass in the font dict as kwargs matplotlib.pylab.xlabel(xLabelStr, fontsize=fontSize) matplotlib.pylab.ylabel(yLabelStr, fontsize=fontSize) matplotlib.pylab.yticks(fontsize=fontSize) matplotlib.pylab.xlim(xMin, xMax) matplotlib.pylab.grid(True) if useAbsoluteTime: # if plot is less than 24 hours, force ticks to be every 4 hours xmin, xmax = matplotlib.pylab.xlim() xmin = xmin / (60*60) xmax = xmax / (60*60) if noDate == True: if xmax % 4 != 0: newXmax = 4 * (int(xmax/4.0) + 1) else: newXmax = xmax newXLocs = [] newXLabels = [] step = int((xmax-xmin-1)/6)+1 xRange = range(0,int(newXmax-xmin),step) for i in xRange: tmp = (xmin + i)*60*60 newXLocs.append(tmp) if (xmax - xmin) < 1: newXLocs.append(xmax*60*60) newXLabels = convertToAbsoluteTimeStr(newXLocs, noDate=noDate, timezone=timezone) matplotlib.pylab.xticks(newXLocs, newXLabels) else: locs, labels = matplotlib.pylab.xticks() if len(locs) > 5: # truncate by len(locs) / 5 scale = 1 + int(len(locs) / 5) new_locs = [] for i in range(len(locs)): if i % scale == 0: new_locs.append(locs[i]) locs = new_locs newXTicks = convertToAbsoluteTimeStr(locs, noTime) matplotlib.pylab.xticks(locs, newXTicks, rotation=15) else: # if plot is less than 48 hours, force ticks to be every 4 hours xmin, xmax = matplotlib.pylab.xlim() if xmax < 49: if xmax % 4 != 0: newXmax = 4 * (int(xmax/4.0) + 1) else: newXmax = xmax newXLocs = [] newXLabels = [] for i in range(0,int(4+newXmax),4): newXLocs.append(i) newXLabels.append(str(i)) matplotlib.pylab.xticks(newXLocs, newXLabels) matplotlib.pylab.xticks(fontsize=fontSize) if yMinimum != None and yMaximum != None: matplotlib.pylab.ylim(yMinimum, yMaximum) elif yMinimum != None and yMaximum == None: matplotlib.pylab.ylim(yMin=yMinimum) elif yMinimum == None and yMaximum != None: matplotlib.pylab.ylim(yMax=yMaximum) matplotlib.pylab.title(titleStr, fontsize=fontSize) matplotlib.pylab.legend(yParmList, numpoints=1, handlelength=0.05) matplotlib.pylab.savefig(fullFilename) matplotlib.pylab.clf()
def displayToScreen(
self)
def displayToScreen(self): pass
def getFigureHandle(
self)
def getFigureHandle(self): pass
def writeToFile(
self, fullFilename)
def writeToFile(self, fullFilename): pass
class madPcolorPlot
madPcolorPlot is the class that produces pcolor plots of x versus y with z intensity.
Assumes the x axis is time.
Usage example::
obj = madPcolorPlot(isprintText, 'Nel (log(m^-3)) - Millstone Hill - Oct. 30, 2003 - Alt code', 'Hours since midnight UT Oct. 30, 2003', 'Altitude (km)', './isprint.png', size = 'large', minColormap = 9, maxColormap = 12, smoothAltitude = False)
Non-standard Python modules used: matplotlib
Change history:
Written by "Bill Rideout":mailto:wrideout@haystack.mit.edu Mar. 31, 2005
class madPcolorPlot: """madPcolorPlot is the class that produces pcolor plots of x versus y with z intensity. Assumes the x axis is time. Usage example:: obj = madPcolorPlot(isprintText, 'Nel (log(m^-3)) - Millstone Hill - Oct. 30, 2003 - Alt code', 'Hours since midnight UT Oct. 30, 2003', 'Altitude (km)', './isprint.png', size = 'large', minColormap = 9, maxColormap = 12, smoothAltitude = False) Non-standard Python modules used: matplotlib Change history: Written by "Bill Rideout":mailto:wrideout@haystack.mit.edu Mar. 31, 2005 """ def __init__(self, isprintText, titleStr, xLabelStr, yLabelStr, fullFilename, size = 'small', minColormap = None, maxColormap = None, smoothAltitude = True, insertDataGap = 5, useAbsoluteTime = False, startTime = None, endTime = None, sortTimeFlag = False, maxNumTimes = None, maxNumAlt = None, truncateIsprint = False, colorMap = matplotlib.cm.jet, yMinimum = None, yMaximum = None, altYTitle = None, altYLabels = None, noTime = False, noDate = False, timezone = 0, background = 'w', peakAltStr = None): """__init__ writes a madPColorPlot to a file. Inputs: isprintText - a string giving isprint output without headers. First parameter must be UTH or UT1, depending on whether time scale should be relative to the experiment beginning (UTH) or absolute (UT1). The second must be gdalt, and third parameter to be plotted. Any missing data should be written as "missing" or other string that cannot be converted to a float. titleStr - plot title (string) - should describe parameter being plotted xLabelStr - x label string yLabelStr - ylabel string fullFilename - full path of file containing pcolor plot to be saved. Extension must be jpeg or png, or exception thrown. size - size of plot to save. Must be "small", "wide", or "large". Defaults to small. minColormap - minimum parameter value (defaults to lowest parameter value) maxColormap - maximum parameter value (defaults to highest parameter value). However, if both minColormap and maxColormap == None, autoscaling applied. smoothAltitude - if True, extrapolate between existing data between altitudes to fill in missing data; if False, leave missing insertDataGap - this parameter sets the threshold for inserting a data gap. The time intervals being plotted are ordered, and the time gap larger than 90% of the rest is determined. Any time interval more than insertDataGap times bigger is then considered missing data. Defaults to five. If None, no gaps are ever inserted. For data with close to uniform time intervals, no gaps will be inserted. useAbsoluteTime - if true, print time as YYYY-MM-DD HH:MM:SS. If false (default), print time as hour since beginning of experiment (UTH). If useAbsoluteTime is true, first parameter in isprintText must be UT1, if false, it must be UTH. startTime - start plot at given time. If useAbsoluteTime == True, then startTime must be in units of seconds since 1/1/1950. If useAbsoluteTime == False, then startTime must be in units of UTH (hours since midnight UT of first day of experiment). Default is None, which means start at lowest time found. endTime - end plot at given time. If useAbsoluteTime == True, then endTime must be in units of seconds since 1/1/1950. If useAbsoluteTime == False, then endTime must be in units of UTH (hours since midnight UT of first day of experiment). Default is None, which means end at largest time found. sortTimeFlag - if true, check that time is correctly sorted. If false (the default), assume time already sorted maxNumTimes - if not None, decimate the number of times in the isprint string to maxNumTimes. If None (the default), plot all times. maxNumAlt - if not None, reduce the number of altitudes to maxNumAlt. If None (the default), plot all altitudes. truncateIsprint - if True, and both maxNumTimes and maxNumAlt not = None, then truncate the number of isprint lines to be maxNumTimes * maxNumAlt colorMap - sets colormap. It not given, defaults to matplotlib.cm.jet yMinimum - minumum y value. If None (default), set by data y minimum. yMaximum - maximum y value. If None (default), set by data y maximum. altYTitle - title of right (second) y axis. If None (the default), no Y axis on the right side. altYLabels - a list of Y labels (strings) for the right axis. If None (the default), no Y labels on the right axis. noDate - if True and useAbsoluteTime True, then times without dates printed on x axis. timezone - The offset of the local (non-DST) timezone, in seconds west of UTC (negative in most of Western Europe, positive in the US, zero in the UK). peakAltStr - if not None (the default), plot the peak altitude with x. Format is a str with each line (time in same format as data, peak altitude) Returns: void Affects: None """ self.__missing = 1.0E30 # special value, used to create a masked array self.__parameter_count = 3 # verify input if size not in ('small', 'wide', 'large'): raise ValueError, 'size must be "small", "wide", or "large", not %s' % (str(size)) if size in ('small'): fontSize = 10 elif size in ('wide'): fontSize = 12 elif size in ('large'): fontSize = 18 if truncateIsprint and maxNumTimes != None and maxNumAlt != None: isprintText = self.__truncateIsprint(isprintText, maxNumTimes * maxNumAlt) # since matplotlib pcolor wants a regular grid, we create a grid with all altitudes # convert the input data into numeric arrays of float assuming no headers and filter the missing values. try: split_data = isprintText.split() float_data = map(self.__filter_missing, split_data) array_data = numpy.asarray(float_data) array_data = numpy.reshape(array_data,(-1,self.__parameter_count)) except: traceback.print_exc() raise ValueError, 'input text is not parseable' if sortTimeFlag: array_data = self.sortArrayInTime(array_data) if maxNumTimes != None and maxNumTimes != 0 and not truncateIsprint: array_data = self.decimateTimes(array_data, int(maxNumTimes), insertDataGap) # The first pass through is to obtain the number and range of the x and y variables xList = [] yList = [] zList = [] zMin = None zMax = None # loop over all the lines of data in the array for j in range(len(array_data)): try: x = array_data[j][0] y = array_data[j][1] z = array_data[j][2] if x not in xList: xList.append(x) if y not in yList: yList.append(y) if z != self.__missing: zList.append(z) if zMin != None: if z < zMin and z != self.__missing: zMin = z elif z != self.__missing: zMin = z if zMax != None: if z > zMax and z != self.__missing: zMax = z elif z != self.__missing: zMax = z except: continue if zMin == None: raise ValueError, 'No valid z data found' # if both minColormap and maxColormap == None, use autoscaling if minColormap == None and maxColormap == None: zList.sort() d10 = zList[int(len(zList)*0.10)] d90 = zList[int(len(zList)*0.90)] zMin = d10 - (d90-d10) * 0.75 zMax = d90 + (d90-d10) * 0.75 # now sort the X and Y axis lists and pull their length xList.sort() if startTime == None: xMin = xList[0] else: xMin = startTime if endTime == None: xMax = xList[-1] else: xMax = endTime yList.sort() max_x_dimension = len(xList) max_y_dimension = len(yList) if yMinimum == None: yMinimum = yList[0] if yMaximum == None: yMaximum = yList[-1] self.truncateAlt = False if maxNumAlt != None: if max_y_dimension > maxNumAlt: self.truncateAlt = True # build dictonary of indexes into xList self.xListDict = {} for i in range(len(xList)): self.xListDict[xList[i]] = i # if self.truncateAlt == False, build dictonary of indexes into yList, # else truncate y values by builing a list of maxNumAlt ranges if self.truncateAlt == False: self.yListDict = {} for i in range(len(yList)): self.yListDict[yList[i]] = i else: self.yListRanges = [] for i in range(maxNumAlt): self.yListRanges.append(yList[int(i*(len(yList)/maxNumAlt))]) max_y_dimension = maxNumAlt # now build arrays to handle the X axis label, Y axis label, and the Z data X = numpy.zeros((max_x_dimension, max_y_dimension), numpy.float32) Y = numpy.zeros((max_x_dimension, max_y_dimension), numpy.float32) Z = numpy.ones((max_x_dimension, max_y_dimension), numpy.float32) # all parameter values default to missing Z = Z * self.__missing # fill the X and Y arrays for i in range(max_x_dimension): for j in range(max_y_dimension): X[i][j] = float(xList[i]) if self.truncateAlt: Y[i][j] = float(yList[int(j*(len(yList)/maxNumAlt))]) else: Y[i][j] = float(yList[j]) # Now load up the data array Z with the array_data measurements as a function of x and y previousIndex = None previousValue = None presentTime = None newTimeFound = True for k in range(len(array_data)): try: xdata = array_data[k][0] ydata = array_data[k][1] zdata = array_data[k][2] if zdata == self.__missing: continue if xdata != presentTime: newTimeFound = True else: newTimeFound = False presentTime = xdata # now find the right place in the array for this data point i = self.xListDict[xdata] j = self.__getYIndex(ydata) Z[i][j] = zdata # now see if we need to fill in any gaps if (not newTimeFound) and smoothAltitude: if previousIndex < j - 1: # fill in all missing points for l in range(previousIndex + 1, j): # simply average between the points based on index thisValue = previousValue + (zdata - previousValue)*(float(l-previousIndex)/float(j-previousIndex)) Z[i][l] = thisValue previousIndex = j previousValue = zdata except: continue # insert missing data to represent gaps if needed if insertDataGap != None: # first find the time interval greater than 90% of others timeIntervalList = [] for i in range(len(xList) - 1): timeIntervalList.append(xList[i+1] - xList[i]) timeIntervalList.sort() index = int(len(timeIntervalList)*0.9) maxInterval = timeIntervalList[index] for i in range(len(xList) - 1): if xList[i+1] - xList[i] > maxInterval * insertDataGap: Z[i,:] = self.__missing # insert missing data to represent gaps if needed in Altitude if insertDataGap != None and not smoothAltitude: # first find the time interval greater than 90% of others altitudeIntervalList = [] for i in range(len(yList) - 1): altitudeIntervalList.append(yList[i+1] - yList[i]) altitudeIntervalList.sort() index = int(len(altitudeIntervalList)*0.9) maxInterval = altitudeIntervalList[index] for j in range(len(yList) - 1): if yList[j+1] - yList[j] > maxInterval * insertDataGap and j < max_y_dimension: Z[:,j] = self.__missing # make Z a masked array Znew = numpy.ma.masked_inside(Z, 0.99*self.__missing, 1.01*self.__missing) # set up plotting parameters if minColormap == None: minColormap = zMin if maxColormap == None: maxColormap = zMax # select the plot size if size == 'small': matplotlib.pylab.figure(1, figsize=(8,3), facecolor = 'w') elif size == 'wide': matplotlib.pylab.figure(1, figsize=(10,4), facecolor = 'w') elif size == 'large': matplotlib.pylab.figure(1, figsize=(14,5), facecolor = 'w') if useAbsoluteTime: # leave room for rotated datetime string if size == 'large': matplotlib.pylab.axes([0.1, 0.1, 0.85, 0.7]) elif size == 'wide': matplotlib.pylab.axes([0.07, 0.2, 0.97, 0.7]) elif size == 'small': matplotlib.pylab.axes([0.1, 0.18, 0.97, 0.7]) else: if size == 'small': matplotlib.pylab.axes([0.1, 0.18, 0.97, 0.7]) elif size == 'large': matplotlib.pylab.axes([0.1, 0.2, 0.9, 0.73]) matplotlib.pylab.pcolor(X,Y,Znew, edgecolors='none', vmin=minColormap, vmax=maxColormap, cmap = colorMap, norm = matplotlib.pylab.Normalize(), edgecolor='face') matplotlib.pylab.colorbar() thisFont = {'size': fontSize} matplotlib.pylab.rc('font', **thisFont) # pass in the font dict as kwargs matplotlib.pylab.xlabel(xLabelStr, fontsize=fontSize) matplotlib.pylab.ylabel(yLabelStr, fontsize=fontSize) matplotlib.pylab.xlim(xMin, xMax) matplotlib.pylab.ylim(yMinimum, yMaximum) matplotlib.pylab.yticks(fontsize=fontSize) matplotlib.pylab.title(titleStr, fontsize=fontSize) if useAbsoluteTime: # if plot is less than 49 hours xmin, xmax = matplotlib.pylab.xlim() xmin = numpy.floor(xmin / (60*60)) xmax = numpy.ceil(xmax / (60*60)) if noDate == True: newXLabels = [] if (xmax - xmin) <= 1: newXLocs = [] xRange = numpy.arange(0,1,0.25) for i in xRange: tmp=(xmin+i)*60*60 newXLocs.append(tmp) elif (xmax - xmin) <= 2: newXLocs = [] xRange = numpy.arange(0,2,0.5) for i in xRange: tmp=(xmin+i)*60*60 newXLocs.append(tmp) else: newXLocs = [] step = int((xmax-xmin-1)/6)+1 xRange = range(0,int(xmax-xmin),step) for i in xRange: tmp = (xmin + i)*60*60 newXLocs.append(tmp) #newXLocs.append(xmax*60*60) newXLabels = convertToAbsoluteTimeStr(newXLocs, noDate=noDate, timezone=timezone) matplotlib.pylab.xticks(newXLocs, newXLabels) else: locs, labels = matplotlib.pylab.xticks() if len(locs) > 5: # truncate by len(locs) / 5 scale = 1 + int(len(locs) / 5) new_locs = [] for i in range(len(locs)): if i % scale == 0: new_locs.append(locs[i]) locs = new_locs newXTicks = convertToAbsoluteTimeStr(locs) matplotlib.pylab.xticks(locs, newXTicks, rotation=15) else: # if plot is less than 48 hours, force ticks to be every 4 hours xmin, xmax = matplotlib.pylab.xlim() if xmax < 49: if xmax % 4 != 0: newXmax = 4 * (int(xmax/4.0) + 1) else: newXmax = xmax newXLocs = [] newXLabels = [] for i in range(0,int(4+newXmax),4): newXLocs.append(i) newXLabels.append(str(i)) matplotlib.pylab.xticks(newXLocs, newXLabels) matplotlib.pylab.xticks(fontsize=fontSize) # add second y-axis if desired if altYTitle != None and altYLabels != None: ax2 = matplotlib.pylab.twinx() matplotlib.pylab.ylabel(altYTitle) ax2.yaxis.tick_right() matplotlib.pylab.yticks(range(len(altYLabels)), altYLabels) matplotlib.pylab.yticks(fontsize=fontSize) # get the handle to the figure now that it has been created so we can manipulate on subsequent calls. #self.__figure = matplotlib.pylab.gcf() if peakAltStr: # plot peak altitudes data = peakAltStr.split() xdata = [float(item) for i, item in enumerate(data) if i % 2 == 0] ydata = [float(item) for i, item in enumerate(data) if i % 2 == 1] matplotlib.pylab.plot(xdata, ydata, 'b+') matplotlib.pylab.savefig(fullFilename) #matplotlib.pylab.show() matplotlib.pylab.clf() def __filter_missing(self,x): try: return float(x) except: return self.__missing def __getYIndex(self, yvalue): """__getYIndex returns the correct index into the y dimension for a given y value. Input: yvalue - value of y parameter Returns: the correct index into the y dimension Algorithm: if self.truncateAlt == False, simple use the dictionary self.yListDict. Else loop through self.yListRanges and return the first greater than the requested value """ if self.truncateAlt == False: return self.yListDict[yvalue] else: i = bisect.bisect_left(self.yListRanges, yvalue) if i >= len(self.yListRanges): i = len(self.yListRanges) - 1 return i def __truncateIsprint(self, isprintText, maxLines): """__truncateIsprint truncates isprintText to have maxLines at most. """ isprintList = isprintText.split('\n') if len(isprintList) < maxLines: return isprintText else: dropNumber = int(1 + len(isprintList)/maxLines) newIsprintText = '' for i in range(0,len(isprintList),dropNumber): newIsprintText += isprintList[i] + '\n' return newIsprintText def displayToScreen(self): " to implement this takes a reworking away from pylab to use the underlying matplotlib code " pass def getFigureHandle(self): return self.__figure def getAverage(self, X): """returns the average of items in a float array. Does not including missing data. If all data missing, returns self.__missing """ count = 0 total = 0.0 for i in range(X.shape[0]): if X[i] != self.__missing: count += 1 total += X[i] if count == 0: return self.__missing else: return total / float(count) def sortArrayInTime(self, array_data): """sortArrayInTime sorts a two-dimensional array so that the first element in each row (time) is in ascending order. Input: array_data - two-dimensional array to be sorted by rearranging rows so that the first element in each row (time) is in ascending order Returns: new_array """ sortIndex = numpy.argsort(array_data[:,0])[0] # if already sorted, just return original array if sortIndex == numpy.sort(sortIndex): return array_data new_array = numpy.zeros(array_data.shape, array_data.dtype) for i in range(len(sortIndex)): new_array[sortIndex[i],:] = array_data[i,:] return new_array def decimateTimes(self, array_data, maxNumTimes, insertDataGap): """decimateTimes decimates array_data to have at most maxNumTimes times. Input: array_data - two-dimensional array to be decimated by deleting times and missing data. maxNumTimes: int representing the maximum number of times to keep in array_data insertDataGap - this parameter sets the threshold for inserting a data gap. The time intervals being plotted are ordered, and the time gap larger than 90% of the rest is determined. Note that this parameter is used here to stop the truncation of isprint lines that will eventually be considered edge lines. Returns: new array built from decimated array_data """ # get the number of times in array_data, and make a list of all unique times numTimes = 0 uniqueTimes = [] time_array = array_data[:, 0] for i in range(len(time_array)): if i == 0: numTimes = 1 uniqueTimes.append(time_array[i]) elif time_array[i-1] != time_array[i]: uniqueTimes.append(time_array[i]) numTimes += 1 if numTimes <= maxNumTimes: return array_data # insert missing data to represent gaps if needed gapTimes = [] if insertDataGap != None: # first find the time interval greater than 90% of others timeIntervalList = [] for i in range(len(time_array) - 1): if time_array[i+1] == time_array[i]: continue timeIntervalList.append(time_array[i+1] - time_array[i]) timeIntervalList.sort() index = int(len(timeIntervalList)*0.9) maxInterval = timeIntervalList[index] for i in range(len(time_array) - 1): if time_array[i+1] - time_array[i] > maxInterval * insertDataGap: gapTimes.append(time_array[i+1]) gapTimes.append(time_array[i]) # get the number of times to skip each time numSkip = numTimes/maxNumTimes # get the number of rows in the new_array numRows = 0 numTimes = 0 useThisTime = False for i in range(len(time_array)): if i == 0: numTimes = 1 elif time_array[i-1] != time_array[i]: numTimes += 1 if numTimes % (numSkip + 1) == 0 or time_array[i] in gapTimes: useThisTime = True if array_data[i, -1] != self.__missing: numRows += 1 else: useThisTime = False else: if useThisTime: if array_data[i, -1] != self.__missing: numRows += 1 # create new_array new_array = numpy.zeros((numRows, array_data.shape[1]), array_data.dtype) # copy selected rows to new_array numRows = 0 numTimes = 0 useThisTime = False for i in range(len(time_array)): if i == 0: numTimes = 1 elif time_array[i-1] != time_array[i]: numTimes += 1 if numTimes % (numSkip + 1) == 0 or time_array[i] in gapTimes: useThisTime = True if array_data[i, -1] != self.__missing: new_array[numRows,:] = array_data[i,:] numRows += 1 else: useThisTime = False else: if useThisTime: if array_data[i, -1] != self.__missing: new_array[numRows,:] = array_data[i,:] numRows += 1 return new_array
Ancestors (in MRO)
Instance variables
var truncateAlt
var xListDict
Methods
def __init__(
self, isprintText, titleStr, xLabelStr, yLabelStr, fullFilename, size='small', minColormap=None, maxColormap=None, smoothAltitude=True, insertDataGap=5, useAbsoluteTime=False, startTime=None, endTime=None, sortTimeFlag=False, maxNumTimes=None, maxNumAlt=None, truncateIsprint=False, colorMap=<matplotlib.colors.LinearSegmentedColormap object at 0x10afdbb90>, yMinimum=None, yMaximum=None, altYTitle=None, altYLabels=None, noTime=False, noDate=False, timezone=0, background='w', peakAltStr=None)
init writes a madPColorPlot to a file.
Inputs:
isprintText - a string giving isprint output without headers. First parameter must be UTH or UT1, depending on whether time scale should be relative to the experiment beginning (UTH) or absolute (UT1). The second must be gdalt, and third parameter to be plotted. Any missing data should be written as "missing" or other string that cannot be converted to a float. titleStr - plot title (string) - should describe parameter being plotted xLabelStr - x label string yLabelStr - ylabel string fullFilename - full path of file containing pcolor plot to be saved. Extension must be jpeg or png, or exception thrown. size - size of plot to save. Must be "small", "wide", or "large". Defaults to small. minColormap - minimum parameter value (defaults to lowest parameter value) maxColormap - maximum parameter value (defaults to highest parameter value). However, if both minColormap and maxColormap == None, autoscaling applied. smoothAltitude - if True, extrapolate between existing data between altitudes to fill in missing data; if False, leave missing insertDataGap - this parameter sets the threshold for inserting a data gap. The time intervals being plotted are ordered, and the time gap larger than 90% of the rest is determined. Any time interval more than insertDataGap times bigger is then considered missing data. Defaults to five. If None, no gaps are ever inserted. For data with close to uniform time intervals, no gaps will be inserted. useAbsoluteTime - if true, print time as YYYY-MM-DD HH:MM:SS. If false (default), print time as hour since beginning of experiment (UTH). If useAbsoluteTime is true, first parameter in isprintText must be UT1, if false, it must be UTH. startTime - start plot at given time. If useAbsoluteTime == True, then startTime must be in units of seconds since 1/1/1950. If useAbsoluteTime == False, then startTime must be in units of UTH (hours since midnight UT of first day of experiment). Default is None, which means start at lowest time found. endTime - end plot at given time. If useAbsoluteTime == True, then endTime must be in units of seconds since 1/1/1950. If useAbsoluteTime == False, then endTime must be in units of UTH (hours since midnight UT of first day of experiment). Default is None, which means end at largest time found. sortTimeFlag - if true, check that time is correctly sorted. If false (the default), assume time already sorted maxNumTimes - if not None, decimate the number of times in the isprint string to maxNumTimes. If None (the default), plot all times. maxNumAlt - if not None, reduce the number of altitudes to maxNumAlt. If None (the default), plot all altitudes. truncateIsprint - if True, and both maxNumTimes and maxNumAlt not = None, then truncate the number of isprint lines to be maxNumTimes * maxNumAlt colorMap - sets colormap. It not given, defaults to matplotlib.cm.jet yMinimum - minumum y value. If None (default), set by data y minimum. yMaximum - maximum y value. If None (default), set by data y maximum. altYTitle - title of right (second) y axis. If None (the default), no Y axis on the right side. altYLabels - a list of Y labels (strings) for the right axis. If None (the default), no Y labels on the right axis. noDate - if True and useAbsoluteTime True, then times without dates printed on x axis. timezone - The offset of the local (non-DST) timezone, in seconds west of UTC (negative in most of Western Europe, positive in the US, zero in the UK). peakAltStr - if not None (the default), plot the peak altitude with x. Format is a str with each line (time in same format as data, peak altitude)
Returns: void
Affects: None
def __init__(self, isprintText, titleStr, xLabelStr, yLabelStr, fullFilename, size = 'small', minColormap = None, maxColormap = None, smoothAltitude = True, insertDataGap = 5, useAbsoluteTime = False, startTime = None, endTime = None, sortTimeFlag = False, maxNumTimes = None, maxNumAlt = None, truncateIsprint = False, colorMap = matplotlib.cm.jet, yMinimum = None, yMaximum = None, altYTitle = None, altYLabels = None, noTime = False, noDate = False, timezone = 0, background = 'w', peakAltStr = None): """__init__ writes a madPColorPlot to a file. Inputs: isprintText - a string giving isprint output without headers. First parameter must be UTH or UT1, depending on whether time scale should be relative to the experiment beginning (UTH) or absolute (UT1). The second must be gdalt, and third parameter to be plotted. Any missing data should be written as "missing" or other string that cannot be converted to a float. titleStr - plot title (string) - should describe parameter being plotted xLabelStr - x label string yLabelStr - ylabel string fullFilename - full path of file containing pcolor plot to be saved. Extension must be jpeg or png, or exception thrown. size - size of plot to save. Must be "small", "wide", or "large". Defaults to small. minColormap - minimum parameter value (defaults to lowest parameter value) maxColormap - maximum parameter value (defaults to highest parameter value). However, if both minColormap and maxColormap == None, autoscaling applied. smoothAltitude - if True, extrapolate between existing data between altitudes to fill in missing data; if False, leave missing insertDataGap - this parameter sets the threshold for inserting a data gap. The time intervals being plotted are ordered, and the time gap larger than 90% of the rest is determined. Any time interval more than insertDataGap times bigger is then considered missing data. Defaults to five. If None, no gaps are ever inserted. For data with close to uniform time intervals, no gaps will be inserted. useAbsoluteTime - if true, print time as YYYY-MM-DD HH:MM:SS. If false (default), print time as hour since beginning of experiment (UTH). If useAbsoluteTime is true, first parameter in isprintText must be UT1, if false, it must be UTH. startTime - start plot at given time. If useAbsoluteTime == True, then startTime must be in units of seconds since 1/1/1950. If useAbsoluteTime == False, then startTime must be in units of UTH (hours since midnight UT of first day of experiment). Default is None, which means start at lowest time found. endTime - end plot at given time. If useAbsoluteTime == True, then endTime must be in units of seconds since 1/1/1950. If useAbsoluteTime == False, then endTime must be in units of UTH (hours since midnight UT of first day of experiment). Default is None, which means end at largest time found. sortTimeFlag - if true, check that time is correctly sorted. If false (the default), assume time already sorted maxNumTimes - if not None, decimate the number of times in the isprint string to maxNumTimes. If None (the default), plot all times. maxNumAlt - if not None, reduce the number of altitudes to maxNumAlt. If None (the default), plot all altitudes. truncateIsprint - if True, and both maxNumTimes and maxNumAlt not = None, then truncate the number of isprint lines to be maxNumTimes * maxNumAlt colorMap - sets colormap. It not given, defaults to matplotlib.cm.jet yMinimum - minumum y value. If None (default), set by data y minimum. yMaximum - maximum y value. If None (default), set by data y maximum. altYTitle - title of right (second) y axis. If None (the default), no Y axis on the right side. altYLabels - a list of Y labels (strings) for the right axis. If None (the default), no Y labels on the right axis. noDate - if True and useAbsoluteTime True, then times without dates printed on x axis. timezone - The offset of the local (non-DST) timezone, in seconds west of UTC (negative in most of Western Europe, positive in the US, zero in the UK). peakAltStr - if not None (the default), plot the peak altitude with x. Format is a str with each line (time in same format as data, peak altitude) Returns: void Affects: None """ self.__missing = 1.0E30 # special value, used to create a masked array self.__parameter_count = 3 # verify input if size not in ('small', 'wide', 'large'): raise ValueError, 'size must be "small", "wide", or "large", not %s' % (str(size)) if size in ('small'): fontSize = 10 elif size in ('wide'): fontSize = 12 elif size in ('large'): fontSize = 18 if truncateIsprint and maxNumTimes != None and maxNumAlt != None: isprintText = self.__truncateIsprint(isprintText, maxNumTimes * maxNumAlt) # since matplotlib pcolor wants a regular grid, we create a grid with all altitudes # convert the input data into numeric arrays of float assuming no headers and filter the missing values. try: split_data = isprintText.split() float_data = map(self.__filter_missing, split_data) array_data = numpy.asarray(float_data) array_data = numpy.reshape(array_data,(-1,self.__parameter_count)) except: traceback.print_exc() raise ValueError, 'input text is not parseable' if sortTimeFlag: array_data = self.sortArrayInTime(array_data) if maxNumTimes != None and maxNumTimes != 0 and not truncateIsprint: array_data = self.decimateTimes(array_data, int(maxNumTimes), insertDataGap) # The first pass through is to obtain the number and range of the x and y variables xList = [] yList = [] zList = [] zMin = None zMax = None # loop over all the lines of data in the array for j in range(len(array_data)): try: x = array_data[j][0] y = array_data[j][1] z = array_data[j][2] if x not in xList: xList.append(x) if y not in yList: yList.append(y) if z != self.__missing: zList.append(z) if zMin != None: if z < zMin and z != self.__missing: zMin = z elif z != self.__missing: zMin = z if zMax != None: if z > zMax and z != self.__missing: zMax = z elif z != self.__missing: zMax = z except: continue if zMin == None: raise ValueError, 'No valid z data found' # if both minColormap and maxColormap == None, use autoscaling if minColormap == None and maxColormap == None: zList.sort() d10 = zList[int(len(zList)*0.10)] d90 = zList[int(len(zList)*0.90)] zMin = d10 - (d90-d10) * 0.75 zMax = d90 + (d90-d10) * 0.75 # now sort the X and Y axis lists and pull their length xList.sort() if startTime == None: xMin = xList[0] else: xMin = startTime if endTime == None: xMax = xList[-1] else: xMax = endTime yList.sort() max_x_dimension = len(xList) max_y_dimension = len(yList) if yMinimum == None: yMinimum = yList[0] if yMaximum == None: yMaximum = yList[-1] self.truncateAlt = False if maxNumAlt != None: if max_y_dimension > maxNumAlt: self.truncateAlt = True # build dictonary of indexes into xList self.xListDict = {} for i in range(len(xList)): self.xListDict[xList[i]] = i # if self.truncateAlt == False, build dictonary of indexes into yList, # else truncate y values by builing a list of maxNumAlt ranges if self.truncateAlt == False: self.yListDict = {} for i in range(len(yList)): self.yListDict[yList[i]] = i else: self.yListRanges = [] for i in range(maxNumAlt): self.yListRanges.append(yList[int(i*(len(yList)/maxNumAlt))]) max_y_dimension = maxNumAlt # now build arrays to handle the X axis label, Y axis label, and the Z data X = numpy.zeros((max_x_dimension, max_y_dimension), numpy.float32) Y = numpy.zeros((max_x_dimension, max_y_dimension), numpy.float32) Z = numpy.ones((max_x_dimension, max_y_dimension), numpy.float32) # all parameter values default to missing Z = Z * self.__missing # fill the X and Y arrays for i in range(max_x_dimension): for j in range(max_y_dimension): X[i][j] = float(xList[i]) if self.truncateAlt: Y[i][j] = float(yList[int(j*(len(yList)/maxNumAlt))]) else: Y[i][j] = float(yList[j]) # Now load up the data array Z with the array_data measurements as a function of x and y previousIndex = None previousValue = None presentTime = None newTimeFound = True for k in range(len(array_data)): try: xdata = array_data[k][0] ydata = array_data[k][1] zdata = array_data[k][2] if zdata == self.__missing: continue if xdata != presentTime: newTimeFound = True else: newTimeFound = False presentTime = xdata # now find the right place in the array for this data point i = self.xListDict[xdata] j = self.__getYIndex(ydata) Z[i][j] = zdata # now see if we need to fill in any gaps if (not newTimeFound) and smoothAltitude: if previousIndex < j - 1: # fill in all missing points for l in range(previousIndex + 1, j): # simply average between the points based on index thisValue = previousValue + (zdata - previousValue)*(float(l-previousIndex)/float(j-previousIndex)) Z[i][l] = thisValue previousIndex = j previousValue = zdata except: continue # insert missing data to represent gaps if needed if insertDataGap != None: # first find the time interval greater than 90% of others timeIntervalList = [] for i in range(len(xList) - 1): timeIntervalList.append(xList[i+1] - xList[i]) timeIntervalList.sort() index = int(len(timeIntervalList)*0.9) maxInterval = timeIntervalList[index] for i in range(len(xList) - 1): if xList[i+1] - xList[i] > maxInterval * insertDataGap: Z[i,:] = self.__missing # insert missing data to represent gaps if needed in Altitude if insertDataGap != None and not smoothAltitude: # first find the time interval greater than 90% of others altitudeIntervalList = [] for i in range(len(yList) - 1): altitudeIntervalList.append(yList[i+1] - yList[i]) altitudeIntervalList.sort() index = int(len(altitudeIntervalList)*0.9) maxInterval = altitudeIntervalList[index] for j in range(len(yList) - 1): if yList[j+1] - yList[j] > maxInterval * insertDataGap and j < max_y_dimension: Z[:,j] = self.__missing # make Z a masked array Znew = numpy.ma.masked_inside(Z, 0.99*self.__missing, 1.01*self.__missing) # set up plotting parameters if minColormap == None: minColormap = zMin if maxColormap == None: maxColormap = zMax # select the plot size if size == 'small': matplotlib.pylab.figure(1, figsize=(8,3), facecolor = 'w') elif size == 'wide': matplotlib.pylab.figure(1, figsize=(10,4), facecolor = 'w') elif size == 'large': matplotlib.pylab.figure(1, figsize=(14,5), facecolor = 'w') if useAbsoluteTime: # leave room for rotated datetime string if size == 'large': matplotlib.pylab.axes([0.1, 0.1, 0.85, 0.7]) elif size == 'wide': matplotlib.pylab.axes([0.07, 0.2, 0.97, 0.7]) elif size == 'small': matplotlib.pylab.axes([0.1, 0.18, 0.97, 0.7]) else: if size == 'small': matplotlib.pylab.axes([0.1, 0.18, 0.97, 0.7]) elif size == 'large': matplotlib.pylab.axes([0.1, 0.2, 0.9, 0.73]) matplotlib.pylab.pcolor(X,Y,Znew, edgecolors='none', vmin=minColormap, vmax=maxColormap, cmap = colorMap, norm = matplotlib.pylab.Normalize(), edgecolor='face') matplotlib.pylab.colorbar() thisFont = {'size': fontSize} matplotlib.pylab.rc('font', **thisFont) # pass in the font dict as kwargs matplotlib.pylab.xlabel(xLabelStr, fontsize=fontSize) matplotlib.pylab.ylabel(yLabelStr, fontsize=fontSize) matplotlib.pylab.xlim(xMin, xMax) matplotlib.pylab.ylim(yMinimum, yMaximum) matplotlib.pylab.yticks(fontsize=fontSize) matplotlib.pylab.title(titleStr, fontsize=fontSize) if useAbsoluteTime: # if plot is less than 49 hours xmin, xmax = matplotlib.pylab.xlim() xmin = numpy.floor(xmin / (60*60)) xmax = numpy.ceil(xmax / (60*60)) if noDate == True: newXLabels = [] if (xmax - xmin) <= 1: newXLocs = [] xRange = numpy.arange(0,1,0.25) for i in xRange: tmp=(xmin+i)*60*60 newXLocs.append(tmp) elif (xmax - xmin) <= 2: newXLocs = [] xRange = numpy.arange(0,2,0.5) for i in xRange: tmp=(xmin+i)*60*60 newXLocs.append(tmp) else: newXLocs = [] step = int((xmax-xmin-1)/6)+1 xRange = range(0,int(xmax-xmin),step) for i in xRange: tmp = (xmin + i)*60*60 newXLocs.append(tmp) #newXLocs.append(xmax*60*60) newXLabels = convertToAbsoluteTimeStr(newXLocs, noDate=noDate, timezone=timezone) matplotlib.pylab.xticks(newXLocs, newXLabels) else: locs, labels = matplotlib.pylab.xticks() if len(locs) > 5: # truncate by len(locs) / 5 scale = 1 + int(len(locs) / 5) new_locs = [] for i in range(len(locs)): if i % scale == 0: new_locs.append(locs[i]) locs = new_locs newXTicks = convertToAbsoluteTimeStr(locs) matplotlib.pylab.xticks(locs, newXTicks, rotation=15) else: # if plot is less than 48 hours, force ticks to be every 4 hours xmin, xmax = matplotlib.pylab.xlim() if xmax < 49: if xmax % 4 != 0: newXmax = 4 * (int(xmax/4.0) + 1) else: newXmax = xmax newXLocs = [] newXLabels = [] for i in range(0,int(4+newXmax),4): newXLocs.append(i) newXLabels.append(str(i)) matplotlib.pylab.xticks(newXLocs, newXLabels) matplotlib.pylab.xticks(fontsize=fontSize) # add second y-axis if desired if altYTitle != None and altYLabels != None: ax2 = matplotlib.pylab.twinx() matplotlib.pylab.ylabel(altYTitle) ax2.yaxis.tick_right() matplotlib.pylab.yticks(range(len(altYLabels)), altYLabels) matplotlib.pylab.yticks(fontsize=fontSize) # get the handle to the figure now that it has been created so we can manipulate on subsequent calls. #self.__figure = matplotlib.pylab.gcf() if peakAltStr: # plot peak altitudes data = peakAltStr.split() xdata = [float(item) for i, item in enumerate(data) if i % 2 == 0] ydata = [float(item) for i, item in enumerate(data) if i % 2 == 1] matplotlib.pylab.plot(xdata, ydata, 'b+') matplotlib.pylab.savefig(fullFilename) #matplotlib.pylab.show() matplotlib.pylab.clf()
def decimateTimes(
self, array_data, maxNumTimes, insertDataGap)
decimateTimes decimates array_data to have at most maxNumTimes times.
Input: array_data - two-dimensional array to be decimated by deleting times and missing data.
maxNumTimes: int representing the maximum number of times to keep in array_data insertDataGap - this parameter sets the threshold for inserting a data gap. The time intervals being plotted are ordered, and the time gap larger than 90% of the rest is determined. Note that this parameter is used here to stop the truncation of isprint lines that will eventually be considered edge lines.
Returns: new array built from decimated array_data
def decimateTimes(self, array_data, maxNumTimes, insertDataGap): """decimateTimes decimates array_data to have at most maxNumTimes times. Input: array_data - two-dimensional array to be decimated by deleting times and missing data. maxNumTimes: int representing the maximum number of times to keep in array_data insertDataGap - this parameter sets the threshold for inserting a data gap. The time intervals being plotted are ordered, and the time gap larger than 90% of the rest is determined. Note that this parameter is used here to stop the truncation of isprint lines that will eventually be considered edge lines. Returns: new array built from decimated array_data """ # get the number of times in array_data, and make a list of all unique times numTimes = 0 uniqueTimes = [] time_array = array_data[:, 0] for i in range(len(time_array)): if i == 0: numTimes = 1 uniqueTimes.append(time_array[i]) elif time_array[i-1] != time_array[i]: uniqueTimes.append(time_array[i]) numTimes += 1 if numTimes <= maxNumTimes: return array_data # insert missing data to represent gaps if needed gapTimes = [] if insertDataGap != None: # first find the time interval greater than 90% of others timeIntervalList = [] for i in range(len(time_array) - 1): if time_array[i+1] == time_array[i]: continue timeIntervalList.append(time_array[i+1] - time_array[i]) timeIntervalList.sort() index = int(len(timeIntervalList)*0.9) maxInterval = timeIntervalList[index] for i in range(len(time_array) - 1): if time_array[i+1] - time_array[i] > maxInterval * insertDataGap: gapTimes.append(time_array[i+1]) gapTimes.append(time_array[i]) # get the number of times to skip each time numSkip = numTimes/maxNumTimes # get the number of rows in the new_array numRows = 0 numTimes = 0 useThisTime = False for i in range(len(time_array)): if i == 0: numTimes = 1 elif time_array[i-1] != time_array[i]: numTimes += 1 if numTimes % (numSkip + 1) == 0 or time_array[i] in gapTimes: useThisTime = True if array_data[i, -1] != self.__missing: numRows += 1 else: useThisTime = False else: if useThisTime: if array_data[i, -1] != self.__missing: numRows += 1 # create new_array new_array = numpy.zeros((numRows, array_data.shape[1]), array_data.dtype) # copy selected rows to new_array numRows = 0 numTimes = 0 useThisTime = False for i in range(len(time_array)): if i == 0: numTimes = 1 elif time_array[i-1] != time_array[i]: numTimes += 1 if numTimes % (numSkip + 1) == 0 or time_array[i] in gapTimes: useThisTime = True if array_data[i, -1] != self.__missing: new_array[numRows,:] = array_data[i,:] numRows += 1 else: useThisTime = False else: if useThisTime: if array_data[i, -1] != self.__missing: new_array[numRows,:] = array_data[i,:] numRows += 1 return new_array
def displayToScreen(
self)
to implement this takes a reworking away from pylab to use the underlying matplotlib code
def displayToScreen(self): " to implement this takes a reworking away from pylab to use the underlying matplotlib code " pass
def getAverage(
self, X)
returns the average of items in a float array. Does not including missing data. If all data missing, returns self.__missing
def getAverage(self, X): """returns the average of items in a float array. Does not including missing data. If all data missing, returns self.__missing """ count = 0 total = 0.0 for i in range(X.shape[0]): if X[i] != self.__missing: count += 1 total += X[i] if count == 0: return self.__missing else: return total / float(count)
def getFigureHandle(
self)
def getFigureHandle(self): return self.__figure
def sortArrayInTime(
self, array_data)
sortArrayInTime sorts a two-dimensional array so that the first element in each row (time) is in ascending order.
Input: array_data - two-dimensional array to be sorted by rearranging rows so that the first element in each row (time) is in ascending order
Returns: new_array
def sortArrayInTime(self, array_data): """sortArrayInTime sorts a two-dimensional array so that the first element in each row (time) is in ascending order. Input: array_data - two-dimensional array to be sorted by rearranging rows so that the first element in each row (time) is in ascending order Returns: new_array """ sortIndex = numpy.argsort(array_data[:,0])[0] # if already sorted, just return original array if sortIndex == numpy.sort(sortIndex): return array_data new_array = numpy.zeros(array_data.shape, array_data.dtype) for i in range(len(sortIndex)): new_array[sortIndex[i],:] = array_data[i,:] return new_array
class madPcolorScan
madPcolorScan is the class that produces pcolor scans.
Usage example::
obj = madPcolorScan(isprintText, 'Nel (log(m^-3)) - 26 June 2006 13:49:43-14:07:36', 'Longitude', 'Latitude', './isprint.png', size = 'large', minColormap = 9, maxColormap = 12)
Non-standard Python modules used: matplotlib
Change history:
Written by "Bill Rideout":mailto:wrideout@haystack.mit.edu Jul. 20, 2006
class madPcolorScan: """madPcolorScan is the class that produces pcolor scans. Usage example:: obj = madPcolorScan(isprintText, 'Nel (log(m^-3)) - 26 June 2006 13:49:43-14:07:36', 'Longitude', 'Latitude', './isprint.png', size = 'large', minColormap = 9, maxColormap = 12) Non-standard Python modules used: matplotlib Change history: Written by "Bill Rideout":mailto:wrideout@haystack.mit.edu Jul. 20, 2006 """ def __init__(self, isprintText, xGridSize, yGridSize, titleStr, xLabelStr, yLabelStr, fullFilename, size = 'small', xMinimum = None, xMaximum = None, yMinimum = None, yMaximum = None, minColormap = None, maxColormap = None, colorMap = matplotlib.cm.jet, maxNumLines = None): """__init__ writes a madPcolorScan to a file. Inputs: isprintText - a string giving isprint output without headers. First parameter must be the X axis value, and the second must be the Y axis value. The third column is the value (intensity). Any missing data should be written as "missing" or other string that cannot be converted to a float. xGridSize - grid size for x data (for example 0.1 for 0.1 degree longitude grid) yGridSize - grid size for x data (for example 0.1 for 0.1 degree latitude grid) titleStr - plot title (string) - should describe parameter being plotted xLabelStr - x label string yLabelStr - ylabel string fullFilename - full path of file containing pcolor plot to be saved. Extension must be jpeg or png, or exception thrown. size - size of plot to save. Must be "small", "wide", or "large". Defaults to small. xMinimum = minumum x value. If None (default), uses lowest x value found. xMaximum = maximum x value. If None (default), uses highest x value found. yMinimum = minumum y value. If None (default), uses lowest y value found. yMaximum = maximum y value. If None (default), uses highest y value found. minColormap - minimum parameter value (defaults to lowest parameter value) maxColormap - maximum parameter value (defaults to highest parameter value). However, if both minColormap and maxColormap == None, autoscaling applied. colorMap - sets colormap. It not given, defaults to matplotlib.cm.jet maxNumLine - max number of lines in isprintText before truncating. If None, no truncation Returns: void Affects: None """ self.__missing = 1.0E30 # special value, used to create a masked array self.__parameter_count = 3 self.__xGridSize = int(xGridSize) self.__yGridSize = int(yGridSize) self.__parseCount = 0 # used to tell which column self.__filter_input is working on # verify input if size not in ('small', 'wide', 'large'): raise ValueError, 'size must be "small", "wide", or "large", not %s' % (str(size)) if size in ('small', 'wide'): fontSize = 12 elif size in ('large'): fontSize = 18 if maxNumLines != None: isprintText = self.__truncateIsprint(isprintText, maxNumLines) # since matplotlib pcolor wants a regular grid, we create a grid with all altitudes # convert the input data into numeric arrays of float assuming no headers and filter the missing values. try: split_data = isprintText.split() float_data = map(self.__filter_input, split_data) array_data = numpy.asarray(float_data) array_data = numpy.reshape(array_data,(-1,self.__parameter_count)) except: traceback.print_exc() raise ValueError, 'input text is not parseable' array_data = self.sortArrayInX(array_data) # The first pass through is to obtain the number and range of the x and y variables xList = [] yList = [] zList = [] zMin = None zMax = None # loop over all the lines of data in the array for j in range(len(array_data)): try: x = array_data[j][0] y = array_data[j][1] z = array_data[j][2] if x not in xList: xList.append(x) if y not in yList: yList.append(y) if z != self.__missing: zList.append(z) if zMin != None: if z < zMin and z != self.__missing: zMin = z elif z != self.__missing: zMin = z if zMax != None: if z > zMax and z != self.__missing: zMax = z elif z != self.__missing: zMax = z except: continue if zMin == None: raise ValueError, 'No valid z data found' # if both minColormap and maxColormap == None, use autoscaling if minColormap == None and maxColormap == None: zList.sort() d10 = zList[int(len(zList)*0.10)] d90 = zList[int(len(zList)*0.90)] zMin = d10 - (d90-d10) * 0.75 zMax = d90 + (d90-d10) * 0.75 # now sort the X and Y axis lists and pull their length xList.sort() xMin = xList[0] xMax = xList[-1] yList.sort() yMin = yList[0] yMax = yList[-1] max_x_dimension = len(xList) max_y_dimension = len(yList) # build dictonary of indexes into xList self.xListDict = {} for i in range(len(xList)): self.xListDict[xList[i]] = i # build dictonary of indexes into yList, self.yListDict = {} for i in range(len(yList)): self.yListDict[yList[i]] = i # now build arrays to handle the X axis label, Y axis label, and the Z data X = numpy.zeros((max_x_dimension, max_y_dimension), numpy.float32) Y = numpy.zeros((max_x_dimension, max_y_dimension), numpy.float32) Z = numpy.ones((max_x_dimension, max_y_dimension), numpy.float32) # all parameter values default to missing Z = Z * self.__missing # fill the X and Y arrays for i in range(max_x_dimension): for j in range(max_y_dimension): X[i][j] = float(xList[i]) Y[i][j] = float(yList[j]) # Now load up the data array Z with the array_data measurements as a function of x and y previousIndex = None previousValue = None presentTime = None newTimeFound = True for k in range(len(array_data)): try: xdata = self.__round(array_data[k][0], self.__xGridSize) ydata = self.__round(array_data[k][1], self.__yGridSize) zdata = array_data[k][2] if zdata == self.__missing: continue if xdata != presentTime: newTimeFound = True else: newTimeFound = False presentTime = xdata # now find the right place in the array for this data point i = self.xListDict[xdata] j = self.yListDict[ydata] Z[i][j] = zdata previousIndex = j previousValue = zdata except: continue # make Z a masked array Znew = numpy.ma.masked_inside(Z, 0.99*self.__missing, 1.01*self.__missing) # set up plotting parameters if xMinimum == None: xMinimum = xMin if xMaximum == None: xMaximum = xMax if yMinimum == None: yMinimum = yMin if yMaximum == None: yMaximum = yMax if minColormap == None: minColormap = zMin if maxColormap == None: maxColormap = zMax # select the plot size if size == 'small': matplotlib.pylab.figure(1, figsize=(6,4), facecolor = 'w') elif size == 'wide': matplotlib.pylab.figure(1, figsize=(10,4), facecolor = 'w') elif size == 'large': matplotlib.pylab.figure(1, figsize=(12,6), facecolor = 'w') matplotlib.pylab.pcolor(X,Y,Znew, edgecolors='none', vmin=minColormap, vmax=maxColormap, cmap = colorMap, norm = matplotlib.pylab.Normalize()) matplotlib.pylab.colorbar() thisFont = {'size': fontSize} matplotlib.pylab.rc('font', **thisFont) # pass in the font dict as kwargs matplotlib.pylab.xlabel(xLabelStr, fontsize=fontSize) matplotlib.pylab.ylabel(yLabelStr, fontsize=fontSize) matplotlib.pylab.xlim(xMinimum, xMaximum) matplotlib.pylab.ylim(yMinimum, yMaximum) matplotlib.pylab.yticks(fontsize=fontSize) matplotlib.pylab.title(titleStr, fontsize=fontSize) # get the handle to the figure now that it has been created so we can manipulate on subsequent calls. #self.__figure = matplotlib.pylab.gcf() try: matplotlib.pylab.savefig(fullFilename) except: matplotlib.pylab.clf() raise #matplotlib.pylab.show() matplotlib.pylab.clf() def __round(self, value, increment): """__round returns a value to the nearest increment """ return value - math.fmod(value, increment) def __filter_input(self,x): """__filter_input is called in map to convert missing strings to self.__missing, and to round x and y vales to the nearest xGridSize or yGridSize """ try: value = float(x) if self.__parseCount % 3 == 0: # x value value = self.__round(value, self.__xGridSize) elif self.__parseCount % 3 == 1: # y value value = self.__round(value, self.__yGridSize) except: value = self.__missing self.__parseCount += 1 return value def __truncateIsprint(self, isprintText, maxLines): """__truncateIsprint truncates isprintText to have maxLines at most. """ isprintList = isprintText.split('\n') if len(isprintList) < maxLines: return isprintText else: dropNumber = int(1 + len(isprintList)/maxLines) newIsprintText = '' for i in range(0,len(isprintList),dropNumber): newIsprintText += isprintList[i] + '\n' return newIsprintText def displayToScreen(self): " to implement this takes a reworking away from pylab to use the underlying matplotlib code " pass def getFigureHandle(self): return self.__figure def getAverage(self, X): """returns the average of items in a float array. Does not including missing data. If all data missing, returns self.__missing """ count = 0 total = 0.0 for i in range(X.shape[0]): if X[i] != self.__missing: count += 1 total += X[i] if count == 0: return self.__missing else: return total / float(count) def sortArrayInX(self, array_data): """sortArrayInX sorts a two-dimensional array so that the first element in each row (x) is in ascending order. Input: array_data - two-dimensional array to be sorted by rearranging rows so that the first element in each row (x) is in ascending order Returns: new_array """ sortIndex = numpy.argsort(array_data[:,0])[0] # if already sorted, just return original array if sortIndex == numpy.sort(sortIndex): return array_data new_array = numpy.zeros(array_data.shape, array_data.dtype) for i in range(len(sortIndex)): new_array[sortIndex[i],:] = array_data[i,:] return new_array
Ancestors (in MRO)
Instance variables
var xListDict
var yListDict
Methods
def __init__(
self, isprintText, xGridSize, yGridSize, titleStr, xLabelStr, yLabelStr, fullFilename, size='small', xMinimum=None, xMaximum=None, yMinimum=None, yMaximum=None, minColormap=None, maxColormap=None, colorMap=<matplotlib.colors.LinearSegmentedColormap object at 0x10afdbb90>, maxNumLines=None)
init writes a madPcolorScan to a file.
Inputs:
isprintText - a string giving isprint output without headers. First parameter must be the X axis value, and the second must be the Y axis value. The third column is the value (intensity). Any missing data should be written as "missing" or other string that cannot be converted to a float. xGridSize - grid size for x data (for example 0.1 for 0.1 degree longitude grid) yGridSize - grid size for x data (for example 0.1 for 0.1 degree latitude grid) titleStr - plot title (string) - should describe parameter being plotted xLabelStr - x label string yLabelStr - ylabel string fullFilename - full path of file containing pcolor plot to be saved. Extension must be jpeg or png, or exception thrown. size - size of plot to save. Must be "small", "wide", or "large". Defaults to small. xMinimum = minumum x value. If None (default), uses lowest x value found. xMaximum = maximum x value. If None (default), uses highest x value found. yMinimum = minumum y value. If None (default), uses lowest y value found. yMaximum = maximum y value. If None (default), uses highest y value found. minColormap - minimum parameter value (defaults to lowest parameter value) maxColormap - maximum parameter value (defaults to highest parameter value). However, if both minColormap and maxColormap == None, autoscaling applied. colorMap - sets colormap. It not given, defaults to matplotlib.cm.jet maxNumLine - max number of lines in isprintText before truncating. If None, no truncation
Returns: void
Affects: None
def __init__(self, isprintText, xGridSize, yGridSize, titleStr, xLabelStr, yLabelStr, fullFilename, size = 'small', xMinimum = None, xMaximum = None, yMinimum = None, yMaximum = None, minColormap = None, maxColormap = None, colorMap = matplotlib.cm.jet, maxNumLines = None): """__init__ writes a madPcolorScan to a file. Inputs: isprintText - a string giving isprint output without headers. First parameter must be the X axis value, and the second must be the Y axis value. The third column is the value (intensity). Any missing data should be written as "missing" or other string that cannot be converted to a float. xGridSize - grid size for x data (for example 0.1 for 0.1 degree longitude grid) yGridSize - grid size for x data (for example 0.1 for 0.1 degree latitude grid) titleStr - plot title (string) - should describe parameter being plotted xLabelStr - x label string yLabelStr - ylabel string fullFilename - full path of file containing pcolor plot to be saved. Extension must be jpeg or png, or exception thrown. size - size of plot to save. Must be "small", "wide", or "large". Defaults to small. xMinimum = minumum x value. If None (default), uses lowest x value found. xMaximum = maximum x value. If None (default), uses highest x value found. yMinimum = minumum y value. If None (default), uses lowest y value found. yMaximum = maximum y value. If None (default), uses highest y value found. minColormap - minimum parameter value (defaults to lowest parameter value) maxColormap - maximum parameter value (defaults to highest parameter value). However, if both minColormap and maxColormap == None, autoscaling applied. colorMap - sets colormap. It not given, defaults to matplotlib.cm.jet maxNumLine - max number of lines in isprintText before truncating. If None, no truncation Returns: void Affects: None """ self.__missing = 1.0E30 # special value, used to create a masked array self.__parameter_count = 3 self.__xGridSize = int(xGridSize) self.__yGridSize = int(yGridSize) self.__parseCount = 0 # used to tell which column self.__filter_input is working on # verify input if size not in ('small', 'wide', 'large'): raise ValueError, 'size must be "small", "wide", or "large", not %s' % (str(size)) if size in ('small', 'wide'): fontSize = 12 elif size in ('large'): fontSize = 18 if maxNumLines != None: isprintText = self.__truncateIsprint(isprintText, maxNumLines) # since matplotlib pcolor wants a regular grid, we create a grid with all altitudes # convert the input data into numeric arrays of float assuming no headers and filter the missing values. try: split_data = isprintText.split() float_data = map(self.__filter_input, split_data) array_data = numpy.asarray(float_data) array_data = numpy.reshape(array_data,(-1,self.__parameter_count)) except: traceback.print_exc() raise ValueError, 'input text is not parseable' array_data = self.sortArrayInX(array_data) # The first pass through is to obtain the number and range of the x and y variables xList = [] yList = [] zList = [] zMin = None zMax = None # loop over all the lines of data in the array for j in range(len(array_data)): try: x = array_data[j][0] y = array_data[j][1] z = array_data[j][2] if x not in xList: xList.append(x) if y not in yList: yList.append(y) if z != self.__missing: zList.append(z) if zMin != None: if z < zMin and z != self.__missing: zMin = z elif z != self.__missing: zMin = z if zMax != None: if z > zMax and z != self.__missing: zMax = z elif z != self.__missing: zMax = z except: continue if zMin == None: raise ValueError, 'No valid z data found' # if both minColormap and maxColormap == None, use autoscaling if minColormap == None and maxColormap == None: zList.sort() d10 = zList[int(len(zList)*0.10)] d90 = zList[int(len(zList)*0.90)] zMin = d10 - (d90-d10) * 0.75 zMax = d90 + (d90-d10) * 0.75 # now sort the X and Y axis lists and pull their length xList.sort() xMin = xList[0] xMax = xList[-1] yList.sort() yMin = yList[0] yMax = yList[-1] max_x_dimension = len(xList) max_y_dimension = len(yList) # build dictonary of indexes into xList self.xListDict = {} for i in range(len(xList)): self.xListDict[xList[i]] = i # build dictonary of indexes into yList, self.yListDict = {} for i in range(len(yList)): self.yListDict[yList[i]] = i # now build arrays to handle the X axis label, Y axis label, and the Z data X = numpy.zeros((max_x_dimension, max_y_dimension), numpy.float32) Y = numpy.zeros((max_x_dimension, max_y_dimension), numpy.float32) Z = numpy.ones((max_x_dimension, max_y_dimension), numpy.float32) # all parameter values default to missing Z = Z * self.__missing # fill the X and Y arrays for i in range(max_x_dimension): for j in range(max_y_dimension): X[i][j] = float(xList[i]) Y[i][j] = float(yList[j]) # Now load up the data array Z with the array_data measurements as a function of x and y previousIndex = None previousValue = None presentTime = None newTimeFound = True for k in range(len(array_data)): try: xdata = self.__round(array_data[k][0], self.__xGridSize) ydata = self.__round(array_data[k][1], self.__yGridSize) zdata = array_data[k][2] if zdata == self.__missing: continue if xdata != presentTime: newTimeFound = True else: newTimeFound = False presentTime = xdata # now find the right place in the array for this data point i = self.xListDict[xdata] j = self.yListDict[ydata] Z[i][j] = zdata previousIndex = j previousValue = zdata except: continue # make Z a masked array Znew = numpy.ma.masked_inside(Z, 0.99*self.__missing, 1.01*self.__missing) # set up plotting parameters if xMinimum == None: xMinimum = xMin if xMaximum == None: xMaximum = xMax if yMinimum == None: yMinimum = yMin if yMaximum == None: yMaximum = yMax if minColormap == None: minColormap = zMin if maxColormap == None: maxColormap = zMax # select the plot size if size == 'small': matplotlib.pylab.figure(1, figsize=(6,4), facecolor = 'w') elif size == 'wide': matplotlib.pylab.figure(1, figsize=(10,4), facecolor = 'w') elif size == 'large': matplotlib.pylab.figure(1, figsize=(12,6), facecolor = 'w') matplotlib.pylab.pcolor(X,Y,Znew, edgecolors='none', vmin=minColormap, vmax=maxColormap, cmap = colorMap, norm = matplotlib.pylab.Normalize()) matplotlib.pylab.colorbar() thisFont = {'size': fontSize} matplotlib.pylab.rc('font', **thisFont) # pass in the font dict as kwargs matplotlib.pylab.xlabel(xLabelStr, fontsize=fontSize) matplotlib.pylab.ylabel(yLabelStr, fontsize=fontSize) matplotlib.pylab.xlim(xMinimum, xMaximum) matplotlib.pylab.ylim(yMinimum, yMaximum) matplotlib.pylab.yticks(fontsize=fontSize) matplotlib.pylab.title(titleStr, fontsize=fontSize) # get the handle to the figure now that it has been created so we can manipulate on subsequent calls. #self.__figure = matplotlib.pylab.gcf() try: matplotlib.pylab.savefig(fullFilename) except: matplotlib.pylab.clf() raise #matplotlib.pylab.show() matplotlib.pylab.clf()
def displayToScreen(
self)
to implement this takes a reworking away from pylab to use the underlying matplotlib code
def displayToScreen(self): " to implement this takes a reworking away from pylab to use the underlying matplotlib code " pass
def getAverage(
self, X)
returns the average of items in a float array. Does not including missing data. If all data missing, returns self.__missing
def getAverage(self, X): """returns the average of items in a float array. Does not including missing data. If all data missing, returns self.__missing """ count = 0 total = 0.0 for i in range(X.shape[0]): if X[i] != self.__missing: count += 1 total += X[i] if count == 0: return self.__missing else: return total / float(count)
def getFigureHandle(
self)
def getFigureHandle(self): return self.__figure
def sortArrayInX(
self, array_data)
sortArrayInX sorts a two-dimensional array so that the first element in each row (x) is in ascending order.
Input: array_data - two-dimensional array to be sorted by rearranging rows so that the first element in each row (x) is in ascending order
Returns: new_array
def sortArrayInX(self, array_data): """sortArrayInX sorts a two-dimensional array so that the first element in each row (x) is in ascending order. Input: array_data - two-dimensional array to be sorted by rearranging rows so that the first element in each row (x) is in ascending order Returns: new_array """ sortIndex = numpy.argsort(array_data[:,0])[0] # if already sorted, just return original array if sortIndex == numpy.sort(sortIndex): return array_data new_array = numpy.zeros(array_data.shape, array_data.dtype) for i in range(len(sortIndex)): new_array[sortIndex[i],:] = array_data[i,:] return new_array
class madPcolorWedgeKmlScan
madPcolorWedgeKmlScan is the class that produces pcolor scan kml files where data is drawn as wedge shapes.
Usage example::
obj = madPcolorWedgeKmlScan(isprintText, 'az', './isprint.kml', minColormap = 9, maxColormap = 12)
Non-standard Python modules used: matplotlib
Change history:
Written by "Bill Rideout":mailto:wrideout@haystack.mit.edu Dec 15, 2010
class madPcolorWedgeKmlScan: """madPcolorWedgeKmlScan is the class that produces pcolor scan kml files where data is drawn as wedge shapes. Usage example:: obj = madPcolorWedgeKmlScan(isprintText, 'az', './isprint.kml', minColormap = 9, maxColormap = 12) Non-standard Python modules used: matplotlib Change history: Written by "Bill Rideout":mailto:wrideout@haystack.mit.edu Dec 15, 2010 """ def __init__(self, isprintText, scanType, fullFilename, minColormap = None, maxColormap = None, instName = None, instDesc = None, instLat = None, instLon = None, instAlt = None, colorMap = None): """__init__ writes a madPcolorWedgeKmlScan to a file. Inputs: isprintText - a string giving isprint output without headers. The 9 parameters are (gdlatr, gdlonr, galtr, range, az1, az2, el1, el2, <parameter value>). Any missing data should be written as "missing" or other string that cannot be converted to a float. gdlatr, gdlonr, galtr are the station location scanType - must be 'az' or 'el_lat' (for north or south el scans), 'el_lon' (for east or west el scans) or 'el_gcdist' (for all other el scans. For az - x is long, y is lat for el_* y is always alt, and x is either lat, lon, or great circle distance fullFilename - full path of file containing kml file to be saved. Extension must be kml, or exception thrown. minColormap - minimum parameter value (defaults to lowest parameter value) maxColormap - maximum parameter value (defaults to highest parameter value). However, if both minColormap and maxColormap == None, autoscaling applied. instName, instDesc, instLat, instLon, instAlt - used to create a placemark for the radar. If instLat or instLon missing, no placemark added. colorMap - A matplotlib colormap to use to create colors. If None, then blue minimum and red maximum Returns: void Affects: Writes fullFilename to disk """ # verify input if scanType not in ('az', 'el_lat', 'el_lon', 'el_gcdist'): raise ValueError, 'scanType must be "az", "el_lat", "el_lon", "el_gcdist", not %s' % (str(scanType)) isprintLines = isprintText.split('\n') newLonMax, newLonMin, newLatMax, newLatMin, newAltMax, newGreatCDist, newParmMax, newParmMin = self._getLimits(isprintLines) # get look point lookLat = (newLatMax + newLatMin)/2.0 lookLon = (newLonMax + newLonMin)/2.0 lookAlt = newAltMax * 10.0 if maxColormap == None: maxColormap = newParmMax if minColormap == None: minColormap = newParmMin # set up wedge generator dataGen = self._generateWedges(isprintLines, scanType) text = self._createKmlText(dataGen, maxColormap, minColormap, lookLat, lookLon, lookAlt, scanType, instName, instDesc, instLat, instLon, instAlt, colorMap) f = open(fullFilename, 'w') f.write(text) f.close() def getGreatCircleDist(self, gdlatr, glonr, gdlat, glon): """getGreatCircleDist return the great circle distance in. Taken from madDeriveMethods c code. Inputs: gdlatr, glonr: reference point on earth's surface gdlat, glon: second point on earth's surface """ dlon = glonr/57.2958 - glon/57.2958 dlat = gdlatr/57.2958 - gdlat/57.2958; a = math.sin(dlat/2.0)*math.sin(dlat/2.0) + math.cos(gdlatr/57.2958)*math.cos(gdlat/57.2958) * math.sin(dlon/2.0)*math.sin(dlon/2.0) if math.sqrt(a) < 1.0: c = 2.0 * math.asin(math.sqrt(a)) else: c = 2.0 * math.asin(1.0) return(c * 6371.2) def _getLimits(self, isprintLines): """returns (newLonMax, newLonMin, newLatMax, newLatMin, newAltMax, newGreatCDist, newParmMax, newParmMin) given isprint lines with parameters (gdlatr, gdlonr, galtr, range, az1, az2, el1, el2, <parameter value>) We only look at the end points of ranges and the station location """ # set initial values to station location items = isprintLines[1].split() slat = float(items[0]) slon = float(items[1]) if slon > 180.0: slon -= 360.0 salt = float(items[2]) maxLon = slon minLon = slon maxLat = slat minLat = slat maxAlt = salt maxGreatCDist = 0.0 maxParm = -1.0e-30 minParm = 1.0e30 lastAz = None lastEl = None lastRange = None for i, isprintLine in enumerate(isprintLines): items = isprintLine.split() if len(items) < 9: continue range = float(items[3]) az1 = float(items[4]) az2 = float(items[5]) thisAz = (az1 + az2)/2 el1 = float(items[6]) el2 = float(items[7]) thisEl = (el1 + el2)/2 try: parm = float(items[8]) if parm > maxParm: maxParm = parm if parm < minParm: minParm = parm except ValueError: continue # see if we're at an end point if lastAz != None: if abs(lastAz - thisAz) > 0.001 or abs(lastEl - thisEl) > 0.001: # the last point was an end point gdlat,glon,gdalt = madrigal._derive.radarToGeodetic(slat,slon,salt,lastAz,lastEl,lastRange) if gdlat > maxLat: maxLat = gdlat if gdlat < minLat: minLat = gdlat if glon > maxLon: maxLon = glon if glon < minLon: minLon = glon if gdalt > maxAlt: maxAlt = gdalt greatCDist = self.getGreatCircleDist(slat, slon, gdlat, glon) if greatCDist > maxGreatCDist: maxGreatCDist = greatCDist lastAz = thisAz lastEl = thisEl lastRange = range # check last point gdlat,glon,gdalt = madrigal._derive.radarToGeodetic(slat,slon,slat,lastAz,lastEl,lastRange) if gdlat > maxLat: maxLat = gdlat if gdlat < minLat: minLat = gdlat if glon > maxLon: maxLon = glon if glon < minLon: minLon = glon if gdalt > maxAlt: maxAlt = gdalt greatCDist = self.getGreatCircleDist(slat, slon, gdlat, glon) if greatCDist > maxGreatCDist: maxGreatCDist = greatCDist return((maxLon, minLon, maxLat, minLat, maxAlt, maxGreatCDist, maxParm, minParm)) def _generateWedges(self, isprintLines, scanType): """_generateWedges is a python generator that return a data wedge in the form (dataValue, (point1_lat, point1_lon, point1_alt), (point2_lat, point2_lon, point2_alt), (point3_lat, point3_lon, point3_alt), (point4_lat, point4_lon, point4_alt)) Inputs: isprintLines - a list of line with 9 parameters that are (gdlatr, gdlonr, galtr, range, az1, az2, el1, el2, <parameter value>). Any missing data should be written as "missing" or other string that cannot be converted to a float. gdlatr, gdlonr, galtr are the station location. No wedge is returned for a missing data line scanType - must be 'az' or 'el_lat' (for north or south el scans), 'el_lon' (for east or west el scans) or 'el_gcdist' (for all other el scans. For az - x is long, y is lat for el_* y is always alt, and x is either lat, lon, or great circle distance """ # state variables lastAz1 = None lastAz2 = None lastEl1 = None lastEl2 = None lastRange = None lastDiffRangeLow = None lastValue = None for isprintLine in isprintLines: items = isprintLine.split() if len(items) < 9: continue gdlatr = float(items[0]) gdlonr = float(items[1]) galtr = float(items[2]) range = float(items[3]) az1 = float(items[4]) az2 = float(items[5]) el1 = float(items[6]) el2 = float(items[7]) valueStr = items[8] if lastAz1 != None and ( abs(lastAz1-az1) > 0.001 or abs(lastEl1-el1) > 0.001 ): # new radar line found, send last point if needed if lastValue != None: dataWedge = self._getWedge(gdlatr, gdlonr, galtr, lastRange, lastDiffRangeLow, lastDiffRangeLow, lastAz1, lastAz2, lastEl1, lastEl2, lastValue) yield(dataWedge) # this is the first point in the line, so no lastDiffRangeLow lastDiffRangeLow = None elif lastAz1 != None and ( abs(lastAz1-az1) < 0.001 and abs(lastEl1-el1) < 0.001 ): # continuing radar line if lastValue != None: lastDiffRangeLow = (range - lastRange)/2.0 dataWedge = self._getWedge(gdlatr, gdlonr, galtr, lastRange, lastDiffRangeLow, (range-lastRange)/2.0, lastAz1, lastAz2, lastEl1, lastEl2, lastValue) yield(dataWedge) else: lastDiffRangeLow = (range - lastRange)/2.0 # reset state variables lastAz1 = az1 lastAz2 = az2 lastEl1 = el1 lastEl2 = el2 lastRange = range try: lastValue = float(valueStr) except: lastValue = None # finally, send last wedge if needed if lastValue != None: dataWedge = self._getWedge(gdlatr, gdlonr, galtr, lastRange, lastDiffRangeLow, lastDiffRangeLow, lastAz1, lastAz2, lastEl1, lastEl2, lastValue) yield(dataWedge) def _getWedge(self, gdlatr, gdlonr, galtr, range, diffRange1, diffRange2, az1, az2, el1, el2, value): """_getWedge returns return a data wedge in the form (dataValue, (point1_lat, point1_lon, point1_alt), (point2_lat, point2_lon, point2_alt), (point3_lat, point3_lon, point3_alt), (point4_lat, point4_lon, point4_alt)). Inputs: gdlatr, gdlonr, galtr - location of radar range, diffRange1, diffRange2 - range of center of wedge, and distance in and out from there az1, az2, el1, el2 - start and end aximuth and elevation. Which is used depends on scanType value - float data value """ point1_lat,point1_lon,point1_alt = madrigal._derive.radarToGeodetic(gdlatr, gdlonr, galtr,az1,el1,range-diffRange1) point2_lat,point2_lon,point2_alt = madrigal._derive.radarToGeodetic(gdlatr, gdlonr, galtr,az2,el2,range-diffRange1) point3_lat,point3_lon,point3_alt = madrigal._derive.radarToGeodetic(gdlatr, gdlonr, galtr,az2,el2,range+diffRange2) point4_lat,point4_lon,point4_alt = madrigal._derive.radarToGeodetic(gdlatr, gdlonr, galtr,az1,el1,range+diffRange2) return((value, (point1_lat,point1_lon,point1_alt), (point2_lat,point2_lon,point2_alt), (point3_lat,point3_lon,point3_alt), (point4_lat,point4_lon,point4_alt))) def _createKmlText(self, dataGen, maxColormap, minColormap, lookLat, lookLon, lookAlt, scanType, instName, instDesc, instLat, instLon, instAlt, colorMap): """_createKmlText creates kml text Inputs: dataGen - list in form (dataValue, (point1_lat, point1_lon, point1_alt), (point2_lat, point2_lon, point2_alt), (point3_lat, point3_lon, point3_alt), (point4_lat, point4_lon, point4_alt)) maxColormap minColormap lookLat lookLon lookAlt scanType instName, instDesc, instLat, instLon, instAlt - - used to create a placemark for the radar. If instLat or instLon missing, no placemark added. colorMap - A matplotlib colormap to use to create colors. If None, then blue minimum and red maximum """ # need to fill in id and color styleTemplate = """ <Style id="p%i"> <PolyStyle> <color>%s</color> <fill>1</fill> <outline>0</outline> </PolyStyle> </Style> """ # need to fill in id and coordinates placemarkTemplate = """ <Placemark> <styleUrl>#%s</styleUrl> <Polygon> <altitudeMode>absolute</altitudeMode> <outerBoundaryIs> <LinearRing> <coordinates> %s </coordinates> </LinearRing> </outerBoundaryIs> </Polygon> </Placemark> """ instTemplate = """<Placemark> <name>%s</name> <description>%s</description> <Point> <coordinates>%f,%f,%f</coordinates> </Point> </Placemark> """ # need to fill in styles and placemarks documentTemplate = """<?xml version="1.0" encoding="UTF-8"?> <kml xmlns="http://www.opengis.net/kml/2.2" xmlns:gx="http://www.google.com/kml/ext/2.2" xmlns:kml="http://www.opengis.net/kml/2.2" xmlns:atom="http://www.w3.org/2005/Atom"> <Document> <name>ScanKmlFile</name> <LookAt> <longitude>%f</longitude> <latitude>%f</latitude> <altitude>%f</altitude> <heading>%f</heading> <tilt>50</tilt> <range>%f</range> <altitudeMode>relativeToGround</altitudeMode> </LookAt> %s %s %s </Document> </kml> """ retStr = '' styleStr = '' # create 100 colors for i in range(100): if not colorMap: colorStr = self._getKmlRGB(i/100.0) else: matLabColorStr = matplotlib.colors.rgb2hex(colorMap(i/100.0)[:3]) red = matLabColorStr[1:3] green = matLabColorStr[3:5] blue = matLabColorStr[5:7] colorStr = 'ff' + blue + green + red # this is the google earth standard for opaque color styleStr += styleTemplate % (i, colorStr) placemarkStr = '' # loop through data adding strings to placemark string while(True): try: p = dataGen.next() except StopIteration: break data = p[0] if data > maxColormap: styleIndex = 99 elif data < minColormap: styleIndex = 0 else: styleIndex = int(99.0 * ((data-minColormap)/(maxColormap-minColormap))) styleId = 'p%i' % (styleIndex) coordStr = ('%f,%f,%f %f,%f,%f %f,%f,%f %f,%f,%f %f,%f,%f' ) % \ (p[1][1], p[1][0], p[1][2]*1000.0, p[2][1], p[2][0], p[2][2]*1000.0, p[3][1], p[3][0], p[3][2]*1000.0, p[4][1], p[4][0], p[4][2]*1000.0, p[1][1], p[1][0], p[1][2]*1000.0) placemarkStr += placemarkTemplate % (styleId, coordStr) if scanType in ('el_lat'): heading = 90.0 distance = 200.0 elif scanType in ('el_lon', 'el_gcdist'): heading = 0.0 distance = 200.0 else: heading = 0.0 distance = 1000.0 # create instStr instStr = '' if instLat != None and instLon != None: if instAlt == None: instAlt = 0.0 if instName == None: instName = 'Radar' if instDesc == None: instDesc = 'This is the location of the radar that produced this scan.' instStr += instTemplate % (instName, instDesc, instLon, instLat, instAlt) retStr += documentTemplate % (lookLon, lookLat, lookAlt*100.0, heading, lookAlt*distance, styleStr, instStr, placemarkStr) return(retStr) def _getKmlRGB(self, value, transparent=False, wrap=False): """_getKmlRGB returns a Kml color string given a value between 0 qnd 1. If transparent == False, solid color. Otherwise transpanency set to 50% If wrap, colors at zero and 1 wrap. Otherwise, extremes red and blue If invert, use value = 1 - value """ if value < 0.0 or value > 1.0: raise ValueError, 'value must be between 0 and 1, not %f' % (value) if wrap: r,g,b = colorsys.hsv_to_rgb(value, 0.9, 0.9) else: r,g,b = colorsys.hsv_to_rgb(value*0.67, 0.9, 0.9) if not transparent: transStr = 'ff' else: transStr = '80' retStr = '%s%s%s%s' % (transStr, hex(int(r*255))[-2:], hex(int(g*255))[-2:], hex(int(b*255))[-2:]) return(retStr)
Ancestors (in MRO)
Methods
def __init__(
self, isprintText, scanType, fullFilename, minColormap=None, maxColormap=None, instName=None, instDesc=None, instLat=None, instLon=None, instAlt=None, colorMap=None)
init writes a madPcolorWedgeKmlScan to a file.
Inputs:
isprintText - a string giving isprint output without headers. The 9 parameters are (gdlatr, gdlonr, galtr, range, az1, az2, el1, el2, <parameter value>). Any missing data should be written as "missing" or other string that cannot be converted to a float. gdlatr, gdlonr, galtr are the station location scanType - must be 'az' or 'el_lat' (for north or south el scans), 'el_lon' (for east or west el scans) or 'el_gcdist' (for all other el scans. For az - x is long, y is lat for el_* y is always alt, and x is either lat, lon, or great circle distance fullFilename - full path of file containing kml file to be saved. Extension must be kml, or exception thrown. minColormap - minimum parameter value (defaults to lowest parameter value) maxColormap - maximum parameter value (defaults to highest parameter value). However, if both minColormap and maxColormap == None, autoscaling applied. instName, instDesc, instLat, instLon, instAlt - used to create a placemark for the radar. If instLat or instLon missing, no placemark added. colorMap - A matplotlib colormap to use to create colors. If None, then blue minimum and red maximum
Returns: void
Affects: Writes fullFilename to disk
def __init__(self, isprintText, scanType, fullFilename, minColormap = None, maxColormap = None, instName = None, instDesc = None, instLat = None, instLon = None, instAlt = None, colorMap = None): """__init__ writes a madPcolorWedgeKmlScan to a file. Inputs: isprintText - a string giving isprint output without headers. The 9 parameters are (gdlatr, gdlonr, galtr, range, az1, az2, el1, el2, <parameter value>). Any missing data should be written as "missing" or other string that cannot be converted to a float. gdlatr, gdlonr, galtr are the station location scanType - must be 'az' or 'el_lat' (for north or south el scans), 'el_lon' (for east or west el scans) or 'el_gcdist' (for all other el scans. For az - x is long, y is lat for el_* y is always alt, and x is either lat, lon, or great circle distance fullFilename - full path of file containing kml file to be saved. Extension must be kml, or exception thrown. minColormap - minimum parameter value (defaults to lowest parameter value) maxColormap - maximum parameter value (defaults to highest parameter value). However, if both minColormap and maxColormap == None, autoscaling applied. instName, instDesc, instLat, instLon, instAlt - used to create a placemark for the radar. If instLat or instLon missing, no placemark added. colorMap - A matplotlib colormap to use to create colors. If None, then blue minimum and red maximum Returns: void Affects: Writes fullFilename to disk """ # verify input if scanType not in ('az', 'el_lat', 'el_lon', 'el_gcdist'): raise ValueError, 'scanType must be "az", "el_lat", "el_lon", "el_gcdist", not %s' % (str(scanType)) isprintLines = isprintText.split('\n') newLonMax, newLonMin, newLatMax, newLatMin, newAltMax, newGreatCDist, newParmMax, newParmMin = self._getLimits(isprintLines) # get look point lookLat = (newLatMax + newLatMin)/2.0 lookLon = (newLonMax + newLonMin)/2.0 lookAlt = newAltMax * 10.0 if maxColormap == None: maxColormap = newParmMax if minColormap == None: minColormap = newParmMin # set up wedge generator dataGen = self._generateWedges(isprintLines, scanType) text = self._createKmlText(dataGen, maxColormap, minColormap, lookLat, lookLon, lookAlt, scanType, instName, instDesc, instLat, instLon, instAlt, colorMap) f = open(fullFilename, 'w') f.write(text) f.close()
def getGreatCircleDist(
self, gdlatr, glonr, gdlat, glon)
getGreatCircleDist return the great circle distance in. Taken from madDeriveMethods c code.
Inputs: gdlatr, glonr: reference point on earth's surface gdlat, glon: second point on earth's surface
def getGreatCircleDist(self, gdlatr, glonr, gdlat, glon): """getGreatCircleDist return the great circle distance in. Taken from madDeriveMethods c code. Inputs: gdlatr, glonr: reference point on earth's surface gdlat, glon: second point on earth's surface """ dlon = glonr/57.2958 - glon/57.2958 dlat = gdlatr/57.2958 - gdlat/57.2958; a = math.sin(dlat/2.0)*math.sin(dlat/2.0) + math.cos(gdlatr/57.2958)*math.cos(gdlat/57.2958) * math.sin(dlon/2.0)*math.sin(dlon/2.0) if math.sqrt(a) < 1.0: c = 2.0 * math.asin(math.sqrt(a)) else: c = 2.0 * math.asin(1.0) return(c * 6371.2)
class madPcolorWedgeScan
madPcolorWedgeScan is the class that produces pcolor scans where data is drawn as wedge shapes.
Usage example::
obj = madPcolorScan(isprintText, 'Nel (log(m^-3)) - 26 June 2006 13:49:43-14:07:36', 'Longitude', 'Latitude', './isprint.png', size = 'large', minColormap = 9, maxColormap = 12)
Non-standard Python modules used: matplotlib
Change history:
Written by "Bill Rideout":mailto:wrideout@haystack.mit.edu Jul. 20, 2006
class madPcolorWedgeScan: """madPcolorWedgeScan is the class that produces pcolor scans where data is drawn as wedge shapes. Usage example:: obj = madPcolorScan(isprintText, 'Nel (log(m^-3)) - 26 June 2006 13:49:43-14:07:36', 'Longitude', 'Latitude', './isprint.png', size = 'large', minColormap = 9, maxColormap = 12) Non-standard Python modules used: matplotlib Change history: Written by "Bill Rideout":mailto:wrideout@haystack.mit.edu Jul. 20, 2006 """ def __init__(self, isprintText, scanType, titleStr, xLabelStr, yLabelStr, fullFilename, size = 'small', xMinimum = None, xMaximum = None, yMinimum = None, yMaximum = None, minColormap = None, maxColormap = None, colorMap = matplotlib.cm.jet): """__init__ writes a madPcolorWedgeScan to a file. Inputs: isprintText - a string giving isprint output without headers. The 9 parameters are (gdlatr, gdlonr, galtr, range, az1, az2, el1, el2, <parameter value>). Any missing data should be written as "missing" or other string that cannot be converted to a float. gdlatr, gdlonr, galtr are the station location scanType - must be 'az' or 'el_lat' (for north or south el scans), 'el_lon' (for east or west el scans) or 'el_gcdist' (for all other el scans. For az - x is long, y is lat for el_* y is always alt, and x is either lat, lon, or great circle distance titleStr - plot title (string) - should describe parameter being plotted xLabelStr - x label string yLabelStr - ylabel string fullFilename - full path of file containing pcolor plot to be saved. Extension must be jpeg or png, or exception thrown. size - size of plot to save. Must be "small", "wide", or "large". Defaults to small. xMinimum = minumum x value. If None (default), uses lowest value found. xMaximum = maximum x value. If None (default), uses highest value found. yMinimum = minumum y value. If None (default), uses lowest value found. yMaximum = maximum y value. If None (default), uses highest value found. minColormap - minimum parameter value (defaults to lowest parameter value) maxColormap - maximum parameter value (defaults to highest parameter value). However, if both minColormap and maxColormap == None, autoscaling applied. colorMap - sets colormap. It not given, defaults to matplotlib.cm.jet Returns: void Affects: Writes fullFilename to disk """ # verify input if scanType not in ('az', 'el_lat', 'el_lon', 'el_gcdist'): raise ValueError, 'scanType must be "az", "el_lat", "el_lon", "el_gcdist", not %s' % (str(scanType)) if size not in ('small', 'wide', 'large'): raise ValueError, 'size must be "small", "wide", or "large", not %s' % (str(size)) if size in ('small', 'wide'): fontSize = 12 elif size in ('large'): fontSize = 18 isprintLines = isprintText.split('\n') if xMaximum == None or xMinimum == None or yMaximum == None or yMinimum or maxColormap == None or minColormap == None: newLonMax, newLonMin, newLatMax, newLatMin, newAltMax, newGreatCDist, newParmMax, newParmMin = self._getLimits(isprintLines) # set values xMaximum, xMinimum, yMaximum, yMinimum = self._setLimits(scanType, xMaximum, xMinimum, yMaximum, yMinimum, newLonMax, newLonMin, newLatMax, newLatMin, newAltMax, newGreatCDist, newParmMax, newParmMin) if maxColormap == None: maxColormap = newParmMax if minColormap == None: minColormap = newParmMin # set up wedge generator dataGen = self._generateWedges(isprintLines, scanType) # select the plot size if size == 'small': matplotlib.pylab.figure(1, figsize=(6,5), facecolor = 'w') elif size == 'wide': matplotlib.pylab.figure(1, figsize=(10,4), facecolor = 'w') elif size == 'large': matplotlib.pylab.figure(1, figsize=(12,6), facecolor = 'w') matplotlib.pylab.hold(True) try: while True: data = dataGen.next() x = [data[1][0], data[2][0], data[3][0], data[4][0]] y = [data[1][1], data[2][1], data[3][1], data[4][1]] dataRatio = (data[0] - minColormap) / (maxColormap - minColormap) colorStr = matplotlib.colors.rgb2hex(colorMap(dataRatio)[:3]) thisPlot = matplotlib.pyplot.fill(x, y, colorStr, edgecolor='none') except StopIteration: pass thisFont = {'size': fontSize} matplotlib.pylab.rc('font', **thisFont) # pass in the font dict as kwargs scalableMappable = matplotlib.cm.ScalarMappable(cmap=colorMap) scalableMappable.set_array(numpy.array([minColormap, maxColormap])) scalableMappable.set_clim(minColormap, maxColormap) def get_alpha(*args, **kw): return(1.0) scalableMappable.get_alpha = get_alpha matplotlib.pylab.xlabel(xLabelStr, fontsize=fontSize) matplotlib.pylab.ylabel(yLabelStr, fontsize=fontSize) matplotlib.pylab.xlim(xMinimum, xMaximum) matplotlib.pylab.ylim(yMinimum, yMaximum) matplotlib.pylab.yticks(fontsize=fontSize) matplotlib.pylab.title(titleStr, fontsize=fontSize) matplotlib.pylab.colorbar(mappable=scalableMappable) matplotlib.pylab.gcf().subplots_adjust(bottom=0.15) try: matplotlib.pylab.savefig(fullFilename) except: matplotlib.pylab.clf() raise matplotlib.pylab.clf() def getGreatCircleDist(self, gdlatr, glonr, gdlat, glon): """getGreatCircleDist return the great circle distance in. Taken from madDeriveMethods c code. Inputs: gdlatr, glonr: reference point on earth's surface gdlat, glon: second point on earth's surface """ dlon = glonr/57.2958 - glon/57.2958 dlat = gdlatr/57.2958 - gdlat/57.2958; a = math.sin(dlat/2.0)*math.sin(dlat/2.0) + math.cos(gdlatr/57.2958)*math.cos(gdlat/57.2958) * math.sin(dlon/2.0)*math.sin(dlon/2.0) if math.sqrt(a) < 1.0: c = 2.0 * math.asin(math.sqrt(a)) else: c = 2.0 * math.asin(1.0) return(c * 6371.2) def _getLimits(self, isprintLines): """returns (newLonMax, newLonMin, newLatMax, newLatMin, newAltMax, newGreatCDist, newParmMax, newParmMin) given isprint lines with parameters (gdlatr, gdlonr, galtr, range, az1, az2, el1, el2, <parameter value>) We only look at the end points of ranges and the station location """ # set initial values to station location items = isprintLines[1].split() slat = float(items[0]) slon = float(items[1]) if slon > 180.0: slon -= 360.0 salt = float(items[2]) maxLon = slon minLon = slon maxLat = slat minLat = slat maxAlt = salt maxGreatCDist = 0.0 maxParm = -1.0e-30 minParm = 1.0e30 lastAz = None lastEl = None lastRange = None for i, isprintLine in enumerate(isprintLines): items = isprintLine.split() if len(items) < 9: continue range = float(items[3]) az1 = float(items[4]) az2 = float(items[5]) thisAz = (az1 + az2)/2 el1 = float(items[6]) el2 = float(items[7]) thisEl = (el1 + el2)/2 try: parm = float(items[8]) if parm > maxParm: maxParm = parm if parm < minParm: minParm = parm except ValueError: continue # see if we're at an end point if lastAz != None: if abs(lastAz - thisAz) > 0.001 or abs(lastEl - thisEl) > 0.001: # the last point was an end point gdlat,glon,gdalt = madrigal._derive.radarToGeodetic(slat,slon,salt,lastAz,lastEl,lastRange) if gdlat > maxLat: maxLat = gdlat if gdlat < minLat: minLat = gdlat if glon > maxLon: maxLon = glon if glon < minLon: minLon = glon if gdalt > maxAlt: maxAlt = gdalt greatCDist = self.getGreatCircleDist(slat, slon, gdlat, glon) if greatCDist > maxGreatCDist: maxGreatCDist = greatCDist lastAz = thisAz lastEl = thisEl lastRange = range # check last point gdlat,glon,gdalt = madrigal._derive.radarToGeodetic(slat,slon,slat,lastAz,lastEl,lastRange) if gdlat > maxLat: maxLat = gdlat if gdlat < minLat: minLat = gdlat if glon > maxLon: maxLon = glon if glon < minLon: minLon = glon if gdalt > maxAlt: maxAlt = gdalt greatCDist = self.getGreatCircleDist(slat, slon, gdlat, glon) if greatCDist > maxGreatCDist: maxGreatCDist = greatCDist return((maxLon, minLon, maxLat, minLat, maxAlt, maxGreatCDist, maxParm, minParm)) def _setLimits(self, scanType, xMaximum, xMinimum, yMaximum, yMinimum, newLonMax, newLonMin, newLatMax, newLatMin, newAltMax, newGreatCDist, newParmMax, newParmMin): """ _setLimits sets xMaximum, xMinimum, yMaximum, yMinimum based on values found in self._getLimits and scanType. If any value in (xMaximum, xMinimum, yMaximum, yMinimum) is not None, it will not be changed. """ newXMax = xMaximum newXMin = xMinimum newYMax = yMaximum newYMin = yMinimum if scanType == 'az': if xMaximum == None: newXMax = newLonMax if xMinimum == None: newXMin = newLonMin if yMaximum == None: newYMax = newLatMax if yMinimum == None: newYMin = newLatMin elif scanType == 'el_lat': if xMaximum == None: newXMax = newLatMax if xMinimum == None: newXMin = newLatMin if yMaximum == None: newYMax = newAltMax if yMinimum == None: newYMin = 0.0 elif scanType == 'el_lon': if xMaximum == None: newXMax = newLonMax if xMinimum == None: newXMin = newLonMin if yMaximum == None: newYMax = newAltMax if yMinimum == None: newYMin = 0.0 elif scanType == 'el_gcdist': if xMaximum == None: newXMax = newGreatCDist if xMinimum == None: newXMin = 0.0 if yMaximum == None: newYMax = newAltMax if yMinimum == None: newYMin = 0.0 return((newXMax, newXMin, newYMax, newYMin)) def _generateWedges(self, isprintLines, scanType): """_generateWedges is a python generator that return a data wedge in the form (dataValue, (point1_x, point1_y), (point2_x, point2_y), (point3_x, point3_y), (point4_x, point4_y)) Inputs: isprintLines - a list of line with 9 parameters that are (gdlatr, gdlonr, galtr, range, az1, az2, el1, el2, <parameter value>). Any missing data should be written as "missing" or other string that cannot be converted to a float. gdlatr, gdlonr, galtr are the station location. No wedge is returned for a missing data line scanType - must be 'az' or 'el_lat' (for north or south el scans), 'el_lon' (for east or west el scans) or 'el_gcdist' (for all other el scans. For az - x is long, y is lat for el_* y is always alt, and x is either lat, lon, or great circle distance """ # state variables lastAz1 = None lastAz2 = None lastEl1 = None lastEl2 = None lastRange = None lastDiffRangeLow = None lastValue = None for isprintLine in isprintLines: items = isprintLine.split() if len(items) < 9: continue gdlatr = float(items[0]) gdlonr = float(items[1]) galtr = float(items[2]) range = float(items[3]) az1 = float(items[4]) az2 = float(items[5]) el1 = float(items[6]) el2 = float(items[7]) valueStr = items[8] if lastAz1 != None and ( abs(lastAz1-az1) > 0.001 or abs(lastEl1-el1) > 0.001 ): # new radar line found, send last point if needed if lastValue != None: dataWedge = self._getWedge(gdlatr, gdlonr, galtr, lastRange, lastDiffRangeLow, lastDiffRangeLow, lastAz1, lastAz2, lastEl1, lastEl2, lastValue, scanType) yield(dataWedge) # this is the first point in the line, so no lastDiffRangeLow lastDiffRangeLow = None elif lastAz1 != None and ( abs(lastAz1-az1) < 0.001 and abs(lastEl1-el1) < 0.001 ): # continuing radar line if lastValue != None: lastDiffRangeLow = (range - lastRange)/2.0 dataWedge = self._getWedge(gdlatr, gdlonr, galtr, lastRange, lastDiffRangeLow, (range-lastRange)/2.0, lastAz1, lastAz2, lastEl1, lastEl2, lastValue, scanType) yield(dataWedge) else: lastDiffRangeLow = (range - lastRange)/2.0 # reset state variables lastAz1 = az1 lastAz2 = az2 lastEl1 = el1 lastEl2 = el2 lastRange = range try: lastValue = float(valueStr) except: lastValue = None # finally, send last wedge if needed if lastValue != None: dataWedge = self._getWedge(gdlatr, gdlonr, galtr, lastRange, lastDiffRangeLow, lastDiffRangeLow, lastAz1, lastAz2, lastEl1, lastEl2, lastValue, scanType) yield(dataWedge) def _getWedge(self, gdlatr, gdlonr, galtr, range, diffRange1, diffRange2, az1, az2, el1, el2, value, scanType): """_getWedge returns return a data wedge in the form (dataValue, (point1_x, point1_y), (point2_x, point2_y), (point3_x, point3_y), (point4_x, point4_y)). The x and y dimensions depend on scanType: az: x: lon, y: lat el_lat: x: lat, y: alt el_lon: x: lon, y: alt el_gcdist: x: great circle distance, y: alt Inputs: gdlatr, gdlonr, galtr - location of radar range, diffRange1, diffRange2 - range of center of wedge, and distance in and out from there az1, az2, el1, el2 - start and end aximuth and elevation. Which is used depends on scanType value - float data value scanType - az, el_lat, el_lon, el_gcdist """ if scanType == 'az': point1_y,point1_x,gdalt = madrigal._derive.radarToGeodetic(gdlatr, gdlonr, galtr,az1,el1,range-diffRange1) point2_y,point2_x,gdalt = madrigal._derive.radarToGeodetic(gdlatr, gdlonr, galtr,az2,el1,range-diffRange1) point3_y,point3_x,gdalt = madrigal._derive.radarToGeodetic(gdlatr, gdlonr, galtr,az2,el1,range+diffRange2) point4_y,point4_x,gdalt = madrigal._derive.radarToGeodetic(gdlatr, gdlonr, galtr,az1,el1,range+diffRange2) elif scanType == 'el_lat': point1_x,glon,point1_y = madrigal._derive.radarToGeodetic(gdlatr, gdlonr, galtr,az1,el1,range-diffRange1) point2_x,glon,point2_y = madrigal._derive.radarToGeodetic(gdlatr, gdlonr, galtr,az1,el2,range-diffRange1) point3_x,glon,point3_y = madrigal._derive.radarToGeodetic(gdlatr, gdlonr, galtr,az1,el2,range+diffRange2) point4_x,glon,point4_y = madrigal._derive.radarToGeodetic(gdlatr, gdlonr, galtr,az1,el1,range+diffRange2) elif scanType == 'el_lon': gdlat,point1_x,point1_y = madrigal._derive.radarToGeodetic(gdlatr, gdlonr, galtr,az1,el1,range-diffRange1) gdlat,point2_x,point2_y = madrigal._derive.radarToGeodetic(gdlatr, gdlonr, galtr,az1,el2,range-diffRange1) gdlat,point3_x,point3_y = madrigal._derive.radarToGeodetic(gdlatr, gdlonr, galtr,az1,el2,range+diffRange2) gdlat,point4_x,point4_y = madrigal._derive.radarToGeodetic(gdlatr, gdlonr, galtr,az1,el1,range+diffRange2) elif scanType == 'el_gcdist': gdlat,glon,point1_y = madrigal._derive.radarToGeodetic(gdlatr, gdlonr, galtr,az1,el1,range-diffRange1) point1_x = self.getGreatCircleDist(gdlatr, gdlonr, gdlat, glon) gdlat,glon,point2_y = madrigal._derive.radarToGeodetic(gdlatr, gdlonr, galtr,az1,el2,range-diffRange1) point2_x = self.getGreatCircleDist(gdlatr, gdlonr, gdlat, glon) gdlat,glon,point3_y = madrigal._derive.radarToGeodetic(gdlatr, gdlonr, galtr,az1,el2,range+diffRange2) point3_x = self.getGreatCircleDist(gdlatr, gdlonr, gdlat, glon) gdlat,glon,point4_y = madrigal._derive.radarToGeodetic(gdlatr, gdlonr, galtr,az1,el1,range+diffRange2) point4_x = self.getGreatCircleDist(gdlatr, gdlonr, gdlat, glon) return((value, (point1_x, point1_y), (point2_x, point2_y), (point3_x, point3_y), (point4_x, point4_y)))
Ancestors (in MRO)
Methods
def __init__(
self, isprintText, scanType, titleStr, xLabelStr, yLabelStr, fullFilename, size='small', xMinimum=None, xMaximum=None, yMinimum=None, yMaximum=None, minColormap=None, maxColormap=None, colorMap=<matplotlib.colors.LinearSegmentedColormap object at 0x10afdbb90>)
init writes a madPcolorWedgeScan to a file.
Inputs:
isprintText - a string giving isprint output without headers. The 9 parameters are (gdlatr, gdlonr, galtr, range, az1, az2, el1, el2, <parameter value>). Any missing data should be written as "missing" or other string that cannot be converted to a float. gdlatr, gdlonr, galtr are the station location scanType - must be 'az' or 'el_lat' (for north or south el scans), 'el_lon' (for east or west el scans) or 'el_gcdist' (for all other el scans. For az - x is long, y is lat for el_* y is always alt, and x is either lat, lon, or great circle distance titleStr - plot title (string) - should describe parameter being plotted xLabelStr - x label string yLabelStr - ylabel string fullFilename - full path of file containing pcolor plot to be saved. Extension must be jpeg or png, or exception thrown. size - size of plot to save. Must be "small", "wide", or "large". Defaults to small. xMinimum = minumum x value. If None (default), uses lowest value found. xMaximum = maximum x value. If None (default), uses highest value found. yMinimum = minumum y value. If None (default), uses lowest value found. yMaximum = maximum y value. If None (default), uses highest value found. minColormap - minimum parameter value (defaults to lowest parameter value) maxColormap - maximum parameter value (defaults to highest parameter value). However, if both minColormap and maxColormap == None, autoscaling applied. colorMap - sets colormap. It not given, defaults to matplotlib.cm.jet
Returns: void
Affects: Writes fullFilename to disk
def __init__(self, isprintText, scanType, titleStr, xLabelStr, yLabelStr, fullFilename, size = 'small', xMinimum = None, xMaximum = None, yMinimum = None, yMaximum = None, minColormap = None, maxColormap = None, colorMap = matplotlib.cm.jet): """__init__ writes a madPcolorWedgeScan to a file. Inputs: isprintText - a string giving isprint output without headers. The 9 parameters are (gdlatr, gdlonr, galtr, range, az1, az2, el1, el2, <parameter value>). Any missing data should be written as "missing" or other string that cannot be converted to a float. gdlatr, gdlonr, galtr are the station location scanType - must be 'az' or 'el_lat' (for north or south el scans), 'el_lon' (for east or west el scans) or 'el_gcdist' (for all other el scans. For az - x is long, y is lat for el_* y is always alt, and x is either lat, lon, or great circle distance titleStr - plot title (string) - should describe parameter being plotted xLabelStr - x label string yLabelStr - ylabel string fullFilename - full path of file containing pcolor plot to be saved. Extension must be jpeg or png, or exception thrown. size - size of plot to save. Must be "small", "wide", or "large". Defaults to small. xMinimum = minumum x value. If None (default), uses lowest value found. xMaximum = maximum x value. If None (default), uses highest value found. yMinimum = minumum y value. If None (default), uses lowest value found. yMaximum = maximum y value. If None (default), uses highest value found. minColormap - minimum parameter value (defaults to lowest parameter value) maxColormap - maximum parameter value (defaults to highest parameter value). However, if both minColormap and maxColormap == None, autoscaling applied. colorMap - sets colormap. It not given, defaults to matplotlib.cm.jet Returns: void Affects: Writes fullFilename to disk """ # verify input if scanType not in ('az', 'el_lat', 'el_lon', 'el_gcdist'): raise ValueError, 'scanType must be "az", "el_lat", "el_lon", "el_gcdist", not %s' % (str(scanType)) if size not in ('small', 'wide', 'large'): raise ValueError, 'size must be "small", "wide", or "large", not %s' % (str(size)) if size in ('small', 'wide'): fontSize = 12 elif size in ('large'): fontSize = 18 isprintLines = isprintText.split('\n') if xMaximum == None or xMinimum == None or yMaximum == None or yMinimum or maxColormap == None or minColormap == None: newLonMax, newLonMin, newLatMax, newLatMin, newAltMax, newGreatCDist, newParmMax, newParmMin = self._getLimits(isprintLines) # set values xMaximum, xMinimum, yMaximum, yMinimum = self._setLimits(scanType, xMaximum, xMinimum, yMaximum, yMinimum, newLonMax, newLonMin, newLatMax, newLatMin, newAltMax, newGreatCDist, newParmMax, newParmMin) if maxColormap == None: maxColormap = newParmMax if minColormap == None: minColormap = newParmMin # set up wedge generator dataGen = self._generateWedges(isprintLines, scanType) # select the plot size if size == 'small': matplotlib.pylab.figure(1, figsize=(6,5), facecolor = 'w') elif size == 'wide': matplotlib.pylab.figure(1, figsize=(10,4), facecolor = 'w') elif size == 'large': matplotlib.pylab.figure(1, figsize=(12,6), facecolor = 'w') matplotlib.pylab.hold(True) try: while True: data = dataGen.next() x = [data[1][0], data[2][0], data[3][0], data[4][0]] y = [data[1][1], data[2][1], data[3][1], data[4][1]] dataRatio = (data[0] - minColormap) / (maxColormap - minColormap) colorStr = matplotlib.colors.rgb2hex(colorMap(dataRatio)[:3]) thisPlot = matplotlib.pyplot.fill(x, y, colorStr, edgecolor='none') except StopIteration: pass thisFont = {'size': fontSize} matplotlib.pylab.rc('font', **thisFont) # pass in the font dict as kwargs scalableMappable = matplotlib.cm.ScalarMappable(cmap=colorMap) scalableMappable.set_array(numpy.array([minColormap, maxColormap])) scalableMappable.set_clim(minColormap, maxColormap) def get_alpha(*args, **kw): return(1.0) scalableMappable.get_alpha = get_alpha matplotlib.pylab.xlabel(xLabelStr, fontsize=fontSize) matplotlib.pylab.ylabel(yLabelStr, fontsize=fontSize) matplotlib.pylab.xlim(xMinimum, xMaximum) matplotlib.pylab.ylim(yMinimum, yMaximum) matplotlib.pylab.yticks(fontsize=fontSize) matplotlib.pylab.title(titleStr, fontsize=fontSize) matplotlib.pylab.colorbar(mappable=scalableMappable) matplotlib.pylab.gcf().subplots_adjust(bottom=0.15) try: matplotlib.pylab.savefig(fullFilename) except: matplotlib.pylab.clf() raise matplotlib.pylab.clf()
def getGreatCircleDist(
self, gdlatr, glonr, gdlat, glon)
getGreatCircleDist return the great circle distance in. Taken from madDeriveMethods c code.
Inputs: gdlatr, glonr: reference point on earth's surface gdlat, glon: second point on earth's surface
def getGreatCircleDist(self, gdlatr, glonr, gdlat, glon): """getGreatCircleDist return the great circle distance in. Taken from madDeriveMethods c code. Inputs: gdlatr, glonr: reference point on earth's surface gdlat, glon: second point on earth's surface """ dlon = glonr/57.2958 - glon/57.2958 dlat = gdlatr/57.2958 - gdlat/57.2958; a = math.sin(dlat/2.0)*math.sin(dlat/2.0) + math.cos(gdlatr/57.2958)*math.cos(gdlat/57.2958) * math.sin(dlon/2.0)*math.sin(dlon/2.0) if math.sqrt(a) < 1.0: c = 2.0 * math.asin(math.sqrt(a)) else: c = 2.0 * math.asin(1.0) return(c * 6371.2)
class madScatterPlot
madScatterPlot is the class the produces two dimensional scatter plots of x versus y.
class madScatterPlot: """madScatterPlot is the class the produces two dimensional scatter plots of x versus y. """ def __init__(self, isprintText, titleStr, xLabelStr, yLabelStr, fullFilename, size = 'small', useAbsoluteTime = False, startTime = None, endTime = None, maxNumPoints = None, noTime = False, noDate = False, yMinimum = None, yMaximum = None, timezone = 0): """__init__ writes a madScatter plot to a file. Inputs: isprintText - a string giving isprint output without headers. First parameter must be UTH or UT1, depending on whether time scale should be relative to the experiment beginning (UTH) or absolute (UT1). The second must be the parameter to be plotted. Any missing data should be written as "missing" or other string that cannot be converted to a float. titleStr - plot title (string) - should describe parameter being plotted xLabelStr - x label string yLabelStr - ylabel string fullFilename - full path of file containing pcolor plot to be saved. Extension must be jpeg or png, or exception thrown. size - size of plot to save. Must be "small", "wide", or "large". Defaults to small. useAbsoluteTime - if true, print time as YYYY-MM-DD HH:MM:SS. If false (default), print time as hour since beginning of experiment (UTH). If useAbsoluteTime is true, first parameter in isprintText must be UT1, if false, it must be UTH. startTime - start plot at given time. If useAbsoluteTime == True, then startTime must be in units of seconds since 1/1/1950. If useAbsoluteTime == False, then startTime must be in units of UTH (hours since midnight UT of first day of experiment). Default is None, which means start at lowest time found. endTime - end plot at given time. If useAbsoluteTime == True, then endTime must be in units of seconds since 1/1/1950. If useAbsoluteTime == False, then endTime must be in units of UTH (hours since midnight UT of first day of experiment). Default is None, which means end at largest time found. maxNumPoints - maximum number of points to plot. If not None, truncate isprintText if needed to have at most maxNumPoints lines. noTime - if True and useAbsoluteTime True, then dates without times printed on x axis. noDate - if True and useAbsoluteTime True, then times without dates printed on x axis. yMinimum - set y minimum. If default=None, use data minimum yMaximum - set y maximum. If default=None, use data maximum timezone - The offset of the local (non-DST) timezone, in seconds west of UTC (negative in most of Western Europe, positive in the US, zero in the UK). Returns: void Affects: None """ self.__missing = 1.0E30 # special value, since numpy doesn't handle NaN self.__parameter_count = 2 # verify input if size not in ('small', 'wide', 'large'): raise ValueError, 'size must be "small", "wide", or "large", not %s' % (str(size)) if size in ('small', 'wide'): fontSize = 12 elif size in ('large'): fontSize = 18 if maxNumPoints != None: isprintText = self.__truncateIsprint(isprintText, maxNumPoints) # convert the input data into numeric arrays of float assuming no headers and filter the missing values. try: split_data = isprintText.split() float_data = map(self.__filter_missing, split_data) array_data = numpy.asarray(float_data) array_data = numpy.reshape(array_data,(-1,self.__parameter_count)) except: traceback.print_exc() raise ValueError, 'input text is not parseable' # find min, max of x (time) if startTime == None: xMin = array_data[0,0] else: xMin = startTime if endTime == None: xMax = array_data[-1,0] else: xMax = endTime # find min, max of y, not including missing yMin = None yMax = None for y in array_data[:,1]: if y == self.__missing: continue if yMin == None: yMin = y elif yMin > y: yMin = y if yMax == None: yMax = y elif yMax < y: yMax = y if yMin == None: raise ValueError, 'No valid y data found' # select the plot size if size == 'small': matplotlib.pylab.figure(1, figsize=(9,3), facecolor = 'w') elif size == 'wide': matplotlib.pylab.figure(1, figsize=(10,4), facecolor = 'w') elif size == 'large': matplotlib.pylab.figure(1, figsize=(10,6), facecolor = 'w') if useAbsoluteTime: # leave room for rotated datetime string if size == 'large': matplotlib.pylab.axes([0.1, 0.2, 0.8, 0.7]) elif size == 'wide': matplotlib.pylab.axes([0.07, 0.2, 0.66, 0.7]) elif size == 'small': matplotlib.pylab.axes([0.14, 0.18, 0.83, 0.7]) matplotlib.pylab.scatter(array_data[:,0],array_data[:,1]) thisFont = {'size': fontSize} matplotlib.pylab.rc('font', **thisFont) # pass in the font dict as kwargs matplotlib.pylab.xlabel(xLabelStr, fontsize=fontSize) matplotlib.pylab.ylabel(yLabelStr, fontsize=fontSize) matplotlib.pylab.yticks(fontsize=fontSize) matplotlib.pylab.xlim(xMin, xMax) matplotlib.pylab.title(titleStr, fontsize=fontSize) matplotlib.pylab.grid(True) if useAbsoluteTime: # if plot is less than 24 hours, force ticks to be every 4 hours xmin, xmax = matplotlib.pylab.xlim() xmin = xmin / (60*60) xmax = xmax / (60*60) if noDate == True: if xmax % 4 != 0: newXmax = 4 * (int(xmax/4.0) + 1) else: newXmax = xmax newXLocs = [] newXLabels = [] step = int((xmax-xmin-1)/6)+1 xRange = range(0,int(newXmax-xmin),step) for i in xRange: tmp = (xmin + i)*60*60 newXLocs.append(tmp) if (xmax - xmin) < 1: newXLocs.append(xmax*60*60) newXLabels = convertToAbsoluteTimeStr(newXLocs, noDate=noDate, timezone=timezone) matplotlib.pylab.xticks(newXLocs, newXLabels) else: locs, labels = matplotlib.pylab.xticks() if len(locs) > 5: # truncate by len(locs) / 5 scale = 1 + int(len(locs) / 5) new_locs = [] for i in range(len(locs)): if i % scale == 0: new_locs.append(locs[i]) locs = new_locs newXTicks = convertToAbsoluteTimeStr(locs) matplotlib.pylab.xticks(locs, newXTicks, rotation=15) matplotlib.pylab.xticks(fontsize=fontSize) if yMinimum != None and yMaximum != None: matplotlib.pylab.ylim(yMinimum, yMaximum) elif yMinimum != None and yMaximum == None: matplotlib.pylab.ylim(yMin=yMinimum) elif yMinimum == None and yMaximum != None: matplotlib.pylab.ylim(yMax=yMaximum) # get the handle to the figure now that it has been created so we can manipulate on subsequent calls. #self.__figure = matplotlib.pylab.gcf() matplotlib.pylab.savefig(fullFilename) #matplotlib.pylab.show() matplotlib.pylab.clf() def __truncateIsprint(self, isprintText, maxLines): """__truncateIsprint truncates isprintText to have maxLines at most. """ isprintList = isprintText.split('\n') if len(isprintList) < maxLines: return isprintText else: dropNumber = int(1 + len(isprintList)/maxLines) newline = '\n' newIsprintText = newline.join(isprintList[::dropNumber]) return newIsprintText def __filter_missing(self,x): try: return float(x) except: return self.__missing
Ancestors (in MRO)
Methods
def __init__(
self, isprintText, titleStr, xLabelStr, yLabelStr, fullFilename, size='small', useAbsoluteTime=False, startTime=None, endTime=None, maxNumPoints=None, noTime=False, noDate=False, yMinimum=None, yMaximum=None, timezone=0)
init writes a madScatter plot to a file.
Inputs:
isprintText - a string giving isprint output without headers. First parameter must be UTH or UT1, depending on whether time scale should be relative to the experiment beginning (UTH) or absolute (UT1). The second must be the parameter to be plotted. Any missing data should be written as "missing" or other string that cannot be converted to a float. titleStr - plot title (string) - should describe parameter being plotted xLabelStr - x label string yLabelStr - ylabel string fullFilename - full path of file containing pcolor plot to be saved. Extension must be jpeg or png, or exception thrown. size - size of plot to save. Must be "small", "wide", or "large". Defaults to small. useAbsoluteTime - if true, print time as YYYY-MM-DD HH:MM:SS. If false (default), print time as hour since beginning of experiment (UTH). If useAbsoluteTime is true, first parameter in isprintText must be UT1, if false, it must be UTH. startTime - start plot at given time. If useAbsoluteTime == True, then startTime must be in units of seconds since 1/1/1950. If useAbsoluteTime == False, then startTime must be in units of UTH (hours since midnight UT of first day of experiment). Default is None, which means start at lowest time found. endTime - end plot at given time. If useAbsoluteTime == True, then endTime must be in units of seconds since 1/1/1950. If useAbsoluteTime == False, then endTime must be in units of UTH (hours since midnight UT of first day of experiment). Default is None, which means end at largest time found. maxNumPoints - maximum number of points to plot. If not None, truncate isprintText if needed to have at most maxNumPoints lines. noTime - if True and useAbsoluteTime True, then dates without times printed on x axis. noDate - if True and useAbsoluteTime True, then times without dates printed on x axis. yMinimum - set y minimum. If default=None, use data minimum yMaximum - set y maximum. If default=None, use data maximum timezone - The offset of the local (non-DST) timezone, in seconds west of UTC (negative in most of Western Europe, positive in the US, zero in the UK).
Returns: void
Affects: None
def __init__(self, isprintText, titleStr, xLabelStr, yLabelStr, fullFilename, size = 'small', useAbsoluteTime = False, startTime = None, endTime = None, maxNumPoints = None, noTime = False, noDate = False, yMinimum = None, yMaximum = None, timezone = 0): """__init__ writes a madScatter plot to a file. Inputs: isprintText - a string giving isprint output without headers. First parameter must be UTH or UT1, depending on whether time scale should be relative to the experiment beginning (UTH) or absolute (UT1). The second must be the parameter to be plotted. Any missing data should be written as "missing" or other string that cannot be converted to a float. titleStr - plot title (string) - should describe parameter being plotted xLabelStr - x label string yLabelStr - ylabel string fullFilename - full path of file containing pcolor plot to be saved. Extension must be jpeg or png, or exception thrown. size - size of plot to save. Must be "small", "wide", or "large". Defaults to small. useAbsoluteTime - if true, print time as YYYY-MM-DD HH:MM:SS. If false (default), print time as hour since beginning of experiment (UTH). If useAbsoluteTime is true, first parameter in isprintText must be UT1, if false, it must be UTH. startTime - start plot at given time. If useAbsoluteTime == True, then startTime must be in units of seconds since 1/1/1950. If useAbsoluteTime == False, then startTime must be in units of UTH (hours since midnight UT of first day of experiment). Default is None, which means start at lowest time found. endTime - end plot at given time. If useAbsoluteTime == True, then endTime must be in units of seconds since 1/1/1950. If useAbsoluteTime == False, then endTime must be in units of UTH (hours since midnight UT of first day of experiment). Default is None, which means end at largest time found. maxNumPoints - maximum number of points to plot. If not None, truncate isprintText if needed to have at most maxNumPoints lines. noTime - if True and useAbsoluteTime True, then dates without times printed on x axis. noDate - if True and useAbsoluteTime True, then times without dates printed on x axis. yMinimum - set y minimum. If default=None, use data minimum yMaximum - set y maximum. If default=None, use data maximum timezone - The offset of the local (non-DST) timezone, in seconds west of UTC (negative in most of Western Europe, positive in the US, zero in the UK). Returns: void Affects: None """ self.__missing = 1.0E30 # special value, since numpy doesn't handle NaN self.__parameter_count = 2 # verify input if size not in ('small', 'wide', 'large'): raise ValueError, 'size must be "small", "wide", or "large", not %s' % (str(size)) if size in ('small', 'wide'): fontSize = 12 elif size in ('large'): fontSize = 18 if maxNumPoints != None: isprintText = self.__truncateIsprint(isprintText, maxNumPoints) # convert the input data into numeric arrays of float assuming no headers and filter the missing values. try: split_data = isprintText.split() float_data = map(self.__filter_missing, split_data) array_data = numpy.asarray(float_data) array_data = numpy.reshape(array_data,(-1,self.__parameter_count)) except: traceback.print_exc() raise ValueError, 'input text is not parseable' # find min, max of x (time) if startTime == None: xMin = array_data[0,0] else: xMin = startTime if endTime == None: xMax = array_data[-1,0] else: xMax = endTime # find min, max of y, not including missing yMin = None yMax = None for y in array_data[:,1]: if y == self.__missing: continue if yMin == None: yMin = y elif yMin > y: yMin = y if yMax == None: yMax = y elif yMax < y: yMax = y if yMin == None: raise ValueError, 'No valid y data found' # select the plot size if size == 'small': matplotlib.pylab.figure(1, figsize=(9,3), facecolor = 'w') elif size == 'wide': matplotlib.pylab.figure(1, figsize=(10,4), facecolor = 'w') elif size == 'large': matplotlib.pylab.figure(1, figsize=(10,6), facecolor = 'w') if useAbsoluteTime: # leave room for rotated datetime string if size == 'large': matplotlib.pylab.axes([0.1, 0.2, 0.8, 0.7]) elif size == 'wide': matplotlib.pylab.axes([0.07, 0.2, 0.66, 0.7]) elif size == 'small': matplotlib.pylab.axes([0.14, 0.18, 0.83, 0.7]) matplotlib.pylab.scatter(array_data[:,0],array_data[:,1]) thisFont = {'size': fontSize} matplotlib.pylab.rc('font', **thisFont) # pass in the font dict as kwargs matplotlib.pylab.xlabel(xLabelStr, fontsize=fontSize) matplotlib.pylab.ylabel(yLabelStr, fontsize=fontSize) matplotlib.pylab.yticks(fontsize=fontSize) matplotlib.pylab.xlim(xMin, xMax) matplotlib.pylab.title(titleStr, fontsize=fontSize) matplotlib.pylab.grid(True) if useAbsoluteTime: # if plot is less than 24 hours, force ticks to be every 4 hours xmin, xmax = matplotlib.pylab.xlim() xmin = xmin / (60*60) xmax = xmax / (60*60) if noDate == True: if xmax % 4 != 0: newXmax = 4 * (int(xmax/4.0) + 1) else: newXmax = xmax newXLocs = [] newXLabels = [] step = int((xmax-xmin-1)/6)+1 xRange = range(0,int(newXmax-xmin),step) for i in xRange: tmp = (xmin + i)*60*60 newXLocs.append(tmp) if (xmax - xmin) < 1: newXLocs.append(xmax*60*60) newXLabels = convertToAbsoluteTimeStr(newXLocs, noDate=noDate, timezone=timezone) matplotlib.pylab.xticks(newXLocs, newXLabels) else: locs, labels = matplotlib.pylab.xticks() if len(locs) > 5: # truncate by len(locs) / 5 scale = 1 + int(len(locs) / 5) new_locs = [] for i in range(len(locs)): if i % scale == 0: new_locs.append(locs[i]) locs = new_locs newXTicks = convertToAbsoluteTimeStr(locs) matplotlib.pylab.xticks(locs, newXTicks, rotation=15) matplotlib.pylab.xticks(fontsize=fontSize) if yMinimum != None and yMaximum != None: matplotlib.pylab.ylim(yMinimum, yMaximum) elif yMinimum != None and yMaximum == None: matplotlib.pylab.ylim(yMin=yMinimum) elif yMinimum == None and yMaximum != None: matplotlib.pylab.ylim(yMax=yMaximum) # get the handle to the figure now that it has been created so we can manipulate on subsequent calls. #self.__figure = matplotlib.pylab.gcf() matplotlib.pylab.savefig(fullFilename) #matplotlib.pylab.show() matplotlib.pylab.clf()
class madXYScatterPlot
madXYScatterPlot is the class the produces XY scatter plots.
Change History:
Written by "Brandon Scott Fines":mailto:bfines@haystack.mit.edu Aug 2, 2006 Written by "Bill Rideout":mailto:brideout@haystack.mit.edu Aug 2, 2006
class madXYScatterPlot: """madXYScatterPlot is the class the produces XY scatter plots. Change History: Written by "Brandon Scott Fines":mailto:bfines@haystack.mit.edu Aug 2, 2006 Written by "Bill Rideout":mailto:brideout@haystack.mit.edu Aug 2, 2006 """ def __init__(self,inputText, titleStr, xLabelStr, yLabelStr, fullFilename, size='small', lowBound=None, highBound=None, maxNumPoints=None, yLegend=None): """ Inputs: inputText - string of values to be plotted. The formatting is as follows: xval yval xval yval xval yval titleStr - title of the Plot xLabelStr - label for the x axis yLabelStr - label for the y axis fullFilename - full file path to save the resulting picture to size - size of plot to be saved. Must be 'small','wide', or 'large'. defaults to 'small'. lowBound - lower bound on the x-axis value. If no bound is specified, the lowest value found in inputText will be used. highBound - upper bound on the x-axis value. If no bound is specified, the highest value found in inputText will be used. maxNumPoints - maximum number of points to be plotted. Outputs: None Affects: Creates a scatter plot using matplotlib and writes that to the file designated by the variable 'fullFilename' Exceptions: ValueError if lowBound or highBound cannot be converted to a float value Non-standard python modules used: matplotlib """ #verify input if size not in ('small','wide','large'): raise ValueError, 'size must be "small","wide", or "large", not %s'%(str(size)) if size in ('small','wide'): fontSize = 12 elif size in 'large': fontSize = 18 if maxNumPoints !=None: inputText = self.__truncateInput(inputText, maxNumPoints) if lowBound !=None: #check that it is a number try: lowBound = float(lowBound) except ValueError: raise ValueError, 'lowBound not a number' try: highBound = float(highBound) except: raise ValueError, 'lowBound not a number' #convert the input data into numeric arrays x=[] y=[] split_data = inputText.split() #send x-values to x, y-values to y i=0 while i <len(split_data)-1: try: newX = float(split_data[i]) newY = float(split_data[i+1]) x.append(newX) y.append(newY) except: pass i=i+2 xlow =None xhigh = None # set min and max in x if specified if lowBound !=None and highBound !=None: xlow = lowBound xhigh = highBound elif lowBound !=None and highBound==None: #find the upper bound in x for i in x: if xhigh==None: xhigh = i if i>xhigh: xhigh = i xlow = lowBound elif lowBound==None and highBound !=None: #find the lower bound in x for i in x: if xlow==None: xlow = i if i<xlow: xlow = i xhigh=highBound else: #find lower and upper bounds for i in x: if xlow==None: xlow = i elif i<xlow: xlow = i if xhigh==None: xhigh = i elif i>xhigh: xhigh = i #find upper and lower bounds in y ylow = None yhigh = None for i in y: if ylow==None: ylow = i elif i<ylow: ylow = i if yhigh==None: yhigh = i elif i>yhigh: yhigh = i #check for good numbers if ylow == None: raise ValueError, 'no valid y data found' #select plot sizes if size=='small': matplotlib.pylab.figure(1,figsize=(6,4),facecolor='w') elif size=='wide': matplotlib.pylab.figure(1,figsize=(10,4),facecolor='w') elif size=='large': matplotlib.pylab.figure(1,figsize=(12,6),facecolor='w') #draw scatter plot #matplotlib.pylab.scatter(x,y) matplotlib.pylab.plot(x,y, 'gd',ms=5,mew=0.5) thisFont = {'size' : fontSize} matplotlib.pylab.rc('font', **thisFont) #pass in font dict as kwargs matplotlib.pylab.xlabel(xLabelStr,fontsize=fontSize) matplotlib.pylab.ylabel(yLabelStr,fontsize=fontSize) matplotlib.pylab.yticks(fontsize=fontSize) matplotlib.pylab.xticks(fontsize=fontSize) matplotlib.pylab.xlim(xlow,xhigh) matplotlib.pylab.title(titleStr,fontsize=fontSize) matplotlib.pylab.grid(True) if yLegend != None: matplotlib.pylab.legend(yLegend,numpoints=1,handlelength = 0.05) #save the figure matplotlib.pylab.savefig(fullFilename) matplotlib.pylab.clf()
Ancestors (in MRO)
Methods
def __init__(
self, inputText, titleStr, xLabelStr, yLabelStr, fullFilename, size='small', lowBound=None, highBound=None, maxNumPoints=None, yLegend=None)
Inputs:
inputText - string of values to be plotted. The formatting is as follows: xval yval xval yval xval yval titleStr - title of the Plot xLabelStr - label for the x axis yLabelStr - label for the y axis fullFilename - full file path to save the resulting picture to size - size of plot to be saved. Must be 'small','wide', or 'large'. defaults to 'small'. lowBound - lower bound on the x-axis value. If no bound is specified, the lowest value found in inputText will be used. highBound - upper bound on the x-axis value. If no bound is specified, the highest value found in inputText will be used. maxNumPoints - maximum number of points to be plotted.
Outputs: None
Affects: Creates a scatter plot using matplotlib and writes that to the file designated by the variable 'fullFilename'
Exceptions: ValueError if lowBound or highBound cannot be converted to a float value
Non-standard python modules used:
matplotlib
def __init__(self,inputText, titleStr, xLabelStr, yLabelStr, fullFilename, size='small', lowBound=None, highBound=None, maxNumPoints=None, yLegend=None): """ Inputs: inputText - string of values to be plotted. The formatting is as follows: xval yval xval yval xval yval titleStr - title of the Plot xLabelStr - label for the x axis yLabelStr - label for the y axis fullFilename - full file path to save the resulting picture to size - size of plot to be saved. Must be 'small','wide', or 'large'. defaults to 'small'. lowBound - lower bound on the x-axis value. If no bound is specified, the lowest value found in inputText will be used. highBound - upper bound on the x-axis value. If no bound is specified, the highest value found in inputText will be used. maxNumPoints - maximum number of points to be plotted. Outputs: None Affects: Creates a scatter plot using matplotlib and writes that to the file designated by the variable 'fullFilename' Exceptions: ValueError if lowBound or highBound cannot be converted to a float value Non-standard python modules used: matplotlib """ #verify input if size not in ('small','wide','large'): raise ValueError, 'size must be "small","wide", or "large", not %s'%(str(size)) if size in ('small','wide'): fontSize = 12 elif size in 'large': fontSize = 18 if maxNumPoints !=None: inputText = self.__truncateInput(inputText, maxNumPoints) if lowBound !=None: #check that it is a number try: lowBound = float(lowBound) except ValueError: raise ValueError, 'lowBound not a number' try: highBound = float(highBound) except: raise ValueError, 'lowBound not a number' #convert the input data into numeric arrays x=[] y=[] split_data = inputText.split() #send x-values to x, y-values to y i=0 while i <len(split_data)-1: try: newX = float(split_data[i]) newY = float(split_data[i+1]) x.append(newX) y.append(newY) except: pass i=i+2 xlow =None xhigh = None # set min and max in x if specified if lowBound !=None and highBound !=None: xlow = lowBound xhigh = highBound elif lowBound !=None and highBound==None: #find the upper bound in x for i in x: if xhigh==None: xhigh = i if i>xhigh: xhigh = i xlow = lowBound elif lowBound==None and highBound !=None: #find the lower bound in x for i in x: if xlow==None: xlow = i if i<xlow: xlow = i xhigh=highBound else: #find lower and upper bounds for i in x: if xlow==None: xlow = i elif i<xlow: xlow = i if xhigh==None: xhigh = i elif i>xhigh: xhigh = i #find upper and lower bounds in y ylow = None yhigh = None for i in y: if ylow==None: ylow = i elif i<ylow: ylow = i if yhigh==None: yhigh = i elif i>yhigh: yhigh = i #check for good numbers if ylow == None: raise ValueError, 'no valid y data found' #select plot sizes if size=='small': matplotlib.pylab.figure(1,figsize=(6,4),facecolor='w') elif size=='wide': matplotlib.pylab.figure(1,figsize=(10,4),facecolor='w') elif size=='large': matplotlib.pylab.figure(1,figsize=(12,6),facecolor='w') #draw scatter plot #matplotlib.pylab.scatter(x,y) matplotlib.pylab.plot(x,y, 'gd',ms=5,mew=0.5) thisFont = {'size' : fontSize} matplotlib.pylab.rc('font', **thisFont) #pass in font dict as kwargs matplotlib.pylab.xlabel(xLabelStr,fontsize=fontSize) matplotlib.pylab.ylabel(yLabelStr,fontsize=fontSize) matplotlib.pylab.yticks(fontsize=fontSize) matplotlib.pylab.xticks(fontsize=fontSize) matplotlib.pylab.xlim(xlow,xhigh) matplotlib.pylab.title(titleStr,fontsize=fontSize) matplotlib.pylab.grid(True) if yLegend != None: matplotlib.pylab.legend(yLegend,numpoints=1,handlelength = 0.05) #save the figure matplotlib.pylab.savefig(fullFilename) matplotlib.pylab.clf()
class madXYwithErrorPlot
madXYwithErrorPlot is the class the produces two dimensional scatter plots of x versus y more its error. Written by "Miguel Urco":mailto:murco@jro.igp.gob.pe Jul 2, 2009
class madXYwithErrorPlot: """madXYwithErrorPlot is the class the produces two dimensional scatter plots of x versus y more its error. Written by "Miguel Urco":mailto:murco@jro.igp.gob.pe Jul 2, 2009 """ def __init__(self, isprintText, titleStr, xLabelStr, yLabelStr, fullFilename, size = 'small', useAbsoluteTime = False, startTime = None, endTime = None, maxNumPoints = None, noTime = False, noDate = False, yMinimum = None, yMaximum = None, timezone = 0): """__init__ writes a madScatter plot to a file. Inputs: isprintText - a string giving isprint output without headers. First of three parameters must be UTH or UT1, depending on whether time scale should be relative to the experiment beginning (UTH) or absolute (UT1). The second must be the parameter to be plotted. Any missing data should be written as "missing" or other string that cannot be converted to a float. titleStr - plot title (string) - should describe parameter being plotted xLabelStr - x label string yLabelStr - y label string fullFilename - full path of file containing pcolor plot to be saved. Extension must be jpeg or png, or exception thrown. size - size of plot to save. Must be "small", "wide", or "large". Defaults to small. useAbsoluteTime - if true, print time as YYYY-MM-DD HH:MM:SS. If false (default), print time as hour since beginning of experiment (UTH). If useAbsoluteTime is true, first parameter in isprintText must be UT1, if false, it must be UTH. startTime - start plot at given time. If useAbsoluteTime == True, then startTime must be in units of seconds since 1/1/1950. If useAbsoluteTime == False, then startTime must be in units of UTH (hours since midnight UT of first day of experiment). Default is None, which means start at lowest time found. endTime - end plot at given time. If useAbsoluteTime == True, then endTime must be in units of seconds since 1/1/1950. If useAbsoluteTime == False, then endTime must be in units of UTH (hours since midnight UT of first day of experiment). Default is None, which means end at largest time found. maxNumPoints - maximum number of points to plot. If not None, truncate isprintText if needed to have at most maxNumPoints lines. noDate - if True and useAbsoluteTime True, then times without dates printed on x axis. yMinimum - set y minimum. If default=None, use data minimum yMaximum - set y maximum. If default=None, use data maximum timezone - The offset of the local (non-DST) timezone, in seconds west of UTC (negative in most of Western Europe, positive in the US, zero in the UK). Returns: void Affects: None Now removes all lines with missing """ self.__missing = 1.0E30 # special value, since numpy doesn't handle NaN self.__parameter_count = 3 # verify input if size not in ('small', 'wide', 'large'): raise ValueError, 'size must be "small", "wide", or "large", not %s' % (str(size)) if size in ('small', 'wide'): fontSize = 12 elif size in ('large'): fontSize = 18 # filter out missing lines newIsprint = '' lines = isprintText.split('\n') for line in lines: try: items = line.split() float(items[0]) float(items[1]) float(items[2]) newIsprint += line + ' ' except: continue isprintText = newIsprint if maxNumPoints != None: isprintText = self.__truncateIsprint(isprintText, maxNumPoints) # convert the input data into numeric arrays of float assuming no headers and filter the missing values. try: split_data = isprintText.split() float_data = map(self.__filter_missing, split_data) array_data = numpy.asarray(float_data) array_data = numpy.reshape(array_data,(-1,self.__parameter_count)) except: traceback.print_exc() raise ValueError, 'input text is not parseable' # find min, max of x (time) if startTime == None: xMin = array_data[0,0] else: xMin = startTime if endTime == None: xMax = array_data[-1,0] else: xMax = endTime # find min, max of y, not including missing yMin = None yMax = None for y in array_data[:,1]: if y == self.__missing: continue if yMin == None: yMin = y elif yMin > y: yMin = y if yMax == None: yMax = y elif yMax < y: yMax = y if yMin == None: raise ValueError, 'No valid y data found' # select the plot size if size == 'small': matplotlib.pylab.figure(1, figsize=(8,3), facecolor = 'w') matplotlib.pylab.axes([0.11, 0.18, 0.78, 0.7]) elif size == 'wide': matplotlib.pylab.figure(1, figsize=(10,4), facecolor = 'w') elif size == 'large': matplotlib.pylab.figure(1, figsize=(10,6), facecolor = 'w') if useAbsoluteTime: # leave room for rotated datetime string if size == 'large': matplotlib.pylab.axes([0.1, 0.2, 0.8, 0.7]) elif size == 'wide': matplotlib.pylab.axes([0.07, 0.2, 0.66, 0.7]) elif size == 'small': matplotlib.pylab.axes([0.1, 0.18, 0.87, 0.7]) matplotlib.pylab.errorbar(array_data[:,0],array_data[:,2],array_data[:,1],ecolor='red',fmt='s',mfc='red',mec='green',ms=1,mew=1) thisFont = {'size': fontSize} matplotlib.pylab.rc('font', **thisFont) # pass in the font dict as kwargs matplotlib.pylab.xlabel(xLabelStr, fontsize=fontSize) matplotlib.pylab.ylabel(yLabelStr, fontsize=fontSize) matplotlib.pylab.yticks(fontsize=fontSize) matplotlib.pylab.xlim(xMin, xMax) matplotlib.pylab.title(titleStr, fontsize=fontSize) matplotlib.pylab.grid(True) if yMinimum != None and yMaximum != None: matplotlib.pylab.ylim(yMinimum, yMaximum) elif yMinimum != None and yMaximum == None: matplotlib.pylab.ylim(yMin=yMinimum) elif yMinimum == None and yMaximum != None: matplotlib.pylab.ylim(yMax=yMaximum) if useAbsoluteTime: # if plot is less than 24 hours, force ticks to be every 4 hours xmin, xmax = matplotlib.pylab.xlim() xmin = xmin / (60*60) xmax = xmax / (60*60) if noDate == True: if xmax % 4 != 0: newXmax = 4 * (int(xmax/4.0)+1) else: newXmax = xmax newXLocs = [] newXLabels = [] step = int((xmax-xmin-1)/6)+1 xRange = range(0,int(newXmax-xmin),step) for i in xRange: tmp = (xmin + i)*60*60 newXLocs.append(tmp) if (xmax - xmin) < 1: newXLocs.append(xmax*60*60) newXLabels = convertToAbsoluteTimeStr(newXLocs, noDate=noDate, timezone=timezone) matplotlib.pylab.xticks(newXLocs, newXLabels) else: locs, labels = matplotlib.pylab.xticks() if len(locs) > 5: # truncate by len(locs) / 5 scale = 1 + int(len(locs) / 5) new_locs = [] for i in range(len(locs)): if i % scale == 0: new_locs.append(locs[i]) locs = new_locs newXTicks = convertToAbsoluteTimeStr(locs) matplotlib.pylab.xticks(locs, newXTicks, rotation=15) matplotlib.pylab.xticks(fontsize=fontSize) # get the handle to the figure now that it has been created so we can manipulate on subsequent calls. #self.__figure = matplotlib.pylab.gcf() matplotlib.pylab.savefig(fullFilename) #matplotlib.pylab.show() matplotlib.pylab.clf() def __truncateInput(self,inputStr,maxLines): """__truncateInput truncates inputStr to have maxLines at most """ inputList = inputStr.split('\n') if len(inputList)<maxLines: return inputStr else: dropNumber = int(len(inputList)/maxLines) newline = '\n' newInputText = newline.join(inputList[::dropNumber]) return newInputText def __filter_missing(self,x): try: return float(x) except: return self.__missing
Ancestors (in MRO)
Methods
def __init__(
self, isprintText, titleStr, xLabelStr, yLabelStr, fullFilename, size='small', useAbsoluteTime=False, startTime=None, endTime=None, maxNumPoints=None, noTime=False, noDate=False, yMinimum=None, yMaximum=None, timezone=0)
init writes a madScatter plot to a file.
Inputs:
isprintText - a string giving isprint output without headers. First of three parameters must be UTH or UT1, depending on whether time scale should be relative to the experiment beginning (UTH) or absolute (UT1). The second must be the parameter to be plotted. Any missing data should be written as "missing" or other string that cannot be converted to a float. titleStr - plot title (string) - should describe parameter being plotted xLabelStr - x label string yLabelStr - y label string fullFilename - full path of file containing pcolor plot to be saved. Extension must be jpeg or png, or exception thrown. size - size of plot to save. Must be "small", "wide", or "large". Defaults to small. useAbsoluteTime - if true, print time as YYYY-MM-DD HH:MM:SS. If false (default), print time as hour since beginning of experiment (UTH). If useAbsoluteTime is true, first parameter in isprintText must be UT1, if false, it must be UTH. startTime - start plot at given time. If useAbsoluteTime == True, then startTime must be in units of seconds since 1/1/1950. If useAbsoluteTime == False, then startTime must be in units of UTH (hours since midnight UT of first day of experiment). Default is None, which means start at lowest time found. endTime - end plot at given time. If useAbsoluteTime == True, then endTime must be in units of seconds since 1/1/1950. If useAbsoluteTime == False, then endTime must be in units of UTH (hours since midnight UT of first day of experiment). Default is None, which means end at largest time found. maxNumPoints - maximum number of points to plot. If not None, truncate isprintText if needed to have at most maxNumPoints lines. noDate - if True and useAbsoluteTime True, then times without dates printed on x axis. yMinimum - set y minimum. If default=None, use data minimum yMaximum - set y maximum. If default=None, use data maximum timezone - The offset of the local (non-DST) timezone, in seconds west of UTC (negative in most of Western Europe, positive in the US, zero in the UK).
Returns: void
Affects: None
Now removes all lines with missing
def __init__(self, isprintText, titleStr, xLabelStr, yLabelStr, fullFilename, size = 'small', useAbsoluteTime = False, startTime = None, endTime = None, maxNumPoints = None, noTime = False, noDate = False, yMinimum = None, yMaximum = None, timezone = 0): """__init__ writes a madScatter plot to a file. Inputs: isprintText - a string giving isprint output without headers. First of three parameters must be UTH or UT1, depending on whether time scale should be relative to the experiment beginning (UTH) or absolute (UT1). The second must be the parameter to be plotted. Any missing data should be written as "missing" or other string that cannot be converted to a float. titleStr - plot title (string) - should describe parameter being plotted xLabelStr - x label string yLabelStr - y label string fullFilename - full path of file containing pcolor plot to be saved. Extension must be jpeg or png, or exception thrown. size - size of plot to save. Must be "small", "wide", or "large". Defaults to small. useAbsoluteTime - if true, print time as YYYY-MM-DD HH:MM:SS. If false (default), print time as hour since beginning of experiment (UTH). If useAbsoluteTime is true, first parameter in isprintText must be UT1, if false, it must be UTH. startTime - start plot at given time. If useAbsoluteTime == True, then startTime must be in units of seconds since 1/1/1950. If useAbsoluteTime == False, then startTime must be in units of UTH (hours since midnight UT of first day of experiment). Default is None, which means start at lowest time found. endTime - end plot at given time. If useAbsoluteTime == True, then endTime must be in units of seconds since 1/1/1950. If useAbsoluteTime == False, then endTime must be in units of UTH (hours since midnight UT of first day of experiment). Default is None, which means end at largest time found. maxNumPoints - maximum number of points to plot. If not None, truncate isprintText if needed to have at most maxNumPoints lines. noDate - if True and useAbsoluteTime True, then times without dates printed on x axis. yMinimum - set y minimum. If default=None, use data minimum yMaximum - set y maximum. If default=None, use data maximum timezone - The offset of the local (non-DST) timezone, in seconds west of UTC (negative in most of Western Europe, positive in the US, zero in the UK). Returns: void Affects: None Now removes all lines with missing """ self.__missing = 1.0E30 # special value, since numpy doesn't handle NaN self.__parameter_count = 3 # verify input if size not in ('small', 'wide', 'large'): raise ValueError, 'size must be "small", "wide", or "large", not %s' % (str(size)) if size in ('small', 'wide'): fontSize = 12 elif size in ('large'): fontSize = 18 # filter out missing lines newIsprint = '' lines = isprintText.split('\n') for line in lines: try: items = line.split() float(items[0]) float(items[1]) float(items[2]) newIsprint += line + ' ' except: continue isprintText = newIsprint if maxNumPoints != None: isprintText = self.__truncateIsprint(isprintText, maxNumPoints) # convert the input data into numeric arrays of float assuming no headers and filter the missing values. try: split_data = isprintText.split() float_data = map(self.__filter_missing, split_data) array_data = numpy.asarray(float_data) array_data = numpy.reshape(array_data,(-1,self.__parameter_count)) except: traceback.print_exc() raise ValueError, 'input text is not parseable' # find min, max of x (time) if startTime == None: xMin = array_data[0,0] else: xMin = startTime if endTime == None: xMax = array_data[-1,0] else: xMax = endTime # find min, max of y, not including missing yMin = None yMax = None for y in array_data[:,1]: if y == self.__missing: continue if yMin == None: yMin = y elif yMin > y: yMin = y if yMax == None: yMax = y elif yMax < y: yMax = y if yMin == None: raise ValueError, 'No valid y data found' # select the plot size if size == 'small': matplotlib.pylab.figure(1, figsize=(8,3), facecolor = 'w') matplotlib.pylab.axes([0.11, 0.18, 0.78, 0.7]) elif size == 'wide': matplotlib.pylab.figure(1, figsize=(10,4), facecolor = 'w') elif size == 'large': matplotlib.pylab.figure(1, figsize=(10,6), facecolor = 'w') if useAbsoluteTime: # leave room for rotated datetime string if size == 'large': matplotlib.pylab.axes([0.1, 0.2, 0.8, 0.7]) elif size == 'wide': matplotlib.pylab.axes([0.07, 0.2, 0.66, 0.7]) elif size == 'small': matplotlib.pylab.axes([0.1, 0.18, 0.87, 0.7]) matplotlib.pylab.errorbar(array_data[:,0],array_data[:,2],array_data[:,1],ecolor='red',fmt='s',mfc='red',mec='green',ms=1,mew=1) thisFont = {'size': fontSize} matplotlib.pylab.rc('font', **thisFont) # pass in the font dict as kwargs matplotlib.pylab.xlabel(xLabelStr, fontsize=fontSize) matplotlib.pylab.ylabel(yLabelStr, fontsize=fontSize) matplotlib.pylab.yticks(fontsize=fontSize) matplotlib.pylab.xlim(xMin, xMax) matplotlib.pylab.title(titleStr, fontsize=fontSize) matplotlib.pylab.grid(True) if yMinimum != None and yMaximum != None: matplotlib.pylab.ylim(yMinimum, yMaximum) elif yMinimum != None and yMaximum == None: matplotlib.pylab.ylim(yMin=yMinimum) elif yMinimum == None and yMaximum != None: matplotlib.pylab.ylim(yMax=yMaximum) if useAbsoluteTime: # if plot is less than 24 hours, force ticks to be every 4 hours xmin, xmax = matplotlib.pylab.xlim() xmin = xmin / (60*60) xmax = xmax / (60*60) if noDate == True: if xmax % 4 != 0: newXmax = 4 * (int(xmax/4.0)+1) else: newXmax = xmax newXLocs = [] newXLabels = [] step = int((xmax-xmin-1)/6)+1 xRange = range(0,int(newXmax-xmin),step) for i in xRange: tmp = (xmin + i)*60*60 newXLocs.append(tmp) if (xmax - xmin) < 1: newXLocs.append(xmax*60*60) newXLabels = convertToAbsoluteTimeStr(newXLocs, noDate=noDate, timezone=timezone) matplotlib.pylab.xticks(newXLocs, newXLabels) else: locs, labels = matplotlib.pylab.xticks() if len(locs) > 5: # truncate by len(locs) / 5 scale = 1 + int(len(locs) / 5) new_locs = [] for i in range(len(locs)): if i % scale == 0: new_locs.append(locs[i]) locs = new_locs newXTicks = convertToAbsoluteTimeStr(locs) matplotlib.pylab.xticks(locs, newXTicks, rotation=15) matplotlib.pylab.xticks(fontsize=fontSize) # get the handle to the figure now that it has been created so we can manipulate on subsequent calls. #self.__figure = matplotlib.pylab.gcf() matplotlib.pylab.savefig(fullFilename) #matplotlib.pylab.show() matplotlib.pylab.clf()
class scanPlotter
scanPlotter is the class that produces a series of scan plots for a single Madrigal file
Non-standard Python modules used: matplotlib
Change history:
Written by "Bill Rideout":mailto:wrideout@haystack.mit.edu Jul. 26, 2006
class scanPlotter: """scanPlotter is the class that produces a series of scan plots for a single Madrigal file Non-standard Python modules used: matplotlib Change history: Written by "Bill Rideout":mailto:wrideout@haystack.mit.edu Jul. 26, 2006 """ def __init__(self, madFile, madDBObj=None): """__init__ initializes a scanPlotter object. Inputs: madFile - the Madrigal file to be analyzed. Must contain SCNTYP and CYCN parameters. madDBObj - a madrigal.metadata.MadrigalDB object. If None (default), one created Returns: void Affects: sets self.madFile, self.madDBObj """ if os.access(madFile, os.R_OK): self.madFile = madFile else: raise IOError, 'unable to read %s' % (str(madFile)) if madDBObj == None: self.madDBObj = madrigal.metadata.MadrigalDB() else: self.madDBObj = madDBObj def plotAllScans(self, scanType, fullFilenameTemplate, plotParm, size = 'small', xMinimum = None, xMaximum = None, yMinimum = None, yMaximum = None, xGridSize = None, yGridSize = None, minColormap = None, maxColormap = None, colorMap = matplotlib.cm.jet, maxNumLines = None, filterStr = ''): """plotAllScans creates a series of az or el scans. Inputs: scanType - must be 'az' or 'el' fullFilename - full path of file containing pcolor plot to be saved. Each image created will have _#.png appended, with # starting at 0 plotParm - mnemonic of parameter to be plotted. size - size of plot to save. Must be "small", "wide", or "large". Defaults to small. xMinimum = minumum x value. If None (default), uses lowest x value found for each scan. xMaximum = maximum x value. If None (default), uses highest x value found for each scan. yMinimum = minumum y value. If None (default), uses lowest y value found for each scan. yMaximum = maximum y value. If None (default), uses highest y value found for each scan. minColormap - minimum parameter value (defaults to lowest parameter value) maxColormap - maximum parameter value (defaults to highest parameter value). However, if both minColormap and maxColormap == None, autoscaling applied. colorMap - sets colormap. It not given, defaults to matplotlib.cm.jet maxNumLine - max number of lines in isprintText before truncating. If None, no truncation filterStr - a filter string to pass to isprint. Defaults to no filtering Returns - a list of tuples, where each tuple has two items: 1. time string, 2. metadata string in form for scanTab.txt. List length = number of plots created """ if scanType not in ('az', 'el'): raise ValueError, 'scantype must be az or el, not %s' % (str(scanType)) self.scanType = scanType retList = [] # handle ion velocity if plotParm.lower() == 'vo': cmap = madrigal.ui.madrigalPlot.get_vo_cmap() else: cmap = matplotlib.cm.jet # create isprint string parms = 'ut1,scntyp,cycn,%s,gdalt,gdlat,glon,azm,elm,gcdist' % (plotParm.strip()) isprintStr = getIsprintString(self.madFile, parms, filterStr) try: scanList = self.createScanInfoList(isprintStr) except: traceback.print_exc() return (retList) # loop through each scan scanFailureCount = 0 # keep track of how many scans fail for i in range(len(scanList)): scanCount = i - scanFailureCount scanInfo = scanList[i] try: startDateStr = self.getDateStrFromUT(scanInfo[1]) except: # no scans may have been found continue endDateStr = self.getTimeStrFromUT(scanInfo[4]) # create title if scanType == 'el': if scanInfo[3] > scanInfo[6]: ind = 'down' direction = 1 else: ind = 'up' direction = 0 titleStr = 'El %s scan (%s) %s-%s, az=%i' % (plotParm, ind, startDateStr, endDateStr, int(scanInfo[2])) timeStr = '%s-%s' % (startDateStr, endDateStr) metaStr = 'El scan: startTime %i el %f az %f stopTime %i el %f az %f dir %i' % (scanInfo[1], scanInfo[3], scanInfo[2], scanInfo[4], scanInfo[6], scanInfo[5], direction) retList.append((timeStr,metaStr)) if scanInfo[7] == 'Gdlat': xLabelStr = 'Geodetic latitude' xGridSize = 1.0 elif scanInfo[7] == 'Glon': xLabelStr = 'Longitude' xGridSize = 1.0 elif scanInfo[7] == 'Gcdist': xLabelStr = 'Ground distance in km' xGridSize = 100.0 xLabelStr = '' yLabelStr = 'Altitude (km)' if xGridSize == None: xGridSize = 1.0 if yGridSize == None: yGridSize = 20.0 else: if scanInfo[2] > scanInfo[5]: ind = 'ccw' direction = 1 else: ind = 'cw' direction = 0 titleStr = 'Az %s scan (%s) %s-%s, el=%i' % (plotParm, ind, startDateStr, endDateStr, int(scanInfo[3])) timeStr = '%s-%s' % (startDateStr, endDateStr) metaStr = 'Az scan: startTime %i az %f el %f stopTime %i az %f el %f dir %i' % (scanInfo[1], scanInfo[2], scanInfo[3], scanInfo[4], scanInfo[5], scanInfo[6], direction) retList.append((timeStr,metaStr)) xLabelStr = 'Longitude' yLabelStr = 'Geodetic latitude' xGridSize = 1.0 yGridSize = 1.0 name = '%s_%06i.png' % (fullFilenameTemplate, scanCount) try: madPcolorScan(scanInfo[0], xGridSize, yGridSize, titleStr, xLabelStr, yLabelStr, name, minColormap = minColormap, maxColormap = maxColormap, colorMap = cmap) except: print 'Problem creating scan %s' % (str(retList[-1])) traceback.print_exc() scanFailureCount += 1 retList.remove(retList[-1]) return (retList) def plotAllWedgeScans(self, scanType, fullFilenameTemplate, plotParm, size = 'small', xMinimum = None, xMaximum = None, yMinimum = None, yMaximum = None, minColormap = None, maxColormap = None, colorMap = matplotlib.cm.jet, maxNumLines = None, filterStr = '', addTitle = '', includeKml = False, radarName = None, radarDesc = None): """plotAllWedgeScans creates a series of az or el scans. Similar to plotAllScans, except produces fancier wedge plots with uniform scalling. Inputs: scanType - must be 'az' or 'el' fullFilename - full path of file containing pcolor plot to be saved. Each image created will have _#.png appended, with # starting at 0 plotParm - mnemonic of parameter to be plotted. size - size of plot to save. Must be "small", "wide", or "large". Defaults to small. xMinimum = minumum x value. If None (default), uses lowest x value found for each scan. xMaximum = maximum x value. If None (default), uses highest x value found for each scan. yMinimum = minumum y value. If None (default), uses lowest y value found for each scan. yMaximum = maximum y value. If None (default), uses highest y value found for each scan. minColormap - minimum parameter value (defaults to lowest parameter value) maxColormap - maximum parameter value (defaults to highest parameter value). However, if both minColormap and maxColormap == None, autoscaling applied. colorMap - sets colormap. It not given, defaults to matplotlib.cm.jet maxNumLine - max number of lines in isprintText before truncating. If None, no truncation filterStr - a filter string to pass to isprint. Defaults to no filtering addTitle - a string with additional title. If empty string (the default), no additional title string. includeKml - if True, create a corresponding kml file for every png file. Same names as png files, except extension = .kml. If False, do not. radarName - name to label radar placemark if kml generated. radarDesc - description text for radar placemark if kml generated Returns - a list of tuples, where each tuple has two items: 1. time string, 2. metadata string in form for scanTab.txt. List length = number of plots created """ if scanType not in ('az', 'el'): raise ValueError, 'scantype must be az or el, not %s' % (str(scanType)) self.scanType = scanType if scanType == 'az': wedgeScanType = 'az' retList = [] # handle ion velocity if plotParm.lower() == 'vo': cmap = madrigal.ui.madrigalPlot.get_vo_cmap() else: cmap = matplotlib.cm.jet # create isprint string parms = 'ut1,scntyp,cycn,%s,gdalt,gdlat,glon,azm,elm,gcdist,gdlatr,gdlonr,galtr,range,az1,az2,el1,el2' % (plotParm.strip()) filterStr += ' filter=%s,, ' % (plotParm.strip()) isprintStr = getIsprintString(self.madFile, parms, filterStr) try: scanList = self.createWedgeScanInfoList(isprintStr) except: traceback.print_exc() return (retList) gdlatr, gdlonr, galtr = self._getInstLocation(isprintStr) # create limit dictionary used to keep all scans of the same type with the same limits limitDict = self._getLimits(scanList, xMinimum, xMaximum, yMinimum, yMaximum) # loop through each scan scanFailureCount = 0 # keep track of how many scans fail for i in range(len(scanList)): scanCount = i - scanFailureCount scanInfo = scanList[i] try: startDateStr = self.getDateStrFromUT(scanInfo[1]) except: # no scans may have been found continue endDateStr = self.getTimeStrFromUT(scanInfo[4]) # create title if scanType == 'el': if scanInfo[3] > scanInfo[6]: ind = 'down' direction = 1 else: ind = 'up' direction = 0 if int(scanInfo[2]) == int(scanInfo[5]): # no change in az titleStr = 'El %s scan (%s) %s-%s, az=%i %s' % (plotParm, ind, startDateStr, endDateStr, int(scanInfo[2]), addTitle) else: # az changed titleStr = 'El (%i-%i) %s scan %s-%s, az=%i-%i %s' % (int(scanInfo[3]), int(scanInfo[6]), plotParm, startDateStr, endDateStr, int(scanInfo[2]), int(scanInfo[5]), addTitle) timeStr = '%s-%s' % (startDateStr, endDateStr) metaStr = 'El scan: startTime %i el %f az %f stopTime %i el %f az %f dir %i' % (scanInfo[1], scanInfo[3], scanInfo[2], scanInfo[4], scanInfo[6], scanInfo[5], direction) retList.append((timeStr,metaStr)) if scanInfo[7] == 'Gdlat': xLabelStr = 'Geodetic latitude' wedgeScanType = 'el_lat' elif scanInfo[7] == 'Glon': xLabelStr = 'Longitude' wedgeScanType = 'el_lon' elif scanInfo[7] == 'Gcdist': xLabelStr = 'Ground distance in km' wedgeScanType = 'el_gcdist' xLabelStr = '' yLabelStr = 'Altitude (km)' else: if scanInfo[2] > scanInfo[5]: ind = 'ccw' direction = 1 else: ind = 'cw' direction = 0 titleStr = 'Az %s scan (%s) %s-%s, el=%i %s' % (plotParm, ind, startDateStr, endDateStr, int(scanInfo[3]), addTitle) timeStr = '%s-%s' % (startDateStr, endDateStr) metaStr = 'Az scan: startTime %i az %f el %f stopTime %i az %f el %f dir %i' % (scanInfo[1], scanInfo[2], scanInfo[3], scanInfo[4], scanInfo[5], scanInfo[6], direction) retList.append((timeStr,metaStr)) xLabelStr = 'Longitude' yLabelStr = 'Geodetic latitude' name = '%s_%06i.png' % (fullFilenameTemplate, scanCount) try: madPcolorWedgeScan(scanInfo[0], wedgeScanType, titleStr, xLabelStr, yLabelStr, name, xMinimum = limitDict[wedgeScanType][0], xMaximum = limitDict[wedgeScanType][1], yMinimum = limitDict[wedgeScanType][2], yMaximum = limitDict[wedgeScanType][3], minColormap = minColormap, maxColormap = maxColormap, colorMap = cmap) success = True except: print 'Problem creating scan %s' % (str(retList[-1])) traceback.print_exc() scanFailureCount += 1 retList.remove(retList[-1]) success = False if includeKml and success: kmlName = name[:-3] + 'kml' try: madPcolorWedgeKmlScan(scanInfo[0], wedgeScanType, kmlName, minColormap = minColormap, maxColormap = maxColormap, instName = radarName, instDesc = radarDesc, instLat = gdlatr, instLon = gdlonr, instAlt = galtr, colorMap = cmap) except: print 'Problem creating kml scan' traceback.print_exc() return (retList) def getDateStrFromUT(self, ut): """getDateStrFromUT returns a date string formated as YYYY-MM-DD HH:MM:SS from a ut time (seconds since 1/1/1950) """ timeList = madrigal._derive.getDateFromUt(float(ut)) return '%04i-%02i-%02i %02i:%02i:%02i' % (timeList[0], timeList[1], timeList[2], timeList[3], timeList[4], timeList[5]) def getTimeStrFromUT(self, ut): """getTimeStrFromUT returns a time string formated as HH:MM:SS from a ut time (seconds since 1/1/1950) """ timeList = madrigal._derive.getDateFromUt(float(ut)) return '%02i:%02i:%02i' % (timeList[3], timeList[4], timeList[5]) def createScanInfoList(self, isprintStr): """createScanInfoList creates a list of tuples, which each tuple representing a single scan, and values of: (isprintString, startUT, startAz, startEl, endUT, endAz, endEl, type, minGdlat, maxGdlat,minGlon, maxGdlon,minGdalt, maxGdalt, minGcdist, maxGcdist). Isprint string has values (x,y,plotParm), where for az scan x=lon, y=lat, and for el scan y=alt, x=lat if starting az within 15 degrees of north or south, x=lon if starting az within 15 degrees of east or west, of x=gcdist if other az. Type is Gdlat or Glon or Gcdist for el scans, None for az scans. Input isprint string has parameters ut1,scntyp,cycn,<parm>,gdalt,gdlat,glon,azm,elm,gcdist Azimuth scans are split whenever direction or elevation changes. For elevation scans, there will be zero or one north-south scans, zero or one east-west scans, and zero or more off azimuth scans. An off azimuth scan is not within 15 degrees of north, south, east or west. Off azimuth scans are not combined with scans 180 degrees in the other direction, because the x axis is ground distance, which does not reverse sign. """ isprintItems = isprintStr.split() retList = [] # loop variables thisIsprintStr = [] cycNum = None startUT = [] startAz = [] startEl = [] endUT = [] endAz = [] endEl = [] elScan = [] minGdlat = [] maxGdlat = [] minGlon = [] maxGlon = [] minGdalt = [] maxGdalt = [] minGcdist = [] maxGcdist = [] thisAzDirection = None # used to detect new azimuth scans lastAzDirection = None # used to detect new azimuth scans lastEl = None # used to detect new azimuth scans thisAz = None lastUt = None # keep track of new ut isNewUt = None # true only when ut changes inAzScan = False for i in range(len(isprintItems)): item = isprintItems[i] mod = i % 10 if mod == 0: thisUt = float(item) if lastUt == None: lastUt = thisUt elif mod == 1: thisScntyp = int(item) elif mod == 2: thisCycn = int(float(item)) if cycNum == None: cycNum = thisCycn elif mod == 3: thisParm = item elif mod == 4: thisGdalt = float(item) elif mod == 5: thisGdlat = float(item) elif mod == 6: thisGlon = float(item) elif mod == 7: if thisAz != None and lastUt < thisUt and inAzScan: if thisAz > float(item): thisAzDirection = 'cw' elif thisAz < float(item): thisAzDirection = 'ccw' thisAz = float(item) elif mod == 8: thisEl = float(item) elif mod == 9: thisGcdist = float(item) # check whether this is a new time if lastUt < thisUt: isNewUt = True lastUt = thisUt else: isNewUt = False # if new cycle, close out value if data exists if thisCycn != cycNum: for i in range(len(thisIsprintStr)): if len(thisIsprintStr[i]) == 0: continue retList.append((thisIsprintStr[i], startUT[i], startAz[i], startEl[i], endUT[i], endAz[i], endEl[i], elScan[i], minGdlat[i], maxGdlat[i], minGlon[i], maxGlon[i], minGdalt[i], maxGdalt[i], minGcdist[i], maxGcdist[i])) thisIsprintStr = [] cycNum = None startUT = [] startAz = [] startEl = [] endUT = [] endAz = [] endEl = [] elScan = [] minGdlat = [] maxGdlat = [] minGlon = [] maxGlon = [] minGdalt = [] maxGdalt = [] minGcdist = [] maxGcdist = [] thisAzDirection = None lastAzDirection = None lastEl = None inAzScan = False # end of line - process it if self.scanType == 'el' and thisScntyp == 3: # add this elevation scan point # check type of el scan inAzScan = False if -15.0 <= thisAz <= 15.0 or -165.0 >= thisAz or thisAz >= 165.0: thisElScan = 'Gdlat' elif 75.0 <= thisAz <= 105.0 or -105.0 <= thisAz <= -75.0: thisElScan = 'Glon' else: thisElScan = 'Gcdist' # get index of this scan, None if a new scan index = None for i, item in enumerate(elScan): if item == 'Gdlat' and thisElScan == 'Gdlat': index = i break elif item == 'Glon' and thisElScan == 'Glon': index = i break elif item == 'Gcdist' and thisElScan == 'Gcdist' and int(thisAz) == int(startAz[i]): index = i break if index == None: # a new scan has been found thisIsprintStr.append('') startUT.append(thisUt) startAz.append(thisAz) startEl.append(thisEl) endUT.append(None) endAz.append(None) endEl.append(None) elScan.append(thisElScan) minGdlat.append(None) maxGdlat.append(None) minGlon.append(None) maxGlon.append(None) minGdalt.append(None) maxGdalt.append(None) minGcdist.append(None) maxGcdist.append(None) index = len(thisIsprintStr) - 1 endUT[index] = thisUt endAz[index] = thisAz endEl[index] = thisEl if thisElScan == 'Gdlat': thisIsprintStr[index] += '%f %f %s\n' % (thisGdlat, thisGdalt, thisParm) elif thisElScan == 'Glon': thisIsprintStr[index] += '%f %f %s\n' % (thisGlon, thisGdalt, thisParm) else: thisIsprintStr[index] += '%f %f %s\n' % (thisGcdist, thisGdalt, thisParm) elif self.scanType == 'az' and thisScntyp == 2: # az scan inAzScan = True # add this azimuth scan point # check if this is a new scan newAzScan = False if lastEl == None: newAzScan = True # check for elevation change elif abs(lastEl - int(thisEl)) > 3: newAzScan = True # check for direction change if lastAzDirection != None: if lastAzDirection != thisAzDirection: newAzScan = True thisAzDirection = None if newAzScan: # a new azimuth scan has been found thisIsprintStr.append('') startUT.append(thisUt) startAz.append(thisAz) startEl.append(thisEl) endUT.append(None) endAz.append(None) endEl.append(None) elScan.append(None) minGdlat.append(None) maxGdlat.append(None) minGlon.append(None) maxGlon.append(None) minGdalt.append(None) maxGdalt.append(None) minGcdist.append(None) maxGcdist.append(None) index = len(thisIsprintStr) - 1 lastEl = int(thisEl) lastAzDirection = None else: # this is at least the second line of the scan if not thisAzDirection is None: lastAzDirection = thisAzDirection endUT[-1] = thisUt endAz[-1] = thisAz endEl[-1] = thisEl thisIsprintStr[-1] += '%f %f %s\n' % (thisGlon, thisGdlat, thisParm) else: # not a scan line inAzScan = False continue if minGdlat[index] == None: minGdlat[index] = thisGdlat maxGdlat[index] = thisGdlat minGlon[index] = thisGlon maxGlon[index] = thisGlon minGdalt[index] = thisGdalt maxGdalt[index] = thisGdalt minGcdist[index] = thisGcdist maxGcdist[index] = thisGcdist else: if minGdlat[index] > thisGdlat: minGdlat[index] = thisGdlat if maxGdlat[index] < thisGdlat: maxGdlat[index] = thisGdlat if minGlon[index] > thisGlon: minGlon[index] = thisGlon if maxGlon[index] < thisGlon: maxGlon[index] = thisGlon if minGdalt[index] > thisGdalt: minGdalt[index] = thisGdalt if maxGdalt[index] < thisGdalt: maxGdalt[index] = thisGdalt if minGcdist[index] > thisGcdist: minGcdist[index] = thisGcdist if maxGcdist[index] < thisGcdist: maxGcdist[index] = thisGcdist # end, close out last cycle for i in range(len(thisIsprintStr)): if len(thisIsprintStr[i]) == 0: continue retList.append((thisIsprintStr[i], startUT[i], startAz[i], startEl[i], endUT[i], endAz[i], endEl[i], elScan[i], minGdlat[i], maxGdlat[i], minGlon[i], maxGlon[i], minGdalt[i], maxGdalt[i], minGcdist[i], maxGcdist[i])) return(retList) def createWedgeScanInfoList(self, isprintStr): """createWedgeScanInfoList creates a list of tuples, which each tuple representing a single scan, and values of: (isprintString, startUT, startAz, startEl, endUT, endAz, endEl, type, minGdlat, maxGdlat,minGlon, maxGdlon,minGdalt, maxGdalt, minGcdist, maxGcdist). Input isprint string has parameters ut1,scntyp,cycn,<parm>,gdalt,gdlat,glon,azm,elm,gcdist, gdlatr,gdlonr,galtr,range,az1,az2,el1,el2 Azimuth scans are split whenever direction or elevation changes. For elevation scans, there will be zero or more north-south scans, zero or more east-west scans, and zero or more off azimuth scans. A south to north elevation scan or a west to east elevation scan is called clockwise, and a switch from clockwise to counterclockwise will create a new elevation scan. An off azimuth scan is not within 15 degrees of north, south, east or west. Off azimuth scans are not combined with scans 180 degrees in the other direction, because the x axis is ground distance, which does not reverse sign. """ isprintItems = isprintStr.split() retList = [] # loop variables thisIsprintStr = [] cycNum = None startUT = [] startAz = [] startEl = [] endUT = [] endAz = [] endEl = [] elScan = [] minGdlat = [] maxGdlat = [] minGlon = [] maxGlon = [] minGdalt = [] maxGdalt = [] minGcdist = [] maxGcdist = [] thisAzDirection = None # used to detect new azimuth scans lastAzDirection = None # used to detect new azimuth scans thisElDirection = None # used to detect new elevation scans (cw or ccw) lastElDirection = None # used to detect new elevation scans (cw or ccw) lastEl = None # used to detect new azimuth scans thisAz = None thisEl = None lastUt = None # keep track of new ut isNewUt = None # true only when ut changes inAzScan = False inElScan = False for i in range(len(isprintItems)): item = isprintItems[i] mod = i % 18 if mod == 0: thisUt = float(item) if lastUt == None: lastUt = thisUt elif mod == 1: thisScntyp = int(item) elif mod == 2: thisCycn = int(float(item)) if cycNum == None: cycNum = thisCycn elif mod == 3: thisParm = item elif mod == 4: thisGdalt = float(item) elif mod == 5: thisGdlat = float(item) elif mod == 6: thisGlon = float(item) elif mod == 7: if thisAz != None and lastUt < thisUt and inAzScan: if thisAz > float(item): thisAzDirection = 'cw' elif thisAz < float(item): thisAzDirection = 'ccw' thisAz = float(item) elif mod == 8: if thisEl != None and inElScan: if abs(float(item) - thisEl) > 1.0: if thisElScan == 'Gdlat': if -165.0 >= thisAz or thisAz >= 165.0: # southern scan if float(item) > thisEl: thisElDirection = 'cw' else: thisElDirection = 'ccw' else: # northern scan if float(item) < thisEl: thisElDirection = 'cw' else: thisElDirection = 'ccw' elif thisElScan == 'Glon': if -105.0 <= thisAz <= -75.0: # western scan if float(item) > thisEl: thisElDirection = 'cw' else: thisElDirection = 'ccw' else: # eastern scan if float(item) < thisEl: thisElDirection = 'cw' else: thisElDirection = 'ccw' elif thisElScan == 'Gcdist': if float(item) > thisEl: thisElDirection = 'up' else: thisElDirection = 'down' thisEl = float(item) elif mod == 9: thisGcdist = float(item) elif mod == 10: thisGdlatr = float(item) elif mod == 11: thisGdlonr = float(item) elif mod == 12: thisGaltr = float(item) elif mod == 13: thisRange = float(item) elif mod == 14: thisAz1 = float(item) elif mod == 15: thisAz2 = float(item) elif mod == 16: thisEl1 = float(item) elif mod == 17: thisEl2 = float(item) # check whether this is a new time if lastUt < thisUt: isNewUt = True lastUt = thisUt else: isNewUt = False # if new cycle or elevation issue, close out value if data exists if (thisCycn != cycNum) or \ (thisElDirection == 'cw' and lastElDirection == 'ccw') or \ (thisElDirection == 'ccw' and lastElDirection == 'cw') or \ (thisElDirection == 'down' and lastElDirection == 'up') or \ (thisElDirection == 'up' and lastElDirection == 'down') or \ (thisElDirection != None and not inElScan) or \ (thisAzDirection != None and not inAzScan): for i in range(len(thisIsprintStr)): if len(thisIsprintStr[i]) == 0: continue retList.append((thisIsprintStr[i], startUT[i], startAz[i], startEl[i], endUT[i], endAz[i], endEl[i], elScan[i], minGdlat[i], maxGdlat[i], minGlon[i], maxGlon[i], minGdalt[i], maxGdalt[i], minGcdist[i], maxGcdist[i])) thisIsprintStr = [] cycNum = None startUT = [] startAz = [] startEl = [] endUT = [] endAz = [] endEl = [] elScan = [] minGdlat = [] maxGdlat = [] minGlon = [] maxGlon = [] minGdalt = [] maxGdalt = [] minGcdist = [] maxGcdist = [] thisAzDirection = None lastAzDirection = None thisElDirection = None # used to detect new elevation scans (cw or ccw) lastElDirection = None lastEl = None inAzScan = False inElScan = False # end of line - process it if self.scanType == 'el' and thisScntyp == 3: # add this elevation scan point # check type of el scan inAzScan = False inElScan = True if (-15.0 <= thisAz <= 15.0 or -165.0 >= thisAz or thisAz >= 165.0) and \ abs(thisAz1 - thisAz2) < 0.5: thisElScan = 'Gdlat' elif (75.0 <= thisAz <= 105.0 or -105.0 <= thisAz <= -75.0) and \ abs(thisAz1 - thisAz2) < 0.5: thisElScan = 'Glon' else: thisElScan = 'Gcdist' # get index of this scan, None if a new scan index = None for i, item in enumerate(elScan): if item == 'Gdlat' and thisElScan == 'Gdlat': index = i break elif item == 'Glon' and thisElScan == 'Glon': index = i break elif item == 'Gcdist' and thisElScan == 'Gcdist' and int(thisAz) == int(startAz[i]): index = i break elif item == 'Gcdist' and thisElScan == 'Gcdist' and i == len(elScan)-1: index = i break if index == None: # a new scan has been found thisIsprintStr.append('') startUT.append(thisUt) startAz.append(thisAz) startEl.append(thisEl) endUT.append(None) endAz.append(None) endEl.append(None) elScan.append(thisElScan) minGdlat.append(None) maxGdlat.append(None) minGlon.append(None) maxGlon.append(None) minGdalt.append(None) maxGdalt.append(None) minGcdist.append(None) maxGcdist.append(None) index = len(thisIsprintStr) - 1 lastElDirection = thisElDirection endUT[index] = thisUt endAz[index] = thisAz endEl[index] = thisEl # gdlatr, gdlonr, galtr, range, az1, az2, el1, el2,plotParm thisIsprintStr[index] += '%f %f %f %f %f %f %f %f %s\n' % (thisGdlatr, thisGdlonr, thisGaltr, thisRange, thisAz1, thisAz2, thisEl1, thisEl2, thisParm) elif self.scanType == 'az' and thisScntyp == 2: # az scan inAzScan = True inElScan = False # add this azimuth scan point # check if this is a new scan newAzScan = False if lastEl == None: newAzScan = True # check for elevation change elif abs(lastEl - int(thisEl)) > 3: newAzScan = True # check for direction change if lastAzDirection != None: if lastAzDirection != thisAzDirection: newAzScan = True thisAzDirection = None if newAzScan: # a new azimuth scan has been found thisIsprintStr.append('') startUT.append(thisUt) startAz.append(thisAz) startEl.append(thisEl) endUT.append(None) endAz.append(None) endEl.append(None) elScan.append(None) minGdlat.append(None) maxGdlat.append(None) minGlon.append(None) maxGlon.append(None) minGdalt.append(None) maxGdalt.append(None) minGcdist.append(None) maxGcdist.append(None) index = len(thisIsprintStr) - 1 lastEl = int(thisEl) lastAzDirection = None else: # this is at least the second line of the scan if not thisAzDirection is None: lastAzDirection = thisAzDirection endUT[-1] = thisUt endAz[-1] = thisAz endEl[-1] = thisEl thisIsprintStr[-1] += '%f %f %f %f %f %f %f %f %s\n' % (thisGdlatr, thisGdlonr, thisGaltr, thisRange, thisAz1, thisAz2, thisEl1, thisEl2, thisParm) else: # not a scan line inAzScan = False inElScan = False continue if minGdlat[index] == None: minGdlat[index] = thisGdlat maxGdlat[index] = thisGdlat minGlon[index] = thisGlon maxGlon[index] = thisGlon minGdalt[index] = thisGdalt maxGdalt[index] = thisGdalt minGcdist[index] = thisGcdist maxGcdist[index] = thisGcdist else: if minGdlat[index] > thisGdlat: minGdlat[index] = thisGdlat if maxGdlat[index] < thisGdlat: maxGdlat[index] = thisGdlat if minGlon[index] > thisGlon: minGlon[index] = thisGlon if maxGlon[index] < thisGlon: maxGlon[index] = thisGlon if minGdalt[index] > thisGdalt: minGdalt[index] = thisGdalt if maxGdalt[index] < thisGdalt: maxGdalt[index] = thisGdalt if minGcdist[index] > thisGcdist: minGcdist[index] = thisGcdist if maxGcdist[index] < thisGcdist: maxGcdist[index] = thisGcdist # end, close out last cycle for i in range(len(thisIsprintStr)): if len(thisIsprintStr[i]) == 0: continue retList.append((thisIsprintStr[i], startUT[i], startAz[i], startEl[i], endUT[i], endAz[i], endEl[i], elScan[i], minGdlat[i], maxGdlat[i], minGlon[i], maxGlon[i], minGdalt[i], maxGdalt[i], minGcdist[i], maxGcdist[i])) return(retList) def _getLimits(self, scanList, xMinimum, xMaximum, yMinimum, yMaximum): """_getLimits returns a dictionary with keys that may include ('az', 'el_lat', 'el_lon', 'el_gcdist'), though not all will neccessarily be there. Values are overall tuple of (xMinimum, xMaximum, yMinimum, yMaximum). These values are set by the input arguments unless it is None, in which case the scanList limits set the values. Inputs: scanList: a list of tuples, which each tuple representing a single scan, and has values of: (isprintString, startUT, startAz, startEl, endUT, endAz, endEl, type, minGdlat, maxGdlat,minGlon, maxGdlon,minGdalt, maxGdalt, minGcdist, maxGcdist). Isprint string has values (gdlatr, gdlonr, galtr, range, az1, az2, el1, el2,plotParm),. Type is Gdlat or Glon or Gcdist for el scans, None for az scans. xMinimum, xMaximum, yMinimum, yMaximum - as passed into scanPlotter """ retDict = {} xMinAz = None xMaxAz = None yMinAz = None yMaxAz = None xMinElLat = None xMaxElLat = None yMinElLat = None yMaxElLat = None xMinElLon = None xMaxElLon = None yMinElLon = None yMaxElLon = None xMinElGcdist = None xMaxElGcdist = None yMinElGcdist = None yMaxElGcdist = None minValue = None maxValue = None for scanItem in scanList: if scanItem[7] == None: # az scan if xMinAz == None: xMinAz = scanItem[10] elif xMinAz > scanItem[10]: xMinAz = scanItem[10] if xMaxAz == None: xMaxAz = scanItem[11] elif xMaxAz < scanItem[11]: xMaxAz = scanItem[11] if yMinAz == None: yMinAz = scanItem[8] elif yMinAz > scanItem[8]: yMinAz = scanItem[8] if yMaxAz == None: yMaxAz = scanItem[9] elif yMaxAz < scanItem[9]: yMaxAz = scanItem[9] elif scanItem[7] == 'Gdlat': # el_lat scan if xMinElLat == None: xMinElLat = scanItem[8] elif xMinElLat > scanItem[8]: xMinElLat = scanItem[8] if xMaxElLat == None: xMaxElLat = scanItem[9] elif xMaxElLat < scanItem[9]: xMaxElLat = scanItem[9] if yMinElLat == None: yMinElLat = scanItem[12] elif yMinElLat > scanItem[12]: yMinElLat = scanItem[12] if yMaxElLat == None: yMaxElLat = scanItem[13] elif yMaxElLat < scanItem[13]: yMaxElLat = scanItem[13] elif scanItem[7] == 'Glon': # el_lon scan if xMinElLon == None: xMinElLon = scanItem[10] elif xMinElLon > scanItem[10]: xMinElLon = scanItem[10] if xMaxElLon == None: xMaxElLon = scanItem[11] elif xMaxElLon < scanItem[11]: xMaxElLon = scanItem[11] if yMinElLon == None: yMinElLon = scanItem[12] elif yMinElLon > scanItem[12]: yMinElLon = scanItem[12] if yMaxElLon == None: yMaxElLon = scanItem[13] elif yMaxElLon < scanItem[13]: yMaxElLon = scanItem[13] elif scanItem[7] == 'Gcdist': # el_gcdist scan if xMinElGcdist == None: xMinElGcdist = scanItem[14] elif xMinElGcdist > scanItem[14]: xMinElGcdist = scanItem[14] if xMaxElGcdist == None: xMaxElGcdist = scanItem[15] elif xMaxElGcdist < scanItem[15]: xMaxElGcdist = scanItem[15] if yMinElGcdist == None: yMinElGcdist = scanItem[12] elif yMinElGcdist > scanItem[12]: yMinElGcdist = scanItem[12] if yMaxElGcdist == None: yMaxElGcdist = scanItem[13] elif yMaxElGcdist < scanItem[13]: yMaxElGcdist = scanItem[13] # fill out the dictionary if xMinAz != None: if xMinimum == None: xMin = xMinAz else: xMin = xMinimum if xMaximum == None: xMax = xMaxAz else: xMax = xMaximum if yMinimum == None: yMin = yMinAz else: yMin = yMinimum if yMaximum == None: yMax = yMaxAz else: yMax = yMaximum retDict['az'] = (xMin, xMax, yMin, yMax) if xMinElLat != None: if xMinimum == None: xMin = xMinElLat else: xMin = xMinimum if xMaximum == None: xMax = xMaxElLat else: xMax = xMaximum if yMinimum == None: yMin = yMinElLat else: yMin = yMinimum if yMaximum == None: yMax = yMaxElLat else: yMax = yMaximum retDict['el_lat'] = (xMin, xMax, yMin, yMax) if xMinElLon != None: if xMinimum == None: xMin = xMinElLon else: xMin = xMinimum if xMaximum == None: xMax = xMaxElLon else: xMax = xMaximum if yMinimum == None: yMin = yMinElLon else: yMin = yMinimum if yMaximum == None: yMax = yMaxElLon else: yMax = yMaximum retDict['el_lon'] = (xMin, xMax, yMin, yMax) if xMinElGcdist != None: if xMinimum == None: xMin = xMinElGcdist else: xMin = xMinimum if xMaximum == None: xMax = xMaxElGcdist else: xMax = xMaximum if yMinimum == None: yMin = yMinElGcdist else: yMin = yMinimum if yMaximum == None: yMax = yMaxElGcdist else: yMax = yMaximum retDict['el_gcdist'] = (xMin, xMax, yMin, yMax) return(retDict) def _getInstLocation(self, isprintStr): """_getInstLocation returns a tuple of instrument location (gdlatr, gdlonr, galtr) Input isprint string has parameters ut1,scntyp,cycn,<parm>,gdalt,gdlat,glon,azm,elm,gcdist, gdlatr,gdlonr,galtr,range,az1,az2,el1,el2 """ isprintItems = isprintStr.split() gdlatr = float(isprintItems[10]) gdlonr = float(isprintItems[11]) if gdlonr > 180.0: gdlonr -= 360.0 galtr = float(isprintItems[12]) return((gdlatr, gdlonr, galtr))
Ancestors (in MRO)
Methods
def __init__(
self, madFile, madDBObj=None)
init initializes a scanPlotter object.
Inputs:
madFile - the Madrigal file to be analyzed. Must contain SCNTYP and CYCN parameters. madDBObj - a madrigal.metadata.MadrigalDB object. If None (default), one created
Returns: void
Affects: sets self.madFile, self.madDBObj
def __init__(self, madFile, madDBObj=None): """__init__ initializes a scanPlotter object. Inputs: madFile - the Madrigal file to be analyzed. Must contain SCNTYP and CYCN parameters. madDBObj - a madrigal.metadata.MadrigalDB object. If None (default), one created Returns: void Affects: sets self.madFile, self.madDBObj """ if os.access(madFile, os.R_OK): self.madFile = madFile else: raise IOError, 'unable to read %s' % (str(madFile)) if madDBObj == None: self.madDBObj = madrigal.metadata.MadrigalDB() else: self.madDBObj = madDBObj
def createScanInfoList(
self, isprintStr)
createScanInfoList creates a list of tuples, which each tuple representing a single scan, and values of:
(isprintString, startUT, startAz, startEl, endUT, endAz, endEl, type, minGdlat, maxGdlat,minGlon, maxGdlon,minGdalt, maxGdalt, minGcdist, maxGcdist). Isprint string has values (x,y,plotParm), where for az scan x=lon, y=lat, and for el scan y=alt, x=lat if starting az within 15 degrees of north or south, x=lon if starting az within 15 degrees of east or west, of x=gcdist if other az. Type is Gdlat or Glon or Gcdist for el scans, None for az scans.
Input isprint string has parameters ut1,scntyp,cycn,
Azimuth scans are split whenever direction or elevation changes. For elevation scans, there will be zero or one north-south scans, zero or one east-west scans, and zero or more off azimuth scans. An off azimuth scan is not within 15 degrees of north, south, east or west. Off azimuth scans are not combined with scans 180 degrees in the other direction, because the x axis is ground distance, which does not reverse sign.
def createScanInfoList(self, isprintStr): """createScanInfoList creates a list of tuples, which each tuple representing a single scan, and values of: (isprintString, startUT, startAz, startEl, endUT, endAz, endEl, type, minGdlat, maxGdlat,minGlon, maxGdlon,minGdalt, maxGdalt, minGcdist, maxGcdist). Isprint string has values (x,y,plotParm), where for az scan x=lon, y=lat, and for el scan y=alt, x=lat if starting az within 15 degrees of north or south, x=lon if starting az within 15 degrees of east or west, of x=gcdist if other az. Type is Gdlat or Glon or Gcdist for el scans, None for az scans. Input isprint string has parameters ut1,scntyp,cycn,<parm>,gdalt,gdlat,glon,azm,elm,gcdist Azimuth scans are split whenever direction or elevation changes. For elevation scans, there will be zero or one north-south scans, zero or one east-west scans, and zero or more off azimuth scans. An off azimuth scan is not within 15 degrees of north, south, east or west. Off azimuth scans are not combined with scans 180 degrees in the other direction, because the x axis is ground distance, which does not reverse sign. """ isprintItems = isprintStr.split() retList = [] # loop variables thisIsprintStr = [] cycNum = None startUT = [] startAz = [] startEl = [] endUT = [] endAz = [] endEl = [] elScan = [] minGdlat = [] maxGdlat = [] minGlon = [] maxGlon = [] minGdalt = [] maxGdalt = [] minGcdist = [] maxGcdist = [] thisAzDirection = None # used to detect new azimuth scans lastAzDirection = None # used to detect new azimuth scans lastEl = None # used to detect new azimuth scans thisAz = None lastUt = None # keep track of new ut isNewUt = None # true only when ut changes inAzScan = False for i in range(len(isprintItems)): item = isprintItems[i] mod = i % 10 if mod == 0: thisUt = float(item) if lastUt == None: lastUt = thisUt elif mod == 1: thisScntyp = int(item) elif mod == 2: thisCycn = int(float(item)) if cycNum == None: cycNum = thisCycn elif mod == 3: thisParm = item elif mod == 4: thisGdalt = float(item) elif mod == 5: thisGdlat = float(item) elif mod == 6: thisGlon = float(item) elif mod == 7: if thisAz != None and lastUt < thisUt and inAzScan: if thisAz > float(item): thisAzDirection = 'cw' elif thisAz < float(item): thisAzDirection = 'ccw' thisAz = float(item) elif mod == 8: thisEl = float(item) elif mod == 9: thisGcdist = float(item) # check whether this is a new time if lastUt < thisUt: isNewUt = True lastUt = thisUt else: isNewUt = False # if new cycle, close out value if data exists if thisCycn != cycNum: for i in range(len(thisIsprintStr)): if len(thisIsprintStr[i]) == 0: continue retList.append((thisIsprintStr[i], startUT[i], startAz[i], startEl[i], endUT[i], endAz[i], endEl[i], elScan[i], minGdlat[i], maxGdlat[i], minGlon[i], maxGlon[i], minGdalt[i], maxGdalt[i], minGcdist[i], maxGcdist[i])) thisIsprintStr = [] cycNum = None startUT = [] startAz = [] startEl = [] endUT = [] endAz = [] endEl = [] elScan = [] minGdlat = [] maxGdlat = [] minGlon = [] maxGlon = [] minGdalt = [] maxGdalt = [] minGcdist = [] maxGcdist = [] thisAzDirection = None lastAzDirection = None lastEl = None inAzScan = False # end of line - process it if self.scanType == 'el' and thisScntyp == 3: # add this elevation scan point # check type of el scan inAzScan = False if -15.0 <= thisAz <= 15.0 or -165.0 >= thisAz or thisAz >= 165.0: thisElScan = 'Gdlat' elif 75.0 <= thisAz <= 105.0 or -105.0 <= thisAz <= -75.0: thisElScan = 'Glon' else: thisElScan = 'Gcdist' # get index of this scan, None if a new scan index = None for i, item in enumerate(elScan): if item == 'Gdlat' and thisElScan == 'Gdlat': index = i break elif item == 'Glon' and thisElScan == 'Glon': index = i break elif item == 'Gcdist' and thisElScan == 'Gcdist' and int(thisAz) == int(startAz[i]): index = i break if index == None: # a new scan has been found thisIsprintStr.append('') startUT.append(thisUt) startAz.append(thisAz) startEl.append(thisEl) endUT.append(None) endAz.append(None) endEl.append(None) elScan.append(thisElScan) minGdlat.append(None) maxGdlat.append(None) minGlon.append(None) maxGlon.append(None) minGdalt.append(None) maxGdalt.append(None) minGcdist.append(None) maxGcdist.append(None) index = len(thisIsprintStr) - 1 endUT[index] = thisUt endAz[index] = thisAz endEl[index] = thisEl if thisElScan == 'Gdlat': thisIsprintStr[index] += '%f %f %s\n' % (thisGdlat, thisGdalt, thisParm) elif thisElScan == 'Glon': thisIsprintStr[index] += '%f %f %s\n' % (thisGlon, thisGdalt, thisParm) else: thisIsprintStr[index] += '%f %f %s\n' % (thisGcdist, thisGdalt, thisParm) elif self.scanType == 'az' and thisScntyp == 2: # az scan inAzScan = True # add this azimuth scan point # check if this is a new scan newAzScan = False if lastEl == None: newAzScan = True # check for elevation change elif abs(lastEl - int(thisEl)) > 3: newAzScan = True # check for direction change if lastAzDirection != None: if lastAzDirection != thisAzDirection: newAzScan = True thisAzDirection = None if newAzScan: # a new azimuth scan has been found thisIsprintStr.append('') startUT.append(thisUt) startAz.append(thisAz) startEl.append(thisEl) endUT.append(None) endAz.append(None) endEl.append(None) elScan.append(None) minGdlat.append(None) maxGdlat.append(None) minGlon.append(None) maxGlon.append(None) minGdalt.append(None) maxGdalt.append(None) minGcdist.append(None) maxGcdist.append(None) index = len(thisIsprintStr) - 1 lastEl = int(thisEl) lastAzDirection = None else: # this is at least the second line of the scan if not thisAzDirection is None: lastAzDirection = thisAzDirection endUT[-1] = thisUt endAz[-1] = thisAz endEl[-1] = thisEl thisIsprintStr[-1] += '%f %f %s\n' % (thisGlon, thisGdlat, thisParm) else: # not a scan line inAzScan = False continue if minGdlat[index] == None: minGdlat[index] = thisGdlat maxGdlat[index] = thisGdlat minGlon[index] = thisGlon maxGlon[index] = thisGlon minGdalt[index] = thisGdalt maxGdalt[index] = thisGdalt minGcdist[index] = thisGcdist maxGcdist[index] = thisGcdist else: if minGdlat[index] > thisGdlat: minGdlat[index] = thisGdlat if maxGdlat[index] < thisGdlat: maxGdlat[index] = thisGdlat if minGlon[index] > thisGlon: minGlon[index] = thisGlon if maxGlon[index] < thisGlon: maxGlon[index] = thisGlon if minGdalt[index] > thisGdalt: minGdalt[index] = thisGdalt if maxGdalt[index] < thisGdalt: maxGdalt[index] = thisGdalt if minGcdist[index] > thisGcdist: minGcdist[index] = thisGcdist if maxGcdist[index] < thisGcdist: maxGcdist[index] = thisGcdist # end, close out last cycle for i in range(len(thisIsprintStr)): if len(thisIsprintStr[i]) == 0: continue retList.append((thisIsprintStr[i], startUT[i], startAz[i], startEl[i], endUT[i], endAz[i], endEl[i], elScan[i], minGdlat[i], maxGdlat[i], minGlon[i], maxGlon[i], minGdalt[i], maxGdalt[i], minGcdist[i], maxGcdist[i])) return(retList)
def createWedgeScanInfoList(
self, isprintStr)
createWedgeScanInfoList creates a list of tuples, which each tuple representing a single scan, and values of:
(isprintString, startUT, startAz, startEl, endUT, endAz, endEl, type, minGdlat, maxGdlat,minGlon, maxGdlon,minGdalt, maxGdalt, minGcdist, maxGcdist).
Input isprint string has parameters ut1,scntyp,cycn,
Azimuth scans are split whenever direction or elevation changes. For elevation scans, there will be zero or more north-south scans, zero or more east-west scans, and zero or more off azimuth scans. A south to north elevation scan or a west to east elevation scan is called clockwise, and a switch from clockwise to counterclockwise will create a new elevation scan. An off azimuth scan is not within 15 degrees of north, south, east or west. Off azimuth scans are not combined with scans 180 degrees in the other direction, because the x axis is ground distance, which does not reverse sign.
def createWedgeScanInfoList(self, isprintStr): """createWedgeScanInfoList creates a list of tuples, which each tuple representing a single scan, and values of: (isprintString, startUT, startAz, startEl, endUT, endAz, endEl, type, minGdlat, maxGdlat,minGlon, maxGdlon,minGdalt, maxGdalt, minGcdist, maxGcdist). Input isprint string has parameters ut1,scntyp,cycn,<parm>,gdalt,gdlat,glon,azm,elm,gcdist, gdlatr,gdlonr,galtr,range,az1,az2,el1,el2 Azimuth scans are split whenever direction or elevation changes. For elevation scans, there will be zero or more north-south scans, zero or more east-west scans, and zero or more off azimuth scans. A south to north elevation scan or a west to east elevation scan is called clockwise, and a switch from clockwise to counterclockwise will create a new elevation scan. An off azimuth scan is not within 15 degrees of north, south, east or west. Off azimuth scans are not combined with scans 180 degrees in the other direction, because the x axis is ground distance, which does not reverse sign. """ isprintItems = isprintStr.split() retList = [] # loop variables thisIsprintStr = [] cycNum = None startUT = [] startAz = [] startEl = [] endUT = [] endAz = [] endEl = [] elScan = [] minGdlat = [] maxGdlat = [] minGlon = [] maxGlon = [] minGdalt = [] maxGdalt = [] minGcdist = [] maxGcdist = [] thisAzDirection = None # used to detect new azimuth scans lastAzDirection = None # used to detect new azimuth scans thisElDirection = None # used to detect new elevation scans (cw or ccw) lastElDirection = None # used to detect new elevation scans (cw or ccw) lastEl = None # used to detect new azimuth scans thisAz = None thisEl = None lastUt = None # keep track of new ut isNewUt = None # true only when ut changes inAzScan = False inElScan = False for i in range(len(isprintItems)): item = isprintItems[i] mod = i % 18 if mod == 0: thisUt = float(item) if lastUt == None: lastUt = thisUt elif mod == 1: thisScntyp = int(item) elif mod == 2: thisCycn = int(float(item)) if cycNum == None: cycNum = thisCycn elif mod == 3: thisParm = item elif mod == 4: thisGdalt = float(item) elif mod == 5: thisGdlat = float(item) elif mod == 6: thisGlon = float(item) elif mod == 7: if thisAz != None and lastUt < thisUt and inAzScan: if thisAz > float(item): thisAzDirection = 'cw' elif thisAz < float(item): thisAzDirection = 'ccw' thisAz = float(item) elif mod == 8: if thisEl != None and inElScan: if abs(float(item) - thisEl) > 1.0: if thisElScan == 'Gdlat': if -165.0 >= thisAz or thisAz >= 165.0: # southern scan if float(item) > thisEl: thisElDirection = 'cw' else: thisElDirection = 'ccw' else: # northern scan if float(item) < thisEl: thisElDirection = 'cw' else: thisElDirection = 'ccw' elif thisElScan == 'Glon': if -105.0 <= thisAz <= -75.0: # western scan if float(item) > thisEl: thisElDirection = 'cw' else: thisElDirection = 'ccw' else: # eastern scan if float(item) < thisEl: thisElDirection = 'cw' else: thisElDirection = 'ccw' elif thisElScan == 'Gcdist': if float(item) > thisEl: thisElDirection = 'up' else: thisElDirection = 'down' thisEl = float(item) elif mod == 9: thisGcdist = float(item) elif mod == 10: thisGdlatr = float(item) elif mod == 11: thisGdlonr = float(item) elif mod == 12: thisGaltr = float(item) elif mod == 13: thisRange = float(item) elif mod == 14: thisAz1 = float(item) elif mod == 15: thisAz2 = float(item) elif mod == 16: thisEl1 = float(item) elif mod == 17: thisEl2 = float(item) # check whether this is a new time if lastUt < thisUt: isNewUt = True lastUt = thisUt else: isNewUt = False # if new cycle or elevation issue, close out value if data exists if (thisCycn != cycNum) or \ (thisElDirection == 'cw' and lastElDirection == 'ccw') or \ (thisElDirection == 'ccw' and lastElDirection == 'cw') or \ (thisElDirection == 'down' and lastElDirection == 'up') or \ (thisElDirection == 'up' and lastElDirection == 'down') or \ (thisElDirection != None and not inElScan) or \ (thisAzDirection != None and not inAzScan): for i in range(len(thisIsprintStr)): if len(thisIsprintStr[i]) == 0: continue retList.append((thisIsprintStr[i], startUT[i], startAz[i], startEl[i], endUT[i], endAz[i], endEl[i], elScan[i], minGdlat[i], maxGdlat[i], minGlon[i], maxGlon[i], minGdalt[i], maxGdalt[i], minGcdist[i], maxGcdist[i])) thisIsprintStr = [] cycNum = None startUT = [] startAz = [] startEl = [] endUT = [] endAz = [] endEl = [] elScan = [] minGdlat = [] maxGdlat = [] minGlon = [] maxGlon = [] minGdalt = [] maxGdalt = [] minGcdist = [] maxGcdist = [] thisAzDirection = None lastAzDirection = None thisElDirection = None # used to detect new elevation scans (cw or ccw) lastElDirection = None lastEl = None inAzScan = False inElScan = False # end of line - process it if self.scanType == 'el' and thisScntyp == 3: # add this elevation scan point # check type of el scan inAzScan = False inElScan = True if (-15.0 <= thisAz <= 15.0 or -165.0 >= thisAz or thisAz >= 165.0) and \ abs(thisAz1 - thisAz2) < 0.5: thisElScan = 'Gdlat' elif (75.0 <= thisAz <= 105.0 or -105.0 <= thisAz <= -75.0) and \ abs(thisAz1 - thisAz2) < 0.5: thisElScan = 'Glon' else: thisElScan = 'Gcdist' # get index of this scan, None if a new scan index = None for i, item in enumerate(elScan): if item == 'Gdlat' and thisElScan == 'Gdlat': index = i break elif item == 'Glon' and thisElScan == 'Glon': index = i break elif item == 'Gcdist' and thisElScan == 'Gcdist' and int(thisAz) == int(startAz[i]): index = i break elif item == 'Gcdist' and thisElScan == 'Gcdist' and i == len(elScan)-1: index = i break if index == None: # a new scan has been found thisIsprintStr.append('') startUT.append(thisUt) startAz.append(thisAz) startEl.append(thisEl) endUT.append(None) endAz.append(None) endEl.append(None) elScan.append(thisElScan) minGdlat.append(None) maxGdlat.append(None) minGlon.append(None) maxGlon.append(None) minGdalt.append(None) maxGdalt.append(None) minGcdist.append(None) maxGcdist.append(None) index = len(thisIsprintStr) - 1 lastElDirection = thisElDirection endUT[index] = thisUt endAz[index] = thisAz endEl[index] = thisEl # gdlatr, gdlonr, galtr, range, az1, az2, el1, el2,plotParm thisIsprintStr[index] += '%f %f %f %f %f %f %f %f %s\n' % (thisGdlatr, thisGdlonr, thisGaltr, thisRange, thisAz1, thisAz2, thisEl1, thisEl2, thisParm) elif self.scanType == 'az' and thisScntyp == 2: # az scan inAzScan = True inElScan = False # add this azimuth scan point # check if this is a new scan newAzScan = False if lastEl == None: newAzScan = True # check for elevation change elif abs(lastEl - int(thisEl)) > 3: newAzScan = True # check for direction change if lastAzDirection != None: if lastAzDirection != thisAzDirection: newAzScan = True thisAzDirection = None if newAzScan: # a new azimuth scan has been found thisIsprintStr.append('') startUT.append(thisUt) startAz.append(thisAz) startEl.append(thisEl) endUT.append(None) endAz.append(None) endEl.append(None) elScan.append(None) minGdlat.append(None) maxGdlat.append(None) minGlon.append(None) maxGlon.append(None) minGdalt.append(None) maxGdalt.append(None) minGcdist.append(None) maxGcdist.append(None) index = len(thisIsprintStr) - 1 lastEl = int(thisEl) lastAzDirection = None else: # this is at least the second line of the scan if not thisAzDirection is None: lastAzDirection = thisAzDirection endUT[-1] = thisUt endAz[-1] = thisAz endEl[-1] = thisEl thisIsprintStr[-1] += '%f %f %f %f %f %f %f %f %s\n' % (thisGdlatr, thisGdlonr, thisGaltr, thisRange, thisAz1, thisAz2, thisEl1, thisEl2, thisParm) else: # not a scan line inAzScan = False inElScan = False continue if minGdlat[index] == None: minGdlat[index] = thisGdlat maxGdlat[index] = thisGdlat minGlon[index] = thisGlon maxGlon[index] = thisGlon minGdalt[index] = thisGdalt maxGdalt[index] = thisGdalt minGcdist[index] = thisGcdist maxGcdist[index] = thisGcdist else: if minGdlat[index] > thisGdlat: minGdlat[index] = thisGdlat if maxGdlat[index] < thisGdlat: maxGdlat[index] = thisGdlat if minGlon[index] > thisGlon: minGlon[index] = thisGlon if maxGlon[index] < thisGlon: maxGlon[index] = thisGlon if minGdalt[index] > thisGdalt: minGdalt[index] = thisGdalt if maxGdalt[index] < thisGdalt: maxGdalt[index] = thisGdalt if minGcdist[index] > thisGcdist: minGcdist[index] = thisGcdist if maxGcdist[index] < thisGcdist: maxGcdist[index] = thisGcdist # end, close out last cycle for i in range(len(thisIsprintStr)): if len(thisIsprintStr[i]) == 0: continue retList.append((thisIsprintStr[i], startUT[i], startAz[i], startEl[i], endUT[i], endAz[i], endEl[i], elScan[i], minGdlat[i], maxGdlat[i], minGlon[i], maxGlon[i], minGdalt[i], maxGdalt[i], minGcdist[i], maxGcdist[i])) return(retList)
def getDateStrFromUT(
self, ut)
getDateStrFromUT returns a date string formated as YYYY-MM-DD HH:MM:SS from a ut time (seconds since 1/1/1950)
def getDateStrFromUT(self, ut): """getDateStrFromUT returns a date string formated as YYYY-MM-DD HH:MM:SS from a ut time (seconds since 1/1/1950) """ timeList = madrigal._derive.getDateFromUt(float(ut)) return '%04i-%02i-%02i %02i:%02i:%02i' % (timeList[0], timeList[1], timeList[2], timeList[3], timeList[4], timeList[5])
def getTimeStrFromUT(
self, ut)
getTimeStrFromUT returns a time string formated as HH:MM:SS from a ut time (seconds since 1/1/1950)
def getTimeStrFromUT(self, ut): """getTimeStrFromUT returns a time string formated as HH:MM:SS from a ut time (seconds since 1/1/1950) """ timeList = madrigal._derive.getDateFromUt(float(ut)) return '%02i:%02i:%02i' % (timeList[3], timeList[4], timeList[5])
def plotAllScans(
self, scanType, fullFilenameTemplate, plotParm, size='small', xMinimum=None, xMaximum=None, yMinimum=None, yMaximum=None, xGridSize=None, yGridSize=None, minColormap=None, maxColormap=None, colorMap=<matplotlib.colors.LinearSegmentedColormap object at 0x10afdbb90>, maxNumLines=None, filterStr='')
plotAllScans creates a series of az or el scans.
Inputs:
scanType - must be 'az' or 'el' fullFilename - full path of file containing pcolor plot to be saved. Each image created will have _#.png appended, with # starting at 0 plotParm - mnemonic of parameter to be plotted. size - size of plot to save. Must be "small", "wide", or "large". Defaults to small. xMinimum = minumum x value. If None (default), uses lowest x value found for each scan. xMaximum = maximum x value. If None (default), uses highest x value found for each scan. yMinimum = minumum y value. If None (default), uses lowest y value found for each scan. yMaximum = maximum y value. If None (default), uses highest y value found for each scan. minColormap - minimum parameter value (defaults to lowest parameter value) maxColormap - maximum parameter value (defaults to highest parameter value). However, if both minColormap and maxColormap == None, autoscaling applied. colorMap - sets colormap. It not given, defaults to matplotlib.cm.jet maxNumLine - max number of lines in isprintText before truncating. If None, no truncation filterStr - a filter string to pass to isprint. Defaults to no filtering
Returns - a list of tuples, where each tuple has two items: 1. time string, 2. metadata string in form for scanTab.txt. List length = number of plots created
def plotAllScans(self, scanType, fullFilenameTemplate, plotParm, size = 'small', xMinimum = None, xMaximum = None, yMinimum = None, yMaximum = None, xGridSize = None, yGridSize = None, minColormap = None, maxColormap = None, colorMap = matplotlib.cm.jet, maxNumLines = None, filterStr = ''): """plotAllScans creates a series of az or el scans. Inputs: scanType - must be 'az' or 'el' fullFilename - full path of file containing pcolor plot to be saved. Each image created will have _#.png appended, with # starting at 0 plotParm - mnemonic of parameter to be plotted. size - size of plot to save. Must be "small", "wide", or "large". Defaults to small. xMinimum = minumum x value. If None (default), uses lowest x value found for each scan. xMaximum = maximum x value. If None (default), uses highest x value found for each scan. yMinimum = minumum y value. If None (default), uses lowest y value found for each scan. yMaximum = maximum y value. If None (default), uses highest y value found for each scan. minColormap - minimum parameter value (defaults to lowest parameter value) maxColormap - maximum parameter value (defaults to highest parameter value). However, if both minColormap and maxColormap == None, autoscaling applied. colorMap - sets colormap. It not given, defaults to matplotlib.cm.jet maxNumLine - max number of lines in isprintText before truncating. If None, no truncation filterStr - a filter string to pass to isprint. Defaults to no filtering Returns - a list of tuples, where each tuple has two items: 1. time string, 2. metadata string in form for scanTab.txt. List length = number of plots created if scanType not in ('az', 'el'): raise ValueError, 'scantype must be az or el, not %s' % (str(scanType)) self.scanType = scanType retList = [] # handle ion velocity if plotParm.lower() == 'vo': cmap = madrigal.ui.madrigalPlot.get_vo_cmap() else: cmap = matplotlib.cm.jet # create isprint string parms = 'ut1,scntyp,cycn,%s,gdalt,gdlat,glon,azm,elm,gcdist' % (plotParm.strip()) isprintStr = getIsprintString(self.madFile, parms, filterStr) try: scanList = self.createScanInfoList(isprintStr) except: traceback.print_exc() return (retList) # loop through each scan scanFailureCount = 0 # keep track of how many scans fail for i in range(len(scanList)): scanCount = i - scanFailureCount scanInfo = scanList[i] try: startDateStr = self.getDateStrFromUT(scanInfo[1]) except: # no scans may have been found continue endDateStr = self.getTimeStrFromUT(scanInfo[4]) # create title if scanType == 'el': if scanInfo[3] > scanInfo[6]: ind = 'down' direction = 1 else: ind = 'up' direction = 0 titleStr = 'El %s scan (%s) %s-%s, az=%i' % (plotParm, ind, startDateStr, endDateStr, int(scanInfo[2])) timeStr = '%s-%s' % (startDateStr, endDateStr) metaStr = 'El scan: startTime %i el %f az %f stopTime %i el %f az %f dir %i' % (scanInfo[1], scanInfo[3], scanInfo[2], scanInfo[4], scanInfo[6], scanInfo[5], direction) retList.append((timeStr,metaStr)) if scanInfo[7] == 'Gdlat': xLabelStr = 'Geodetic latitude' xGridSize = 1.0 elif scanInfo[7] == 'Glon': xLabelStr = 'Longitude' xGridSize = 1.0 elif scanInfo[7] == 'Gcdist': xLabelStr = 'Ground distance in km' xGridSize = 100.0 xLabelStr = '' yLabelStr = 'Altitude (km)' if xGridSize == None: xGridSize = 1.0 if yGridSize == None: yGridSize = 20.0 else: if scanInfo[2] > scanInfo[5]: ind = 'ccw' direction = 1 else: ind = 'cw' direction = 0 titleStr = 'Az %s scan (%s) %s-%s, el=%i' % (plotParm, ind, startDateStr, endDateStr, int(scanInfo[3])) timeStr = '%s-%s' % (startDateStr, endDateStr) metaStr = 'Az scan: startTime %i az %f el %f stopTime %i az %f el %f dir %i' % (scanInfo[1], scanInfo[2], scanInfo[3], scanInfo[4], scanInfo[5], scanInfo[6], direction) retList.append((timeStr,metaStr)) xLabelStr = 'Longitude' yLabelStr = 'Geodetic latitude' xGridSize = 1.0 yGridSize = 1.0 name = '%s_%06i.png' % (fullFilenameTemplate, scanCount) try: madPcolorScan(scanInfo[0], xGridSize, yGridSize, titleStr, xLabelStr, yLabelStr, name, minColormap = minColormap, maxColormap = maxColormap, colorMap = cmap) except: print 'Problem creating scan %s' % (str(retList[-1])) traceback.print_exc() scanFailureCount += 1 retList.remove(retList[-1]) return (retList)
def plotAllWedgeScans(
self, scanType, fullFilenameTemplate, plotParm, size='small', xMinimum=None, xMaximum=None, yMinimum=None, yMaximum=None, minColormap=None, maxColormap=None, colorMap=<matplotlib.colors.LinearSegmentedColormap object at 0x10afdbb90>, maxNumLines=None, filterStr='', addTitle='', includeKml=False, radarName=None, radarDesc=None)
plotAllWedgeScans creates a series of az or el scans. Similar to plotAllScans, except produces fancier wedge plots with uniform scalling.
Inputs:
scanType - must be 'az' or 'el' fullFilename - full path of file containing pcolor plot to be saved. Each image created will have _#.png appended, with # starting at 0 plotParm - mnemonic of parameter to be plotted. size - size of plot to save. Must be "small", "wide", or "large". Defaults to small. xMinimum = minumum x value. If None (default), uses lowest x value found for each scan. xMaximum = maximum x value. If None (default), uses highest x value found for each scan. yMinimum = minumum y value. If None (default), uses lowest y value found for each scan. yMaximum = maximum y value. If None (default), uses highest y value found for each scan. minColormap - minimum parameter value (defaults to lowest parameter value) maxColormap - maximum parameter value (defaults to highest parameter value). However, if both minColormap and maxColormap == None, autoscaling applied. colorMap - sets colormap. It not given, defaults to matplotlib.cm.jet maxNumLine - max number of lines in isprintText before truncating. If None, no truncation filterStr - a filter string to pass to isprint. Defaults to no filtering addTitle - a string with additional title. If empty string (the default), no additional title string. includeKml - if True, create a corresponding kml file for every png file. Same names as png files, except extension = .kml. If False, do not. radarName - name to label radar placemark if kml generated. radarDesc - description text for radar placemark if kml generated
Returns - a list of tuples, where each tuple has two items: 1. time string, 2. metadata string in form for scanTab.txt. List length = number of plots created
def plotAllWedgeScans(self, scanType, fullFilenameTemplate, plotParm, size = 'small', xMinimum = None, xMaximum = None, yMinimum = None, yMaximum = None, minColormap = None, maxColormap = None, colorMap = matplotlib.cm.jet, maxNumLines = None, filterStr = '', addTitle = '', includeKml = False, radarName = None, radarDesc = None): """plotAllWedgeScans creates a series of az or el scans. Similar to plotAllScans, except produces fancier wedge plots with uniform scalling. Inputs: scanType - must be 'az' or 'el' fullFilename - full path of file containing pcolor plot to be saved. Each image created will have _#.png appended, with # starting at 0 plotParm - mnemonic of parameter to be plotted. size - size of plot to save. Must be "small", "wide", or "large". Defaults to small. xMinimum = minumum x value. If None (default), uses lowest x value found for each scan. xMaximum = maximum x value. If None (default), uses highest x value found for each scan. yMinimum = minumum y value. If None (default), uses lowest y value found for each scan. yMaximum = maximum y value. If None (default), uses highest y value found for each scan. minColormap - minimum parameter value (defaults to lowest parameter value) maxColormap - maximum parameter value (defaults to highest parameter value). However, if both minColormap and maxColormap == None, autoscaling applied. colorMap - sets colormap. It not given, defaults to matplotlib.cm.jet maxNumLine - max number of lines in isprintText before truncating. If None, no truncation filterStr - a filter string to pass to isprint. Defaults to no filtering addTitle - a string with additional title. If empty string (the default), no additional title string. includeKml - if True, create a corresponding kml file for every png file. Same names as png files, except extension = .kml. If False, do not. radarName - name to label radar placemark if kml generated. radarDesc - description text for radar placemark if kml generated Returns - a list of tuples, where each tuple has two items: 1. time string, 2. metadata string in form for scanTab.txt. List length = number of plots created """ if scanType not in ('az', 'el'): raise ValueError, 'scantype must be az or el, not %s' % (str(scanType)) self.scanType = scanType if scanType == 'az': wedgeScanType = 'az' retList = [] # handle ion velocity if plotParm.lower() == 'vo': cmap = madrigal.ui.madrigalPlot.get_vo_cmap() else: cmap = matplotlib.cm.jet # create isprint string parms = 'ut1,scntyp,cycn,%s,gdalt,gdlat,glon,azm,elm,gcdist,gdlatr,gdlonr,galtr,range,az1,az2,el1,el2' % (plotParm.strip()) filterStr += ' filter=%s,, ' % (plotParm.strip()) isprintStr = getIsprintString(self.madFile, parms, filterStr) try: scanList = self.createWedgeScanInfoList(isprintStr) except: traceback.print_exc() return (retList) gdlatr, gdlonr, galtr = self._getInstLocation(isprintStr) # create limit dictionary used to keep all scans of the same type with the same limits limitDict = self._getLimits(scanList, xMinimum, xMaximum, yMinimum, yMaximum) # loop through each scan scanFailureCount = 0 # keep track of how many scans fail for i in range(len(scanList)): scanCount = i - scanFailureCount scanInfo = scanList[i] try: startDateStr = self.getDateStrFromUT(scanInfo[1]) except: # no scans may have been found continue endDateStr = self.getTimeStrFromUT(scanInfo[4]) # create title if scanType == 'el': if scanInfo[3] > scanInfo[6]: ind = 'down' direction = 1 else: ind = 'up' direction = 0 if int(scanInfo[2]) == int(scanInfo[5]): # no change in az titleStr = 'El %s scan (%s) %s-%s, az=%i %s' % (plotParm, ind, startDateStr, endDateStr, int(scanInfo[2]), addTitle) else: # az changed titleStr = 'El (%i-%i) %s scan %s-%s, az=%i-%i %s' % (int(scanInfo[3]), int(scanInfo[6]), plotParm, startDateStr, endDateStr, int(scanInfo[2]), int(scanInfo[5]), addTitle) timeStr = '%s-%s' % (startDateStr, endDateStr) metaStr = 'El scan: startTime %i el %f az %f stopTime %i el %f az %f dir %i' % (scanInfo[1], scanInfo[3], scanInfo[2], scanInfo[4], scanInfo[6], scanInfo[5], direction) retList.append((timeStr,metaStr)) if scanInfo[7] == 'Gdlat': xLabelStr = 'Geodetic latitude' wedgeScanType = 'el_lat' elif scanInfo[7] == 'Glon': xLabelStr = 'Longitude' wedgeScanType = 'el_lon' elif scanInfo[7] == 'Gcdist': xLabelStr = 'Ground distance in km' wedgeScanType = 'el_gcdist' xLabelStr = '' yLabelStr = 'Altitude (km)' else: if scanInfo[2] > scanInfo[5]: ind = 'ccw' direction = 1 else: ind = 'cw' direction = 0 titleStr = 'Az %s scan (%s) %s-%s, el=%i %s' % (plotParm, ind, startDateStr, endDateStr, int(scanInfo[3]), addTitle) timeStr = '%s-%s' % (startDateStr, endDateStr) metaStr = 'Az scan: startTime %i az %f el %f stopTime %i az %f el %f dir %i' % (scanInfo[1], scanInfo[2], scanInfo[3], scanInfo[4], scanInfo[5], scanInfo[6], direction) retList.append((timeStr,metaStr)) xLabelStr = 'Longitude' yLabelStr = 'Geodetic latitude' name = '%s_%06i.png' % (fullFilenameTemplate, scanCount) try: madPcolorWedgeScan(scanInfo[0], wedgeScanType, titleStr, xLabelStr, yLabelStr, name, xMinimum = limitDict[wedgeScanType][0], xMaximum = limitDict[wedgeScanType][1], yMinimum = limitDict[wedgeScanType][2], yMaximum = limitDict[wedgeScanType][3], minColormap = minColormap, maxColormap = maxColormap, colorMap = cmap) success = True except: print 'Problem creating scan %s' % (str(retList[-1])) traceback.print_exc() scanFailureCount += 1 retList.remove(retList[-1]) success = False if includeKml and success: kmlName = name[:-3] + 'kml' try: madPcolorWedgeKmlScan(scanInfo[0], wedgeScanType, kmlName, minColormap = minColormap, maxColormap = maxColormap, instName = radarName, instDesc = radarDesc, instLat = gdlatr, instLon = gdlonr, instAlt = galtr, colorMap = cmap) except: print 'Problem creating kml scan' traceback.print_exc() return (retList)