source: branches/casa-prerelease/pre-asap/python/asapplotter.py@ 2061

Last change on this file since 2061 was 2057, checked in by Kana Sugimoto, 14 years ago

merged a bug fix in trunk (r2056)

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