source: trunk/python/asapplotter.py@ 2169

Last change on this file since 2169 was 2168, checked in by Kana Sugimoto, 14 years ago

New Development: Yes

JIRA Issue: No

Ready for Test: Yes

Interface Changes: No

What Interface Changed:

Test Programs: Interactive test with PyQt4 backend

Put in Release Notes: Yes

Module(s): asapplotter, asaplotbase, and sdplot

Description: Enabled additional toolbar, casabar, in asapplotter for Qt4Agg bacend


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