source: trunk/python/asapplotter.py@ 2452

Last change on this file since 2452 was 2452, 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:

Put in Release Notes: No

Module(s): asapplotter

Description: A bug fix in asapplotter._reload_plotter()


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