source: trunk/python/asapplotter.py@ 2355

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

New Development: Yes

JIRA Issue: Yes (CAS-3219/ASAP-247)

Ready for Test: Yes

Interface Changes: No

What Interface Changed:

Test Programs: sdlist unit test (reference data to be updated)

Put in Release Notes: Yes

Module(s): scantable.summary, sdlist

Description:

Output format of scantable summary changed.
Less use of TableIterator for speed up scantable.summary/sdlist now lists a scantable
with 348,000 records (NRO 45m w/ 25beams x 13,920scans) in ~30sec (was ~7 min previously).


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