import os import time from taskinit import * from casa_system import procmgr def plotms(vis=None, gridrows=None, gridcols=None, rowindex=None,colindex=None, plotindex=None, xaxis=None, xdatacolumn=None, xframe=None, xinterp=None, yaxis=None, ydatacolumn=None, yframe=None, yinterp=None, yaxislocation=None, selectdata=None, field=None, spw=None, timerange=None, uvrange=None, antenna=None, scan=None, correlation=None, array=None, observation=None, intent=None, feed=None, msselect=None, averagedata=None, avgchannel=None, avgtime=None, avgscan=None, avgfield=None, avgbaseline=None, avgantenna=None, avgspw=None, scalar=None, transform=None, freqframe=None,restfreq=None,veldef=None,shift=None, extendflag=None, extcorr=None, extchannel=None, iteraxis=None,xselfscale=None,yselfscale=None, xsharedaxis=None, ysharedaxis=None, customsymbol=None, symbolshape=None, symbolsize=None, symbolcolor=None, symbolfill=None, symboloutline=None, coloraxis=None, customflaggedsymbol=None, flaggedsymbolshape=None, flaggedsymbolsize=None, flaggedsymbolcolor=None, flaggedsymbolfill=None, flaggedsymboloutline=None, xconnector=None, timeconnector=False, plotrange=None, title=None, titlefont=None, xlabel=None, xaxisfont=None, ylabel=None, yaxisfont=None, showmajorgrid=None, majorwidth=None, majorstyle=None, majorcolor=None, showminorgrid=None, minorwidth=None, minorstyle=None, minorcolor=None, showlegend=None, legendposition=None, plotfile=None, expformat=None, verbose=True, exprange=None, highres=None, dpi=None, width=None, height=None, overwrite=None, showgui=None, clearplots=None, callib=None, headeritems=None, showatm=None, showtsky=None, showimage=None): # we'll add these later # extspw=None, extantenna=None, # exttime=None, extscans=None, extfield=None, """ Task for plotting and interacting with visibility data. A variety of axes choices (including data column) along with MS selection and averaging options are provided for data selection. Flag extension parameters are also available for flagging operations in the plotter. All of the provided parameters can also be set using the GUI once the application has been launched. Additional and more specific operations are available through the GUI and/or through the plotms tool (pm). Keyword arguments: vis -- input visibility dataset default: '' gridrows -- Number of subplot rows. default: 1 gridcols -- Number of subplot columns. default: 1 rowindex -- Row location of the subplot (0-based). default: 0 colindex -- Column location of the subplot (0-based). default: 0 plotindex -- Index to address a subplot (0-based). default: 0 xaxis, yaxis -- what to plot on the two axes default: '' (uses PlotMS defaults/current set). >>> xaxis, yaxis expandable parameters xdatacolumn, ydatacolumn -- which data column to use for data axes default: '' (uses PlotMS default/current set). xframe, yframe -- which coordinates frame to use for ant-ra,ant-dec axes default: '' (uses PlotMS default/current set). xinterp, yinterp -- which interpolation method to use for ant-ra,ant-dec axes default: '' (uses PlotMS default/current set). yaxislocation -- whether the data should be plotted using the left or right y-axis default: '' (uses PlotMS default). iteraxis -- what axis to iterate on when doing iteration plots default: '' >>> xsharedaxis, ysharedaxis, xselfscale, yselfscale expandable parameters xselfscale -- If true, iterated plots should share a common x-axis label per column. default: False. yselfscale -- If true, iterated plots should share a common y-axis label per row. default: False. xsharedaxis -- use a common x-axis for vertically aligned plots (must also set xselfscale=True) default: False. ysharedaxis -- use a common y-axis for horizontally aligned plots (must also set yselfscale=True) default: False. selectdata -- data selection parameters flag (see help par.selectdata for more detailed information) default: False >>> selectdata expandable parameters field -- select using field ID(s) or field name(s) default: '' (all). spw -- select using spectral window/channels default: '' (all) timerange -- select using time range default: '' (all). uvrange -- select using uvrange default: '' (all). antenna -- select using antenna/baseline default: '' (all). scan -- select using scan number default: '' (all). correlation -- select using correlations default: '' (all). array -- select using (sub)-array range default: '' (all). observation -- select by observation ID(s). default: '' (all). intent -- select observing intent default: '' (no selection by intent) intent='*BANDPASS*' (selects data labelled with BANDPASS intent) feed -- select feed ID default: '' (all) feed='1~2' msselect -- TaQL selection expression default: '' (all). averagedata -- data averaging parameters flag default: False. >>> averagedata expandable parameters avgchannel -- average over channel? either blank for none, or a value in channels. default: '' (none). avgtime -- average over time? either blank for none, or a value in seconds. default: '' (none). avgscan -- average over scans? only valid if time averaging is turned on. default: False. avgfield -- average over fields? only valid if time averaging is turned on. default: False. avgbaseline -- average over all baselines? mutually exclusive with avgantenna. default: False. avgantenna -- average by per-antenna? mutually exclusive with avgbaseline. default: False. avgspw -- average over all spectral windows? default: False. extendflag -- have flagging extend to other data points? default: False. >>> extendflag expandable parameters extcorr -- extend flags based on correlation? blank = none. default: ''. extchannel -- extend flags based on channel? default: False. extspw -- extend flags based on spw? default: False. extantenna -- extend flags based on antenna? should be either blank, 'all' for all baselines, or an antenna-based value. default: ''. exttime -- extend flags based on time (within scans)? default: False. extscans -- extend flags based on scans? only valid if time extension is turned on. default: False. extfield -- extend flags based on field? only valid if time extension is turned on. default: False. coloraxis -- which axis to use for colorizing default: '' (ignored - same as colorizing off) title -- title along top of plot (called "canvas" in some places) titlefont -- plot title font size default: 0 (autosize depending on grid) exprange -- Export all iteration plots ('all') or only the current one. default: '' (only export the current iteration plot) xlabel, ylabel -- text to label horiz. and vert. axes, with formatting (%% and so on) xaxisfont, yaxisfont -- int for axis font size showlegend -- show a legend on the plot default: False legendposition -- position for the legend. Legends can be interior or exterior to the plot Interior legends can be located in the upper right, lower right, upper left, or lower left. Exterior legends can be located on the right, left, top, or bottom. default: 'upperright' showgui -- Whether or not to display the plotting GUI default: True; example showgui=False clearplots -- clear existing plots so that the new ones coming in can replace them. callib -- calibration library string, list of strings, or filename for on-the-fly calibration headeritems -- string of comma-separated page header items keywords showatm -- show atmospheric transmission curve showtsky -- show sky temperature curve showimage -- show image sideband curve """ # Check if DISPLAY environment variable is set. if os.getenv('DISPLAY') == None: casalog.post('ERROR: DISPLAY environment variable is not set! Cannot run plotms.', 'SEVERE') return False # using procmgr? usingprocmgr = False if casa['state']['init_version'] > 0: usingprocmgr = True if not procIsRunning("dbus"): casalog.post('ERROR: dbus-daemon has stopped, cannot run plotms. Please restart casa.', 'SEVERE') return False # check arguments # check plotfile for export if plotfile: if not os.path.dirname(plotfile): # CAS-7148: Use dir that user cd'ed to in casapy session # instead of dir that plotfile = os.path.join(os.getcwd(), plotfile) if (os.path.exists(plotfile) and not overwrite): casalog.post("Plot file " + plotfile + " exists and overwrite is false, cannot write the file", "SEVERE") return False # Define axis synonyms # format is: synonym['new_term'] = 'existing_term' # existing_term in PlotMSConstants.h # CAS-8532: match capitalization in axis names in GUI if True: synonyms = {} synonyms['Scan'] = 'scan' synonyms['Field'] = 'field' synonyms['Time'] = 'time' synonyms['timeinterval'] = synonyms['timeint'] = synonyms['time_interval'] = synonyms['Interval'] = 'interval' synonyms['Spw'] = 'spw' synonyms['chan'] = synonyms['Channel'] = 'channel' synonyms['freq'] = synonyms['Frequency'] = 'frequency' synonyms['vel'] = synonyms['Velocity'] = 'velocity' synonyms['correlation'] = synonyms['Corr'] = 'corr' synonyms['ant1'] = synonyms['Antenna1'] = 'antenna1' synonyms['ant2'] = synonyms['Antenna2'] = 'antenna2' synonyms['Baseline'] = 'baseline' synonyms['Row'] = 'row' synonyms['Observation'] = 'observation' synonyms['Intent'] = 'intent' synonyms['Feed1'] = 'feed1' synonyms['Feed2'] = 'feed2' synonyms['amplitude'] = synonyms['Amp'] = 'amp' synonyms['Phase'] = 'phase' synonyms['Real'] = 'real' synonyms['imaginary'] = synonyms['Imag'] = 'imag' synonyms['weight'] = synonyms['Wt'] = synonyms['Weight'] = 'wt' synonyms['wtamp'] = synonyms['Wt*Amp'] = 'wtamp' synonyms['weightspectrum'] = synonyms['WtSp'] = synonyms['WeightSpectrum'] = 'wtsp' synonyms['Sigma'] = 'sigma' synonyms['sigmaspectrum'] = synonyms['SigmaSpectrum'] = synonyms['SigmaSp'] = 'sigmasp' synonyms['Flag'] = 'flag' synonyms['FlagRow'] = 'flagrow' synonyms['UVdist'] = 'uvdist' synonyms['uvdistl'] = synonyms['uvdist_l']=synonyms['UVwave'] = 'uvwave' synonyms['U'] = 'u' synonyms['V'] = 'v' synonyms['W'] = 'w' synonyms['Uwave'] = 'uwave' synonyms['Vwave'] = 'vwave' synonyms['Wwave'] = 'wwave' synonyms['Azimuth'] = 'azimuth' synonyms['Elevation'] = 'elevation' synonyms['hourang'] = synonyms['HourAngle'] = 'hourangle' synonyms['parang'] = synonyms['parallacticangle'] = synonyms['ParAngle'] = 'parangle' synonyms['ant'] = synonyms['Antenna'] = 'antenna' synonyms['Ant-Azimuth'] = 'ant-azimuth' synonyms['Ant-Elevation'] = 'ant-elevation' synonyms['Ant-Ra'] = synonyms['Ant-RA'] = 'ant-ra' synonyms['Ant-Dec'] = synonyms['Ant-DEC'] = 'ant-dec' synonyms['ant-parallacticangle']=synonyms['ant-parang'] = synonyms['Ant-ParAngle'] = 'ant-parangle' synonyms['gamp']=synonyms['gainamp']=synonyms['GainAmp']='Gain Amp' synonyms['gphase']=synonyms['gainphase']=synonyms['GainPhase']='Gain Phase' synonyms['greal']=synonyms['gainreal']=synonyms['GainReal']='Gain Real' synonyms['gimag']=synonyms['gainimag']=synonyms['GainImag']='Gain Imag' synonyms['del']=synonyms['delay']=synonyms['Delay']='delay' synonyms['swp']=synonyms['swpower']=synonyms['switchedpower']=synonyms['SwPower']=synonyms['spgain']='swpower' synonyms['tsys']=synonyms['Tsys']=synonyms['TSYS']='tsys' synonyms['opac']=synonyms['opacity']=synonyms['Opac']='opac' synonyms['snr']=synonyms['SNR']='SNR' synonyms['antpos']='Antenna Positions' synonyms['radialvelocity']= synonyms['Radial Velocity'] = 'Radial Velocity [km/s]' synonyms['rho']=synonyms['Distance']='Distance (rho) [km]' # data columns: unspecified residuals default to vector synonyms['residual']=synonyms['corrected-model']='corrected-model_vector' synonyms['data-model']='data-model_vector' synonyms['corrected/model']='corrected/model_vector' synonyms['data/model']='data/model_vector' if True: # ant-ra/ant-dec axes parameters: Python/C++ parameters maps # Reference Frames cpp_radec_frame = {} for py_radec_ref_frame in ['icrs','j2000','b1950','azelgeo','galactic']: cpp_radec_frame[py_radec_ref_frame] = py_radec_ref_frame.upper() # Interpolation Methods cpp_radec_interp = {} for py_radec_interp in ['nearest','cubic spline']: cpp_radec_interp[py_radec_interp] = ' '.join( [word.capitalize() for word in py_radec_interp.split()] ) cpp_radec_interp['spline']=cpp_radec_interp['cubic spline'] try: # Do preliminary checks on argument values # Set synonyms to existing_terms if(synonyms.has_key(xaxis)): xaxis = synonyms[xaxis] if isinstance(yaxis, str): if synonyms.has_key(yaxis): yaxis = synonyms[yaxis] elif isinstance(yaxis, list): for index,axis in enumerate(yaxis): if synonyms.has_key(axis): yaxis[index] = synonyms[axis] if isinstance(coloraxis, str): if synonyms.has_key(coloraxis): coloraxis = synonyms[coloraxis] if(synonyms.has_key(xdatacolumn)): xdatacolumn = synonyms[xdatacolumn] if isinstance(ydatacolumn, str): if synonyms.has_key(ydatacolumn): yaxis = synonyms[ydatacolumn] elif isinstance(ydatacolumn, list): for index,col in enumerate(ydatacolumn): if synonyms.has_key(col): ydatacolumn[index] = synonyms[col] for param_name in ['xframe','yframe']: param_py_value = eval(param_name) if isinstance(param_py_value, str): if cpp_radec_frame.has_key(param_py_value): exec('{p_name} = cpp_radec_frame[param_py_value]'.format( p_name=param_name) ) elif isinstance(param_py_value, list): for index,frame in enumerate(param_py_value): if cpp_radec_frame.has_key(frame): exec('{p_name}[{index}] = cpp_radec_frame[frame]'.format( p_name=param_name, index=index) ) for param_name in ['xinterp','yinterp']: param_py_value = eval(param_name) if isinstance(param_py_value, str): if cpp_radec_interp.has_key(param_py_value): exec('{p_name} = cpp_radec_interp[param_py_value]'.format( p_name=param_name) ) elif isinstance(param_py_value, list): for index,interp in enumerate(param_py_value): if cpp_radec_interp.has_key(interp): exec('{p_name}[{index}] = cpp_radec_interp[interp]'.format( p_name=param_name, index=index) ) # check vis exists vis = vis.strip() if len(vis) > 0: vis = os.path.abspath(vis) if not os.path.exists(vis): casalog.post('\n'.join(['Input file not found:',vis]),"SEVERE") return False # check plotindex if not plotindex: plotindex = 0 if plotindex < 0: casalog.post("A negative plotindex is not valid.", "SEVERE") return False if clearplots and plotindex > 0: casalog.post("A nonzero plotindex is not valid when clearing plots.", "SEVERE") return False # start plotms with the procmgr, use casa logfile startProcess = False if usingprocmgr: if not procIsRunning("plotms"): # set plotmsApp plotmsApp = 'casaplotms' for dir in os.getenv('PATH').split(':'): dd = dir + os.sep + plotmsApp if os.path.exists(dd) and os.access(dd, os.X_OK): plotmsApp = dd break # set logfile try: logfile = casa['files']['logfile'] except KeyError: logfile = "" # start process with procmgr startProcess = True procmgr.create("plotms", [plotmsApp, "--nogui", "--nopopups", "--casapy", "--logfilename="+logfile]) if procIsRunning("plotms"): # plotms is running, but is it connected? CAS-11306 procmgrPid = procmgr.fetch('plotms').pid plotmsPid = pm.getPlotMSPid() if plotmsPid != procmgrPid: # connect future pm calls to procmgr plotms pm.setPlotMSPid(procmgrPid) else: casalog.post("plotms failed to start", "SEVERE") return False # check clearplots and valid plotindex if startProcess and not clearplots: clearplots = True if startProcess and plotindex > 0: casalog.post("Invalid initial plot index, setting to 0", "WARN") plotindex = 0 else: numplots = pm.getNumPlots() if plotindex > numplots: casalog.post("Invalid plot index, setting to " + str(numplots), "WARN") plotindex = numplots # Determine whether this is going to be a scripting client or # a full GUI supporting user interaction. This must be done # before any other properties are set because it affects the # constructor of plotms. if casa['flags'].nogui: showgui = False pm.setShowGui( showgui ) if clearplots: # Clear any existing plots unless still drawing last one if pm.isDrawing(): casalog.post("Plotms is running in GUI mode and cannot be run again until the current drawing completes.", "SEVERE") return False pm.clearPlots() # set grid gridChange = False if gridrows > 0 or gridcols > 0: gridChange = True if not gridrows: gridrows = 1 if not gridcols: gridcols = 1 if gridChange: pm.setGridSize( gridrows, gridcols ) # set vis filename pm.setPlotMSFilename(vis, False, plotindex ) # set yaxis defaults as needed if isinstance(yaxis, tuple): # yaxis default from xml is str or list: yaxis=('', []) # set it to the empty string yaxis = yaxis[0] if not yaxis or isinstance(yaxis, str): if not yaxis: yaxis = '' if yaxis == 'ant-ra' or yaxis == 'ant-dec': # Handle empty lists as empty strings if isinstance(yinterp, list) and not yinterp: yinterp = '' if isinstance(yframe, list) and not yframe: yframe = '' if isinstance(yinterp, str) and isinstance(yframe, str): # For now, ignore cases where xinterp or xframe is a list if isinstance(xframe, list): msg_fmt = "Assuming xframe={assumed} instead of xframe={org}" assumed_xframe = '' if not xframe else xframe[0] msg = msg_fmt.format(assumed=assumed_xframe, org=xframe) casalog.post(msg,'WARN','set_axes') xframe = assumed_xframe if isinstance(xinterp, list): msg_fmt = "Assuming xinterp={assumed} instead of xinterp={org}" assumed_xinterp = '' if not xinterp else xinterp[0] msg = msg_fmt.format(assumed=assumed_xinterp, org=xinterp) casalog.post(msg,'WARN','set_axes') xinterp = assumed_xinterp if isinstance(yaxislocation, list): yaxislocation= 'left' if not yaxislocation else yaxislocation[0] if not isinstance(yaxislocation, str): yaxislocation= 'left' xdatacolumn = ydatacolumn = '' pm.setPlotAxes(xaxis, yaxis, xdatacolumn, ydatacolumn, xframe, yframe, xinterp, yinterp, yaxislocation, False, plotindex, 0) else: # Handle yinterp, yframe and yaxislocation as parallel lists, which # 1. must have the same length # 2. must NOT contain empty strings, otherwise C++ vectors won't have the same length if isinstance(yinterp, list): if isinstance(yframe, str): # Allow usage: plotms(yinterp=['nearest','spline'],yframe='') if not yframe: yframe = 'icrs' yframe = [yframe for i in yinterp] else: if len(yframe) != len(yinterp): msg_fmt = "Length mismatch: yframe={0} and yinterp={1}" msg = msg_fmt.format(yframe,yinterp) casalog.post(msg,'ERROR',set_axes) return False if isinstance(yaxislocation, str): # Allow usage: plotms(yinterp=['nearest','spline'],yaxislocation='') if not yaxislocation: yaxislocation = 'left' yaxislocation = [yaxislocation for i in yinterp] else: if len(yaxislocation) != len(yinterp): msg_fmt = "Length mismatch: yaxislocation={0} and yinterp={1}" msg = msg_fmt.format(yaxislocation,yinterp) casalog.post(msg,'ERROR',set_axes) return False # For now: enforce xframe=yframe, xinterp=yinterp in this case casalog.post('Enforcing xframe=yframe, xinterp=yinterp','WARN','set_axes') xdatacolumn = ydatacolumn = 'data' if not xaxis: xaxis = 'time' for dataindex, (frame,interp,yaxisloc) in enumerate(zip(yframe,yinterp,yaxislocation)): pm.setPlotAxes(xaxis, yaxis, xdatacolumn, ydatacolumn, frame, frame, interp, interp, yaxisloc, False, plotindex, dataindex) else: casalog.post('Not yet implemented: yframe=list','SEVERE','set_axes') return False else: if not yaxislocation or not isinstance(yaxislocation, str): yaxislocation='left' if not ydatacolumn or not isinstance(ydatacolumn, str): ydatacolumn='' pm.setPlotAxes(xaxis, yaxis, xdatacolumn, ydatacolumn, xframe, yframe, xinterp, yinterp, yaxislocation, False, plotindex, 0) else: # make ydatacolumn and yaxislocation same length as yaxis # and check that no duplicate y axes yAxisCount = len(yaxis) yDataCount = 0 if ydatacolumn!=['']: yDataCount = len(ydatacolumn) yLocationCount = 0 if yaxislocation!=['']: yLocationCount = len(yaxislocation) '''Make sure all the y-axis values are unique.''' uniqueY = True for i in range( yAxisCount ): yDataColumnI = '' if i < yDataCount : yDataColumnI = ydatacolumn[i] for j in range(i): if yaxis[j] == yaxis[i] : yDataColumnJ = '' if j < yDataCount: yDataColumnJ = ydatacolumn[j] if yDataColumnI == yDataColumnJ : # same axis, same datacolumn! uniqueY = False break if not uniqueY : break if ( uniqueY ): for i in range(yAxisCount): yDataColumn='' if i < yDataCount: yDataColumn = ydatacolumn[i] yAxisLocation = 'left' if i < yLocationCount: yAxisLocation = yaxislocation[i] if xaxis in ['ant-ra','ant-dec'] or yaxis[i] in ['ant-ra','ant-dec']: raise Exception, 'Currently not supported: multiple y-axes involving ant-ra or ant-dec' # Always make C++ ra/dec parameters vectors the same length as yaxis xframe = yframe = 'icrs' xinterp = yinterp = 'nearest' pm.setPlotAxes(xaxis, yaxis[i], xdatacolumn, yDataColumn, xframe, yframe, xinterp, yinterp, yAxisLocation, False, plotindex, i) else : raise Exception, 'Please remove duplicate y-axes.' if not showatm: showatm = False if not showtsky: showtsky = False if not showimage: showimage = False if showatm and showtsky: casalog.post('You have selected both showatm and showtsky. Defaulting to showatm=True only.', "WARN") showtsky = False if showatm or showtsky: # check that xaxis is None, chan, or freq validxaxis = not xaxis or xaxis in ["channel", "frequency"] if not validxaxis: casalog.post('showatm and showtsky are only valid when xaxis is channel or frequency', 'SEVERE') return False if showimage and (not showatm and not showtsky): casalog.post('Defaulting to showimage=False because showatm and showtsky are False.', "WARN") showimage = False pm.setShowCurve(showatm, showtsky, showimage, False, plotindex) # Set selection if selectdata: pm.setPlotMSSelection(field, spw, timerange, uvrange, antenna, scan, correlation, array, str(observation), intent, feed, msselect, False, plotindex) else: pm.setPlotMSSelection('', '', '', '', '', '', '', '', '', '', '', '', False, plotindex) # Set averaging if not averagedata: avgchannel = avgtime = '' avgscan = avgfield = avgbaseline = avgantenna = avgspw = False scalar = False if avgbaseline and avgantenna: casalog.post('Averaging over baselines is mutually exclusive with per-antenna averaging.', "SEVERE") return False if avgchannel and (float(avgchannel) < 0.0): casalog.post('Cannot average negative number of channels', "SEVERE") return False try: if avgtime and (float(avgtime) < 0.0): casalog.post('Cannot average negative time value', "SEVERE") return False except ValueError: casalog.post('avgtime value must be numerical string in seconds (no units)', "SEVERE") return False pm.setPlotMSAveraging(avgchannel, avgtime, avgscan, avgfield, avgbaseline, avgantenna, avgspw, scalar, False, plotindex) # Set transformations if not transform: freqframe='' restfreq='' veldef='RADIO' shift=[0.0,0.0] pm.setPlotMSTransformations(freqframe,veldef,restfreq,shift[0],shift[1], False, plotindex) # Set calibration: None or string (filename) useCallib = False callibString = '' if isinstance(callib, str): # Determine if filename or string of params if '=' in callib: useCallib = True callibString = callib else: callibFile = callib.strip() if len(callibFile) > 0: callibFile = os.path.abspath(callib) if os.path.exists(callibFile): useCallib = True callibString = callibFile else: casalog.post("Callib file does not exist", "SEVERE") return False elif isinstance(callib, list): # default is callib=[''] if len(callib[0]) > 0: # argument set to list of strings useCallib = True callibString = ",".join(callib) pm.setPlotMSCalibration(useCallib, callibString, False, plotindex) # Set flag extensions; for now, some options here are not available # pm.setFlagExtension(extendflag, extcorrelation, extchannel, extspw, # extantenna, exttime, extscans, extfield) extcorrstr='' if extcorr: extcorrstr='all' pm.setFlagExtension(extendflag, extcorrstr, extchannel) # Export range if not exprange or exprange == "": exprange='current' pm.setExportRange(exprange) # for pm.save: if not dpi: dpi = -1 if not width: width = -1 if not height: height = -1 # Set additional axes (iteration, colorization, etc.) # (Iteration) if not iteraxis: iteraxis = "" if iteraxis=="": xselfscale = yselfscale = False xsharedaxis = ysharedaxis = False if not rowindex: rowindex = 0 if not colindex: colindex = 0 if not xselfscale: xselfscale = False if not yselfscale: yselfscale = False if not xsharedaxis: xsharedaxis = False if not ysharedaxis: ysharedaxis = False if not xselfscale and xsharedaxis: casalog.post("Plots cannot share an x-axis unless they use the same x-axis scale.", "ERROR") return False if not yselfscale and ysharedaxis: casalog.post( "Plots cannot share a y-axis unless they use the same y-axis scale.", "ERROR") return False if xsharedaxis and gridrows < 2: casalog.post( "Plots cannot share an x-axis when gridrows=1.", "WARN") xsharedaxis=False if ysharedaxis and gridcols < 2: casalog.post( "Plots cannot share a y-axis when gridcols=1.", "WARN") ysharedaxis=False pm.setPlotMSIterate(iteraxis,rowindex,colindex, xselfscale,yselfscale, xsharedaxis,ysharedaxis,False,plotindex); # (Colorization) if coloraxis: pm.setColorAxis(coloraxis,False,plotindex) # Set custom symbol # Make the custom symbol into a list if it is not already. if type(customsymbol) is bool and customsymbol: customSymbolValue = customsymbol customsymbol=[customSymbolValue] if type(symbolshape) is str: symbolValue = symbolshape symbolshape=[symbolValue] if type(symbolsize) is int: symbolValue = symbolsize symbolsize=[symbolValue] if type(symbolcolor) is str: symbolValue = symbolcolor symbolcolor=[symbolValue] if type(symbolfill) is str: symbolValue = symbolfill symbolfill=[symbolValue] if type(symboloutline) is bool: symbolValue = symboloutline symboloutline=[symbolValue] if type(customsymbol) is list: customSymbolCount = len(customsymbol) for i in range(0,customSymbolCount): if i >= len(symbolshape) or not symbolshape[i]: symbolShapeI = 'autoscaling' else: symbolShapeI = symbolshape[i] symbolShape = symbolShapeI if customsymbol[i]: if i >=len(symbolsize) or not symbolsize[i]: symbolSizeI = 2 else: symbolSizeI = symbolsize[i] symbolSize = symbolSizeI if i>=len(symbolcolor) or not symbolcolor[i]: symbolColorI = '0000ff' else: symbolColorI = symbolcolor[i] symbolColor = symbolColorI if i>=len(symbolfill) or not symbolfill[i]: symbolFillI = 'fill' else: symbolFillI = symbolfill[i] symbolFill = symbolFillI if type( symboloutline) is bool: symbolOutlineI = symboloutline elif type(symboloutline) is list: if i>=len(symboloutline) or not symboloutline[i]: symbolOutlineI=False else: symbolOutlineI = symboloutline[i] else: symbolOutlineI = False symbolOutline = symbolOutlineI else: symbolSize = 2 symbolColor = '0000ff' symbolFill = 'fill' symbolOutline = False pm.setSymbol(symbolShape, symbolSize, symbolColor, symbolFill, symbolOutline, False,plotindex,i) # Set custom flagged symbol if type(customflaggedsymbol) is bool and customflaggedsymbol: customSymbolValue = customflaggedsymbol customflaggedsymbol=[customSymbolValue] if type(flaggedsymbolshape) is str: symbolValue = flaggedsymbolshape flaggedsymbolshape=[symbolValue] if type(flaggedsymbolsize) is int: symbolValue = flaggedsymbolsize flaggedsymbolsize=[symbolValue] if type(flaggedsymbolcolor) is str: symbolValue = flaggedsymbolcolor flaggedsymbolcolor=[symbolValue] if type(flaggedsymbolfill) is str: symbolValue = flaggedsymbolfill flaggedsymbolfill=[symbolValue] if type(flaggedsymboloutline) is bool: symbolValue = flaggedsymboloutline flaggedsymboloutline=[symbolValue] if type(customflaggedsymbol) is list: customSymbolCount = len(customflaggedsymbol) for i in range(0,customSymbolCount): if i>=len(flaggedsymbolshape) or not flaggedsymbolshape[i]: flaggedSymbolShapeI = 'nosymbol' else: flaggedSymbolShapeI = flaggedsymbolshape[i] flaggedSymbolShape = flaggedSymbolShapeI if customflaggedsymbol[i]: if i >=len(flaggedsymbolsize) or not flaggedsymbolsize[i]: flaggedSymbolSizeI = 2 else: flaggedSymbolSizeI = flaggedsymbolsize[i] flaggedSymbolSize = flaggedSymbolSizeI if i >=len(flaggedsymbolcolor) or not flaggedsymbolcolor[i]: flaggedSymbolColorI = 'ff0000' else: flaggedSymbolColorI = flaggedsymbolcolor[i] flaggedSymbolColor = flaggedSymbolColorI if i>=len(flaggedsymbolfill) or not flaggedsymbolfill[i]: flaggedSymbolFillI = 'fill' else: flaggedSymbolFillI = flaggedsymbolfill[i] flaggedSymbolFill = flaggedSymbolFillI if type(flaggedsymboloutline) is bool: flaggedSymbolOutlineI = flaggedsymboloutline elif type(flaggedsymboloutline) is list: if i>=len(flaggedsymboloutline) or not flaggedsymboloutline[i]: flaggedSymbolOutlineI = False else: flaggedSymbolOutlineI = flaggedsymboloutline[i] else: flaggedSymbolOutlineI = False flaggedSymbolOutline = flaggedSymbolOutlineI else: flaggedSymbolSize = 2 flaggedSymbolColor = 'ff0000' flaggedSymbolFill = 'fill' flaggedSymbolOutline = False pm.setFlaggedSymbol(flaggedSymbolShape, flaggedSymbolSize, flaggedSymbolColor, flaggedSymbolFill, flaggedSymbolOutline, False, plotindex, i) # connect the dots if not xconnector: xconnector = 'none' if not timeconnector: timeconnector = False pm.setConnect(xconnector, timeconnector, False, plotindex) # Legend if not showlegend: showlegend = False if not legendposition: legendposition = 'upperRight' pm.setLegend( showlegend, legendposition, False, plotindex ) # Set various user-directed appearance parameters pm.setTitle(title,False,plotindex) pm.setTitleFont(titlefont,False,plotindex) pm.setXAxisLabel(xlabel,False,plotindex) pm.setXAxisFont(xaxisfont,False,plotindex) pm.setYAxisLabel(ylabel,False,plotindex) pm.setYAxisFont(yaxisfont,False,plotindex) pm.setGridParams(showmajorgrid, majorwidth, majorstyle, majorcolor, showminorgrid, minorwidth, minorstyle, minorcolor, False, plotindex) # Plot ranges if len(plotrange) == 0: plotrange=[0.0, 0.0, 0.0, 0.0] elif len(plotrange) != 4: casalog.post('plotrange parameter has incorrect number of elements.', 'SEVERE') return False else: try: for i,val in enumerate(plotrange): plotrange[i] = float(val) except (TypeError, ValueError) as e: casalog.post("plotrange elements must be numeric", 'SEVERE') return False xranges = plotrange[1] - plotrange[0] yranges = plotrange[3] - plotrange[2] pm.setXRange((xranges<=0.0), plotrange[0], plotrange[1], False, plotindex) pm.setYRange((yranges<=0.0), plotrange[2], plotrange[3], False, plotindex) # Page Header Items # Python keywords for specifying header items are defined in CAS-8082, # Erik's comment dated 9-jun-2016 # Python / C++ header items keywords map # format is header_cpp_kw['python_keyword'] = 'c++_keyword', where # the c++ keyword is what's coded in PlotMSPageHeaderParam.h header_cpp_kw = {} header_cpp_kw['filename'] = 'filename' header_cpp_kw['ycolumn'] = 'y_columns' header_cpp_kw['obsdate'] = 'obs_start_date' header_cpp_kw['obstime'] = 'obs_start_time' header_cpp_kw['observer'] = 'obs_observer' header_cpp_kw['projid'] = 'obs_project' header_cpp_kw['telescope'] = 'obs_telescope_name' header_cpp_kw['targname'] = 'target_name' header_cpp_kw['targdir'] = 'target_direction' if type(headeritems) is str: cpp_headeritems = [] for headeritem_word in headeritems.split(','): py_headeritem = headeritem_word.strip() if py_headeritem == "": continue if py_headeritem in header_cpp_kw: ccp_headeritem = header_cpp_kw[py_headeritem] cpp_headeritems.append(ccp_headeritem) else: casalog.post("Ignoring invalid page header item: " + py_headeritem ,"WARN") pm.setPlotMSPageHeaderItems(','.join(cpp_headeritems), False, plotindex) # Update - ready to plot! plotUpdated = pm.update() if not plotUpdated: casalog.post( "There was a problem updating the plot.", "ERROR") else: # write file if requested if(plotfile != ""): casalog.post("Plot file " + plotfile, 'NORMAL') # kluge: isDrawing checks if *any* thread is running, could be cache # thread or drawing thread! Give it time for cache to finish... time.sleep(0.5) if (pm.isDrawing()): casalog.post("Will wait until drawing of the plot has completed before exporting it",'NORMAL') while (pm.isDrawing()): time.sleep(1.0) casalog.post("Exporting the plot.",'NORMAL') plotUpdated = pm.save( plotfile, expformat, verbose, highres, dpi, width, height) except Exception, instance: plotUpdated = False print "Exception during plotms task: ", instance if not plotUpdated: checkProcesses() # see if something crashed, log failure return plotUpdated def procIsRunning(procname): procrun = procmgr.running(procname) if not procrun: time.sleep(2) # for slow startups procrun = procmgr.running(procname) if procrun: try: process = procmgr.fetch(procname) if not process.is_alive(): # crash! process.stop() # let procmgr know it crashed procrun = False except AttributeError: # fetch returned None: None.is_alive() pass return procrun def checkProcesses(): if not procIsRunning('plotms'): casalog.post( "plotms has stopped running. Check logs for error and run again.", "SEVERE") if not procIsRunning('dbus'): casalog.post( "dbus-daemon has stopped running. Please restart casa.", "SEVERE")