source: trunk/python/asapplotter.py@ 2052

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

New Development: No

JIRA Issue: Yes (CAS-2764, ATNF-238)

Ready for Test: Yes

Interface Changes: No

What Interface Changed:

Test Programs: interactive test is necessary.

plot single dish spectra by sdplot + header=True or asapplotter.plot+asapplotter.print_header, and move between pages.
Check if you see header strings plotted in the same size and position in every page.

Put in Release Notes: No

Module(s): asapplotter, sdplot

Description: fixed a bug in asapplotter. asapplotter now prints header strings in every page.


  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 57.9 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 = []
[2051]57 self._headstring = None
58 self._headsize = None
[1023]59
[920]60 def _translate(self, instr):
[1910]61 keys = "s b i p t r".split()
[920]62 if isinstance(instr, str):
63 for key in keys:
64 if instr.lower().startswith(key):
65 return key
66 return None
67
[1563]68 def _newplotter(self, **kwargs):
[1819]69 backend=matplotlib.get_backend()
70 if not self._visible:
71 from asap.asaplot import asaplot
72 elif backend == 'TkAgg':
[710]73 from asap.asaplotgui import asaplotgui as asaplot
[1819]74 elif backend == 'Qt4Agg':
75 from asap.asaplotgui_qt4 import asaplotgui as asaplot
76 elif backend == 'GTkAgg':
77 from asap.asaplotgui_gtk import asaplotgui as asaplot
[710]78 else:
79 from asap.asaplot import asaplot
[1563]80 return asaplot(**kwargs)
[710]81
[1819]82 def _newcasabar(self):
83 backend=matplotlib.get_backend()
84 if self._visible and backend == "TkAgg":
85 from asap.casatoolbar import CustomToolbarTkAgg
86 return CustomToolbarTkAgg(self)
[1989]87 #from asap.casatoolbar import CustomFlagToolbarTkAgg
88 #return CustomFlagToolbarTkAgg(self)
[1995]89 return None
[1819]90
[1862]91 @asaplog_post_dec
[935]92 def plot(self, scan=None):
[203]93 """
[920]94 Plot a scantable.
[203]95 Parameters:
[920]96 scan: a scantable
[203]97 Note:
[920]98 If a scantable was specified in a previous call
[203]99 to plot, no argument has to be given to 'replot'
[920]100 NO checking is done that the abcissas of the scantable
[203]101 are consistent e.g. all 'channel' or all 'velocity' etc.
102 """
[1981]103 self._startrow = 0
104 self._ipanel = -1
[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)
[2051]846 self._reset_header()
[920]847
[2051]848 def _reset_header(self):
849 self._headsize = None
850 self._headstring = None
851
[920]852 def _plot(self, scan):
[947]853 savesel = scan.get_selection()
854 sel = savesel + self._selection
[1910]855 order = self._get_sortstring([self._panelling,self._stacking])
856 if order:
857 sel.set_order(order)
[947]858 scan.set_selection(sel)
[920]859 d = {'b': scan.getbeam, 's': scan.getscan,
[1949]860 'i': scan.getif, 'p': scan.getpol, 't': scan.get_time,
[1989]861 'r': int}#, '_r': int}
[920]862
[1148]863 polmodes = dict(zip(self._selection.get_pols(),
864 self._selection.get_poltypes()))
865 # this returns either a tuple of numbers or a length (ncycles)
866 # convert this into lengths
867 n0,nstack0 = self._get_selected_n(scan)
868 if isinstance(n0, int): n = n0
[1175]869 else: n = len(n0)
[1148]870 if isinstance(nstack0, int): nstack = nstack0
[1175]871 else: nstack = len(nstack0)
[1989]872 # In case of row stacking
873 rowstack = False
874 titlemode = self._panelling
875 if self._stacking == "r" and self._panelling != "r":
876 rowstack = True
877 titlemode = '_r'
[1913]878 nptot = n
[1582]879 maxpanel, maxstack = 16,16
[1913]880 if nstack > maxstack:
881 msg ="Scan to be overlayed contains more than %d selections.\n" \
882 "Selecting first %d selections..." % (maxstack, maxstack)
[920]883 asaplog.push(msg)
[1861]884 asaplog.post('WARN')
[998]885 nstack = min(nstack,maxstack)
[2038]886 #n = min(n-self._ipanel-1,maxpanel)
887 n = n-self._ipanel-1
[2011]888
889 ganged = False
[920]890 if n > 1:
891 ganged = rcParams['plotter.ganged']
[1819]892 if self._panelling == 'i':
893 ganged = False
[920]894 if self._rows and self._cols:
895 n = min(n,self._rows*self._cols)
896 self._plotter.set_panels(rows=self._rows,cols=self._cols,
[2037]897 nplots=n,margin=self._margins,ganged=ganged)
[920]898 else:
[2038]899 n = min(n,maxpanel)
[2037]900 self._plotter.set_panels(rows=n,cols=0,nplots=n,margin=self._margins,ganged=ganged)
[920]901 else:
[2037]902 self._plotter.set_panels(margin=self._margins)
[1913]903 #r = 0
[1981]904 r = self._startrow
[920]905 nr = scan.nrow()
906 a0,b0 = -1,-1
907 allxlim = []
[1018]908 allylim = []
[1981]909 #newpanel=True
910 newpanel=False
[920]911 panelcount,stackcount = 0,0
[1981]912 # If this is not the first page
913 if r > 0:
914 # panelling value of the prev page
915 a0 = d[self._panelling](r-1)
916 # set the initial stackcount large not to plot
917 # the start row automatically
918 stackcount = nstack
919
[1002]920 while r < nr:
[920]921 a = d[self._panelling](r)
922 b = d[self._stacking](r)
923 if a > a0 and panelcount < n:
924 if n > 1:
925 self._plotter.subplot(panelcount)
926 self._plotter.palette(0)
927 #title
928 xlab = self._abcissa and self._abcissa[panelcount] \
929 or scan._getabcissalabel()
[1897]930 if self._offset and not self._abcissa:
931 xlab += " (relative)"
[920]932 ylab = self._ordinate and self._ordinate[panelcount] \
933 or scan._get_ordinate_label()
[1547]934 self._plotter.set_axes('xlabel', xlab)
935 self._plotter.set_axes('ylabel', ylab)
[1989]936 #lbl = self._get_label(scan, r, self._panelling, self._title)
937 lbl = self._get_label(scan, r, titlemode, self._title)
[920]938 if isinstance(lbl, list) or isinstance(lbl, tuple):
939 if 0 <= panelcount < len(lbl):
940 lbl = lbl[panelcount]
941 else:
942 # get default label
[1989]943 #lbl = self._get_label(scan, r, self._panelling, None)
944 lbl = self._get_label(scan, r, titlemode, None)
[920]945 self._plotter.set_axes('title',lbl)
946 newpanel = True
[1913]947 stackcount = 0
[920]948 panelcount += 1
[1981]949 # save the start row to plot this panel for future revisit.
950 if self._panelling != 'r' and \
951 len(self._panelrows) < self._ipanel+1+panelcount:
952 self._panelrows += [r]
953
[1944]954 #if (b > b0 or newpanel) and stackcount < nstack:
[1989]955 if stackcount < nstack and (newpanel or rowstack or (a == a0 and b > b0)):
[920]956 y = []
957 if len(polmodes):
958 y = scan._getspectrum(r, polmodes[scan.getpol(r)])
959 else:
960 y = scan._getspectrum(r)
[1995]961 # flag application
962 mr = scan._getflagrow(r)
[1739]963 from numpy import ma, array
[1995]964 if mr:
965 y = ma.masked_array(y,mask=mr)
966 else:
967 m = scan._getmask(r)
968 from numpy import logical_not, logical_and
969 if self._maskselection and len(self._usermask) == len(m):
970 if d[self._stacking](r) in self._maskselection[self._stacking]:
971 m = logical_and(m, self._usermask)
972 y = ma.masked_array(y,mask=logical_not(array(m,copy=False)))
973
[1897]974 x = array(scan._getabcissa(r))
975 if self._offset:
976 x += self._offset
[920]977 if self._minmaxx is not None:
978 s,e = self._slice_indeces(x)
979 x = x[s:e]
980 y = y[s:e]
[1096]981 if len(x) > 1024 and rcParams['plotter.decimate']:
982 fac = len(x)/1024
[920]983 x = x[::fac]
984 y = y[::fac]
985 llbl = self._get_label(scan, r, self._stacking, self._lmap)
986 if isinstance(llbl, list) or isinstance(llbl, tuple):
987 if 0 <= stackcount < len(llbl):
988 # use user label
989 llbl = llbl[stackcount]
990 else:
991 # get default label
992 llbl = self._get_label(scan, r, self._stacking, None)
993 self._plotter.set_line(label=llbl)
[1023]994 plotit = self._plotter.plot
995 if self._hist: plotit = self._plotter.hist
[1995]996 if len(x) > 0 and not mr:
[1146]997 plotit(x,y)
998 xlim= self._minmaxx or [min(x),max(x)]
999 allxlim += xlim
1000 ylim= self._minmaxy or [ma.minimum(y),ma.maximum(y)]
1001 allylim += ylim
[1819]1002 else:
1003 xlim = self._minmaxx or []
1004 allxlim += xlim
1005 ylim= self._minmaxy or []
1006 allylim += ylim
[920]1007 stackcount += 1
[1981]1008 a0=a
1009 b0=b
[920]1010 # last in colour stack -> autoscale x
[1819]1011 if stackcount == nstack and len(allxlim) > 0:
[920]1012 allxlim.sort()
[1819]1013 self._plotter.subplots[panelcount-1]['axes'].set_xlim([allxlim[0],allxlim[-1]])
[1989]1014 if ganged:
1015 allxlim = [allxlim[0],allxlim[-1]]
1016 else:
1017 # clear
1018 allxlim =[]
[920]1019
1020 newpanel = False
[1981]1021 #a0=a
1022 #b0=b
[920]1023 # ignore following rows
[1981]1024 if (panelcount == n and stackcount == nstack) or (r == nr-1):
[1018]1025 # last panel -> autoscale y if ganged
[1989]1026 #if rcParams['plotter.ganged'] and len(allylim) > 0:
1027 if ganged and len(allylim) > 0:
[1018]1028 allylim.sort()
1029 self._plotter.set_limits(ylim=[allylim[0],allylim[-1]])
[998]1030 break
[920]1031 r+=1 # next row
[1981]1032
1033 # save the current counter for multi-page plotting
1034 self._startrow = r+1
1035 self._ipanel += panelcount
[1913]1036 if self._plotter.figmgr.casabar:
[1981]1037 if self._ipanel >= nptot-1:
[1913]1038 self._plotter.figmgr.casabar.disable_next()
1039 else:
1040 self._plotter.figmgr.casabar.enable_next()
[1981]1041 if self._ipanel + 1 - panelcount > 0:
1042 self._plotter.figmgr.casabar.enable_prev()
1043 else:
1044 self._plotter.figmgr.casabar.disable_prev()
1045
[947]1046 #reset the selector to the scantable's original
1047 scan.set_selection(savesel)
[1824]1048
[1819]1049 #temporary switch-off for older matplotlib
1050 #if self._fp is not None:
1051 if self._fp is not None and getattr(self._plotter.figure,'findobj',False):
[1556]1052 for o in self._plotter.figure.findobj(Text):
1053 o.set_fontproperties(self._fp)
[920]1054
[1910]1055 def _get_sortstring(self, lorders):
1056 d0 = {'s': 'SCANNO', 'b': 'BEAMNO', 'i':'IFNO',
1057 'p': 'POLNO', 'c': 'CYCLENO', 't' : 'TIME', 'r':None, '_r':None }
[1944]1058 if not (type(lorders) == list) and not (type(lorders) == tuple):
[1910]1059 return None
1060 if len(lorders) > 0:
1061 lsorts = []
1062 for order in lorders:
[1989]1063 if order == "r":
1064 # don't sort if row panelling/stacking
1065 return None
[1910]1066 ssort = d0[order]
1067 if ssort:
1068 lsorts.append(ssort)
1069 return lsorts
1070 return None
1071
[1582]1072 def set_selection(self, selection=None, refresh=True, **kw):
[1819]1073 """
1074 Parameters:
1075 selection: a selector object (default unset the selection)
1076 refresh: True (default) or False. If True, the plot is
[1824]1077 replotted based on the new parameter setting(s).
[1819]1078 Otherwise,the parameter(s) are set without replotting.
1079 """
[1582]1080 if selection is None:
1081 # reset
1082 if len(kw) == 0:
1083 self._selection = selector()
1084 else:
1085 # try keywords
1086 for k in kw:
1087 if k not in selector.fields:
1088 raise KeyError("Invalid selection key '%s', valid keys are %s" % (k, selector.fields))
1089 self._selection = selector(**kw)
1090 elif isinstance(selection, selector):
1091 self._selection = selection
1092 else:
1093 raise TypeError("'selection' is not of type selector")
1094
[1910]1095 order = self._get_sortstring([self._panelling,self._stacking])
1096 if order:
1097 self._selection.set_order(order)
[1819]1098 if refresh and self._data: self.plot(self._data)
[920]1099
1100 def _get_selected_n(self, scan):
[1148]1101 d1 = {'b': scan.getbeamnos, 's': scan.getscannos,
[1910]1102 'i': scan.getifnos, 'p': scan.getpolnos, 't': scan.ncycle,
[1989]1103 'r': scan.nrow}#, '_r': False}
[1148]1104 d2 = { 'b': self._selection.get_beams(),
1105 's': self._selection.get_scans(),
1106 'i': self._selection.get_ifs(),
1107 'p': self._selection.get_pols(),
[1910]1108 't': self._selection.get_cycles(),
[1989]1109 'r': False}#, '_r': 1}
[920]1110 n = d2[self._panelling] or d1[self._panelling]()
1111 nstack = d2[self._stacking] or d1[self._stacking]()
[1989]1112 # handle row panelling/stacking
1113 if self._panelling == 'r':
1114 nstack = 1
1115 elif self._stacking == 'r':
1116 n = 1
[920]1117 return n,nstack
1118
1119 def _get_label(self, scan, row, mode, userlabel=None):
[1153]1120 if isinstance(userlabel, list) and len(userlabel) == 0:
1121 userlabel = " "
[947]1122 pms = dict(zip(self._selection.get_pols(),self._selection.get_poltypes()))
[920]1123 if len(pms):
1124 poleval = scan._getpollabel(scan.getpol(row),pms[scan.getpol(row)])
1125 else:
1126 poleval = scan._getpollabel(scan.getpol(row),scan.poltype())
1127 d = {'b': "Beam "+str(scan.getbeam(row)),
[1819]1128 #'s': scan._getsourcename(row),
1129 's': "Scan "+str(scan.getscan(row))+\
1130 " ("+str(scan._getsourcename(row))+")",
[920]1131 'i': "IF"+str(scan.getif(row)),
[964]1132 'p': poleval,
[1910]1133 't': str(scan.get_time(row)),
1134 'r': "row "+str(row),
[1913]1135 #'_r': str(scan.get_time(row))+",\nIF"+str(scan.getif(row))+", "+poleval+", Beam"+str(scan.getbeam(row)) }
1136 '_r': "" }
[920]1137 return userlabel or d[mode]
[1153]1138
[1819]1139 def plotazel(self, scan=None, outfile=None):
[1391]1140 """
[1696]1141 plot azimuth and elevation versus time of a scantable
[1391]1142 """
[1923]1143 visible = rcParams['plotter.gui']
[1696]1144 from matplotlib import pylab as PL
1145 from matplotlib.dates import DateFormatter, timezone
1146 from matplotlib.dates import HourLocator, MinuteLocator,SecondLocator, DayLocator
[1391]1147 from matplotlib.ticker import MultipleLocator
[1739]1148 from numpy import array, pi
[1923]1149 if not visible or not self._visible:
1150 PL.ioff()
1151 from matplotlib.backends.backend_agg import FigureCanvasAgg
1152 PL.gcf().canvas.switch_backends(FigureCanvasAgg)
[1819]1153 self._data = scan
1154 self._outfile = outfile
[1556]1155 dates = self._data.get_time(asdatetime=True)
[1391]1156 t = PL.date2num(dates)
1157 tz = timezone('UTC')
1158 PL.cla()
1159 PL.ioff()
1160 PL.clf()
[2037]1161 # Adjust subplot margins
1162 if len(self._margins) != 6:
1163 self.set_margin(refresh=False)
1164 lef, bot, rig, top, wsp, hsp = self._margins
[1819]1165 PL.gcf().subplots_adjust(left=lef,bottom=bot,right=rig,top=top,
1166 wspace=wsp,hspace=hsp)
[1824]1167
[1391]1168 tdel = max(t) - min(t)
1169 ax = PL.subplot(2,1,1)
1170 el = array(self._data.get_elevation())*180./pi
1171 PL.ylabel('El [deg.]')
1172 dstr = dates[0].strftime('%Y/%m/%d')
1173 if tdel > 1.0:
1174 dstr2 = dates[len(dates)-1].strftime('%Y/%m/%d')
1175 dstr = dstr + " - " + dstr2
1176 majloc = DayLocator()
1177 minloc = HourLocator(range(0,23,12))
1178 timefmt = DateFormatter("%b%d")
[1696]1179 elif tdel > 24./60.:
1180 timefmt = DateFormatter('%H:%M')
1181 majloc = HourLocator()
1182 minloc = MinuteLocator(30)
[1391]1183 else:
[1696]1184 timefmt = DateFormatter('%H:%M')
1185 majloc = MinuteLocator(interval=5)
1186 minloc = SecondLocator(30)
1187
[1391]1188 PL.title(dstr)
[1819]1189 if tdel == 0.0:
1190 th = (t - PL.floor(t))*24.0
1191 PL.plot(th,el,'o',markersize=2, markerfacecolor='b', markeredgecolor='b')
1192 else:
1193 PL.plot_date(t,el,'o', markersize=2, markerfacecolor='b', markeredgecolor='b',tz=tz)
1194 #ax.grid(True)
1195 ax.xaxis.set_major_formatter(timefmt)
1196 ax.xaxis.set_major_locator(majloc)
1197 ax.xaxis.set_minor_locator(minloc)
[1391]1198 ax.yaxis.grid(True)
[1819]1199 yloc = MultipleLocator(30)
1200 ax.set_ylim(0,90)
1201 ax.yaxis.set_major_locator(yloc)
[1391]1202 if tdel > 1.0:
1203 labels = ax.get_xticklabels()
1204 # PL.setp(labels, fontsize=10, rotation=45)
1205 PL.setp(labels, fontsize=10)
[1819]1206
[1391]1207 # Az plot
1208 az = array(self._data.get_azimuth())*180./pi
1209 if min(az) < 0:
1210 for irow in range(len(az)):
1211 if az[irow] < 0: az[irow] += 360.0
1212
[1819]1213 ax2 = PL.subplot(2,1,2)
1214 #PL.xlabel('Time (UT [hour])')
1215 PL.ylabel('Az [deg.]')
1216 if tdel == 0.0:
1217 PL.plot(th,az,'o',markersize=2, markeredgecolor='b',markerfacecolor='b')
1218 else:
1219 PL.plot_date(t,az,'o', markersize=2,markeredgecolor='b',markerfacecolor='b',tz=tz)
1220 ax2.xaxis.set_major_formatter(timefmt)
1221 ax2.xaxis.set_major_locator(majloc)
1222 ax2.xaxis.set_minor_locator(minloc)
1223 #ax2.grid(True)
1224 ax2.set_ylim(0,360)
[1696]1225 ax2.yaxis.grid(True)
[1819]1226 #hfmt = DateFormatter('%H')
1227 #hloc = HourLocator()
1228 yloc = MultipleLocator(60)
1229 ax2.yaxis.set_major_locator(yloc)
1230 if tdel > 1.0:
1231 labels = ax2.get_xticklabels()
1232 PL.setp(labels, fontsize=10)
1233 PL.xlabel('Time (UT [day])')
1234 else:
1235 PL.xlabel('Time (UT [hour])')
1236
[1391]1237 PL.ion()
1238 PL.draw()
[1819]1239 if (self._outfile is not None):
1240 PL.savefig(self._outfile)
[1391]1241
[1819]1242 def plotpointing(self, scan=None, outfile=None):
[1391]1243 """
1244 plot telescope pointings
1245 """
[1923]1246 visible = rcParams['plotter.gui']
[1696]1247 from matplotlib import pylab as PL
[1819]1248 from numpy import array, pi
[1923]1249 if not visible or not self._visible:
1250 PL.ioff()
1251 from matplotlib.backends.backend_agg import FigureCanvasAgg
1252 PL.gcf().canvas.switch_backends(FigureCanvasAgg)
[1819]1253 self._data = scan
1254 self._outfile = outfile
[1391]1255 dir = array(self._data.get_directionval()).transpose()
1256 ra = dir[0]*180./pi
1257 dec = dir[1]*180./pi
1258 PL.cla()
[1819]1259 #PL.ioff()
[1391]1260 PL.clf()
[2037]1261 # Adjust subplot margins
1262 if len(self._margins) != 6:
1263 self.set_margin(refresh=False)
1264 lef, bot, rig, top, wsp, hsp = self._margins
[1819]1265 PL.gcf().subplots_adjust(left=lef,bottom=bot,right=rig,top=top,
1266 wspace=wsp,hspace=hsp)
1267 ax = PL.gca()
1268 #ax = PL.axes([0.1,0.1,0.8,0.8])
1269 #ax = PL.axes([0.1,0.1,0.8,0.8])
[1391]1270 ax.set_aspect('equal')
[1696]1271 PL.plot(ra, dec, 'b,')
[1391]1272 PL.xlabel('RA [deg.]')
1273 PL.ylabel('Declination [deg.]')
1274 PL.title('Telescope pointings')
1275 [xmin,xmax,ymin,ymax] = PL.axis()
1276 PL.axis([xmax,xmin,ymin,ymax])
[1819]1277 #PL.ion()
[1391]1278 PL.draw()
[1819]1279 if (self._outfile is not None):
1280 PL.savefig(self._outfile)
1281
1282 # plot total power data
1283 # plotting in time is not yet implemented..
[1862]1284 @asaplog_post_dec
[1819]1285 def plottp(self, scan=None, outfile=None):
1286 if self._plotter.is_dead:
1287 if hasattr(self._plotter.figmgr,'casabar'):
1288 del self._plotter.figmgr.casabar
1289 self._plotter = self._newplotter()
1290 self._plotter.figmgr.casabar=self._newcasabar()
1291 self._plotter.hold()
1292 self._plotter.clear()
1293 from asap import scantable
1294 if not self._data and not scan:
1295 msg = "Input is not a scantable"
1296 raise TypeError(msg)
1297 if isinstance(scan, scantable):
1298 if self._data is not None:
1299 if scan != self._data:
1300 self._data = scan
1301 # reset
1302 self._reset()
1303 else:
1304 self._data = scan
1305 self._reset()
1306 # ranges become invalid when abcissa changes?
1307 #if self._abcunit and self._abcunit != self._data.get_unit():
1308 # self._minmaxx = None
1309 # self._minmaxy = None
1310 # self._abcunit = self._data.get_unit()
1311 # self._datamask = None
1312
[2037]1313 # Adjust subplot margins
1314 if len(self._margins) !=6: self.set_margin(refresh=False)
1315 lef, bot, rig, top, wsp, hsp = self._margins
[1819]1316 self._plotter.figure.subplots_adjust(
1317 left=lef,bottom=bot,right=rig,top=top,wspace=wsp,hspace=hsp)
1318 if self._plotter.figmgr.casabar: self._plotter.figmgr.casabar.disable_button()
1319 self._plottp(self._data)
1320 if self._minmaxy is not None:
1321 self._plotter.set_limits(ylim=self._minmaxy)
1322 self._plotter.release()
1323 self._plotter.tidy()
1324 self._plotter.show(hardrefresh=False)
1325 return
1326
1327 def _plottp(self,scan):
1328 """
1329 private method for plotting total power data
1330 """
1331 from numpy import ma, array, arange, logical_not
1332 r=0
1333 nr = scan.nrow()
1334 a0,b0 = -1,-1
1335 allxlim = []
1336 allylim = []
1337 y=[]
1338 self._plotter.set_panels()
1339 self._plotter.palette(0)
1340 #title
1341 #xlab = self._abcissa and self._abcissa[panelcount] \
1342 # or scan._getabcissalabel()
1343 #ylab = self._ordinate and self._ordinate[panelcount] \
1344 # or scan._get_ordinate_label()
1345 xlab = self._abcissa or 'row number' #or Time
1346 ylab = self._ordinate or scan._get_ordinate_label()
1347 self._plotter.set_axes('xlabel',xlab)
1348 self._plotter.set_axes('ylabel',ylab)
1349 lbl = self._get_label(scan, r, 's', self._title)
1350 if isinstance(lbl, list) or isinstance(lbl, tuple):
1351 # if 0 <= panelcount < len(lbl):
1352 # lbl = lbl[panelcount]
1353 # else:
1354 # get default label
1355 lbl = self._get_label(scan, r, self._panelling, None)
1356 self._plotter.set_axes('title',lbl)
1357 y=array(scan._get_column(scan._getspectrum,-1))
1358 m = array(scan._get_column(scan._getmask,-1))
1359 y = ma.masked_array(y,mask=logical_not(array(m,copy=False)))
1360 x = arange(len(y))
1361 # try to handle spectral data somewhat...
1362 l,m = y.shape
1363 if m > 1:
1364 y=y.mean(axis=1)
1365 plotit = self._plotter.plot
1366 llbl = self._get_label(scan, r, self._stacking, None)
1367 self._plotter.set_line(label=llbl)
1368 if len(x) > 0:
1369 plotit(x,y)
1370
1371
1372 # forwards to matplotlib.Figure.text
1373 def figtext(self, *args, **kwargs):
1374 """
1375 Add text to figure at location x,y (relative 0-1 coords).
1376 This method forwards *args and **kwargs to a Matplotlib method,
1377 matplotlib.Figure.text.
1378 See the method help for detailed information.
1379 """
1380 self._plotter.text(*args, **kwargs)
1381 # end matplotlib.Figure.text forwarding function
1382
1383
1384 # printing header information
[1862]1385 @asaplog_post_dec
[2051]1386 def print_header(self, plot=True, fontsize=None, logger=False, selstr='', extrastr=''):
[1819]1387 """
1388 print data (scantable) header on the plot and/or logger.
1389 Parameters:
[1824]1390 plot: whether or not print header info on the plot.
[2051]1391 fontsize: header font size (valid only plot=True) default: 9
[1819]1392 logger: whether or not print header info on the logger.
1393 selstr: additional selection string (not verified)
1394 extrastr: additional string to print (not verified)
1395 """
[1859]1396 if not plot and not logger:
1397 return
1398 if not self._data:
1399 raise RuntimeError("No scantable has been set yet.")
[1824]1400 # Now header will be printed on plot and/or logger.
1401 # Get header information and format it.
[1819]1402 ssum=self._data.__str__()
1403 # Print Observation header to the upper-left corner of plot
[2051]1404 if self._headstring:
1405 headstr = self._headstring
1406 if extrastr != '': headstr[0]=extrastr+'\n'+headstr[0]
1407 if selstr != '': headstr[2] += selstr
1408 fontsize = fontsize or self._headsize
1409 else:
[1819]1410 headstr=[ssum[ssum.find('Observer:'):ssum.find('Flux Unit:')]]
1411 headstr.append(ssum[ssum.find('Beams:'):ssum.find('Observer:')]
[2051]1412 +ssum[ssum.find('Rest Freqs:'):ssum.find('Abcissa:')])
[1819]1413 if extrastr != '': headstr[0]=extrastr+'\n'+headstr[0]
1414 ssel='***Selections***\n'+(selstr+self._data.get_selection().__str__() or 'none')
1415 headstr.append(ssel)
[2051]1416 del ssel
1417 fontsize = fontsize or 9
1418 self._headsize = fontsize
1419 self._headstring = headstr
[1824]1420
[2051]1421 if plot:
[1819]1422 self._plotter.hold()
[2051]1423 nstcol=len(headstr)
[1819]1424 for i in range(nstcol):
1425 self._plotter.figure.text(0.03+float(i)/nstcol,0.98,
1426 headstr[i],
1427 horizontalalignment='left',
1428 verticalalignment='top',
1429 fontsize=fontsize)
1430 import time
1431 self._plotter.figure.text(0.99,0.0,
1432 time.strftime("%a %d %b %Y %H:%M:%S %Z"),
1433 horizontalalignment='right',
1434 verticalalignment='bottom',fontsize=8)
1435 self._plotter.release()
1436 if logger:
[2051]1437 sextra = headstr[0][0:headstr[0].find('Observer:')].rstrip('\n')
1438 selstr = "Selections: "+(headstr[2].lstrip('***Selections***\n') or 'none')+"\n \n"
1439
[1819]1440 asaplog.push("----------------\n Plot Summary\n----------------")
[2051]1441 asaplog.push(sextra)
1442 asaplog.push(ssum[ssum.find('Beams:'):ssum.find('Selection:')]\
1443 + selstr + ssum[ssum.find('Scan Source'):])
1444 del ssum, headstr
1445
1446# def clear_header(self):
1447# if not self._headstring or len(self._plotter.figure.texts) == 0:
1448# asaplog.push("No header has been plotted. Exit without any operation")
1449# asaplog.post("WARN")
1450# else:
1451# self._plotter.hold()
1452# for textobj in self._plotter.figure.texts:
1453# if textobj.get_text() in self._headstring:
1454# try:
1455# textobj.remove()
1456# except NotImplementedError:
1457# self._plotter.figure.texts.pop(self._plotter.figure.texts.index(textobj))
1458# self._plotter.release()
1459# self._reset_header()
Note: See TracBrowser for help on using the repository browser.