source: trunk/python/asapplotter.py@ 2484

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

New Development: No

JIRA Issue: Yes (CAS-3749/Trac-266)

Ready for Test: Yes

Interface Changes: Yes

What Interface Changed: renamed a parameter of asapplotter._assert_plotter from mode to action

Test Programs:

Put in Release Notes: No

Module(s):

Description: renamed a parameter of asapplotter._assert_plotter from mode to action


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