source: branches/Release2.0/python/asapplotter.py@ 1196

Last change on this file since 1196 was 1034, checked in by mar637, 18 years ago

Removed debug print

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 19.7 KB
Line 
1from asap import rcParams, print_log, selector
2from numarray import logical_and
3
4class asapplotter:
5 """
6 The ASAP plotter.
7 By default the plotter is set up to plot polarisations
8 'colour stacked' and scantables across panels.
9 Note:
10 Currenly it only plots 'spectra' not Tsys or
11 other variables.
12 """
13 def __init__(self, visible=None):
14 self._visible = rcParams['plotter.gui']
15 if visible is not None:
16 self._visible = visible
17 self._plotter = self._newplotter()
18
19
20 self._panelling = None
21 self._stacking = None
22 self.set_panelling()
23 self.set_stacking()
24 self._rows = None
25 self._cols = None
26 self._autoplot = False
27 self._minmaxx = None
28 self._minmaxy = None
29 self._datamask = None
30 self._data = None
31 self._lmap = None
32 self._title = None
33 self._ordinate = None
34 self._abcissa = None
35 self._abcunit = None
36 self._usermask = []
37 self._maskselection = None
38 self._selection = selector()
39 self._hist = rcParams['plotter.histogram']
40
41 def _translate(self, instr):
42 keys = "s b i p t".split()
43 if isinstance(instr, str):
44 for key in keys:
45 if instr.lower().startswith(key):
46 return key
47 return None
48
49 def _newplotter(self):
50 if self._visible:
51 from asap.asaplotgui import asaplotgui as asaplot
52 else:
53 from asap.asaplot import asaplot
54 return asaplot()
55
56
57 def plot(self, scan=None):
58 """
59 Plot a scantable.
60 Parameters:
61 scan: a scantable
62 Note:
63 If a scantable was specified in a previous call
64 to plot, no argument has to be given to 'replot'
65 NO checking is done that the abcissas of the scantable
66 are consistent e.g. all 'channel' or all 'velocity' etc.
67 """
68 if self._plotter.is_dead:
69 self._plotter = self._newplotter()
70 self._plotter.hold()
71 self._plotter.clear()
72 from asap import scantable
73 if not self._data and not scan:
74 print "please provide a scantable to plot"
75 if isinstance(scan, scantable):
76 if self._data is not None:
77 if scan != self._data:
78 self._data = scan
79 # reset
80 self._reset()
81 else:
82 self._data = scan
83 self._reset()
84 # ranges become invalid when unit changes
85 if self._abcunit and self._abcunit != self._data.get_unit():
86 self._minmaxx = None
87 self._minmaxy = None
88 self._abcunit = self._data.get_unit()
89 self._datamask = None
90 self._plot(self._data)
91 if self._minmaxy is not None:
92 self._plotter.set_limits(ylim=self._minmaxy)
93 self._plotter.release()
94 print_log()
95 return
96
97 def set_mode(self, stacking=None, panelling=None):
98 """
99 Set the plots look and feel, i.e. what you want to see on the plot.
100 Parameters:
101 stacking: tell the plotter which variable to plot
102 as line color overlays (default 'pol')
103 panelling: tell the plotter which variable to plot
104 across multiple panels (default 'scan'
105 Note:
106 Valid modes are:
107 'beam' 'Beam' 'b': Beams
108 'if' 'IF' 'i': IFs
109 'pol' 'Pol' 'p': Polarisations
110 'scan' 'Scan' 's': Scans
111 'time' 'Time' 't': Times
112 """
113 msg = "Invalid mode"
114 if not self.set_panelling(panelling) or \
115 not self.set_stacking(stacking):
116 if rcParams['verbose']:
117 print msg
118 return
119 else:
120 raise TypeError(msg)
121 if self._data: self.plot(self._data)
122 return
123
124 def set_panelling(self, what=None):
125 mode = what
126 if mode is None:
127 mode = rcParams['plotter.panelling']
128 md = self._translate(mode)
129 if md:
130 self._panelling = md
131 self._title = None
132 return True
133 return False
134
135 def set_layout(self,rows=None,cols=None):
136 """
137 Set the multi-panel layout, i.e. how many rows and columns plots
138 are visible.
139 Parameters:
140 rows: The number of rows of plots
141 cols: The number of columns of plots
142 Note:
143 If no argument is given, the potter reverts to its auto-plot
144 behaviour.
145 """
146 self._rows = rows
147 self._cols = cols
148 if self._data: self.plot(self._data)
149 return
150
151 def set_stacking(self, what=None):
152 mode = what
153 if mode is None:
154 mode = rcParams['plotter.stacking']
155 md = self._translate(mode)
156 if md:
157 self._stacking = md
158 self._lmap = None
159 return True
160 return False
161
162 def set_range(self,xstart=None,xend=None,ystart=None,yend=None):
163 """
164 Set the range of interest on the abcissa of the plot
165 Parameters:
166 [x,y]start,[x,y]end: The start and end points of the 'zoom' window
167 Note:
168 These become non-sensical when the unit changes.
169 use plotter.set_range() without parameters to reset
170
171 """
172 if xstart is None and xend is None:
173 self._minmaxx = None
174 else:
175 self._minmaxx = [xstart,xend]
176 if ystart is None and yend is None:
177 self._minmaxy = None
178 else:
179 self._minmaxy = [ystart,yend]
180 if self._data: self.plot(self._data)
181 return
182
183 def set_legend(self, mp=None):
184 """
185 Specify a mapping for the legend instead of using the default
186 indices:
187 Parameters:
188 mp: a list of 'strings'. This should have the same length
189 as the number of elements on the legend and then maps
190 to the indeces in order. It is possible to uses latex
191 math expression. These have to be enclosed in r'', e.g. r'$x^{2}$'
192
193 Example:
194 If the data has two IFs/rest frequencies with index 0 and 1
195 for CO and SiO:
196 plotter.set_stacking('i')
197 plotter.set_legend(['CO','SiO'])
198 plotter.plot()
199 plotter.set_legend([r'$^{12}CO$', r'SiO'])
200 """
201 self._lmap = mp
202 if self._data: self.plot(self._data)
203 return
204
205 def set_title(self, title=None):
206 """
207 Set the title of the plot. If multiple panels are plotted,
208 multiple titles have to be specified.
209 Example:
210 # two panels are visible on the plotter
211 plotter.set_title(["First Panel","Second Panel"])
212 """
213 self._title = title
214 if self._data: self.plot(self._data)
215 return
216
217 def set_ordinate(self, ordinate=None):
218 """
219 Set the y-axis label of the plot. If multiple panels are plotted,
220 multiple labels have to be specified.
221 Parameters:
222 ordinate: a list of ordinate labels. None (default) let
223 data determine the labels
224 Example:
225 # two panels are visible on the plotter
226 plotter.set_ordinate(["First Y-Axis","Second Y-Axis"])
227 """
228 self._ordinate = ordinate
229 if self._data: self.plot(self._data)
230 return
231
232 def set_abcissa(self, abcissa=None):
233 """
234 Set the x-axis label of the plot. If multiple panels are plotted,
235 multiple labels have to be specified.
236 Parameters:
237 abcissa: a list of abcissa labels. None (default) let
238 data determine the labels
239 Example:
240 # two panels are visible on the plotter
241 plotter.set_ordinate(["First X-Axis","Second X-Axis"])
242 """
243 self._abcissa = abcissa
244 if self._data: self.plot(self._data)
245 return
246
247 def set_colors(self, colormap):
248 """
249 Set the colors to be used. The plotter will cycle through
250 these colors when lines are overlaid (stacking mode).
251 Parameters:
252 colormap: a list of colour names
253 Example:
254 plotter.set_colors("red green blue")
255 # If for example four lines are overlaid e.g I Q U V
256 # 'I' will be 'red', 'Q' will be 'green', U will be 'blue'
257 # and 'V' will be 'red' again.
258 """
259 if isinstance(colormap,str):
260 colormap = colormap.split()
261 self._plotter.palette(0,colormap=colormap)
262 if self._data: self.plot(self._data)
263
264 def set_histogram(self, hist=True):
265 """
266 Enable/Disable histogram-like plotting.
267 Parameters:
268 hist: True (default) or False. The fisrt default
269 is taken from the .asaprc setting
270 plotter.histogram
271 """
272 self._hist = hist
273 if self._data: self.plot(self._data)
274
275 def set_linestyles(self, linestyles):
276 """
277 Set the linestyles to be used. The plotter will cycle through
278 these linestyles when lines are overlaid (stacking mode) AND
279 only one color has been set.
280 Parameters:
281 linestyles: a list of linestyles to use.
282 'line', 'dashed', 'dotted', 'dashdot',
283 'dashdotdot' and 'dashdashdot' are
284 possible
285
286 Example:
287 plotter.set_colors("black")
288 plotter.set_linestyles("line dashed dotted dashdot")
289 # If for example four lines are overlaid e.g I Q U V
290 # 'I' will be 'solid', 'Q' will be 'dashed',
291 # U will be 'dotted' and 'V' will be 'dashdot'.
292 """
293 if isinstance(linestyles,str):
294 linestyles = linestyles.split()
295 self._plotter.palette(color=0,linestyle=0,linestyles=linestyles)
296 if self._data: self.plot(self._data)
297
298 def save(self, filename=None, orientation=None, dpi=None):
299 """
300 Save the plot to a file. The know formats are 'png', 'ps', 'eps'.
301 Parameters:
302 filename: The name of the output file. This is optional
303 and autodetects the image format from the file
304 suffix. If non filename is specified a file
305 called 'yyyymmdd_hhmmss.png' is created in the
306 current directory.
307 orientation: optional parameter for postscript only (not eps).
308 'landscape', 'portrait' or None (default) are valid.
309 If None is choosen for 'ps' output, the plot is
310 automatically oriented to fill the page.
311 dpi: The dpi of the output non-ps plot
312 """
313 self._plotter.save(filename,orientation,dpi)
314 return
315
316
317 def set_mask(self, mask=None, selection=None):
318 """
319 Set a plotting mask for a specific polarization.
320 This is useful for masking out "noise" Pangle outside a source.
321 Parameters:
322 mask: a mask from scantable.create_mask
323 selection: the spectra to apply the mask to.
324 Example:
325 select = selector()
326 select.setpolstrings("Pangle")
327 plotter.set_mask(mymask, select)
328 """
329 if not self._data:
330 msg = "Can only set mask after a first call to plot()"
331 if rcParams['verbose']:
332 print msg
333 return
334 else:
335 raise RuntimeError(msg)
336 if len(mask):
337 if isinstance(mask, list) or isinstance(mask, tuple):
338 self._usermask = array(mask)
339 else:
340 self._usermask = mask
341 if mask is None and selection is None:
342 self._usermask = []
343 self._maskselection = None
344 if isinstance(selection, selector):
345 self._maskselection = {'b': selection.get_beams(),
346 's': selection.get_scans(),
347 'i': selection.get_ifs(),
348 'p': selection.get_pols(),
349 't': [] }
350 else:
351 self._maskselection = None
352 self.plot(self._data)
353
354 def _slice_indeces(self, data):
355 mn = self._minmaxx[0]
356 mx = self._minmaxx[1]
357 asc = data[0] < data[-1]
358 start=0
359 end = len(data)-1
360 inc = 1
361 if not asc:
362 start = len(data)-1
363 end = 0
364 inc = -1
365 # find min index
366 while data[start] < mn:
367 start+= inc
368 # find max index
369 while data[end] > mx:
370 end-=inc
371 end +=1
372 if start > end:
373 return end,start
374 return start,end
375
376 def _reset(self):
377 self._usermask = []
378 self._usermaskspectra = None
379 self.set_selection(None, False)
380
381 def _plot(self, scan):
382 savesel = scan.get_selection()
383 sel = savesel + self._selection
384 d0 = {'s': 'SCANNO', 'b': 'BEAMNO', 'i':'IFNO',
385 'p': 'POLNO', 'c': 'CYCLENO', 't' : 'TIME' }
386 order = [d0[self._panelling],d0[self._stacking]]
387 sel.set_order(order)
388 scan.set_selection(sel)
389 d = {'b': scan.getbeam, 's': scan.getscan,
390 'i': scan.getif, 'p': scan.getpol, 't': scan._gettime }
391
392 polmodes = dict(zip(self._selection.get_pols(),self._selection.get_poltypes()))
393 n,nstack = self._get_selected_n(scan)
394 maxpanel, maxstack = 16,8
395 if n > maxpanel or nstack > maxstack:
396 from asap import asaplog
397 msg ="Scan to be plotted contains more than %d selections.\n" \
398 "Selecting first %d selections..." % (maxpanel,maxpanel)
399 asaplog.push(msg)
400 print_log()
401 n = min(n,maxpanel)
402 nstack = min(nstack,maxstack)
403
404 if n > 1:
405 ganged = rcParams['plotter.ganged']
406 if self._rows and self._cols:
407 n = min(n,self._rows*self._cols)
408 self._plotter.set_panels(rows=self._rows,cols=self._cols,
409 nplots=n,ganged=ganged)
410 else:
411 self._plotter.set_panels(rows=n,cols=0,nplots=n,ganged=ganged)
412 else:
413 self._plotter.set_panels()
414 r=0
415 nr = scan.nrow()
416 a0,b0 = -1,-1
417 allxlim = []
418 allylim = []
419 newpanel=True
420 panelcount,stackcount = 0,0
421 while r < nr:
422 a = d[self._panelling](r)
423 b = d[self._stacking](r)
424 if a > a0 and panelcount < n:
425 if n > 1:
426 self._plotter.subplot(panelcount)
427 self._plotter.palette(0)
428 #title
429 xlab = self._abcissa and self._abcissa[panelcount] \
430 or scan._getabcissalabel()
431 ylab = self._ordinate and self._ordinate[panelcount] \
432 or scan._get_ordinate_label()
433 self._plotter.set_axes('xlabel',xlab)
434 self._plotter.set_axes('ylabel',ylab)
435 lbl = self._get_label(scan, r, self._panelling, self._title)
436 if isinstance(lbl, list) or isinstance(lbl, tuple):
437 if 0 <= panelcount < len(lbl):
438 lbl = lbl[panelcount]
439 else:
440 # get default label
441 lbl = self._get_label(scan, r, self._panelling, None)
442 self._plotter.set_axes('title',lbl)
443 newpanel = True
444 stackcount =0
445 panelcount += 1
446 if (b > b0 or newpanel) and stackcount < nstack:
447 y = []
448 if len(polmodes):
449 y = scan._getspectrum(r, polmodes[scan.getpol(r)])
450 else:
451 y = scan._getspectrum(r)
452 m = scan._getmask(r)
453 if self._maskselection and len(self._usermask) == len(m):
454 if d[self._stacking](r) in self._maskselection[self._stacking]:
455 m = logical_and(m, self._usermask)
456 x = scan._getabcissa(r)
457 if self._minmaxx is not None:
458 s,e = self._slice_indeces(x)
459 x = x[s:e]
460 y = y[s:e]
461 m = m[s:e]
462 if len(x) > 2048 and rcParams['plotter.decimate']:
463 fac = len(x)/2048
464 x = x[::fac]
465 m = m[::fac]
466 y = y[::fac]
467 llbl = self._get_label(scan, r, self._stacking, self._lmap)
468 if isinstance(llbl, list) or isinstance(llbl, tuple):
469 if 0 <= stackcount < len(llbl):
470 # use user label
471 llbl = llbl[stackcount]
472 else:
473 # get default label
474 llbl = self._get_label(scan, r, self._stacking, None)
475 self._plotter.set_line(label=llbl)
476 plotit = self._plotter.plot
477 if self._hist: plotit = self._plotter.hist
478 plotit(x,y,m)
479 xlim= self._minmaxx or [min(x),max(x)]
480 allxlim += xlim
481 ylim= self._minmaxy or [min(y),max(y)]
482 allylim += ylim
483 stackcount += 1
484 # last in colour stack -> autoscale x
485 if stackcount == nstack:
486 allxlim.sort()
487 self._plotter.axes.set_xlim([allxlim[0],allxlim[-1]])
488 # clear
489 allxlim =[]
490
491 newpanel = False
492 a0=a
493 b0=b
494 # ignore following rows
495 if (panelcount == n) and (stackcount == nstack):
496 # last panel -> autoscale y if ganged
497 if rcParams['plotter.ganged']:
498 allylim.sort()
499 self._plotter.set_limits(ylim=[allylim[0],allylim[-1]])
500 break
501 r+=1 # next row
502 #reset the selector to the scantable's original
503 scan.set_selection(savesel)
504
505 def set_selection(self, selection=None, refresh=True):
506 self._selection = isinstance(selection,selector) and selection or selector()
507 d0 = {'s': 'SCANNO', 'b': 'BEAMNO', 'i':'IFNO',
508 'p': 'POLNO', 'c': 'CYCLENO', 't' : 'TIME' }
509 order = [d0[self._panelling],d0[self._stacking]]
510 self._selection.set_order(order)
511 if self._data and refresh: self.plot(self._data)
512
513 def _get_selected_n(self, scan):
514 d1 = {'b': scan.nbeam, 's': scan.nscan,
515 'i': scan.nif, 'p': scan.npol, 't': scan.ncycle }
516 d2 = { 'b': len(self._selection.get_beams()),
517 's': len(self._selection.get_scans()),
518 'i': len(self._selection.get_ifs()),
519 'p': len(self._selection.get_pols()),
520 't': len(self._selection.get_cycles()) }
521 n = d2[self._panelling] or d1[self._panelling]()
522 nstack = d2[self._stacking] or d1[self._stacking]()
523 return n,nstack
524
525 def _get_label(self, scan, row, mode, userlabel=None):
526 pms = dict(zip(self._selection.get_pols(),self._selection.get_poltypes()))
527 if len(pms):
528 poleval = scan._getpollabel(scan.getpol(row),pms[scan.getpol(row)])
529 else:
530 poleval = scan._getpollabel(scan.getpol(row),scan.poltype())
531 d = {'b': "Beam "+str(scan.getbeam(row)),
532 's': scan._getsourcename(row),
533 'i': "IF"+str(scan.getif(row)),
534 'p': poleval,
535 't': scan._gettime(row) }
536 return userlabel or d[mode]
Note: See TracBrowser for help on using the repository browser.