source: trunk/python/asapplotter.py@ 2154

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

New Development: No

JIRA Issue: No (a fix)

Ready for Test: Yes

Interface Changes: added a new method new_asaplot() to module asapplotter which returns asaplot instance based on your backend selection.

What Interface Changed:

Test Programs: sdaverage, sdsmooth with verify=True and plotlevel > 0

Put in Release Notes: No

Module(s):

Description: proper handling of plotting in non-TkAgg backend.


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