source: trunk/python/asapplotter.py@ 2416

Last change on this file since 2416 was 2416, checked in by Kana Sugimoto, 13 years ago

New Development: No

JIRA Issue: Yes (CAS-3749)

Ready for Test: Yes

Interface Changes: No

What Interface Changed:

Test Programs: an interactive test

  1. load casapy (or standalone asap)
  2. matplotlib.pyplot.show() ---> 2 plotters (ASAP plotter and matplotlib plotter) are displayed and casapy prompt is paused.
  3. close all plotter windows ---> casapy prompt should be back

Put in Release Notes: No

Module(s): sdplot, asap.plotter

Description:

Fixed a bug in asapplotter with Tk backend which caused scripts and python shells
freeze after the initial invocation of matplotlib.pyplot.show() (known as pl.show() on CASA).
plus minor fixes which handle backend dependencies.

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 58.3 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,ganged=ganged)
917 else:
918 n = min(n,maxpanel)
919 self._plotter.set_panels(rows=n,cols=0,nplots=n,margin=self._margins,ganged=ganged)
920 else:
921 self._plotter.set_panels(margin=self._margins)
922 #r = 0
923 r = self._startrow
924 nr = scan.nrow()
925 a0,b0 = -1,-1
926 allxlim = []
927 allylim = []
928 #newpanel=True
929 newpanel=False
930 panelcount,stackcount = 0,0
931 # If this is not the first page
932 if r > 0:
933 # panelling value of the prev page
934 a0 = d[self._panelling](r-1)
935 # set the initial stackcount large not to plot
936 # the start row automatically
937 stackcount = nstack
938
939 while r < nr:
940 a = d[self._panelling](r)
941 b = d[self._stacking](r)
942 if a > a0 and panelcount < n:
943 if n > 1:
944 self._plotter.subplot(panelcount)
945 self._plotter.palette(0)
946 #title
947 xlab = self._abcissa and self._abcissa[panelcount] \
948 or scan._getabcissalabel()
949 if self._offset and not self._abcissa:
950 xlab += " (relative)"
951 ylab = self._ordinate and self._ordinate[panelcount] \
952 or scan._get_ordinate_label()
953 self._plotter.set_axes('xlabel', xlab)
954 self._plotter.set_axes('ylabel', ylab)
955 #lbl = self._get_label(scan, r, self._panelling, self._title)
956 lbl = self._get_label(scan, r, titlemode, self._title)
957 if isinstance(lbl, list) or isinstance(lbl, tuple):
958 if 0 <= panelcount < len(lbl):
959 lbl = lbl[panelcount]
960 else:
961 # get default label
962 #lbl = self._get_label(scan, r, self._panelling, None)
963 lbl = self._get_label(scan, r, titlemode, None)
964 self._plotter.set_axes('title',lbl)
965 newpanel = True
966 stackcount = 0
967 panelcount += 1
968 # save the start row to plot this panel for future revisit.
969 if self._panelling != 'r' and \
970 len(self._panelrows) < self._ipanel+1+panelcount:
971 self._panelrows += [r]
972
973 #if (b > b0 or newpanel) and stackcount < nstack:
974 if stackcount < nstack and (newpanel or rowstack or (a == a0 and b > b0)):
975 y = []
976 if len(polmodes):
977 y = scan._getspectrum(r, polmodes[scan.getpol(r)])
978 else:
979 y = scan._getspectrum(r)
980 # flag application
981 mr = scan._getflagrow(r)
982 from numpy import ma, array
983 if mr:
984 y = ma.masked_array(y,mask=mr)
985 else:
986 m = scan._getmask(r)
987 from numpy import logical_not, logical_and
988 if self._maskselection and len(self._usermask) == len(m):
989 if d[self._stacking](r) in self._maskselection[self._stacking]:
990 m = logical_and(m, self._usermask)
991 y = ma.masked_array(y,mask=logical_not(array(m,copy=False)))
992
993 x = array(scan._getabcissa(r))
994 if self._offset:
995 x += self._offset
996 if self._minmaxx is not None:
997 s,e = self._slice_indeces(x)
998 x = x[s:e]
999 y = y[s:e]
1000 if len(x) > 1024 and rcParams['plotter.decimate']:
1001 fac = len(x)/1024
1002 x = x[::fac]
1003 y = y[::fac]
1004 llbl = self._get_label(scan, r, self._stacking, self._lmap)
1005 if isinstance(llbl, list) or isinstance(llbl, tuple):
1006 if 0 <= stackcount < len(llbl):
1007 # use user label
1008 llbl = llbl[stackcount]
1009 else:
1010 # get default label
1011 llbl = self._get_label(scan, r, self._stacking, None)
1012 self._plotter.set_line(label=llbl)
1013 plotit = self._plotter.plot
1014 if self._hist: plotit = self._plotter.hist
1015 if len(x) > 0 and not mr:
1016 plotit(x,y)
1017 xlim= self._minmaxx or [min(x),max(x)]
1018 allxlim += xlim
1019 ylim= self._minmaxy or [ma.minimum(y),ma.maximum(y)]
1020 allylim += ylim
1021 else:
1022 xlim = self._minmaxx or []
1023 allxlim += xlim
1024 ylim= self._minmaxy or []
1025 allylim += ylim
1026 stackcount += 1
1027 a0=a
1028 b0=b
1029 # last in colour stack -> autoscale x
1030 if stackcount == nstack and len(allxlim) > 0:
1031 allxlim.sort()
1032 self._plotter.subplots[panelcount-1]['axes'].set_xlim([allxlim[0],allxlim[-1]])
1033 if ganged:
1034 allxlim = [allxlim[0],allxlim[-1]]
1035 else:
1036 # clear
1037 allxlim =[]
1038
1039 newpanel = False
1040 #a0=a
1041 #b0=b
1042 # ignore following rows
1043 if (panelcount == n and stackcount == nstack) or (r == nr-1):
1044 # last panel -> autoscale y if ganged
1045 #if rcParams['plotter.ganged'] and len(allylim) > 0:
1046 if ganged and len(allylim) > 0:
1047 allylim.sort()
1048 self._plotter.set_limits(ylim=[allylim[0],allylim[-1]])
1049 break
1050 r+=1 # next row
1051
1052 # save the current counter for multi-page plotting
1053 self._startrow = r+1
1054 self._ipanel += panelcount
1055 if self.casabar_exists():
1056 if self._ipanel >= nptot-1:
1057 self._plotter.figmgr.casabar.disable_next()
1058 else:
1059 self._plotter.figmgr.casabar.enable_next()
1060 if self._ipanel + 1 - panelcount > 0:
1061 self._plotter.figmgr.casabar.enable_prev()
1062 else:
1063 self._plotter.figmgr.casabar.disable_prev()
1064
1065 #reset the selector to the scantable's original
1066 scan.set_selection(savesel)
1067
1068 #temporary switch-off for older matplotlib
1069 #if self._fp is not None:
1070 if self._fp is not None and getattr(self._plotter.figure,'findobj',False):
1071 for o in self._plotter.figure.findobj(Text):
1072 o.set_fontproperties(self._fp)
1073
1074 def _get_sortstring(self, lorders):
1075 d0 = {'s': 'SCANNO', 'b': 'BEAMNO', 'i':'IFNO',
1076 'p': 'POLNO', 'c': 'CYCLENO', 't' : 'TIME', 'r':None, '_r':None }
1077 if not (type(lorders) == list) and not (type(lorders) == tuple):
1078 return None
1079 if len(lorders) > 0:
1080 lsorts = []
1081 for order in lorders:
1082 if order == "r":
1083 # don't sort if row panelling/stacking
1084 return None
1085 ssort = d0[order]
1086 if ssort:
1087 lsorts.append(ssort)
1088 return lsorts
1089 return None
1090
1091 def set_selection(self, selection=None, refresh=True, **kw):
1092 """
1093 Parameters:
1094 selection: a selector object (default unset the selection)
1095 refresh: True (default) or False. If True, the plot is
1096 replotted based on the new parameter setting(s).
1097 Otherwise,the parameter(s) are set without replotting.
1098 """
1099 if selection is None:
1100 # reset
1101 if len(kw) == 0:
1102 self._selection = selector()
1103 else:
1104 # try keywords
1105 for k in kw:
1106 if k not in selector.fields:
1107 raise KeyError("Invalid selection key '%s', valid keys are %s" % (k, selector.fields))
1108 self._selection = selector(**kw)
1109 elif isinstance(selection, selector):
1110 self._selection = selection
1111 else:
1112 raise TypeError("'selection' is not of type selector")
1113
1114 order = self._get_sortstring([self._panelling,self._stacking])
1115 if order:
1116 self._selection.set_order(order)
1117 if refresh and self._data: self.plot(self._data)
1118
1119 def _get_selected_n(self, scan):
1120 d1 = {'b': scan.getbeamnos, 's': scan.getscannos,
1121 'i': scan.getifnos, 'p': scan.getpolnos, 't': scan.ncycle,
1122 'r': scan.nrow}#, '_r': False}
1123 d2 = { 'b': self._selection.get_beams(),
1124 's': self._selection.get_scans(),
1125 'i': self._selection.get_ifs(),
1126 'p': self._selection.get_pols(),
1127 't': self._selection.get_cycles(),
1128 'r': False}#, '_r': 1}
1129 n = d2[self._panelling] or d1[self._panelling]()
1130 nstack = d2[self._stacking] or d1[self._stacking]()
1131 # handle row panelling/stacking
1132 if self._panelling == 'r':
1133 nstack = 1
1134 elif self._stacking == 'r':
1135 n = 1
1136 return n,nstack
1137
1138 def _get_label(self, scan, row, mode, userlabel=None):
1139 if isinstance(userlabel, list) and len(userlabel) == 0:
1140 userlabel = " "
1141 pms = dict(zip(self._selection.get_pols(),self._selection.get_poltypes()))
1142 if len(pms):
1143 poleval = scan._getpollabel(scan.getpol(row),pms[scan.getpol(row)])
1144 else:
1145 poleval = scan._getpollabel(scan.getpol(row),scan.poltype())
1146 d = {'b': "Beam "+str(scan.getbeam(row)),
1147 #'s': scan._getsourcename(row),
1148 's': "Scan "+str(scan.getscan(row))+\
1149 " ("+str(scan._getsourcename(row))+")",
1150 'i': "IF"+str(scan.getif(row)),
1151 'p': poleval,
1152 't': str(scan.get_time(row)),
1153 'r': "row "+str(row),
1154 #'_r': str(scan.get_time(row))+",\nIF"+str(scan.getif(row))+", "+poleval+", Beam"+str(scan.getbeam(row)) }
1155 '_r': "" }
1156 return userlabel or d[mode]
1157
1158 def plotazel(self, scan=None, outfile=None):
1159 """
1160 plot azimuth and elevation versus time of a scantable
1161 """
1162 visible = rcParams['plotter.gui']
1163 from matplotlib import pylab as PL
1164 from matplotlib.dates import DateFormatter, timezone
1165 from matplotlib.dates import HourLocator, MinuteLocator,SecondLocator, DayLocator
1166 from matplotlib.ticker import MultipleLocator
1167 from numpy import array, pi
1168 if not visible or not self._visible:
1169 PL.ioff()
1170 from matplotlib.backends.backend_agg import FigureCanvasAgg
1171 PL.gcf().canvas.switch_backends(FigureCanvasAgg)
1172 self._data = scan
1173 self._outfile = outfile
1174 dates = self._data.get_time(asdatetime=True)
1175 t = PL.date2num(dates)
1176 tz = timezone('UTC')
1177 PL.cla()
1178 PL.ioff()
1179 PL.clf()
1180 # Adjust subplot margins
1181 if len(self._margins) != 6:
1182 self.set_margin(refresh=False)
1183 lef, bot, rig, top, wsp, hsp = self._margins
1184 PL.gcf().subplots_adjust(left=lef,bottom=bot,right=rig,top=top,
1185 wspace=wsp,hspace=hsp)
1186
1187 tdel = max(t) - min(t)
1188 ax = PL.subplot(2,1,1)
1189 el = array(self._data.get_elevation())*180./pi
1190 PL.ylabel('El [deg.]')
1191 dstr = dates[0].strftime('%Y/%m/%d')
1192 if tdel > 1.0:
1193 dstr2 = dates[len(dates)-1].strftime('%Y/%m/%d')
1194 dstr = dstr + " - " + dstr2
1195 majloc = DayLocator()
1196 minloc = HourLocator(range(0,23,12))
1197 timefmt = DateFormatter("%b%d")
1198 elif tdel > 24./60.:
1199 timefmt = DateFormatter('%H:%M')
1200 majloc = HourLocator()
1201 minloc = MinuteLocator(30)
1202 else:
1203 timefmt = DateFormatter('%H:%M')
1204 majloc = MinuteLocator(interval=5)
1205 minloc = SecondLocator(30)
1206
1207 PL.title(dstr)
1208 if tdel == 0.0:
1209 th = (t - PL.floor(t))*24.0
1210 PL.plot(th,el,'o',markersize=2, markerfacecolor='b', markeredgecolor='b')
1211 else:
1212 PL.plot_date(t,el,'o', markersize=2, markerfacecolor='b', markeredgecolor='b',tz=tz)
1213 #ax.grid(True)
1214 ax.xaxis.set_major_formatter(timefmt)
1215 ax.xaxis.set_major_locator(majloc)
1216 ax.xaxis.set_minor_locator(minloc)
1217 ax.yaxis.grid(True)
1218 yloc = MultipleLocator(30)
1219 ax.set_ylim(0,90)
1220 ax.yaxis.set_major_locator(yloc)
1221 if tdel > 1.0:
1222 labels = ax.get_xticklabels()
1223 # PL.setp(labels, fontsize=10, rotation=45)
1224 PL.setp(labels, fontsize=10)
1225
1226 # Az plot
1227 az = array(self._data.get_azimuth())*180./pi
1228 if min(az) < 0:
1229 for irow in range(len(az)):
1230 if az[irow] < 0: az[irow] += 360.0
1231
1232 ax2 = PL.subplot(2,1,2)
1233 #PL.xlabel('Time (UT [hour])')
1234 PL.ylabel('Az [deg.]')
1235 if tdel == 0.0:
1236 PL.plot(th,az,'o',markersize=2, markeredgecolor='b',markerfacecolor='b')
1237 else:
1238 PL.plot_date(t,az,'o', markersize=2,markeredgecolor='b',markerfacecolor='b',tz=tz)
1239 ax2.xaxis.set_major_formatter(timefmt)
1240 ax2.xaxis.set_major_locator(majloc)
1241 ax2.xaxis.set_minor_locator(minloc)
1242 #ax2.grid(True)
1243 ax2.set_ylim(0,360)
1244 ax2.yaxis.grid(True)
1245 #hfmt = DateFormatter('%H')
1246 #hloc = HourLocator()
1247 yloc = MultipleLocator(60)
1248 ax2.yaxis.set_major_locator(yloc)
1249 if tdel > 1.0:
1250 labels = ax2.get_xticklabels()
1251 PL.setp(labels, fontsize=10)
1252 PL.xlabel('Time (UT [day])')
1253 else:
1254 PL.xlabel('Time (UT [hour])')
1255
1256 PL.ion()
1257 PL.draw()
1258 if matplotlib.get_backend() == 'Qt4Agg': PL.gcf().show()
1259 if (self._outfile is not None):
1260 PL.savefig(self._outfile)
1261
1262 def plotpointing(self, scan=None, outfile=None):
1263 """
1264 plot telescope pointings
1265 """
1266 visible = rcParams['plotter.gui']
1267 from matplotlib import pylab as PL
1268 from numpy import array, pi
1269 if not visible or not self._visible:
1270 PL.ioff()
1271 from matplotlib.backends.backend_agg import FigureCanvasAgg
1272 PL.gcf().canvas.switch_backends(FigureCanvasAgg)
1273 self._data = scan
1274 self._outfile = outfile
1275 dir = array(self._data.get_directionval()).transpose()
1276 ra = dir[0]*180./pi
1277 dec = dir[1]*180./pi
1278 PL.cla()
1279 #PL.ioff()
1280 PL.clf()
1281 # Adjust subplot margins
1282 if len(self._margins) != 6:
1283 self.set_margin(refresh=False)
1284 lef, bot, rig, top, wsp, hsp = self._margins
1285 PL.gcf().subplots_adjust(left=lef,bottom=bot,right=rig,top=top,
1286 wspace=wsp,hspace=hsp)
1287 ax = PL.gca()
1288 #ax = PL.axes([0.1,0.1,0.8,0.8])
1289 #ax = PL.axes([0.1,0.1,0.8,0.8])
1290 ax.set_aspect('equal')
1291 PL.plot(ra, dec, 'b,')
1292 PL.xlabel('RA [deg.]')
1293 PL.ylabel('Declination [deg.]')
1294 PL.title('Telescope pointings')
1295 [xmin,xmax,ymin,ymax] = PL.axis()
1296 PL.axis([xmax,xmin,ymin,ymax])
1297 PL.ion()
1298 PL.draw()
1299 if matplotlib.get_backend() == 'Qt4Agg': PL.gcf().show()
1300 if (self._outfile is not None):
1301 PL.savefig(self._outfile)
1302
1303 # plot total power data
1304 # plotting in time is not yet implemented..
1305 @asaplog_post_dec
1306 def plottp(self, scan=None, outfile=None):
1307 if self._plotter.is_dead:
1308 if self.casabar_exists():
1309 del self._plotter.figmgr.casabar
1310 self._plotter = self._newplotter()
1311 self._plotter.figmgr.casabar=self._new_custombar()
1312 self._plotter.hold()
1313 self._plotter.clear()
1314 from asap import scantable
1315 if not self._data and not scan:
1316 msg = "Input is not a scantable"
1317 raise TypeError(msg)
1318 if isinstance(scan, scantable):
1319 if self._data is not None:
1320 if scan != self._data:
1321 self._data = scan
1322 # reset
1323 self._reset()
1324 else:
1325 self._data = scan
1326 self._reset()
1327 # ranges become invalid when abcissa changes?
1328 #if self._abcunit and self._abcunit != self._data.get_unit():
1329 # self._minmaxx = None
1330 # self._minmaxy = None
1331 # self._abcunit = self._data.get_unit()
1332 # self._datamask = None
1333
1334 # Adjust subplot margins
1335 if len(self._margins) !=6: self.set_margin(refresh=False)
1336 lef, bot, rig, top, wsp, hsp = self._margins
1337 self._plotter.figure.subplots_adjust(
1338 left=lef,bottom=bot,right=rig,top=top,wspace=wsp,hspace=hsp)
1339 if self.casabar_exists(): self._plotter.figmgr.casabar.disable_button()
1340 self._plottp(self._data)
1341 if self._minmaxy is not None:
1342 self._plotter.set_limits(ylim=self._minmaxy)
1343 self._plotter.release()
1344 self._plotter.tidy()
1345 self._plotter.show(hardrefresh=False)
1346 return
1347
1348 def _plottp(self,scan):
1349 """
1350 private method for plotting total power data
1351 """
1352 from numpy import ma, array, arange, logical_not
1353 r=0
1354 nr = scan.nrow()
1355 a0,b0 = -1,-1
1356 allxlim = []
1357 allylim = []
1358 y=[]
1359 self._plotter.set_panels()
1360 self._plotter.palette(0)
1361 #title
1362 #xlab = self._abcissa and self._abcissa[panelcount] \
1363 # or scan._getabcissalabel()
1364 #ylab = self._ordinate and self._ordinate[panelcount] \
1365 # or scan._get_ordinate_label()
1366 xlab = self._abcissa or 'row number' #or Time
1367 ylab = self._ordinate or scan._get_ordinate_label()
1368 self._plotter.set_axes('xlabel',xlab)
1369 self._plotter.set_axes('ylabel',ylab)
1370 lbl = self._get_label(scan, r, 's', self._title)
1371 if isinstance(lbl, list) or isinstance(lbl, tuple):
1372 # if 0 <= panelcount < len(lbl):
1373 # lbl = lbl[panelcount]
1374 # else:
1375 # get default label
1376 lbl = self._get_label(scan, r, self._panelling, None)
1377 self._plotter.set_axes('title',lbl)
1378 y=array(scan._get_column(scan._getspectrum,-1))
1379 m = array(scan._get_column(scan._getmask,-1))
1380 y = ma.masked_array(y,mask=logical_not(array(m,copy=False)))
1381 x = arange(len(y))
1382 # try to handle spectral data somewhat...
1383 l,m = y.shape
1384 if m > 1:
1385 y=y.mean(axis=1)
1386 plotit = self._plotter.plot
1387 llbl = self._get_label(scan, r, self._stacking, None)
1388 self._plotter.set_line(label=llbl)
1389 if len(x) > 0:
1390 plotit(x,y)
1391
1392
1393 # forwards to matplotlib.Figure.text
1394 def figtext(self, *args, **kwargs):
1395 """
1396 Add text to figure at location x,y (relative 0-1 coords).
1397 This method forwards *args and **kwargs to a Matplotlib method,
1398 matplotlib.Figure.text.
1399 See the method help for detailed information.
1400 """
1401 self._plotter.text(*args, **kwargs)
1402 # end matplotlib.Figure.text forwarding function
1403
1404
1405 # printing header information
1406 @asaplog_post_dec
1407 def print_header(self, plot=True, fontsize=9, logger=False, selstr='', extrastr=''):
1408 """
1409 print data (scantable) header on the plot and/or logger.
1410 To plot the header on the plot, this method should be called after
1411 plotting spectra by the method, asapplotter.plot.
1412 Parameters:
1413 plot: whether or not print header info on the plot.
1414 fontsize: header font size (valid only plot=True)
1415 logger: whether or not print header info on the logger.
1416 selstr: additional selection string (not verified)
1417 extrastr: additional string to print at the beginning (not verified)
1418 """
1419 if not plot and not logger:
1420 return
1421 if not self._data:
1422 raise RuntimeError("No scantable has been set yet.")
1423 # Now header will be printed on plot and/or logger.
1424 # Get header information and format it.
1425 ssum=self._data._list_header()
1426 # Print Observation header to the upper-left corner of plot
1427 headstr=[ssum[0:ssum.find('Obs. Type:')]]
1428 headstr.append(ssum[ssum.find('Obs. Type:'):ssum.find('Flux Unit:')])
1429 if extrastr != '':
1430 headstr[0]=extrastr+'\n'+headstr[0]
1431 self._headtext['extrastr'] = extrastr
1432 if selstr != '':
1433 selstr += '\n'
1434 self._headtext['selstr'] = selstr
1435 ssel=(selstr+self._data.get_selection().__str__()+self._selection.__str__() or 'none')
1436 headstr.append('***Selections***\n'+ssel)
1437
1438 if plot:
1439 self._plotter.hold()
1440 self._header_plot(headstr,fontsize=fontsize)
1441 import time
1442 self._plotter.figure.text(0.99,0.01,
1443 time.strftime("%a %d %b %Y %H:%M:%S %Z"),
1444 horizontalalignment='right',
1445 verticalalignment='bottom',fontsize=8)
1446 self._plotter.release()
1447 if logger:
1448 selstr = "Selections: "+ssel
1449 asaplog.push("----------------\n Plot Summary\n----------------")
1450 asaplog.push(extrastr)
1451 asaplog.push(ssum[0:ssum.find('Selection:')]\
1452 + selstr)
1453 self._headtext['string'] = headstr
1454 del ssel, ssum, headstr
1455
1456 def _header_plot(self, texts, fontsize=9):
1457 self._headtext['textobj']=[]
1458 nstcol=len(texts)
1459 for i in range(nstcol):
1460 self._headtext['textobj'].append(
1461 self._plotter.figure.text(0.03+float(i)/nstcol,0.98,
1462 texts[i],
1463 horizontalalignment='left',
1464 verticalalignment='top',
1465 fontsize=fontsize))
1466
1467 def clear_header(self):
1468 if not self._headtext['textobj']:
1469 asaplog.push("No header has been plotted. Exit without any operation")
1470 asaplog.post("WARN")
1471 else:
1472 self._plotter.hold()
1473 for textobj in self._headtext['textobj']:
1474 #if textobj.get_text() in self._headstring:
1475 try:
1476 textobj.remove()
1477 except NotImplementedError:
1478 self._plotter.figure.texts.pop(self._plotter.figure.texts.index(textobj))
1479 self._plotter.release()
1480 self._reset_header()
Note: See TracBrowser for help on using the repository browser.