source: trunk/python/asapplotter.py@ 2276

Last change on this file since 2276 was 2276, checked in by Malte Marquarding, 14 years ago

Created 3.1.0 release tag

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 58.7 KB
Line 
1from asap.parameters import rcParams
2from asap.selector import selector
3from asap.scantable import scantable
4from asap.logging import asaplog, asaplog_post_dec
5import matplotlib.axes
6from matplotlib.font_manager import FontProperties
7from matplotlib.text import Text
8
9import re
10
11def new_asaplot(visible=None,**kwargs):
12 """
13 Returns a new asaplot instance based on the backend settings.
14 """
15 if visible == None:
16 visible = rcParams['plotter.gui']
17
18 backend=matplotlib.get_backend()
19 if not visible:
20 from asap.asaplot import asaplot
21 elif backend == 'TkAgg':
22 from asap.asaplotgui import asaplotgui as asaplot
23 elif backend == 'Qt4Agg':
24 from asap.asaplotgui_qt4 import asaplotgui as asaplot
25 elif backend == 'GTkAgg':
26 from asap.asaplotgui_gtk import asaplotgui as asaplot
27 else:
28 from asap.asaplot import asaplot
29 return asaplot(**kwargs)
30
31class asapplotter:
32 """
33 The ASAP plotter.
34 By default the plotter is set up to plot polarisations
35 'colour stacked' and scantables across panels.
36
37 .. note::
38
39 Currenly it only plots 'spectra' not Tsys or
40 other variables.
41
42 """
43 def __init__(self, visible=None , **kwargs):
44 self._visible = rcParams['plotter.gui']
45 if visible is not None:
46 self._visible = visible
47 self._plotter = self._newplotter(**kwargs)
48 # additional tool bar
49 self._plotter.figmgr.casabar=self._new_custombar()
50
51 self._panelling = None
52 self._stacking = None
53 self.set_panelling()
54 self.set_stacking()
55 self._rows = None
56 self._cols = None
57 self._autoplot = False
58 self._minmaxx = None
59 self._minmaxy = None
60 self._datamask = None
61 self._data = None
62 self._lmap = None
63 self._title = None
64 self._ordinate = None
65 self._abcissa = None
66 self._abcunit = None
67 self._usermask = []
68 self._maskselection = None
69 self._selection = selector()
70 self._hist = rcParams['plotter.histogram']
71 self._fp = FontProperties()
72 self._margins = self.set_margin(refresh=False)
73 self._offset = None
74 self._startrow = 0
75 self._ipanel = -1
76 self._panelrows = []
77 self._headtext={'string': None, 'textobj': None}
78
79 def _translate(self, instr):
80 keys = "s b i p t r".split()
81 if isinstance(instr, str):
82 for key in keys:
83 if instr.lower().startswith(key):
84 return key
85 return None
86
87 def _newplotter(self, **kwargs):
88 return new_asaplot(self._visible,**kwargs)
89
90 def _new_custombar(self):
91 backend=matplotlib.get_backend()
92 if not self._visible:
93 return None
94 elif backend == "TkAgg":
95 from asap.customgui_tkagg import CustomToolbarTkAgg
96 return CustomToolbarTkAgg(self)
97 elif backend == "Qt4Agg":
98 from asap.customgui_qt4agg import CustomToolbarQT4Agg
99 return CustomToolbarQT4Agg(self)
100 return None
101
102 def casabar_exists(self):
103 if not hasattr(self._plotter.figmgr,'casabar'):
104 return False
105 elif self._plotter.figmgr.casabar:
106 return True
107 return False
108
109 @asaplog_post_dec
110 def plot(self, scan=None):
111 """
112 Plot a scantable.
113 Parameters:
114 scan: a scantable
115 Note:
116 If a scantable was specified in a previous call
117 to plot, no argument has to be given to 'replot'
118 NO checking is done that the abcissas of the scantable
119 are consistent e.g. all 'channel' or all 'velocity' etc.
120 """
121 self._startrow = 0
122 self._ipanel = -1
123 self._reset_header()
124 if self._plotter.is_dead:
125 if self.casabar_exists():
126 del self._plotter.figmgr.casabar
127 self._plotter = self._newplotter()
128 self._plotter.figmgr.casabar=self._new_custombar()
129 if self.casabar_exists():
130 self._plotter.figmgr.casabar.set_pagecounter(1)
131 self._panelrows = []
132 self._plotter.hold()
133 #self._plotter.clear()
134 if not self._data and not scan:
135 msg = "Input is not a scantable"
136 raise TypeError(msg)
137 if scan:
138 self.set_data(scan, refresh=False)
139 self._plot(self._data)
140 if self._minmaxy is not None:
141 self._plotter.set_limits(ylim=self._minmaxy)
142 if self.casabar_exists(): self._plotter.figmgr.casabar.enable_button()
143 self._plotter.release()
144 self._plotter.tidy()
145 self._plotter.show(hardrefresh=False)
146 return
147
148 def gca(self):
149 return self._plotter.figure.gca()
150
151 def refresh(self):
152 """Do a soft refresh"""
153 self._plotter.figure.show()
154
155 def create_mask(self, nwin=1, panel=0, color=None):
156 """
157 Interactively define a mask. It retruns a mask that is equivalent to
158 the one created manually with scantable.create_mask.
159 Parameters:
160 nwin: The number of mask windows to create interactively
161 default is 1.
162 panel: Which panel to use for mask selection. This is useful
163 if different IFs are spread over panels (default 0)
164 """
165 if self._data is None:
166 return []
167 outmask = []
168 self._plotter.subplot(panel)
169 xmin, xmax = self._plotter.axes.get_xlim()
170 marg = 0.05*(xmax-xmin)
171 self._plotter.axes.set_xlim(xmin-marg, xmax+marg)
172 self.refresh()
173
174 def cleanup(lines=False, texts=False, refresh=False):
175 if lines:
176 del self._plotter.axes.lines[-1]
177 if texts:
178 del self._plotter.axes.texts[-1]
179 if refresh:
180 self.refresh()
181
182 for w in xrange(nwin):
183 wpos = []
184 self.text(0.05,1.0, "Add start boundary",
185 coords="relative", fontsize=10)
186 point = self._plotter.get_point()
187 cleanup(texts=True)
188 if point is None:
189 continue
190 wpos.append(point[0])
191 self.axvline(wpos[0], color=color)
192 self.text(0.05,1.0, "Add end boundary", coords="relative", fontsize=10)
193 point = self._plotter.get_point()
194 cleanup(texts=True, lines=True)
195 if point is None:
196 self.refresh()
197 continue
198 wpos.append(point[0])
199 self.axvspan(wpos[0], wpos[1], alpha=0.1,
200 edgecolor=color, facecolor=color)
201 ymin, ymax = self._plotter.axes.get_ylim()
202 outmask.append(wpos)
203
204 self._plotter.axes.set_xlim(xmin, xmax)
205 self.refresh()
206 if len(outmask) > 0:
207 return self._data.create_mask(*outmask)
208 return []
209
210 # forwards to matplotlib axes
211 def text(self, *args, **kwargs):
212 if kwargs.has_key("interactive"):
213 if kwargs.pop("interactive"):
214 pos = self._plotter.get_point()
215 args = tuple(pos)+args
216 self._axes_callback("text", *args, **kwargs)
217
218 text.__doc__ = matplotlib.axes.Axes.text.__doc__
219
220 def arrow(self, *args, **kwargs):
221 if kwargs.has_key("interactive"):
222 if kwargs.pop("interactive"):
223 pos = self._plotter.get_region()
224 dpos = (pos[0][0], pos[0][1],
225 pos[1][0]-pos[0][0],
226 pos[1][1] - pos[0][1])
227 args = dpos + args
228 self._axes_callback("arrow", *args, **kwargs)
229
230 arrow.__doc__ = matplotlib.axes.Axes.arrow.__doc__
231
232 def annotate(self, text, xy=None, xytext=None, **kwargs):
233 if kwargs.has_key("interactive"):
234 if kwargs.pop("interactive"):
235 xy = self._plotter.get_point()
236 xytext = self._plotter.get_point()
237 if not kwargs.has_key("arrowprops"):
238 kwargs["arrowprops"] = dict(arrowstyle="->")
239 self._axes_callback("annotate", text, xy, xytext, **kwargs)
240
241 annotate.__doc__ = matplotlib.axes.Axes.annotate.__doc__
242
243 def axvline(self, *args, **kwargs):
244 if kwargs.has_key("interactive"):
245 if kwargs.pop("interactive"):
246 pos = self._plotter.get_point()
247 args = (pos[0],)+args
248 self._axes_callback("axvline", *args, **kwargs)
249
250 axvline.__doc__ = matplotlib.axes.Axes.axvline.__doc__
251
252 def axhline(self, *args, **kwargs):
253 if kwargs.has_key("interactive"):
254 if kwargs.pop("interactive"):
255 pos = self._plotter.get_point()
256 args = (pos[1],)+args
257 self._axes_callback("axhline", *args, **kwargs)
258
259 axhline.__doc__ = matplotlib.axes.Axes.axhline.__doc__
260
261 def axvspan(self, *args, **kwargs):
262 if kwargs.has_key("interactive"):
263 if kwargs.pop("interactive"):
264 pos = self._plotter.get_region()
265 dpos = (pos[0][0], pos[1][0])
266 args = dpos + args
267 self._axes_callback("axvspan", *args, **kwargs)
268 # hack to preventy mpl from redrawing the patch
269 # it seem to convert the patch into lines on every draw.
270 # This doesn't happen in a test script???
271 #del self._plotter.axes.patches[-1]
272
273 axvspan.__doc__ = matplotlib.axes.Axes.axvspan.__doc__
274
275 def axhspan(self, *args, **kwargs):
276 if kwargs.has_key("interactive"):
277 if kwargs.pop("interactive"):
278 pos = self._plotter.get_region()
279 dpos = (pos[0][1], pos[1][1])
280 args = dpos + args
281 self._axes_callback("axhspan", *args, **kwargs)
282 # hack to preventy mpl from redrawing the patch
283 # it seem to convert the patch into lines on every draw.
284 # This doesn't happen in a test script???
285 #del self._plotter.axes.patches[-1]
286
287 axhspan.__doc__ = matplotlib.axes.Axes.axhspan.__doc__
288
289 def _axes_callback(self, axesfunc, *args, **kwargs):
290 panel = 0
291 if kwargs.has_key("panel"):
292 panel = kwargs.pop("panel")
293 coords = None
294 if kwargs.has_key("coords"):
295 coords = kwargs.pop("coords")
296 if coords.lower() == 'world':
297 kwargs["transform"] = self._plotter.axes.transData
298 elif coords.lower() == 'relative':
299 kwargs["transform"] = self._plotter.axes.transAxes
300 self._plotter.subplot(panel)
301 self._plotter.axes.set_autoscale_on(False)
302 getattr(self._plotter.axes, axesfunc)(*args, **kwargs)
303 self._plotter.show(False)
304 self._plotter.axes.set_autoscale_on(True)
305 # end matplotlib.axes fowarding functions
306
307 @asaplog_post_dec
308 def set_data(self, scan, refresh=True):
309 """
310 Set a scantable to plot.
311 Parameters:
312 scan: a scantable
313 refresh: True (default) or False. If True, the plot is
314 replotted based on the new parameter setting(s).
315 Otherwise,the parameter(s) are set without replotting.
316 Note:
317 The user specified masks and data selections will be reset
318 if a new scantable is set. This method should be called before
319 setting data selections (set_selection) and/or masks (set_mask).
320 """
321 from asap import scantable
322 if isinstance(scan, scantable):
323 if self._data is not None:
324 if scan != self._data:
325 del self._data
326 self._data = scan
327 # reset
328 self._reset()
329 msg = "A new scantable is set to the plotter. "\
330 "The masks and data selections are reset."
331 asaplog.push( msg )
332 else:
333 self._data = scan
334 self._reset()
335 else:
336 msg = "Input is not a scantable"
337 raise TypeError(msg)
338
339 # ranges become invalid when unit changes
340 if self._abcunit and self._abcunit != self._data.get_unit():
341 self._minmaxx = None
342 self._minmaxy = None
343 self._abcunit = self._data.get_unit()
344 self._datamask = None
345 if refresh: self.plot()
346
347 @asaplog_post_dec
348 def set_mode(self, stacking=None, panelling=None, refresh=True):
349 """
350 Set the plots look and feel, i.e. what you want to see on the plot.
351 Parameters:
352 stacking: tell the plotter which variable to plot
353 as line colour overlays (default 'pol')
354 panelling: tell the plotter which variable to plot
355 across multiple panels (default 'scan'
356 refresh: True (default) or False. If True, the plot is
357 replotted based on the new parameter setting(s).
358 Otherwise,the parameter(s) are set without replotting.
359 Note:
360 Valid modes are:
361 'beam' 'Beam' 'b': Beams
362 'if' 'IF' 'i': IFs
363 'pol' 'Pol' 'p': Polarisations
364 'scan' 'Scan' 's': Scans
365 'time' 'Time' 't': Times
366 'row' 'Row' 'r': Rows
367 When either 'stacking' or 'panelling' is set to 'row',
368 the other parameter setting is ignored.
369 """
370 msg = "Invalid mode"
371 if not self.set_panelling(panelling) or \
372 not self.set_stacking(stacking):
373 raise TypeError(msg)
374 #if self._panelling == 'r':
375 # self._stacking = '_r'
376 #if self._stacking == 'r':
377 # self._panelling = '_r'
378 if refresh and self._data: self.plot(self._data)
379 return
380
381 def set_panelling(self, what=None):
382 """Set the 'panelling' mode i.e. which type of spectra should be
383 spread across different panels.
384 """
385
386 mode = what
387 if mode is None:
388 mode = rcParams['plotter.panelling']
389 md = self._translate(mode)
390 if md:
391 self._panelling = md
392 self._title = None
393 #if md == 'r':
394 # self._stacking = '_r'
395 # you need to reset counters for multi page plotting
396 self._reset_counters()
397 return True
398 return False
399
400 def set_layout(self,rows=None,cols=None,refresh=True):
401 """
402 Set the multi-panel layout, i.e. how many rows and columns plots
403 are visible.
404 Parameters:
405 rows: The number of rows of plots
406 cols: The number of columns of plots
407 refresh: True (default) or False. If True, the plot is
408 replotted based on the new parameter setting(s).
409 Otherwise,the parameter(s) are set without replotting.
410 Note:
411 If no argument is given, the potter reverts to its auto-plot
412 behaviour.
413 """
414 self._rows = rows
415 self._cols = cols
416 if refresh and self._data: self.plot(self._data)
417 return
418
419 def set_stacking(self, what=None):
420 """Set the 'stacking' mode i.e. which type of spectra should be
421 overlayed.
422 """
423 mode = what
424 if mode is None:
425 mode = rcParams['plotter.stacking']
426 md = self._translate(mode)
427 if md:
428 self._stacking = md
429 self._lmap = None
430 #if md == 'r':
431 # self._panelling = '_r'
432 # you need to reset counters for multi page plotting
433 self._reset_counters()
434 return True
435 return False
436
437 def _reset_counters(self):
438 self._startrow = 0
439 self._ipanel = -1
440 self._panelrows = []
441
442 def set_range(self,xstart=None,xend=None,ystart=None,yend=None,refresh=True, offset=None):
443 """
444 Set the range of interest on the abcissa of the plot
445 Parameters:
446 [x,y]start,[x,y]end: The start and end points of the 'zoom' window
447 refresh: True (default) or False. If True, the plot is
448 replotted based on the new parameter setting(s).
449 Otherwise,the parameter(s) are set without replotting.
450 offset: shift the abcissa by the given amount. The abcissa label will
451 have '(relative)' appended to it.
452 Note:
453 These become non-sensical when the unit changes.
454 use plotter.set_range() without parameters to reset
455
456 """
457 self._offset = offset
458 if xstart is None and xend is None:
459 self._minmaxx = None
460 else:
461 self._minmaxx = [xstart,xend]
462 if ystart is None and yend is None:
463 self._minmaxy = None
464 else:
465 self._minmaxy = [ystart,yend]
466 if refresh and self._data: self.plot(self._data)
467 return
468
469 def set_legend(self, mp=None, fontsize = None, mode = 0, refresh=True):
470 """
471 Specify a mapping for the legend instead of using the default
472 indices:
473 Parameters:
474 mp: a list of 'strings'. This should have the same length
475 as the number of elements on the legend and then maps
476 to the indeces in order. It is possible to uses latex
477 math expression. These have to be enclosed in r'',
478 e.g. r'$x^{2}$'
479 fontsize: The font size of the label (default None)
480 mode: where to display the legend
481 Any other value for loc else disables the legend:
482 0: auto
483 1: upper right
484 2: upper left
485 3: lower left
486 4: lower right
487 5: right
488 6: center left
489 7: center right
490 8: lower center
491 9: upper center
492 10: center
493 refresh: True (default) or False. If True, the plot is
494 replotted based on the new parameter setting(s).
495 Otherwise,the parameter(s) are set without replotting.
496
497 Example:
498 If the data has two IFs/rest frequencies with index 0 and 1
499 for CO and SiO:
500 plotter.set_stacking('i')
501 plotter.set_legend(['CO','SiO'])
502 plotter.plot()
503 plotter.set_legend([r'$^{12}CO$', r'SiO'])
504 """
505 self._lmap = mp
506 self._plotter.legend(mode)
507 if isinstance(fontsize, int):
508 from matplotlib import rc as rcp
509 rcp('legend', fontsize=fontsize)
510 if refresh and self._data: self.plot(self._data)
511 return
512
513 def set_title(self, title=None, fontsize=None, refresh=True):
514 """
515 Set the title of the plot. If multiple panels are plotted,
516 multiple titles have to be specified.
517 Parameters:
518 refresh: True (default) or False. If True, the plot is
519 replotted based on the new parameter setting(s).
520 Otherwise,the parameter(s) are set without replotting.
521 Example:
522 # two panels are visible on the plotter
523 plotter.set_title(["First Panel","Second Panel"])
524 """
525 self._title = title
526 if isinstance(fontsize, int):
527 from matplotlib import rc as rcp
528 rcp('axes', titlesize=fontsize)
529 if refresh and self._data: self.plot(self._data)
530 return
531
532 def set_ordinate(self, ordinate=None, fontsize=None, refresh=True):
533 """
534 Set the y-axis label of the plot. If multiple panels are plotted,
535 multiple labels have to be specified.
536 Parameters:
537 ordinate: a list of ordinate labels. None (default) let
538 data determine the labels
539 refresh: True (default) or False. If True, the plot is
540 replotted based on the new parameter setting(s).
541 Otherwise,the parameter(s) are set without replotting.
542 Example:
543 # two panels are visible on the plotter
544 plotter.set_ordinate(["First Y-Axis","Second Y-Axis"])
545 """
546 self._ordinate = ordinate
547 if isinstance(fontsize, int):
548 from matplotlib import rc as rcp
549 rcp('axes', labelsize=fontsize)
550 rcp('ytick', labelsize=fontsize)
551 if refresh and self._data: self.plot(self._data)
552 return
553
554 def set_abcissa(self, abcissa=None, fontsize=None, refresh=True):
555 """
556 Set the x-axis label of the plot. If multiple panels are plotted,
557 multiple labels have to be specified.
558 Parameters:
559 abcissa: a list of abcissa labels. None (default) let
560 data determine the labels
561 refresh: True (default) or False. If True, the plot is
562 replotted based on the new parameter setting(s).
563 Otherwise,the parameter(s) are set without replotting.
564 Example:
565 # two panels are visible on the plotter
566 plotter.set_ordinate(["First X-Axis","Second X-Axis"])
567 """
568 self._abcissa = abcissa
569 if isinstance(fontsize, int):
570 from matplotlib import rc as rcp
571 rcp('axes', labelsize=fontsize)
572 rcp('xtick', labelsize=fontsize)
573 if refresh and self._data: self.plot(self._data)
574 return
575
576 def set_colors(self, colmap, refresh=True):
577 """
578 Set the colours to be used. The plotter will cycle through
579 these colours when lines are overlaid (stacking mode).
580 Parameters:
581 colmap: a list of colour names
582 refresh: True (default) or False. If True, the plot is
583 replotted based on the new parameter setting(s).
584 Otherwise,the parameter(s) are set without replotting.
585 Example:
586 plotter.set_colors("red green blue")
587 # If for example four lines are overlaid e.g I Q U V
588 # 'I' will be 'red', 'Q' will be 'green', U will be 'blue'
589 # and 'V' will be 'red' again.
590 """
591 if isinstance(colmap,str):
592 colmap = colmap.split()
593 self._plotter.palette(0, colormap=colmap)
594 if refresh and self._data: self.plot(self._data)
595
596 # alias for english speakers
597 set_colours = set_colors
598
599 def set_histogram(self, hist=True, linewidth=None, refresh=True):
600 """
601 Enable/Disable histogram-like plotting.
602 Parameters:
603 hist: True (default) or False. The fisrt default
604 is taken from the .asaprc setting
605 plotter.histogram
606 refresh: True (default) or False. If True, the plot is
607 replotted based on the new parameter setting(s).
608 Otherwise,the parameter(s) are set without replotting.
609 """
610 self._hist = hist
611 if isinstance(linewidth, float) or isinstance(linewidth, int):
612 from matplotlib import rc as rcp
613 rcp('lines', linewidth=linewidth)
614 if refresh and self._data: self.plot(self._data)
615
616 def set_linestyles(self, linestyles=None, linewidth=None, refresh=True):
617 """
618 Set the linestyles to be used. The plotter will cycle through
619 these linestyles when lines are overlaid (stacking mode) AND
620 only one color has been set.
621 Parameters:
622 linestyles: a list of linestyles to use.
623 'line', 'dashed', 'dotted', 'dashdot',
624 'dashdotdot' and 'dashdashdot' are
625 possible
626 refresh: True (default) or False. If True, the plot is
627 replotted based on the new parameter setting(s).
628 Otherwise,the parameter(s) are set without replotting.
629 Example:
630 plotter.set_colors("black")
631 plotter.set_linestyles("line dashed dotted dashdot")
632 # If for example four lines are overlaid e.g I Q U V
633 # 'I' will be 'solid', 'Q' will be 'dashed',
634 # U will be 'dotted' and 'V' will be 'dashdot'.
635 """
636 if isinstance(linestyles,str):
637 linestyles = linestyles.split()
638 self._plotter.palette(color=0,linestyle=0,linestyles=linestyles)
639 if isinstance(linewidth, float) or isinstance(linewidth, int):
640 from matplotlib import rc as rcp
641 rcp('lines', linewidth=linewidth)
642 if refresh and self._data: self.plot(self._data)
643
644 def set_font(self, refresh=True,**kwargs):
645 """
646 Set font properties.
647 Parameters:
648 family: one of 'sans-serif', 'serif', 'cursive', 'fantasy', 'monospace'
649 style: one of 'normal' (or 'roman'), 'italic' or 'oblique'
650 weight: one of 'normal or 'bold'
651 size: the 'general' font size, individual elements can be adjusted
652 seperately
653 refresh: True (default) or False. If True, the plot is
654 replotted based on the new parameter setting(s).
655 Otherwise,the parameter(s) are set without replotting.
656 """
657 from matplotlib import rc as rcp
658 fdict = {}
659 for k,v in kwargs.iteritems():
660 if v:
661 fdict[k] = v
662 self._fp = FontProperties(**fdict)
663 if refresh and self._data: self.plot(self._data)
664
665 def set_margin(self,margin=[],refresh=True):
666 """
667 Set margins between subplots and plot edges.
668 Parameters:
669 margin: a list of margins in figure coordinate (0-1),
670 i.e., fraction of the figure width or height.
671 The order of elements should be:
672 [left, bottom, right, top, horizontal space btw panels,
673 vertical space btw panels].
674 refresh: True (default) or False. If True, the plot is
675 replotted based on the new parameter setting(s).
676 Otherwise,the parameter(s) are set without replotting.
677 Note
678 * When margin is not specified, the values are reset to the defaults
679 of matplotlib.
680 * If any element is set to be None, the current value is adopted.
681 """
682 if margin == []: self._margins=self._reset_margin()
683 else:
684 self._margins=[None]*6
685 self._margins[0:len(margin)]=margin
686 #print "panel margin set to ",self._margins
687 if refresh and self._data: self.plot(self._data)
688
689 def _reset_margin(self):
690 ks=map(lambda x: 'figure.subplot.'+x,
691 ['left','bottom','right','top','hspace','wspace'])
692 return map(matplotlib.rcParams.get,ks)
693
694 def plot_lines(self, linecat=None, doppler=0.0, deltachan=10, rotate=90.0,
695 location=None):
696 """
697 Plot a line catalog.
698 Parameters:
699 linecat: the linecatalog to plot
700 doppler: the velocity shift to apply to the frequencies
701 deltachan: the number of channels to include each side of the
702 line to determine a local maximum/minimum
703 rotate: the rotation (in degrees) for the text label (default 90.0)
704 location: the location of the line annotation from the 'top',
705 'bottom' or alternate (None - the default)
706 Notes:
707 If the spectrum is flagged no line will be drawn in that location.
708 """
709 if not self._data:
710 raise RuntimeError("No scantable has been plotted yet.")
711 from asap._asap import linecatalog
712 if not isinstance(linecat, linecatalog):
713 raise ValueError("'linecat' isn't of type linecatalog.")
714 if not self._data.get_unit().endswith("Hz"):
715 raise RuntimeError("Can only overlay linecatalogs when data is in frequency.")
716 from numpy import ma
717 for j in range(len(self._plotter.subplots)):
718 self._plotter.subplot(j)
719 lims = self._plotter.axes.get_xlim()
720 for row in range(linecat.nrow()):
721 # get_frequency returns MHz
722 base = { "GHz": 1000.0, "MHz": 1.0, "Hz": 1.0e-6 }
723 restf = linecat.get_frequency(row)/base[self._data.get_unit()]
724 c = 299792.458
725 freq = restf*(1.0-doppler/c)
726 if lims[0] < freq < lims[1]:
727 if location is None:
728 loc = 'bottom'
729 if row%2: loc='top'
730 else: loc = location
731 maxys = []
732 for line in self._plotter.axes.lines:
733 v = line._x
734 asc = v[0] < v[-1]
735
736 idx = None
737 if not asc:
738 if v[len(v)-1] <= freq <= v[0]:
739 i = len(v)-1
740 while i>=0 and v[i] < freq:
741 idx = i
742 i-=1
743 else:
744 if v[0] <= freq <= v[len(v)-1]:
745 i = 0
746 while i<len(v) and v[i] < freq:
747 idx = i
748 i+=1
749 if idx is not None:
750 lower = idx - deltachan
751 upper = idx + deltachan
752 if lower < 0: lower = 0
753 if upper > len(v): upper = len(v)
754 s = slice(lower, upper)
755 y = line._y[s]
756 maxy = ma.maximum(y)
757 if isinstance( maxy, float):
758 maxys.append(maxy)
759 if len(maxys):
760 peak = max(maxys)
761 if peak > self._plotter.axes.get_ylim()[1]:
762 loc = 'bottom'
763 else:
764 continue
765 self._plotter.vline_with_label(freq, peak,
766 linecat.get_name(row),
767 location=loc, rotate=rotate)
768 self._plotter.show(hardrefresh=False)
769
770
771 def save(self, filename=None, orientation=None, dpi=None):
772 """
773 Save the plot to a file. The known formats are 'png', 'ps', 'eps'.
774 Parameters:
775 filename: The name of the output file. This is optional
776 and autodetects the image format from the file
777 suffix. If non filename is specified a file
778 called 'yyyymmdd_hhmmss.png' is created in the
779 current directory.
780 orientation: optional parameter for postscript only (not eps).
781 'landscape', 'portrait' or None (default) are valid.
782 If None is choosen for 'ps' output, the plot is
783 automatically oriented to fill the page.
784 dpi: The dpi of the output non-ps plot
785 """
786 self._plotter.save(filename,orientation,dpi)
787 return
788
789 @asaplog_post_dec
790 def set_mask(self, mask=None, selection=None, refresh=True):
791 """
792 Set a plotting mask for a specific polarization.
793 This is useful for masking out "noise" Pangle outside a source.
794 Parameters:
795 mask: a mask from scantable.create_mask
796 selection: the spectra to apply the mask to.
797 refresh: True (default) or False. If True, the plot is
798 replotted based on the new parameter setting(s).
799 Otherwise,the parameter(s) are set without replotting.
800 Example:
801 select = selector()
802 select.setpolstrings("Pangle")
803 plotter.set_mask(mymask, select)
804 """
805 if not self._data:
806 msg = "Can only set mask after a first call to plot()"
807 raise RuntimeError(msg)
808 if len(mask):
809 if isinstance(mask, list) or isinstance(mask, tuple):
810 self._usermask = array(mask)
811 else:
812 self._usermask = mask
813 if mask is None and selection is None:
814 self._usermask = []
815 self._maskselection = None
816 if isinstance(selection, selector):
817 self._maskselection = {'b': selection.get_beams(),
818 's': selection.get_scans(),
819 'i': selection.get_ifs(),
820 'p': selection.get_pols(),
821 't': [] }
822 else:
823 self._maskselection = None
824 if refresh: self.plot(self._data)
825
826 def _slice_indeces(self, data):
827 mn = self._minmaxx[0]
828 mx = self._minmaxx[1]
829 asc = data[0] < data[-1]
830 start=0
831 end = len(data)-1
832 inc = 1
833 if not asc:
834 start = len(data)-1
835 end = 0
836 inc = -1
837 # find min index
838 #while start > 0 and data[start] < mn:
839 # start+= inc
840 minind=start
841 for ind in xrange(start,end+inc,inc):
842 if data[ind] > mn: break
843 minind=ind
844 # find max index
845 #while end > 0 and data[end] > mx:
846 # end-=inc
847 #if end > 0: end +=1
848 maxind=end
849 for ind in xrange(end,start-inc,-inc):
850 if data[ind] < mx: break
851 maxind=ind
852 start=minind
853 end=maxind
854 if start > end:
855 return end,start+1
856 elif start < end:
857 return start,end+1
858 else:
859 return start,end
860
861 def _reset(self):
862 self._usermask = []
863 self._usermaskspectra = None
864 self._offset = None
865 self.set_selection(None, False)
866 self._reset_header()
867
868 def _reset_header(self):
869 self._headtext={'string': None, 'textobj': None}
870
871 def _plot(self, scan):
872 savesel = scan.get_selection()
873 sel = savesel + self._selection
874 order = self._get_sortstring([self._panelling,self._stacking])
875 if order:
876 sel.set_order(order)
877 scan.set_selection(sel)
878 d = {'b': scan.getbeam, 's': scan.getscan,
879 'i': scan.getif, 'p': scan.getpol, 't': scan.get_time,
880 'r': int}#, '_r': int}
881
882 polmodes = dict(zip(self._selection.get_pols(),
883 self._selection.get_poltypes()))
884 # this returns either a tuple of numbers or a length (ncycles)
885 # convert this into lengths
886 n0,nstack0 = self._get_selected_n(scan)
887 if isinstance(n0, int): n = n0
888 else: n = len(n0)
889 if isinstance(nstack0, int): nstack = nstack0
890 else: nstack = len(nstack0)
891 # In case of row stacking
892 rowstack = False
893 titlemode = self._panelling
894 if self._stacking == "r" and self._panelling != "r":
895 rowstack = True
896 titlemode = '_r'
897 nptot = n
898 maxpanel, maxstack = 16,16
899 if nstack > maxstack:
900 msg ="Scan to be overlayed contains more than %d selections.\n" \
901 "Selecting first %d selections..." % (maxstack, maxstack)
902 asaplog.push(msg)
903 asaplog.post('WARN')
904 nstack = min(nstack,maxstack)
905 #n = min(n-self._ipanel-1,maxpanel)
906 n = n-self._ipanel-1
907
908 ganged = False
909 if n > 1:
910 ganged = rcParams['plotter.ganged']
911 if self._panelling == 'i':
912 ganged = False
913 if self._rows and self._cols:
914 n = min(n,self._rows*self._cols)
915 self._plotter.set_panels(rows=self._rows,cols=self._cols,
916 nplots=n,margin=self._margins,
917 ganged=ganged)
918 else:
919 n = min(n,maxpanel)
920 self._plotter.set_panels(rows=n,cols=0,nplots=n,
921 margin=self._margins,ganged=ganged)
922 else:
923 self._plotter.set_panels(margin=self._margins)
924 #r = 0
925 r = self._startrow
926 nr = scan.nrow()
927 a0,b0 = -1,-1
928 allxlim = []
929 allylim = []
930 #newpanel=True
931 newpanel=False
932 panelcount,stackcount = 0,0
933 # If this is not the first page
934 if r > 0:
935 # panelling value of the prev page
936 a0 = d[self._panelling](r-1)
937 # set the initial stackcount large not to plot
938 # the start row automatically
939 stackcount = nstack
940
941 while r < nr:
942 a = d[self._panelling](r)
943 b = d[self._stacking](r)
944 if a > a0 and panelcount < n:
945 if n > 1:
946 self._plotter.subplot(panelcount)
947 self._plotter.palette(0)
948 #title
949 xlab = self._abcissa and self._abcissa[panelcount] \
950 or scan._getabcissalabel()
951 if self._offset and not self._abcissa:
952 xlab += " (relative)"
953 ylab = self._ordinate and self._ordinate[panelcount] \
954 or scan._get_ordinate_label()
955 self._plotter.set_axes('xlabel', xlab)
956 self._plotter.set_axes('ylabel', ylab)
957 #lbl = self._get_label(scan, r, self._panelling, self._title)
958 lbl = self._get_label(scan, r, titlemode, self._title)
959 if isinstance(lbl, list) or isinstance(lbl, tuple):
960 if 0 <= panelcount < len(lbl):
961 lbl = lbl[panelcount]
962 else:
963 # get default label
964 #lbl = self._get_label(scan, r, self._panelling, None)
965 lbl = self._get_label(scan, r, titlemode, None)
966 self._plotter.set_axes('title',lbl)
967 newpanel = True
968 stackcount = 0
969 panelcount += 1
970 # save the start row to plot this panel for future revisit.
971 if self._panelling != 'r' and \
972 len(self._panelrows) < self._ipanel+1+panelcount:
973 self._panelrows += [r]
974
975 #if (b > b0 or newpanel) and stackcount < nstack:
976 if stackcount < nstack and (newpanel or rowstack
977 or (a == a0 and b > b0)):
978 y = []
979 if len(polmodes):
980 y = scan._getspectrum(r, polmodes[scan.getpol(r)])
981 else:
982 y = scan._getspectrum(r)
983 # flag application
984 mr = scan._getflagrow(r)
985 #mr = False
986 from numpy import ma, array
987 if mr:
988 y = ma.masked_array(y,mask=mr)
989 else:
990 m = scan._getmask(r)
991 from numpy import logical_not, logical_and
992 if self._maskselection and len(self._usermask) == len(m):
993 if d[self._stacking](r) in \
994 self._maskselection[self._stacking]:
995 m = logical_and(m, self._usermask)
996 y = ma.masked_array(y,mask=logical_not(array(m,
997 copy=False)))
998
999 x = array(scan._getabcissa(r))
1000 if self._offset:
1001 x += self._offset
1002 if self._minmaxx is not None:
1003 s,e = self._slice_indeces(x)
1004 x = x[s:e]
1005 y = y[s:e]
1006 if len(x) > 1024 and rcParams['plotter.decimate']:
1007 fac = len(x)/1024
1008 x = x[::fac]
1009 y = y[::fac]
1010 llbl = self._get_label(scan, r, self._stacking, self._lmap)
1011 if isinstance(llbl, list) or isinstance(llbl, tuple):
1012 if 0 <= stackcount < len(llbl):
1013 # use user label
1014 llbl = llbl[stackcount]
1015 else:
1016 # get default label
1017 llbl = self._get_label(scan, r, self._stacking, None)
1018 self._plotter.set_line(label=llbl)
1019 plotit = self._plotter.plot
1020 if self._hist: plotit = self._plotter.hist
1021 if len(x) > 0 and not mr:
1022 plotit(x,y)
1023 xlim= self._minmaxx or [min(x),max(x)]
1024 allxlim += xlim
1025 ylim= self._minmaxy or [ma.minimum(y),ma.maximum(y)]
1026 allylim += ylim
1027 else:
1028 xlim = self._minmaxx or []
1029 allxlim += xlim
1030 ylim= self._minmaxy or []
1031 allylim += ylim
1032 stackcount += 1
1033 a0=a
1034 b0=b
1035 # last in colour stack -> autoscale x
1036 if stackcount == nstack and len(allxlim) > 0:
1037 allxlim.sort()
1038 self._plotter.subplots[panelcount-1]['axes'].set_xlim([allxlim[0],allxlim[-1]])
1039 if ganged:
1040 allxlim = [allxlim[0],allxlim[-1]]
1041 else:
1042 # clear
1043 allxlim =[]
1044
1045 newpanel = False
1046 #a0=a
1047 #b0=b
1048 # ignore following rows
1049 if (panelcount == n and stackcount == nstack) or (r == nr-1):
1050 # last panel -> autoscale y if ganged
1051 #if rcParams['plotter.ganged'] and len(allylim) > 0:
1052 if ganged and len(allylim) > 0:
1053 allylim.sort()
1054 self._plotter.set_limits(ylim=[allylim[0],allylim[-1]])
1055 break
1056 r+=1 # next row
1057
1058 # save the current counter for multi-page plotting
1059 self._startrow = r+1
1060 self._ipanel += panelcount
1061 if self.casabar_exists():
1062 if self._ipanel >= nptot-1:
1063 self._plotter.figmgr.casabar.disable_next()
1064 else:
1065 self._plotter.figmgr.casabar.enable_next()
1066 if self._ipanel + 1 - panelcount > 0:
1067 self._plotter.figmgr.casabar.enable_prev()
1068 else:
1069 self._plotter.figmgr.casabar.disable_prev()
1070
1071 #reset the selector to the scantable's original
1072 scan.set_selection(savesel)
1073
1074 #temporary switch-off for older matplotlib
1075 #if self._fp is not None:
1076 if self._fp is not None and getattr(self._plotter.figure,'findobj',False):
1077 for o in self._plotter.figure.findobj(Text):
1078 o.set_fontproperties(self._fp)
1079
1080 def _get_sortstring(self, lorders):
1081 d0 = {'s': 'SCANNO', 'b': 'BEAMNO', 'i':'IFNO',
1082 'p': 'POLNO', 'c': 'CYCLENO', 't' : 'TIME', 'r':None, '_r':None }
1083 if not (type(lorders) == list) and not (type(lorders) == tuple):
1084 return None
1085 if len(lorders) > 0:
1086 lsorts = []
1087 for order in lorders:
1088 if order == "r":
1089 # don't sort if row panelling/stacking
1090 return None
1091 ssort = d0[order]
1092 if ssort:
1093 lsorts.append(ssort)
1094 return lsorts
1095 return None
1096
1097 def set_selection(self, selection=None, refresh=True, **kw):
1098 """
1099 Parameters:
1100 selection: a selector object (default unset the selection)
1101 refresh: True (default) or False. If True, the plot is
1102 replotted based on the new parameter setting(s).
1103 Otherwise,the parameter(s) are set without replotting.
1104 """
1105 if selection is None:
1106 # reset
1107 if len(kw) == 0:
1108 self._selection = selector()
1109 else:
1110 # try keywords
1111 for k in kw:
1112 if k not in selector.fields:
1113 raise KeyError("Invalid selection key '%s', valid keys are %s" % (k, selector.fields))
1114 self._selection = selector(**kw)
1115 elif isinstance(selection, selector):
1116 self._selection = selection
1117 else:
1118 raise TypeError("'selection' is not of type selector")
1119
1120 order = self._get_sortstring([self._panelling,self._stacking])
1121 if order:
1122 self._selection.set_order(order)
1123 if refresh and self._data: self.plot(self._data)
1124
1125 def _get_selected_n(self, scan):
1126 d1 = {'b': scan.getbeamnos, 's': scan.getscannos,
1127 'i': scan.getifnos, 'p': scan.getpolnos, 't': scan.ncycle,
1128 'r': scan.nrow}#, '_r': False}
1129 d2 = { 'b': self._selection.get_beams(),
1130 's': self._selection.get_scans(),
1131 'i': self._selection.get_ifs(),
1132 'p': self._selection.get_pols(),
1133 't': self._selection.get_cycles(),
1134 'r': False}#, '_r': 1}
1135 n = d2[self._panelling] or d1[self._panelling]()
1136 nstack = d2[self._stacking] or d1[self._stacking]()
1137 # handle row panelling/stacking
1138 if self._panelling == 'r':
1139 nstack = 1
1140 elif self._stacking == 'r':
1141 n = 1
1142 return n,nstack
1143
1144 def _get_label(self, scan, row, mode, userlabel=None):
1145 if isinstance(userlabel, list) and len(userlabel) == 0:
1146 userlabel = " "
1147 pms = dict(zip(self._selection.get_pols(),self._selection.get_poltypes()))
1148 if len(pms):
1149 poleval = scan._getpollabel(scan.getpol(row),pms[scan.getpol(row)])
1150 else:
1151 poleval = scan._getpollabel(scan.getpol(row),scan.poltype())
1152 d = {'b': "Beam "+str(scan.getbeam(row)),
1153 #'s': scan._getsourcename(row),
1154 's': "Scan "+str(scan.getscan(row))+\
1155 " ("+str(scan._getsourcename(row))+")",
1156 'i': "IF"+str(scan.getif(row)),
1157 'p': poleval,
1158 't': str(scan.get_time(row)),
1159 'r': "row "+str(row),
1160 #'_r': str(scan.get_time(row))+",\nIF"+str(scan.getif(row))+", "+poleval+", Beam"+str(scan.getbeam(row)) }
1161 '_r': "" }
1162 return userlabel or d[mode]
1163
1164 def plotazel(self, scan=None, outfile=None):
1165 """
1166 plot azimuth and elevation versus time of a scantable
1167 """
1168 visible = rcParams['plotter.gui']
1169 from matplotlib import pylab as PL
1170 from matplotlib.dates import DateFormatter, timezone
1171 from matplotlib.dates import HourLocator, MinuteLocator,SecondLocator, DayLocator
1172 from matplotlib.ticker import MultipleLocator
1173 from numpy import array, pi
1174 if not visible or not self._visible:
1175 PL.ioff()
1176 from matplotlib.backends.backend_agg import FigureCanvasAgg
1177 PL.gcf().canvas.switch_backends(FigureCanvasAgg)
1178 self._data = scan
1179 self._outfile = outfile
1180 dates = self._data.get_time(asdatetime=True)
1181 t = PL.date2num(dates)
1182 tz = timezone('UTC')
1183 PL.cla()
1184 PL.ioff()
1185 PL.clf()
1186 # Adjust subplot margins
1187 if len(self._margins) != 6:
1188 self.set_margin(refresh=False)
1189 lef, bot, rig, top, wsp, hsp = self._margins
1190 PL.gcf().subplots_adjust(left=lef,bottom=bot,right=rig,top=top,
1191 wspace=wsp,hspace=hsp)
1192
1193 tdel = max(t) - min(t)
1194 ax = PL.subplot(2,1,1)
1195 el = array(self._data.get_elevation())*180./pi
1196 PL.ylabel('El [deg.]')
1197 dstr = dates[0].strftime('%Y/%m/%d')
1198 if tdel > 1.0:
1199 dstr2 = dates[len(dates)-1].strftime('%Y/%m/%d')
1200 dstr = dstr + " - " + dstr2
1201 majloc = DayLocator()
1202 minloc = HourLocator(range(0,23,12))
1203 timefmt = DateFormatter("%b%d")
1204 elif tdel > 24./60.:
1205 timefmt = DateFormatter('%H:%M')
1206 majloc = HourLocator()
1207 minloc = MinuteLocator(30)
1208 else:
1209 timefmt = DateFormatter('%H:%M')
1210 majloc = MinuteLocator(interval=5)
1211 minloc = SecondLocator(30)
1212
1213 PL.title(dstr)
1214 if tdel == 0.0:
1215 th = (t - PL.floor(t))*24.0
1216 PL.plot(th,el,'o',markersize=2, markerfacecolor='b', markeredgecolor='b')
1217 else:
1218 PL.plot_date(t,el,'o', markersize=2, markerfacecolor='b', markeredgecolor='b',tz=tz)
1219 #ax.grid(True)
1220 ax.xaxis.set_major_formatter(timefmt)
1221 ax.xaxis.set_major_locator(majloc)
1222 ax.xaxis.set_minor_locator(minloc)
1223 ax.yaxis.grid(True)
1224 yloc = MultipleLocator(30)
1225 ax.set_ylim(0,90)
1226 ax.yaxis.set_major_locator(yloc)
1227 if tdel > 1.0:
1228 labels = ax.get_xticklabels()
1229 # PL.setp(labels, fontsize=10, rotation=45)
1230 PL.setp(labels, fontsize=10)
1231
1232 # Az plot
1233 az = array(self._data.get_azimuth())*180./pi
1234 if min(az) < 0:
1235 for irow in range(len(az)):
1236 if az[irow] < 0: az[irow] += 360.0
1237
1238 ax2 = PL.subplot(2,1,2)
1239 #PL.xlabel('Time (UT [hour])')
1240 PL.ylabel('Az [deg.]')
1241 if tdel == 0.0:
1242 PL.plot(th,az,'o',markersize=2, markeredgecolor='b',markerfacecolor='b')
1243 else:
1244 PL.plot_date(t,az,'o', markersize=2,markeredgecolor='b',markerfacecolor='b',tz=tz)
1245 ax2.xaxis.set_major_formatter(timefmt)
1246 ax2.xaxis.set_major_locator(majloc)
1247 ax2.xaxis.set_minor_locator(minloc)
1248 #ax2.grid(True)
1249 ax2.set_ylim(0,360)
1250 ax2.yaxis.grid(True)
1251 #hfmt = DateFormatter('%H')
1252 #hloc = HourLocator()
1253 yloc = MultipleLocator(60)
1254 ax2.yaxis.set_major_locator(yloc)
1255 if tdel > 1.0:
1256 labels = ax2.get_xticklabels()
1257 PL.setp(labels, fontsize=10)
1258 PL.xlabel('Time (UT [day])')
1259 else:
1260 PL.xlabel('Time (UT [hour])')
1261
1262 PL.ion()
1263 PL.draw()
1264 PL.gcf().show()
1265 if (self._outfile is not None):
1266 PL.savefig(self._outfile)
1267
1268 def plotpointing(self, scan=None, outfile=None):
1269 """
1270 plot telescope pointings
1271 """
1272 visible = rcParams['plotter.gui']
1273 from matplotlib import pylab as PL
1274 from numpy import array, pi
1275 if not visible or not self._visible:
1276 PL.ioff()
1277 from matplotlib.backends.backend_agg import FigureCanvasAgg
1278 PL.gcf().canvas.switch_backends(FigureCanvasAgg)
1279 self._data = scan
1280 self._outfile = outfile
1281 dir = array(self._data.get_directionval()).transpose()
1282 ra = dir[0]*180./pi
1283 dec = dir[1]*180./pi
1284 PL.cla()
1285 #PL.ioff()
1286 PL.clf()
1287 # Adjust subplot margins
1288 if len(self._margins) != 6:
1289 self.set_margin(refresh=False)
1290 lef, bot, rig, top, wsp, hsp = self._margins
1291 PL.gcf().subplots_adjust(left=lef,bottom=bot,right=rig,top=top,
1292 wspace=wsp,hspace=hsp)
1293 ax = PL.gca()
1294 #ax = PL.axes([0.1,0.1,0.8,0.8])
1295 #ax = PL.axes([0.1,0.1,0.8,0.8])
1296 ax.set_aspect('equal')
1297 PL.plot(ra, dec, 'b,')
1298 PL.xlabel('RA [deg.]')
1299 PL.ylabel('Declination [deg.]')
1300 PL.title('Telescope pointings')
1301 [xmin,xmax,ymin,ymax] = PL.axis()
1302 PL.axis([xmax,xmin,ymin,ymax])
1303 #PL.ion()
1304 PL.draw()
1305 PL.gcf().show()
1306 if (self._outfile is not None):
1307 PL.savefig(self._outfile)
1308
1309 # plot total power data
1310 # plotting in time is not yet implemented..
1311 @asaplog_post_dec
1312 def plottp(self, scan=None, outfile=None):
1313 if self._plotter.is_dead:
1314 if self.casabar_exists():
1315 del self._plotter.figmgr.casabar
1316 self._plotter = self._newplotter()
1317 self._plotter.figmgr.casabar=self._new_custombar()
1318 self._plotter.hold()
1319 self._plotter.clear()
1320 from asap import scantable
1321 if not self._data and not scan:
1322 msg = "Input is not a scantable"
1323 raise TypeError(msg)
1324 if isinstance(scan, scantable):
1325 if self._data is not None:
1326 if scan != self._data:
1327 self._data = scan
1328 # reset
1329 self._reset()
1330 else:
1331 self._data = scan
1332 self._reset()
1333 # ranges become invalid when abcissa changes?
1334 #if self._abcunit and self._abcunit != self._data.get_unit():
1335 # self._minmaxx = None
1336 # self._minmaxy = None
1337 # self._abcunit = self._data.get_unit()
1338 # self._datamask = None
1339
1340 # Adjust subplot margins
1341 if len(self._margins) !=6: self.set_margin(refresh=False)
1342 lef, bot, rig, top, wsp, hsp = self._margins
1343 self._plotter.figure.subplots_adjust(
1344 left=lef,bottom=bot,right=rig,top=top,wspace=wsp,hspace=hsp)
1345 if self.casabar_exists(): self._plotter.figmgr.casabar.disable_button()
1346 self._plottp(self._data)
1347 if self._minmaxy is not None:
1348 self._plotter.set_limits(ylim=self._minmaxy)
1349 self._plotter.release()
1350 self._plotter.tidy()
1351 self._plotter.show(hardrefresh=False)
1352 return
1353
1354 def _plottp(self,scan):
1355 """
1356 private method for plotting total power data
1357 """
1358 from numpy import ma, array, arange, logical_not
1359 r=0
1360 nr = scan.nrow()
1361 a0,b0 = -1,-1
1362 allxlim = []
1363 allylim = []
1364 y=[]
1365 self._plotter.set_panels()
1366 self._plotter.palette(0)
1367 #title
1368 #xlab = self._abcissa and self._abcissa[panelcount] \
1369 # or scan._getabcissalabel()
1370 #ylab = self._ordinate and self._ordinate[panelcount] \
1371 # or scan._get_ordinate_label()
1372 xlab = self._abcissa or 'row number' #or Time
1373 ylab = self._ordinate or scan._get_ordinate_label()
1374 self._plotter.set_axes('xlabel',xlab)
1375 self._plotter.set_axes('ylabel',ylab)
1376 lbl = self._get_label(scan, r, 's', self._title)
1377 if isinstance(lbl, list) or isinstance(lbl, tuple):
1378 # if 0 <= panelcount < len(lbl):
1379 # lbl = lbl[panelcount]
1380 # else:
1381 # get default label
1382 lbl = self._get_label(scan, r, self._panelling, None)
1383 self._plotter.set_axes('title',lbl)
1384 y=array(scan._get_column(scan._getspectrum,-1))
1385 m = array(scan._get_column(scan._getmask,-1))
1386 y = ma.masked_array(y,mask=logical_not(array(m,copy=False)))
1387 x = arange(len(y))
1388 # try to handle spectral data somewhat...
1389 l,m = y.shape
1390 if m > 1:
1391 y=y.mean(axis=1)
1392 plotit = self._plotter.plot
1393 llbl = self._get_label(scan, r, self._stacking, None)
1394 self._plotter.set_line(label=llbl)
1395 if len(x) > 0:
1396 plotit(x,y)
1397
1398
1399 # forwards to matplotlib.Figure.text
1400 def figtext(self, *args, **kwargs):
1401 """
1402 Add text to figure at location x,y (relative 0-1 coords).
1403 This method forwards *args and **kwargs to a Matplotlib method,
1404 matplotlib.Figure.text.
1405 See the method help for detailed information.
1406 """
1407 self._plotter.text(*args, **kwargs)
1408 # end matplotlib.Figure.text forwarding function
1409
1410
1411 # printing header information
1412 @asaplog_post_dec
1413 def print_header(self, plot=True, fontsize=9, logger=False, selstr='', extrastr=''):
1414 """
1415 print data (scantable) header on the plot and/or logger.
1416 To plot the header on the plot, this method should be called after
1417 plotting spectra by the method, asapplotter.plot.
1418 Parameters:
1419 plot: whether or not print header info on the plot.
1420 fontsize: header font size (valid only plot=True)
1421 logger: whether or not print header info on the logger.
1422 selstr: additional selection string (not verified)
1423 extrastr: additional string to print at the beginning (not verified)
1424 """
1425 if not plot and not logger:
1426 return
1427 if not self._data:
1428 raise RuntimeError("No scantable has been set yet.")
1429 # Now header will be printed on plot and/or logger.
1430 # Get header information and format it.
1431 ssum=self._data._list_header()
1432 # Print Observation header to the upper-left corner of plot
1433 headstr=[ssum[ssum.find('Observer:'):ssum.find('Flux Unit:')]]
1434 headstr.append(ssum[ssum.find('Beams:'):ssum.find('Observer:')]
1435 +ssum[ssum.find('Rest Freqs:'):ssum.find('Abcissa:')])
1436 if extrastr != '':
1437 headstr[0]=extrastr+'\n'+headstr[0]
1438 self._headtext['extrastr'] = extrastr
1439 if selstr != '':
1440 selstr += '\n'
1441 self._headtext['selstr'] = selstr
1442 ssel=(selstr+self._data.get_selection().__str__()+self._selection.__str__() or 'none')
1443 headstr.append('***Selections***\n'+ssel)
1444
1445 if plot:
1446 self._plotter.hold()
1447 self._header_plot(headstr,fontsize=fontsize)
1448 import time
1449 self._plotter.figure.text(0.99,0.01,
1450 time.strftime("%a %d %b %Y %H:%M:%S %Z"),
1451 horizontalalignment='right',
1452 verticalalignment='bottom',fontsize=8)
1453 self._plotter.release()
1454 if logger:
1455 selstr = "Selections: "+ssel
1456 asaplog.push("----------------\n Plot Summary\n----------------")
1457 asaplog.push(extrastr)
1458 asaplog.push(ssum[ssum.find('Beams:'):ssum.find('Selection:')]\
1459 #+ selstr + ssum[ssum.find('Scan Source'):])
1460 + selstr)
1461 self._headtext['string'] = headstr
1462 del ssel, ssum, headstr
1463
1464 def _header_plot(self, texts, fontsize=9):
1465 self._headtext['textobj']=[]
1466 nstcol=len(texts)
1467 for i in range(nstcol):
1468 self._headtext['textobj'].append(
1469 self._plotter.figure.text(0.03+float(i)/nstcol,0.98,
1470 texts[i],
1471 horizontalalignment='left',
1472 verticalalignment='top',
1473 fontsize=fontsize))
1474
1475 def clear_header(self):
1476 if not self._headtext['textobj']:
1477 asaplog.push("No header has been plotted. Exit without any operation")
1478 asaplog.post("WARN")
1479 else:
1480 self._plotter.hold()
1481 for textobj in self._headtext['textobj']:
1482 #if textobj.get_text() in self._headstring:
1483 try:
1484 textobj.remove()
1485 except NotImplementedError:
1486 self._plotter.figure.texts.pop(self._plotter.figure.texts.index(textobj))
1487 self._plotter.release()
1488 self._reset_header()
Note: See TracBrowser for help on using the repository browser.