source: trunk/python/asapplotter.py@ 3044

Last change on this file since 3044 was 3038, checked in by Kana Sugimoto, 9 years ago

New Development: No

JIRA Issue: No (a bug fix)

Ready for Test: Yes

Interface Changes: Yes

What Interface Changed: added axlim parameter (optional) to asapplotter._get_date_axis_setup.

Test Programs: runUnitTest.main(test_sdplot[test_totalpowerCflag])

Put in Release Notes: No

Module(s): asapplotter, sdplot

Description: Fixed a bug in tick interval for > 1year


  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 86.0 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
[2535]8from matplotlib import _pylab_helpers
[1556]9
[1317]10import re
[203]11
[2150]12def new_asaplot(visible=None,**kwargs):
13 """
14 Returns a new asaplot instance based on the backend settings.
15 """
16 if visible == None:
17 visible = rcParams['plotter.gui']
18
19 backend=matplotlib.get_backend()
20 if not visible:
21 from asap.asaplot import asaplot
22 elif backend == 'TkAgg':
23 from asap.asaplotgui import asaplotgui as asaplot
24 elif backend == 'Qt4Agg':
25 from asap.asaplotgui_qt4 import asaplotgui as asaplot
26 elif backend == 'GTkAgg':
27 from asap.asaplotgui_gtk import asaplotgui as asaplot
28 else:
29 from asap.asaplot import asaplot
30 return asaplot(**kwargs)
31
[203]32class asapplotter:
[226]33 """
34 The ASAP plotter.
35 By default the plotter is set up to plot polarisations
36 'colour stacked' and scantables across panels.
[1858]37
38 .. note::
39
[226]40 Currenly it only plots 'spectra' not Tsys or
41 other variables.
[1858]42
[226]43 """
[1563]44 def __init__(self, visible=None , **kwargs):
[734]45 self._visible = rcParams['plotter.gui']
46 if visible is not None:
47 self._visible = visible
[2451]48 self._plotter = None
49 self._inikwg = kwargs
[710]50
[2699]51 ### plot settings
[2698]52 self._colormap = None
53 self._linestyles = None
54 self._fp = FontProperties()
55 self._rows = None
56 self._cols = None
57 self._minmaxx = None
58 self._minmaxy = None
59 self._margins = self.set_margin(refresh=False)
60 self._legendloc = None
[2699]61 ### scantable plot settings
[2704]62 self._plotmode = "spectra"
[554]63 self._panelling = None
64 self._stacking = None
65 self.set_panelling()
66 self.set_stacking()
[2698]67 self._hist = rcParams['plotter.histogram']
[2699]68 ### scantable dependent settings
[203]69 self._data = None
[2698]70 self._abcunit = None
71 self._headtext = {'string': None, 'textobj': None}
72 self._selection = selector()
73 self._usermask = []
74 self._maskselection = None
75 self._offset = None
[607]76 self._lmap = None
[226]77 self._title = None
[257]78 self._ordinate = None
79 self._abcissa = None
[2699]80 ### cursors for page iteration
[1981]81 self._startrow = 0
82 self._ipanel = -1
83 self._panelrows = []
[1023]84
[920]85 def _translate(self, instr):
[1910]86 keys = "s b i p t r".split()
[920]87 if isinstance(instr, str):
88 for key in keys:
89 if instr.lower().startswith(key):
90 return key
91 return None
92
[2535]93 @asaplog_post_dec
[2451]94 def _reload_plotter(self):
95 if self._plotter is not None:
[2535]96 #if not self._plotter.is_dead:
97 # # clear lines and axes
98 # try:
99 # self._plotter.clear()
100 # except: # Can't remove when already killed.
101 # pass
[2451]102 if self.casabar_exists():
103 del self._plotter.figmgr.casabar
104 self._plotter.quit()
105 del self._plotter
[2535]106 asaplog.push('Loading new plotter')
[2451]107 self._plotter = new_asaplot(self._visible,**self._inikwg)
108 self._plotter.figmgr.casabar=self._new_custombar()
109 # just to make sure they're set
110 self._plotter.palette(color=0,colormap=self._colormap,
111 linestyle=0,linestyles=self._linestyles)
112 self._plotter.legend(self._legendloc)
[710]113
[2714]114 ### TODO: it's probably better to define following two methods in
115 ### backend dependent class.
[2173]116 def _new_custombar(self):
[1819]117 backend=matplotlib.get_backend()
[2168]118 if not self._visible:
119 return None
120 elif backend == "TkAgg":
[2155]121 from asap.customgui_tkagg import CustomToolbarTkAgg
[1819]122 return CustomToolbarTkAgg(self)
[2168]123 elif backend == "Qt4Agg":
124 from asap.customgui_qt4agg import CustomToolbarQT4Agg
125 return CustomToolbarQT4Agg(self)
[1995]126 return None
[1819]127
[2147]128 def casabar_exists(self):
129 if not hasattr(self._plotter.figmgr,'casabar'):
130 return False
131 elif self._plotter.figmgr.casabar:
132 return True
133 return False
[2714]134 ### end of TODO
[2147]135
[2453]136 def _assert_plotter(self,action="status",errmsg=None):
[2451]137 """
[2453]138 Check plot window status. Returns True if plot window is alive.
[2451]139 Parameters
[2453]140 action: An action to take if the plotter window is not alive.
141 ['status'|'reload'|'halt']
142 The action 'status' simply returns False if asaplot
143 is not alive. When action='reload', plot window is
144 reloaded and the method returns True. Finally, an
145 error is raised when action='halt'.
[2451]146 errmsg: An error (warning) message to send to the logger,
[2453]147 when plot window is not alive.
[2451]148 """
[2538]149 isAlive = (self._plotter is not None) and self._plotter._alive()
[2535]150 # More tests
[2538]151 #if isAlive:
152 # if self._plotter.figmgr:
153 # figmgr = self._plotter.figmgr
154 # figid = figmgr.num
155 # # Make sure figid=0 is what asapplotter expects.
156 # # It might be already destroied/overridden by matplotlib
157 # # commands or other plotting methods using asaplot.
158 # isAlive = _pylab_helpers.Gcf.has_fignum(figid) and \
159 # (figmgr == \
160 # _pylab_helpers.Gcf.get_fig_manager(figid))
161 # else:
162 # isAlive = False
[2535]163
164 if isAlive:
[2451]165 return True
166 # Plotter is not alive.
167 haltmsg = "Plotter window has not yet been loaded or is closed."
168 if type(errmsg)==str and len(errmsg) > 0:
169 haltmsg = errmsg
170
[2453]171 if action.upper().startswith("R"):
[2451]172 # reload plotter
173 self._reload_plotter()
174 return True
[2453]175 elif action.upper().startswith("H"):
[2451]176 # halt
177 asaplog.push(haltmsg)
178 asaplog.post("ERROR")
179 raise RuntimeError(haltmsg)
180 else:
181 if errmsg:
182 asaplog.push(errmsg)
183 asaplog.post("WARN")
184 return False
185
186
[1572]187 def gca(self):
[2451]188 errmsg = "No axis to retun. Need to plot first."
[2453]189 if not self._assert_plotter(action="status",errmsg=errmsg):
[2451]190 return None
[1572]191 return self._plotter.figure.gca()
192
[1550]193 def refresh(self):
[1572]194 """Do a soft refresh"""
[2451]195 errmsg = "No figure to re-plot. Need to plot first."
[2453]196 self._assert_plotter(action="halt",errmsg=errmsg)
[2451]197
[1550]198 self._plotter.figure.show()
199
[2698]200 def save(self, filename=None, orientation=None, dpi=None):
201 """
202 Save the plot to a file. The known formats are 'png', 'ps', 'eps'.
203 Parameters:
204 filename: The name of the output file. This is optional
205 and autodetects the image format from the file
206 suffix. If non filename is specified a file
207 called 'yyyymmdd_hhmmss.png' is created in the
208 current directory.
209 orientation: optional parameter for postscript only (not eps).
210 'landscape', 'portrait' or None (default) are valid.
211 If None is choosen for 'ps' output, the plot is
212 automatically oriented to fill the page.
213 dpi: The dpi of the output non-ps plot
214 """
215 errmsg = "Cannot save figure. Need to plot first."
216 self._assert_plotter(action="halt",errmsg=errmsg)
217
218 self._plotter.save(filename,orientation,dpi)
219 return
220
[1555]221 def create_mask(self, nwin=1, panel=0, color=None):
[1597]222 """
[1927]223 Interactively define a mask. It retruns a mask that is equivalent to
[1597]224 the one created manually with scantable.create_mask.
225 Parameters:
226 nwin: The number of mask windows to create interactively
227 default is 1.
228 panel: Which panel to use for mask selection. This is useful
229 if different IFs are spread over panels (default 0)
230 """
[2451]231 ## this method relies on already plotted figure
[2453]232 if not self._assert_plotter(action="status") or (self._data is None):
[2451]233 msg = "Cannot create mask interactively on plot. Can only create mask after plotting."
234 asaplog.push( msg )
235 asaplog.post( "ERROR" )
[1555]236 return []
[1547]237 outmask = []
[1549]238 self._plotter.subplot(panel)
239 xmin, xmax = self._plotter.axes.get_xlim()
[1548]240 marg = 0.05*(xmax-xmin)
[1549]241 self._plotter.axes.set_xlim(xmin-marg, xmax+marg)
[1550]242 self.refresh()
[1695]243
[1555]244 def cleanup(lines=False, texts=False, refresh=False):
245 if lines:
246 del self._plotter.axes.lines[-1]
247 if texts:
248 del self._plotter.axes.texts[-1]
249 if refresh:
250 self.refresh()
251
252 for w in xrange(nwin):
[1547]253 wpos = []
[1695]254 self.text(0.05,1.0, "Add start boundary",
[1555]255 coords="relative", fontsize=10)
256 point = self._plotter.get_point()
257 cleanup(texts=True)
258 if point is None:
259 continue
260 wpos.append(point[0])
[1695]261 self.axvline(wpos[0], color=color)
[1551]262 self.text(0.05,1.0, "Add end boundary", coords="relative", fontsize=10)
[1555]263 point = self._plotter.get_point()
264 cleanup(texts=True, lines=True)
265 if point is None:
266 self.refresh()
267 continue
268 wpos.append(point[0])
269 self.axvspan(wpos[0], wpos[1], alpha=0.1,
270 edgecolor=color, facecolor=color)
271 ymin, ymax = self._plotter.axes.get_ylim()
[1547]272 outmask.append(wpos)
[1153]273
[1555]274 self._plotter.axes.set_xlim(xmin, xmax)
275 self.refresh()
276 if len(outmask) > 0:
277 return self._data.create_mask(*outmask)
278 return []
279
[2699]280
[2714]281 ### Forwards to methods in matplotlib axes ###
[1153]282 def text(self, *args, **kwargs):
[2453]283 self._assert_plotter(action="reload")
[1547]284 if kwargs.has_key("interactive"):
285 if kwargs.pop("interactive"):
286 pos = self._plotter.get_point()
287 args = tuple(pos)+args
[1153]288 self._axes_callback("text", *args, **kwargs)
[1547]289
[1358]290 text.__doc__ = matplotlib.axes.Axes.text.__doc__
[1559]291
[1153]292 def arrow(self, *args, **kwargs):
[2453]293 self._assert_plotter(action="reload")
[1547]294 if kwargs.has_key("interactive"):
295 if kwargs.pop("interactive"):
296 pos = self._plotter.get_region()
297 dpos = (pos[0][0], pos[0][1],
298 pos[1][0]-pos[0][0],
299 pos[1][1] - pos[0][1])
300 args = dpos + args
[1153]301 self._axes_callback("arrow", *args, **kwargs)
[1547]302
[1358]303 arrow.__doc__ = matplotlib.axes.Axes.arrow.__doc__
[1559]304
305 def annotate(self, text, xy=None, xytext=None, **kwargs):
[2453]306 self._assert_plotter(action="reload")
[1559]307 if kwargs.has_key("interactive"):
308 if kwargs.pop("interactive"):
309 xy = self._plotter.get_point()
310 xytext = self._plotter.get_point()
311 if not kwargs.has_key("arrowprops"):
312 kwargs["arrowprops"] = dict(arrowstyle="->")
313 self._axes_callback("annotate", text, xy, xytext, **kwargs)
314
315 annotate.__doc__ = matplotlib.axes.Axes.annotate.__doc__
316
[1153]317 def axvline(self, *args, **kwargs):
[2453]318 self._assert_plotter(action="reload")
[1547]319 if kwargs.has_key("interactive"):
320 if kwargs.pop("interactive"):
321 pos = self._plotter.get_point()
322 args = (pos[0],)+args
[1153]323 self._axes_callback("axvline", *args, **kwargs)
[1559]324
[1358]325 axvline.__doc__ = matplotlib.axes.Axes.axvline.__doc__
[1547]326
[1153]327 def axhline(self, *args, **kwargs):
[2453]328 self._assert_plotter(action="reload")
[1547]329 if kwargs.has_key("interactive"):
330 if kwargs.pop("interactive"):
331 pos = self._plotter.get_point()
332 args = (pos[1],)+args
[1153]333 self._axes_callback("axhline", *args, **kwargs)
[1559]334
[1358]335 axhline.__doc__ = matplotlib.axes.Axes.axhline.__doc__
[1547]336
[1153]337 def axvspan(self, *args, **kwargs):
[2453]338 self._assert_plotter(action="reload")
[1547]339 if kwargs.has_key("interactive"):
340 if kwargs.pop("interactive"):
341 pos = self._plotter.get_region()
342 dpos = (pos[0][0], pos[1][0])
343 args = dpos + args
[1153]344 self._axes_callback("axvspan", *args, **kwargs)
345 # hack to preventy mpl from redrawing the patch
346 # it seem to convert the patch into lines on every draw.
347 # This doesn't happen in a test script???
[1547]348 #del self._plotter.axes.patches[-1]
349
[1358]350 axvspan.__doc__ = matplotlib.axes.Axes.axvspan.__doc__
[1232]351
[1153]352 def axhspan(self, *args, **kwargs):
[2453]353 self._assert_plotter(action="reload")
[1547]354 if kwargs.has_key("interactive"):
355 if kwargs.pop("interactive"):
356 pos = self._plotter.get_region()
357 dpos = (pos[0][1], pos[1][1])
358 args = dpos + args
[1232]359 self._axes_callback("axhspan", *args, **kwargs)
[1153]360 # hack to preventy mpl from redrawing the patch
361 # it seem to convert the patch into lines on every draw.
362 # This doesn't happen in a test script???
[1547]363 #del self._plotter.axes.patches[-1]
[1559]364
[1358]365 axhspan.__doc__ = matplotlib.axes.Axes.axhspan.__doc__
[1153]366
367 def _axes_callback(self, axesfunc, *args, **kwargs):
[2453]368 self._assert_plotter(action="reload")
[1153]369 panel = 0
370 if kwargs.has_key("panel"):
371 panel = kwargs.pop("panel")
372 coords = None
373 if kwargs.has_key("coords"):
374 coords = kwargs.pop("coords")
375 if coords.lower() == 'world':
376 kwargs["transform"] = self._plotter.axes.transData
377 elif coords.lower() == 'relative':
378 kwargs["transform"] = self._plotter.axes.transAxes
379 self._plotter.subplot(panel)
380 self._plotter.axes.set_autoscale_on(False)
381 getattr(self._plotter.axes, axesfunc)(*args, **kwargs)
382 self._plotter.show(False)
383 self._plotter.axes.set_autoscale_on(True)
384 # end matplotlib.axes fowarding functions
385
[2699]386
387 ### Forwards to matplotlib.Figure.text ###
[2698]388 def figtext(self, *args, **kwargs):
389 """
390 Add text to figure at location x,y (relative 0-1 coords).
391 This method forwards *args and **kwargs to a Matplotlib method,
392 matplotlib.Figure.text.
393 See the method help for detailed information.
394 """
395 self._assert_plotter(action="reload")
396 self._plotter.text(*args, **kwargs)
397 # end matplotlib.Figure.text forwarding function
398
[2699]399
400 ### Set Plot parameters ###
[1862]401 @asaplog_post_dec
[1819]402 def set_data(self, scan, refresh=True):
403 """
[1824]404 Set a scantable to plot.
[1819]405 Parameters:
406 scan: a scantable
407 refresh: True (default) or False. If True, the plot is
[1824]408 replotted based on the new parameter setting(s).
[1819]409 Otherwise,the parameter(s) are set without replotting.
410 Note:
411 The user specified masks and data selections will be reset
412 if a new scantable is set. This method should be called before
[1824]413 setting data selections (set_selection) and/or masks (set_mask).
[1819]414 """
415 from asap import scantable
416 if isinstance(scan, scantable):
[2604]417 if (self._data is not None) and (scan != self._data):
418 del self._data
419 msg = "A new scantable is set to the plotter. "\
[2714]420 "The masks, data selections, and labels are reset."
421 asaplog.push(msg)
[2604]422 self._data = scan
423 # reset
424 self._reset()
[1819]425 else:
426 msg = "Input is not a scantable"
427 raise TypeError(msg)
[1547]428
[1819]429 # ranges become invalid when unit changes
430 if self._abcunit and self._abcunit != self._data.get_unit():
431 self._minmaxx = None
432 self._minmaxy = None
433 self._abcunit = self._data.get_unit()
434 if refresh: self.plot()
435
[1862]436 @asaplog_post_dec
[1819]437 def set_mode(self, stacking=None, panelling=None, refresh=True):
[203]438 """
[377]439 Set the plots look and feel, i.e. what you want to see on the plot.
[203]440 Parameters:
441 stacking: tell the plotter which variable to plot
[1217]442 as line colour overlays (default 'pol')
[203]443 panelling: tell the plotter which variable to plot
444 across multiple panels (default 'scan'
[1819]445 refresh: True (default) or False. If True, the plot is
[1824]446 replotted based on the new parameter setting(s).
[1819]447 Otherwise,the parameter(s) are set without replotting.
[203]448 Note:
449 Valid modes are:
450 'beam' 'Beam' 'b': Beams
451 'if' 'IF' 'i': IFs
452 'pol' 'Pol' 'p': Polarisations
453 'scan' 'Scan' 's': Scans
454 'time' 'Time' 't': Times
[1989]455 'row' 'Row' 'r': Rows
456 When either 'stacking' or 'panelling' is set to 'row',
457 the other parameter setting is ignored.
[203]458 """
[753]459 msg = "Invalid mode"
460 if not self.set_panelling(panelling) or \
461 not self.set_stacking(stacking):
[1859]462 raise TypeError(msg)
[1989]463 #if self._panelling == 'r':
464 # self._stacking = '_r'
465 #if self._stacking == 'r':
466 # self._panelling = '_r'
[1819]467 if refresh and self._data: self.plot(self._data)
[203]468 return
469
[2698]470 def set_stacking(self, what=None):
471 """Set the 'stacking' mode i.e. which type of spectra should be
472 overlayed.
473 """
474 mode = what
475 if mode is None:
476 mode = rcParams['plotter.stacking']
477 md = self._translate(mode)
478 if md:
479 self._stacking = md
480 self._lmap = None
481 # new mode is set. need to reset counters for multi page plotting
482 self._reset_counters()
483 return True
484 return False
485
[554]486 def set_panelling(self, what=None):
[1858]487 """Set the 'panelling' mode i.e. which type of spectra should be
488 spread across different panels.
489 """
490
[554]491 mode = what
492 if mode is None:
493 mode = rcParams['plotter.panelling']
494 md = self._translate(mode)
[203]495 if md:
[554]496 self._panelling = md
[226]497 self._title = None
[2698]498 # new mode is set. need to reset counters for multi page plotting
[1981]499 self._reset_counters()
[203]500 return True
501 return False
502
[1819]503 def set_layout(self,rows=None,cols=None,refresh=True):
[377]504 """
505 Set the multi-panel layout, i.e. how many rows and columns plots
506 are visible.
507 Parameters:
508 rows: The number of rows of plots
509 cols: The number of columns of plots
[1819]510 refresh: True (default) or False. If True, the plot is
[1824]511 replotted based on the new parameter setting(s).
[1819]512 Otherwise,the parameter(s) are set without replotting.
[377]513 Note:
514 If no argument is given, the potter reverts to its auto-plot
515 behaviour.
516 """
517 self._rows = rows
518 self._cols = cols
[2715]519 # new layout is set. need to reset counters for multi page plotting
520 self._reset_counters()
[1819]521 if refresh and self._data: self.plot(self._data)
[377]522 return
523
[1897]524 def set_range(self,xstart=None,xend=None,ystart=None,yend=None,refresh=True, offset=None):
[203]525 """
526 Set the range of interest on the abcissa of the plot
527 Parameters:
[525]528 [x,y]start,[x,y]end: The start and end points of the 'zoom' window
[1819]529 refresh: True (default) or False. If True, the plot is
[1824]530 replotted based on the new parameter setting(s).
[1819]531 Otherwise,the parameter(s) are set without replotting.
[1897]532 offset: shift the abcissa by the given amount. The abcissa label will
533 have '(relative)' appended to it.
[203]534 Note:
535 These become non-sensical when the unit changes.
536 use plotter.set_range() without parameters to reset
537
538 """
[1897]539 self._offset = offset
[525]540 if xstart is None and xend is None:
541 self._minmaxx = None
[600]542 else:
543 self._minmaxx = [xstart,xend]
[525]544 if ystart is None and yend is None:
545 self._minmaxy = None
[600]546 else:
[709]547 self._minmaxy = [ystart,yend]
[1819]548 if refresh and self._data: self.plot(self._data)
[203]549 return
[709]550
[1819]551 def set_legend(self, mp=None, fontsize = None, mode = 0, refresh=True):
[203]552 """
553 Specify a mapping for the legend instead of using the default
554 indices:
555 Parameters:
[1101]556 mp: a list of 'strings'. This should have the same length
557 as the number of elements on the legend and then maps
558 to the indeces in order. It is possible to uses latex
559 math expression. These have to be enclosed in r'',
560 e.g. r'$x^{2}$'
561 fontsize: The font size of the label (default None)
562 mode: where to display the legend
563 Any other value for loc else disables the legend:
[1096]564 0: auto
565 1: upper right
566 2: upper left
567 3: lower left
568 4: lower right
569 5: right
570 6: center left
571 7: center right
572 8: lower center
573 9: upper center
574 10: center
[1819]575 refresh: True (default) or False. If True, the plot is
[1824]576 replotted based on the new parameter setting(s).
[1819]577 Otherwise,the parameter(s) are set without replotting.
[203]578
579 Example:
[485]580 If the data has two IFs/rest frequencies with index 0 and 1
[203]581 for CO and SiO:
582 plotter.set_stacking('i')
[710]583 plotter.set_legend(['CO','SiO'])
[203]584 plotter.plot()
[710]585 plotter.set_legend([r'$^{12}CO$', r'SiO'])
[203]586 """
587 self._lmap = mp
[2451]588 #self._plotter.legend(mode)
589 self._legendloc = mode
[1101]590 if isinstance(fontsize, int):
591 from matplotlib import rc as rcp
592 rcp('legend', fontsize=fontsize)
[1819]593 if refresh and self._data: self.plot(self._data)
[226]594 return
595
[1819]596 def set_title(self, title=None, fontsize=None, refresh=True):
[710]597 """
[2451]598 Set the title of sub-plots. If multiple sub-plots are plotted,
[710]599 multiple titles have to be specified.
[1819]600 Parameters:
[2451]601 title: a list of titles of sub-plots.
602 fontsize: a font size of titles (integer)
[1819]603 refresh: True (default) or False. If True, the plot is
[1824]604 replotted based on the new parameter setting(s).
[1819]605 Otherwise,the parameter(s) are set without replotting.
[710]606 Example:
607 # two panels are visible on the plotter
[2451]608 plotter.set_title(['First Panel','Second Panel'])
[710]609 """
[226]610 self._title = title
[1101]611 if isinstance(fontsize, int):
612 from matplotlib import rc as rcp
613 rcp('axes', titlesize=fontsize)
[1819]614 if refresh and self._data: self.plot(self._data)
[226]615 return
616
[1819]617 def set_ordinate(self, ordinate=None, fontsize=None, refresh=True):
[710]618 """
619 Set the y-axis label of the plot. If multiple panels are plotted,
620 multiple labels have to be specified.
[1021]621 Parameters:
622 ordinate: a list of ordinate labels. None (default) let
623 data determine the labels
[2451]624 fontsize: a font size of vertical axis labels (integer)
[1819]625 refresh: True (default) or False. If True, the plot is
[1824]626 replotted based on the new parameter setting(s).
[1819]627 Otherwise,the parameter(s) are set without replotting.
[710]628 Example:
629 # two panels are visible on the plotter
[2451]630 plotter.set_ordinate(['First Y-Axis','Second Y-Axis'])
[710]631 """
[257]632 self._ordinate = ordinate
[1101]633 if isinstance(fontsize, int):
634 from matplotlib import rc as rcp
635 rcp('axes', labelsize=fontsize)
636 rcp('ytick', labelsize=fontsize)
[1819]637 if refresh and self._data: self.plot(self._data)
[257]638 return
639
[1819]640 def set_abcissa(self, abcissa=None, fontsize=None, refresh=True):
[710]641 """
642 Set the x-axis label of the plot. If multiple panels are plotted,
643 multiple labels have to be specified.
[1021]644 Parameters:
645 abcissa: a list of abcissa labels. None (default) let
646 data determine the labels
[2451]647 fontsize: a font size of horizontal axis labels (integer)
[1819]648 refresh: True (default) or False. If True, the plot is
[1824]649 replotted based on the new parameter setting(s).
[1819]650 Otherwise,the parameter(s) are set without replotting.
[710]651 Example:
652 # two panels are visible on the plotter
[2451]653 plotter.set_ordinate(['First X-Axis','Second X-Axis'])
[710]654 """
[257]655 self._abcissa = abcissa
[1101]656 if isinstance(fontsize, int):
657 from matplotlib import rc as rcp
658 rcp('axes', labelsize=fontsize)
659 rcp('xtick', labelsize=fontsize)
[1819]660 if refresh and self._data: self.plot(self._data)
[257]661 return
662
[2700]663 def set_histogram(self, hist=True, linewidth=None, refresh=True):
664 """
665 Enable/Disable histogram-like plotting.
666 Parameters:
667 hist: True (default) or False. The fisrt default
668 is taken from the .asaprc setting
669 plotter.histogram
670 linewidth: a line width
671 refresh: True (default) or False. If True, the plot is
672 replotted based on the new parameter setting(s).
673 Otherwise,the parameter(s) are set without replotting.
674 """
675 self._hist = hist
676 if isinstance(linewidth, float) or isinstance(linewidth, int):
677 from matplotlib import rc as rcp
678 rcp('lines', linewidth=linewidth)
679 if refresh and self._data: self.plot(self._data)
680
[1819]681 def set_colors(self, colmap, refresh=True):
[377]682 """
[1217]683 Set the colours to be used. The plotter will cycle through
684 these colours when lines are overlaid (stacking mode).
[1021]685 Parameters:
[1217]686 colmap: a list of colour names
[1819]687 refresh: True (default) or False. If True, the plot is
[1824]688 replotted based on the new parameter setting(s).
[1819]689 Otherwise,the parameter(s) are set without replotting.
[710]690 Example:
[2451]691 plotter.set_colors('red green blue')
[710]692 # If for example four lines are overlaid e.g I Q U V
693 # 'I' will be 'red', 'Q' will be 'green', U will be 'blue'
694 # and 'V' will be 'red' again.
695 """
[2451]696 #if isinstance(colmap,str):
697 # colmap = colmap.split()
698 #self._plotter.palette(0, colormap=colmap)
699 self._colormap = colmap
[1819]700 if refresh and self._data: self.plot(self._data)
[710]701
[1217]702 # alias for english speakers
703 set_colours = set_colors
704
[1819]705 def set_linestyles(self, linestyles=None, linewidth=None, refresh=True):
[710]706 """
[734]707 Set the linestyles to be used. The plotter will cycle through
708 these linestyles when lines are overlaid (stacking mode) AND
709 only one color has been set.
[710]710 Parameters:
[2451]711 linestyles: a list of linestyles to use.
[710]712 'line', 'dashed', 'dotted', 'dashdot',
713 'dashdotdot' and 'dashdashdot' are
714 possible
[2451]715 linewidth: a line width
[1819]716 refresh: True (default) or False. If True, the plot is
[1824]717 replotted based on the new parameter setting(s).
[1819]718 Otherwise,the parameter(s) are set without replotting.
[710]719 Example:
[2451]720 plotter.set_colors('black')
721 plotter.set_linestyles('line dashed dotted dashdot')
[710]722 # If for example four lines are overlaid e.g I Q U V
723 # 'I' will be 'solid', 'Q' will be 'dashed',
724 # U will be 'dotted' and 'V' will be 'dashdot'.
725 """
[2451]726 #if isinstance(linestyles,str):
727 # linestyles = linestyles.split()
728 #self._plotter.palette(color=0,linestyle=0,linestyles=linestyles)
729 self._linestyles = linestyles
[1101]730 if isinstance(linewidth, float) or isinstance(linewidth, int):
731 from matplotlib import rc as rcp
732 rcp('lines', linewidth=linewidth)
[1819]733 if refresh and self._data: self.plot(self._data)
[710]734
[1819]735 def set_font(self, refresh=True,**kwargs):
[1101]736 """
737 Set font properties.
738 Parameters:
739 family: one of 'sans-serif', 'serif', 'cursive', 'fantasy', 'monospace'
740 style: one of 'normal' (or 'roman'), 'italic' or 'oblique'
741 weight: one of 'normal or 'bold'
742 size: the 'general' font size, individual elements can be adjusted
743 seperately
[1819]744 refresh: True (default) or False. If True, the plot is
[1824]745 replotted based on the new parameter setting(s).
[1819]746 Otherwise,the parameter(s) are set without replotting.
[1101]747 """
748 from matplotlib import rc as rcp
[1547]749 fdict = {}
750 for k,v in kwargs.iteritems():
751 if v:
752 fdict[k] = v
[1556]753 self._fp = FontProperties(**fdict)
[1819]754 if refresh and self._data: self.plot(self._data)
[1101]755
[2037]756 def set_margin(self,margin=[],refresh=True):
[1819]757 """
[2037]758 Set margins between subplots and plot edges.
[1819]759 Parameters:
[2037]760 margin: a list of margins in figure coordinate (0-1),
[1824]761 i.e., fraction of the figure width or height.
[1819]762 The order of elements should be:
763 [left, bottom, right, top, horizontal space btw panels,
[1824]764 vertical space btw panels].
[1819]765 refresh: True (default) or False. If True, the plot is
[1824]766 replotted based on the new parameter setting(s).
[1819]767 Otherwise,the parameter(s) are set without replotting.
768 Note
[2037]769 * When margin is not specified, the values are reset to the defaults
[1819]770 of matplotlib.
[1824]771 * If any element is set to be None, the current value is adopted.
[1819]772 """
[2037]773 if margin == []: self._margins=self._reset_margin()
[1824]774 else:
[2037]775 self._margins=[None]*6
776 self._margins[0:len(margin)]=margin
777 #print "panel margin set to ",self._margins
[1819]778 if refresh and self._data: self.plot(self._data)
779
[2037]780 def _reset_margin(self):
[1819]781 ks=map(lambda x: 'figure.subplot.'+x,
782 ['left','bottom','right','top','hspace','wspace'])
783 return map(matplotlib.rcParams.get,ks)
784
[1259]785 def plot_lines(self, linecat=None, doppler=0.0, deltachan=10, rotate=90.0,
[1146]786 location=None):
787 """
[1158]788 Plot a line catalog.
789 Parameters:
790 linecat: the linecatalog to plot
[1168]791 doppler: the velocity shift to apply to the frequencies
[1158]792 deltachan: the number of channels to include each side of the
793 line to determine a local maximum/minimum
[1927]794 rotate: the rotation (in degrees) for the text label (default 90.0)
[1158]795 location: the location of the line annotation from the 'top',
796 'bottom' or alternate (None - the default)
[1165]797 Notes:
798 If the spectrum is flagged no line will be drawn in that location.
[1146]799 """
[2451]800 errmsg = "Cannot plot spectral lines. Need to plot scantable first."
[2453]801 self._assert_plotter(action="halt",errmsg=errmsg)
[1259]802 if not self._data:
803 raise RuntimeError("No scantable has been plotted yet.")
[1146]804 from asap._asap import linecatalog
[1259]805 if not isinstance(linecat, linecatalog):
806 raise ValueError("'linecat' isn't of type linecatalog.")
807 if not self._data.get_unit().endswith("Hz"):
808 raise RuntimeError("Can only overlay linecatalogs when data is in frequency.")
[1739]809 from numpy import ma
[1146]810 for j in range(len(self._plotter.subplots)):
811 self._plotter.subplot(j)
812 lims = self._plotter.axes.get_xlim()
[1153]813 for row in range(linecat.nrow()):
[1259]814 # get_frequency returns MHz
815 base = { "GHz": 1000.0, "MHz": 1.0, "Hz": 1.0e-6 }
816 restf = linecat.get_frequency(row)/base[self._data.get_unit()]
[1165]817 c = 299792.458
[1174]818 freq = restf*(1.0-doppler/c)
[1146]819 if lims[0] < freq < lims[1]:
820 if location is None:
821 loc = 'bottom'
[1153]822 if row%2: loc='top'
[1146]823 else: loc = location
[1153]824 maxys = []
825 for line in self._plotter.axes.lines:
826 v = line._x
827 asc = v[0] < v[-1]
828
829 idx = None
830 if not asc:
831 if v[len(v)-1] <= freq <= v[0]:
832 i = len(v)-1
833 while i>=0 and v[i] < freq:
834 idx = i
835 i-=1
836 else:
837 if v[0] <= freq <= v[len(v)-1]:
838 i = 0
839 while i<len(v) and v[i] < freq:
840 idx = i
841 i+=1
842 if idx is not None:
843 lower = idx - deltachan
844 upper = idx + deltachan
845 if lower < 0: lower = 0
846 if upper > len(v): upper = len(v)
847 s = slice(lower, upper)
[1167]848 y = line._y[s]
[1165]849 maxy = ma.maximum(y)
850 if isinstance( maxy, float):
851 maxys.append(maxy)
[1164]852 if len(maxys):
853 peak = max(maxys)
[1165]854 if peak > self._plotter.axes.get_ylim()[1]:
855 loc = 'bottom'
[1164]856 else:
857 continue
[1157]858 self._plotter.vline_with_label(freq, peak,
859 linecat.get_name(row),
860 location=loc, rotate=rotate)
[1153]861 self._plotter.show(hardrefresh=False)
[1146]862
[1153]863
[2698]864 def set_selection(self, selection=None, refresh=True, **kw):
[710]865 """
[377]866 Parameters:
[2698]867 selection: a selector object (default unset the selection)
868 refresh: True (default) or False. If True, the plot is
869 replotted based on the new parameter setting(s).
870 Otherwise,the parameter(s) are set without replotting.
[377]871 """
[2698]872 if selection is None:
873 # reset
874 if len(kw) == 0:
875 self._selection = selector()
876 else:
877 # try keywords
878 for k in kw:
879 if k not in selector.fields:
880 raise KeyError("Invalid selection key '%s', valid keys are %s" % (k, selector.fields))
881 self._selection = selector(**kw)
882 elif isinstance(selection, selector):
883 self._selection = selection
884 else:
885 raise TypeError("'selection' is not of type selector")
[709]886
[2698]887 order = self._get_sortstring([self._panelling,self._stacking])
888 if order:
889 self._selection.set_order(order)
890 if refresh and self._data:
891 self.plot()
892
[1862]893 @asaplog_post_dec
[1819]894 def set_mask(self, mask=None, selection=None, refresh=True):
[525]895 """
[734]896 Set a plotting mask for a specific polarization.
[2451]897 This is useful for masking out 'noise' Pangle outside a source.
[734]898 Parameters:
[920]899 mask: a mask from scantable.create_mask
900 selection: the spectra to apply the mask to.
[1819]901 refresh: True (default) or False. If True, the plot is
[1824]902 replotted based on the new parameter setting(s).
[1819]903 Otherwise,the parameter(s) are set without replotting.
[734]904 Example:
[920]905 select = selector()
[2451]906 select.setpolstrings('Pangle')
[920]907 plotter.set_mask(mymask, select)
[734]908 """
[710]909 if not self._data:
[920]910 msg = "Can only set mask after a first call to plot()"
[1859]911 raise RuntimeError(msg)
[2714]912 if (mask is not None) and len(mask):
[920]913 if isinstance(mask, list) or isinstance(mask, tuple):
914 self._usermask = array(mask)
[710]915 else:
[920]916 self._usermask = mask
917 if mask is None and selection is None:
918 self._usermask = []
919 self._maskselection = None
920 if isinstance(selection, selector):
[947]921 self._maskselection = {'b': selection.get_beams(),
922 's': selection.get_scans(),
923 'i': selection.get_ifs(),
924 'p': selection.get_pols(),
[920]925 't': [] }
[710]926 else:
[920]927 self._maskselection = None
[1819]928 if refresh: self.plot(self._data)
[710]929
[709]930
[2699]931 ### Reset methods ###
[710]932 def _reset(self):
[2714]933 """Reset method called when new data is set"""
934 # reset selections and masks
935 self.set_selection(None, False)
936 self.set_mask(None, None, False)
937 # reset offset
[1897]938 self._offset = None
[2714]939 # reset header
[2051]940 self._reset_header()
[2714]941 # reset labels
942 self._lmap = None # related to stack
943 self.set_title(None, None, False)
944 self.set_ordinate(None, None, False)
945 self.set_abcissa(None, None, False)
[920]946
[2051]947 def _reset_header(self):
[2053]948 self._headtext={'string': None, 'textobj': None}
[2051]949
[2697]950 def _reset_counter(self):
951 self._startrow = 0
952 self._ipanel = -1
[2715]953 self._panelrows = []
[2697]954 self._reset_header()
955 if self.casabar_exists():
956 self._plotter.figmgr.casabar.set_pagecounter(1)
957
[2698]958 def _reset_counters(self):
959 self._startrow = 0
960 self._ipanel = -1
961 self._panelrows = []
962
[2699]963
964 ### Actual scantable plot methods ###
[2698]965 @asaplog_post_dec
966 def plot(self, scan=None):
967 """
968 Plot a scantable.
969 Parameters:
970 scan: a scantable
971 Note:
972 If a scantable was specified in a previous call
973 to plot, no argument has to be given to 'replot'
974 NO checking is done that the abcissas of the scantable
975 are consistent e.g. all 'channel' or all 'velocity' etc.
976 """
[2704]977 self._plotmode = "spectra"
[2698]978 if not self._data and not scan:
979 msg = "Input is not a scantable"
980 raise TypeError(msg)
981
982 self._assert_plotter(action="reload")
983 self._plotter.hold()
984 self._reset_counter()
985 #self._plotter.clear()
986 if scan:
987 self.set_data(scan, refresh=False)
988 self._plotter.palette(color=0,colormap=self._colormap,
989 linestyle=0,linestyles=self._linestyles)
990 self._plotter.legend(self._legendloc)
991 self._plot(self._data)
992 if self._minmaxy is not None:
993 self._plotter.set_limits(ylim=self._minmaxy)
994 if self.casabar_exists(): self._plotter.figmgr.casabar.enable_button()
995 self._plotter.release()
996 self._plotter.tidy()
997 self._plotter.show(hardrefresh=False)
998 return
999
[920]1000 def _plot(self, scan):
[947]1001 savesel = scan.get_selection()
1002 sel = savesel + self._selection
[1910]1003 order = self._get_sortstring([self._panelling,self._stacking])
1004 if order:
1005 sel.set_order(order)
[947]1006 scan.set_selection(sel)
[920]1007 d = {'b': scan.getbeam, 's': scan.getscan,
[1949]1008 'i': scan.getif, 'p': scan.getpol, 't': scan.get_time,
[1989]1009 'r': int}#, '_r': int}
[920]1010
[2650]1011 polmodes = dict(zip(sel.get_pols(), sel.get_poltypes()))
[1148]1012 # this returns either a tuple of numbers or a length (ncycles)
1013 # convert this into lengths
1014 n0,nstack0 = self._get_selected_n(scan)
1015 if isinstance(n0, int): n = n0
[1175]1016 else: n = len(n0)
[1148]1017 if isinstance(nstack0, int): nstack = nstack0
[1175]1018 else: nstack = len(nstack0)
[1989]1019 # In case of row stacking
1020 rowstack = False
1021 titlemode = self._panelling
1022 if self._stacking == "r" and self._panelling != "r":
1023 rowstack = True
1024 titlemode = '_r'
[1913]1025 nptot = n
[1582]1026 maxpanel, maxstack = 16,16
[1913]1027 if nstack > maxstack:
1028 msg ="Scan to be overlayed contains more than %d selections.\n" \
1029 "Selecting first %d selections..." % (maxstack, maxstack)
[920]1030 asaplog.push(msg)
[1861]1031 asaplog.post('WARN')
[998]1032 nstack = min(nstack,maxstack)
[2038]1033 #n = min(n-self._ipanel-1,maxpanel)
1034 n = n-self._ipanel-1
[2697]1035 # the number of panels in this page
1036 if self._rows and self._cols:
1037 n = min(n,self._rows*self._cols)
1038 else:
1039 n = min(n,maxpanel)
[2011]1040
[2697]1041 firstpage = (self._ipanel < 0)
1042 #ganged = False
1043 ganged = rcParams['plotter.ganged']
1044 if self._panelling == 'i':
1045 ganged = False
[2715]1046 if (not firstpage) and \
1047 self._plotter._subplotsOk(self._rows, self._cols, n):
1048 # Not the first page and subplot number is ok.
1049 # Just clear the axis
[2697]1050 nx = self._plotter.cols
1051 ipaxx = n - nx - 1 #the max panel id to supress x-label
1052 for ip in xrange(len(self._plotter.subplots)):
1053 self._plotter.subplot(ip)
1054 self._plotter.clear()
1055 self._plotter.axes.set_visible((ip<n))
1056 if ganged:
1057 self._plotter.axes.xaxis.label.set_visible((ip > ipaxx))
1058 if ip <= ipaxx:
1059 map(lambda x: x.set_visible(False), \
1060 self._plotter.axes.get_xticklabels())
1061 self._plotter.axes.yaxis.label.set_visible((ip % nx)==0)
1062 if ip % nx:
1063 map(lambda y: y.set_visible(False), \
1064 self._plotter.axes.get_yticklabels())
1065 elif (n > 1 and self._rows and self._cols):
[920]1066 self._plotter.set_panels(rows=self._rows,cols=self._cols,
[2650]1067 nplots=n,margin=self._margins,
1068 ganged=ganged)
[920]1069 else:
[2697]1070 self._plotter.set_panels(rows=n,cols=0,nplots=n,
1071 margin=self._margins,ganged=ganged)
[1913]1072 #r = 0
[1981]1073 r = self._startrow
[920]1074 nr = scan.nrow()
1075 a0,b0 = -1,-1
1076 allxlim = []
[1018]1077 allylim = []
[1981]1078 #newpanel=True
1079 newpanel=False
[920]1080 panelcount,stackcount = 0,0
[1981]1081 # If this is not the first page
1082 if r > 0:
1083 # panelling value of the prev page
1084 a0 = d[self._panelling](r-1)
1085 # set the initial stackcount large not to plot
1086 # the start row automatically
1087 stackcount = nstack
1088
[1002]1089 while r < nr:
[920]1090 a = d[self._panelling](r)
1091 b = d[self._stacking](r)
1092 if a > a0 and panelcount < n:
1093 if n > 1:
1094 self._plotter.subplot(panelcount)
1095 self._plotter.palette(0)
1096 #title
1097 xlab = self._abcissa and self._abcissa[panelcount] \
1098 or scan._getabcissalabel()
[1897]1099 if self._offset and not self._abcissa:
1100 xlab += " (relative)"
[920]1101 ylab = self._ordinate and self._ordinate[panelcount] \
1102 or scan._get_ordinate_label()
[1547]1103 self._plotter.set_axes('xlabel', xlab)
1104 self._plotter.set_axes('ylabel', ylab)
[1989]1105 #lbl = self._get_label(scan, r, self._panelling, self._title)
1106 lbl = self._get_label(scan, r, titlemode, self._title)
[920]1107 if isinstance(lbl, list) or isinstance(lbl, tuple):
1108 if 0 <= panelcount < len(lbl):
1109 lbl = lbl[panelcount]
1110 else:
1111 # get default label
[1989]1112 #lbl = self._get_label(scan, r, self._panelling, None)
1113 lbl = self._get_label(scan, r, titlemode, None)
[920]1114 self._plotter.set_axes('title',lbl)
1115 newpanel = True
[1913]1116 stackcount = 0
[920]1117 panelcount += 1
[1981]1118 # save the start row to plot this panel for future revisit.
1119 if self._panelling != 'r' and \
1120 len(self._panelrows) < self._ipanel+1+panelcount:
1121 self._panelrows += [r]
1122
[1944]1123 #if (b > b0 or newpanel) and stackcount < nstack:
[2650]1124 if stackcount < nstack and (newpanel or \
1125 rowstack or (a == a0 and b > b0)):
[920]1126 y = []
1127 if len(polmodes):
1128 y = scan._getspectrum(r, polmodes[scan.getpol(r)])
1129 else:
1130 y = scan._getspectrum(r)
[1995]1131 # flag application
1132 mr = scan._getflagrow(r)
[1739]1133 from numpy import ma, array
[1995]1134 if mr:
1135 y = ma.masked_array(y,mask=mr)
1136 else:
1137 m = scan._getmask(r)
1138 from numpy import logical_not, logical_and
1139 if self._maskselection and len(self._usermask) == len(m):
[2277]1140 if d[self._stacking](r) in self._maskselection[self._stacking]:
[1995]1141 m = logical_and(m, self._usermask)
[2277]1142 y = ma.masked_array(y,mask=logical_not(array(m,copy=False)))
[1995]1143
[1897]1144 x = array(scan._getabcissa(r))
1145 if self._offset:
1146 x += self._offset
[920]1147 if self._minmaxx is not None:
1148 s,e = self._slice_indeces(x)
1149 x = x[s:e]
1150 y = y[s:e]
[1096]1151 if len(x) > 1024 and rcParams['plotter.decimate']:
1152 fac = len(x)/1024
[920]1153 x = x[::fac]
1154 y = y[::fac]
1155 llbl = self._get_label(scan, r, self._stacking, self._lmap)
1156 if isinstance(llbl, list) or isinstance(llbl, tuple):
1157 if 0 <= stackcount < len(llbl):
1158 # use user label
1159 llbl = llbl[stackcount]
1160 else:
1161 # get default label
1162 llbl = self._get_label(scan, r, self._stacking, None)
1163 self._plotter.set_line(label=llbl)
[1023]1164 plotit = self._plotter.plot
1165 if self._hist: plotit = self._plotter.hist
[1995]1166 if len(x) > 0 and not mr:
[1146]1167 plotit(x,y)
1168 xlim= self._minmaxx or [min(x),max(x)]
1169 allxlim += xlim
1170 ylim= self._minmaxy or [ma.minimum(y),ma.maximum(y)]
1171 allylim += ylim
[1819]1172 else:
1173 xlim = self._minmaxx or []
1174 allxlim += xlim
1175 ylim= self._minmaxy or []
1176 allylim += ylim
[920]1177 stackcount += 1
[1981]1178 a0=a
1179 b0=b
[920]1180 # last in colour stack -> autoscale x
[1819]1181 if stackcount == nstack and len(allxlim) > 0:
[920]1182 allxlim.sort()
[1819]1183 self._plotter.subplots[panelcount-1]['axes'].set_xlim([allxlim[0],allxlim[-1]])
[1989]1184 if ganged:
1185 allxlim = [allxlim[0],allxlim[-1]]
1186 else:
1187 # clear
1188 allxlim =[]
[920]1189
1190 newpanel = False
[1981]1191 #a0=a
1192 #b0=b
[920]1193 # ignore following rows
[1981]1194 if (panelcount == n and stackcount == nstack) or (r == nr-1):
[1018]1195 # last panel -> autoscale y if ganged
[1989]1196 #if rcParams['plotter.ganged'] and len(allylim) > 0:
1197 if ganged and len(allylim) > 0:
[1018]1198 allylim.sort()
1199 self._plotter.set_limits(ylim=[allylim[0],allylim[-1]])
[998]1200 break
[920]1201 r+=1 # next row
[1981]1202
1203 # save the current counter for multi-page plotting
1204 self._startrow = r+1
1205 self._ipanel += panelcount
[2147]1206 if self.casabar_exists():
[1981]1207 if self._ipanel >= nptot-1:
[1913]1208 self._plotter.figmgr.casabar.disable_next()
1209 else:
1210 self._plotter.figmgr.casabar.enable_next()
[1981]1211 if self._ipanel + 1 - panelcount > 0:
1212 self._plotter.figmgr.casabar.enable_prev()
1213 else:
1214 self._plotter.figmgr.casabar.disable_prev()
1215
[947]1216 #reset the selector to the scantable's original
1217 scan.set_selection(savesel)
[1824]1218
[1819]1219 #temporary switch-off for older matplotlib
1220 #if self._fp is not None:
[2698]1221 if self._fp is not None and \
1222 getattr(self._plotter.figure,'findobj',False):
[1556]1223 for o in self._plotter.figure.findobj(Text):
[2697]1224 if not self._headtext['textobj'] or \
1225 not (o in self._headtext['textobj']):
1226 o.set_fontproperties(self._fp)
[920]1227
[1910]1228 def _get_sortstring(self, lorders):
1229 d0 = {'s': 'SCANNO', 'b': 'BEAMNO', 'i':'IFNO',
1230 'p': 'POLNO', 'c': 'CYCLENO', 't' : 'TIME', 'r':None, '_r':None }
[1944]1231 if not (type(lorders) == list) and not (type(lorders) == tuple):
[1910]1232 return None
1233 if len(lorders) > 0:
1234 lsorts = []
1235 for order in lorders:
[1989]1236 if order == "r":
1237 # don't sort if row panelling/stacking
1238 return None
[1910]1239 ssort = d0[order]
1240 if ssort:
1241 lsorts.append(ssort)
1242 return lsorts
1243 return None
1244
[920]1245 def _get_selected_n(self, scan):
[1148]1246 d1 = {'b': scan.getbeamnos, 's': scan.getscannos,
[1910]1247 'i': scan.getifnos, 'p': scan.getpolnos, 't': scan.ncycle,
[1989]1248 'r': scan.nrow}#, '_r': False}
[1148]1249 d2 = { 'b': self._selection.get_beams(),
1250 's': self._selection.get_scans(),
1251 'i': self._selection.get_ifs(),
1252 'p': self._selection.get_pols(),
[1910]1253 't': self._selection.get_cycles(),
[1989]1254 'r': False}#, '_r': 1}
[920]1255 n = d2[self._panelling] or d1[self._panelling]()
1256 nstack = d2[self._stacking] or d1[self._stacking]()
[1989]1257 # handle row panelling/stacking
1258 if self._panelling == 'r':
1259 nstack = 1
1260 elif self._stacking == 'r':
1261 n = 1
[920]1262 return n,nstack
1263
1264 def _get_label(self, scan, row, mode, userlabel=None):
[1153]1265 if isinstance(userlabel, list) and len(userlabel) == 0:
1266 userlabel = " "
[947]1267 pms = dict(zip(self._selection.get_pols(),self._selection.get_poltypes()))
[920]1268 if len(pms):
1269 poleval = scan._getpollabel(scan.getpol(row),pms[scan.getpol(row)])
1270 else:
1271 poleval = scan._getpollabel(scan.getpol(row),scan.poltype())
1272 d = {'b': "Beam "+str(scan.getbeam(row)),
[1819]1273 #'s': scan._getsourcename(row),
1274 's': "Scan "+str(scan.getscan(row))+\
1275 " ("+str(scan._getsourcename(row))+")",
[920]1276 'i': "IF"+str(scan.getif(row)),
[964]1277 'p': poleval,
[1910]1278 't': str(scan.get_time(row)),
1279 'r': "row "+str(row),
[1913]1280 #'_r': str(scan.get_time(row))+",\nIF"+str(scan.getif(row))+", "+poleval+", Beam"+str(scan.getbeam(row)) }
1281 '_r': "" }
[920]1282 return userlabel or d[mode]
[1153]1283
[2700]1284 def _slice_indeces(self, data):
1285 mn = self._minmaxx[0]
1286 mx = self._minmaxx[1]
1287 asc = data[0] < data[-1]
1288 start=0
1289 end = len(data)-1
1290 inc = 1
1291 if not asc:
1292 start = len(data)-1
1293 end = 0
1294 inc = -1
1295 # find min index
1296 #while start > 0 and data[start] < mn:
1297 # start+= inc
1298 minind=start
1299 for ind in xrange(start,end+inc,inc):
1300 if data[ind] > mn: break
1301 minind=ind
1302 # find max index
1303 #while end > 0 and data[end] > mx:
1304 # end-=inc
1305 #if end > 0: end +=1
1306 maxind=end
1307 for ind in xrange(end,start-inc,-inc):
1308 if data[ind] < mx: break
1309 maxind=ind
1310 start=minind
1311 end=maxind
1312 if start > end:
1313 return end,start+1
1314 elif start < end:
1315 return start,end+1
1316 else:
1317 return start,end
1318
[3038]1319 def _get_date_axis_setup(self, dates, axlim=None):
[2988]1320 """
1321 Returns proper axis title and formatters for a list of dates
1322 Input
1323 dates : a list of datetime objects returned by,
1324 e.g. scantable.get_time(asdatetime=True)
[3038]1325 axlim : a tuple of min and max day range in the plot axis.
1326 if defined, the values are taken into account.
[2988]1327 Output
1328 a set of
1329 * date axis title string
1330 * formatter of date axis
1331 * major axis locator
1332 * minor axis locator
1333 """
1334 from matplotlib import pylab as PL
1335 from matplotlib.dates import DateFormatter
[3038]1336 from matplotlib.dates import HourLocator, MinuteLocator,SecondLocator, DayLocator, YearLocator, MonthLocator
[2988]1337 t = PL.date2num(dates)
[3038]1338 tmin = min(t)
1339 tmax = max(t)
1340 if axlim is not None:
1341 tmin = min(tmin, min(axlim))
1342 tmax = max(tmax, max(axlim))
1343 tdel = tmax - tmin # interval in day
[2988]1344 dstr = dates[0].strftime('%Y/%m/%d')
[3038]1345 if tdel > 365.0: # >1year (also the case for single or very small time range)
1346 majloc = YearLocator()
1347 minloc = MonthLocator(range(1,12,6))
1348 timefmt = DateFormatter('%Y/%m/%d')
1349 elif tdel > 1.0: # >1day
[2988]1350 dstr2 = dates[len(dates)-1].strftime('%Y/%m/%d')
1351 dstr = dstr + " - " + dstr2
1352 majloc = DayLocator()
1353 minloc = HourLocator(range(0,23,12))
1354 timefmt = DateFormatter("%b%d")
1355 elif tdel > 24./60.: # 9.6h - 1day
1356 timefmt = DateFormatter('%H:%M')
1357 majloc = HourLocator()
1358 minloc = MinuteLocator(range(0,60,30))
1359 elif tdel > 2./24.: # 2h-9.6h
1360 timefmt = DateFormatter('%H:%M')
1361 majloc = HourLocator()
1362 minloc = MinuteLocator(range(0,60,10))
1363 elif tdel> 10./24./60.: # 10min-2h
1364 timefmt = DateFormatter('%H:%M')
1365 majloc = MinuteLocator(range(0,60,10))
1366 minloc = MinuteLocator()
1367 else: # <10min
1368 timefmt = DateFormatter('%H:%M')
1369 majloc = MinuteLocator()
1370 minloc = SecondLocator(30)
1371 return (dstr, timefmt, majloc, minloc)
1372
[1819]1373 def plotazel(self, scan=None, outfile=None):
[1391]1374 """
[1696]1375 plot azimuth and elevation versus time of a scantable
[1391]1376 """
[2704]1377 self._plotmode = "azel"
[1923]1378 visible = rcParams['plotter.gui']
[1696]1379 from matplotlib import pylab as PL
[2586]1380 from pytz import timezone
[1391]1381 from matplotlib.ticker import MultipleLocator
[2953]1382 from numpy import array, pi, ma
[2704]1383 if self._plotter and (PL.gcf() == self._plotter.figure):
[2699]1384 # the current figure is ASAP plotter. Use mpl plotter
1385 figids = PL.get_fignums()
[2704]1386 PL.figure(max(figids[-1],1))
1387
[1923]1388 if not visible or not self._visible:
1389 PL.ioff()
1390 from matplotlib.backends.backend_agg import FigureCanvasAgg
1391 PL.gcf().canvas.switch_backends(FigureCanvasAgg)
[1819]1392 self._data = scan
[1556]1393 dates = self._data.get_time(asdatetime=True)
[2953]1394 # for flag handling
1395 mask = [ self._data._is_all_chan_flagged(i) for i in range(self._data.nrow())]
[1391]1396 t = PL.date2num(dates)
1397 tz = timezone('UTC')
1398 PL.cla()
1399 PL.ioff()
1400 PL.clf()
[2037]1401 # Adjust subplot margins
[2576]1402 if not self._margins or len(self._margins) != 6:
[2037]1403 self.set_margin(refresh=False)
1404 lef, bot, rig, top, wsp, hsp = self._margins
[1819]1405 PL.gcf().subplots_adjust(left=lef,bottom=bot,right=rig,top=top,
1406 wspace=wsp,hspace=hsp)
[1824]1407
[2977]1408 tdel = max(t) - min(t) # interval in day
[1391]1409 ax = PL.subplot(2,1,1)
[2953]1410 el = ma.masked_array(array(self._data.get_elevation())*180./pi, mask)
[1391]1411 PL.ylabel('El [deg.]')
[2988]1412 (dstr, timefmt, majloc, minloc) = self._get_date_axis_setup(dates)
1413
[1391]1414 PL.title(dstr)
[1819]1415 if tdel == 0.0:
1416 th = (t - PL.floor(t))*24.0
1417 PL.plot(th,el,'o',markersize=2, markerfacecolor='b', markeredgecolor='b')
1418 else:
1419 PL.plot_date(t,el,'o', markersize=2, markerfacecolor='b', markeredgecolor='b',tz=tz)
[3016]1420 #ax.xaxis.set_major_formatter(timefmt)
1421 #ax.xaxis.set_major_locator(majloc)
1422 #ax.xaxis.set_minor_locator(minloc)
[1391]1423 ax.yaxis.grid(True)
[1819]1424 ax.set_ylim(0,90)
[3016]1425 #yloc = MultipleLocator(30)
1426 #ax.yaxis.set_major_locator(yloc)
[1391]1427 if tdel > 1.0:
1428 labels = ax.get_xticklabels()
1429 # PL.setp(labels, fontsize=10, rotation=45)
1430 PL.setp(labels, fontsize=10)
[1819]1431
[1391]1432 # Az plot
[2953]1433 az = ma.masked_array(array(self._data.get_azimuth())*180./pi, mask)
[1391]1434 if min(az) < 0:
1435 for irow in range(len(az)):
1436 if az[irow] < 0: az[irow] += 360.0
1437
[1819]1438 ax2 = PL.subplot(2,1,2)
1439 #PL.xlabel('Time (UT [hour])')
1440 PL.ylabel('Az [deg.]')
1441 if tdel == 0.0:
1442 PL.plot(th,az,'o',markersize=2, markeredgecolor='b',markerfacecolor='b')
1443 else:
1444 PL.plot_date(t,az,'o', markersize=2,markeredgecolor='b',markerfacecolor='b',tz=tz)
[3016]1445 #ax2.xaxis.set_major_formatter(timefmt)
1446 #ax2.xaxis.set_major_locator(majloc)
1447 #ax2.xaxis.set_minor_locator(minloc)
[1819]1448 ax2.set_ylim(0,360)
[1696]1449 ax2.yaxis.grid(True)
[1819]1450 #hfmt = DateFormatter('%H')
1451 #hloc = HourLocator()
[3016]1452 #yloc = MultipleLocator(60)
1453 #ax2.yaxis.set_major_locator(yloc)
[1819]1454 if tdel > 1.0:
1455 labels = ax2.get_xticklabels()
1456 PL.setp(labels, fontsize=10)
[3016]1457 # PL.xlabel('Time (UT [day])')
1458 #else:
1459 # PL.xlabel('Time (UT [hour])')
1460 PL.xlabel('Time (UT)')
[1819]1461
[1391]1462 PL.ion()
1463 PL.draw()
[2416]1464 if matplotlib.get_backend() == 'Qt4Agg': PL.gcf().show()
[2576]1465 if (outfile is not None):
1466 PL.savefig(outfile)
[1391]1467
[2693]1468
1469 def plotpointing2(self, scan=None, colorby='', showline=False, projection=''):
1470 """
1471 plot telescope pointings
1472 Parameters:
[2990]1473 scan : input scantable instance
[2693]1474 colorby : change color by either
1475 'type'(source type)|'scan'|'if'|'pol'|'beam'
1476 showline : show dotted line
1477 projection : projection type either
1478 ''(no projection [deg])|'coord'(not implemented)
1479 """
[2704]1480 self._plotmode = "pointing"
[2953]1481 from numpy import array, pi, ma
[2693]1482 from asap import scantable
1483 # check for scantable
1484 if isinstance(scan, scantable):
1485 if self._data is not None:
1486 if scan != self._data:
1487 self._data = scan
1488 # reset
1489 self._reset()
1490 else:
1491 self._data = scan
1492 self._reset()
1493 if not self._data:
1494 msg = "Input is not a scantable"
1495 raise TypeError(msg)
1496 # check for color mode
1497 validtypes=['type','scan','if','pol', 'beam']
1498 stype = None
1499 if (colorby in validtypes):
1500 stype = colorby[0]
1501 elif len(colorby) > 0:
1502 msg = "Invalid choice of 'colorby' (choices: %s)" % str(validtypes)
1503 raise ValueError(msg)
1504 self._assert_plotter(action="reload")
1505 self._plotter.hold()
[2697]1506 self._reset_counter()
[2694]1507 if self.casabar_exists():
1508 self._plotter.figmgr.casabar.disable_button()
[2693]1509 # for now, only one plot
1510 self._plotter.set_panels(rows=1,cols=1)
1511 # first panel
1512 self._plotter.subplot(0)
1513 # first color and linestyles
1514 self._plotter.palette(0)
1515 self.gca().set_aspect('equal')
1516 basesel = scan.get_selection()
[2694]1517 attrback = self._plotter.get_line()
1518 marker = "o"
[2693]1519 if showline:
1520 basesel.set_order(["TIME"])
1521 scan.set_selection(basesel)
1522 if not (stype in ["t", "s"]):
[2694]1523 marker += ":"
1524 self._plotter.set_line(markersize=3, markeredgewidth=0)
1525
[2693]1526 if not stype:
1527 selIds = [""] # cheating
1528 sellab = "all points"
1529 elif stype == 't':
1530 selIds = range(15)
1531 sellab = "src type "
1532 else:
1533 selIds = getattr(self._data,'get'+colorby+'nos')()
1534 sellab = colorby.upper()
1535 selFunc = "set_"+colorby+"s"
1536 for idx in selIds:
1537 sel = selector() + basesel
1538 if stype:
1539 bid = getattr(basesel,'get_'+colorby+"s")()
1540 if (len(bid) > 0) and (not idx in bid):
1541 # base selection doesn't contain idx
1542 # Note summation of selector is logical sum if
1543 continue
1544 getattr(sel, selFunc)([idx])
1545 if not sel.is_empty():
1546 try:
1547 self._data.set_selection(sel)
1548 except RuntimeError, instance:
1549 if stype == 't' and str(instance).startswith("Selection contains no data."):
1550 continue
1551 else:
1552 self._data.set_selection(basesel)
1553 raise RuntimeError, instance
1554 if self._data.nrow() == 0:
1555 self._data.set_selection(basesel)
1556 continue
[2795]1557 #print "Plotting direction of %s = %s" % (colorby, str(idx))
[2694]1558 # getting data to plot
[2693]1559 dir = array(self._data.get_directionval()).transpose()
[2953]1560 # for flag handling
1561 mask = [ self._data._is_all_chan_flagged(i) for i in range(self._data.nrow())]
[2693]1562 ra = dir[0]*180./pi
[2953]1563 dec = ma.masked_array(dir[1]*180./pi, mask)
[2694]1564 # actual plot
[2693]1565 self._plotter.set_line(label=(sellab+str(idx)))
1566 self._plotter.plot(ra,dec,marker)
1567
1568 # restore original selection
1569 self._data.set_selection(basesel)
1570 # need to plot scan pattern explicitly
1571 if showline and (stype in ["t", "s"]):
1572 dir = array(self._data.get_directionval()).transpose()
1573 ra = dir[0]*180./pi
1574 dec = dir[1]*180./pi
1575 self._plotter.set_line(label="scan pattern")
1576 self._plotter.plot(ra,dec,":")
[2694]1577 # set color for only this line
1578 self._plotter.lines[-1][0].set_color("gray")
1579
[2693]1580 xlab = 'RA [deg.]'
1581 ylab = 'Declination [deg.]'
1582 self._plotter.set_axes('xlabel', xlab)
1583 self._plotter.set_axes('ylabel', ylab)
1584 self._plotter.set_axes('title', 'Telescope pointings')
1585 if stype: self._plotter.legend(self._legendloc)
1586 else: self._plotter.legend(None)
1587 # reverse x-axis
1588 xmin, xmax = self.gca().get_xlim()
[2989]1589 ymin, ymax = self.gca().get_ylim()
1590 # expand plotrange if xmin==xmax or ymin==ymax
1591 if abs(ymax-ymin) < 1.e-3: #~4arcsec
1592 delx = 0.5*abs(xmax - xmin)
1593 if delx < 5.e-4:
1594 dxy = 5.e-4 #~2arcsec
1595 (ymin, ymax) = (ymin-dxy, ymax+dxy)
1596 (xmin, xmax) = (xmin-dxy, xmax+dxy)
1597 (ymin, ymax) = (ymin-delx, ymax+delx)
1598 elif abs(xmax-xmin) < 1.e-3:
1599 dely = 0.5*abs(ymax - ymin)
1600 (xmin, xmax) = (xmin-dely, xmax+dely)
1601 self._plotter.set_limits(xlim=[xmax,xmin], ylim=[ymin, ymax])
[2693]1602
1603 self._plotter.release()
1604 self._plotter.show(hardrefresh=False)
[2694]1605 # reset line settings
1606 self._plotter.set_line(**attrback)
[2693]1607 return
1608
[1819]1609 def plotpointing(self, scan=None, outfile=None):
[1391]1610 """
1611 plot telescope pointings
1612 """
[1923]1613 visible = rcParams['plotter.gui']
[1696]1614 from matplotlib import pylab as PL
[1819]1615 from numpy import array, pi
[2704]1616 if self._plotter and (PL.gcf() == self._plotter.figure):
[2699]1617 # the current figure is ASAP plotter. Use mpl plotter
1618 figids = PL.get_fignums()
[2704]1619 PL.figure(max(figids[-1],1))
1620
[1923]1621 if not visible or not self._visible:
1622 PL.ioff()
1623 from matplotlib.backends.backend_agg import FigureCanvasAgg
1624 PL.gcf().canvas.switch_backends(FigureCanvasAgg)
[1819]1625 self._data = scan
[1391]1626 dir = array(self._data.get_directionval()).transpose()
1627 ra = dir[0]*180./pi
1628 dec = dir[1]*180./pi
1629 PL.cla()
[1819]1630 #PL.ioff()
[1391]1631 PL.clf()
[2037]1632 # Adjust subplot margins
[2576]1633 if not self._margins or len(self._margins) != 6:
[2037]1634 self.set_margin(refresh=False)
1635 lef, bot, rig, top, wsp, hsp = self._margins
[1819]1636 PL.gcf().subplots_adjust(left=lef,bottom=bot,right=rig,top=top,
1637 wspace=wsp,hspace=hsp)
1638 ax = PL.gca()
1639 #ax = PL.axes([0.1,0.1,0.8,0.8])
1640 #ax = PL.axes([0.1,0.1,0.8,0.8])
[1391]1641 ax.set_aspect('equal')
[1696]1642 PL.plot(ra, dec, 'b,')
[1391]1643 PL.xlabel('RA [deg.]')
1644 PL.ylabel('Declination [deg.]')
1645 PL.title('Telescope pointings')
1646 [xmin,xmax,ymin,ymax] = PL.axis()
1647 PL.axis([xmax,xmin,ymin,ymax])
[2416]1648 PL.ion()
[1391]1649 PL.draw()
[2416]1650 if matplotlib.get_backend() == 'Qt4Agg': PL.gcf().show()
[2576]1651 if (outfile is not None):
1652 PL.savefig(outfile)
[1819]1653
1654 # plot total power data
1655 # plotting in time is not yet implemented..
[1862]1656 @asaplog_post_dec
[2990]1657 def plottp(self, scan=None, colorby=''):
1658 """
1659 Plot averaged spectra (total power) in time or in row ID (colorby='')
1660 Parameters:
1661 scan : input scantable instance
1662 colorby : change color by either
1663 'type'(source type)|'scan'|'if'|'pol'|'beam'|''
1664 """
[2704]1665 self._plotmode = "totalpower"
[1819]1666 from asap import scantable
1667 if not self._data and not scan:
1668 msg = "Input is not a scantable"
1669 raise TypeError(msg)
1670 if isinstance(scan, scantable):
1671 if self._data is not None:
1672 if scan != self._data:
1673 self._data = scan
1674 # reset
1675 self._reset()
1676 else:
1677 self._data = scan
1678 self._reset()
1679 # ranges become invalid when abcissa changes?
1680 #if self._abcunit and self._abcunit != self._data.get_unit():
1681 # self._minmaxx = None
1682 # self._minmaxy = None
1683 # self._abcunit = self._data.get_unit()
1684
[2693]1685 self._assert_plotter(action="reload")
1686 self._plotter.hold()
1687 self._plotter.clear()
[2037]1688 # Adjust subplot margins
[2576]1689 if not self._margins or len(self._margins) !=6:
1690 self.set_margin(refresh=False)
[2037]1691 lef, bot, rig, top, wsp, hsp = self._margins
[1819]1692 self._plotter.figure.subplots_adjust(
1693 left=lef,bottom=bot,right=rig,top=top,wspace=wsp,hspace=hsp)
[2147]1694 if self.casabar_exists(): self._plotter.figmgr.casabar.disable_button()
[2990]1695 if len(colorby) == 0:
1696 self._plottp(self._data)
1697 else:
[2991]1698 self._plottp_in_time(self._data,colorby)
[1819]1699 if self._minmaxy is not None:
1700 self._plotter.set_limits(ylim=self._minmaxy)
1701 self._plotter.release()
1702 self._plotter.tidy()
1703 self._plotter.show(hardrefresh=False)
1704 return
1705
[2991]1706 def _plottp_in_time(self,scan,colorby):
[2990]1707 """
1708 private method for plotting total power data in time
[2991]1709 Parameters:
1710 scan : input scantable instance
1711 colorby : change color by either
1712 'type'(source type)|'scan'|'if'|'pol'|'beam'
[2990]1713 """
1714 from numpy import ma, array, arange, logical_not
1715 r=0
1716 nr = scan.nrow()
1717 a0,b0 = -1,-1
1718 allxlim = []
1719 allylim = []
1720 y=[]
1721 self._plotter.set_panels()
1722 self._plotter.palette(0)
1723 # check of overlay settings
[2992]1724 time_types = ['type','scan'] # time dependent meta-data
1725 misc_types = ['if','pol','beam'] # time independent meta-data
1726 validtypes=time_types + misc_types
[2990]1727 stype = None
[2991]1728 col_msg = "Invalid choice of 'colorby' (choices: %s)" % str(validtypes)
[2992]1729 colorby = colorby.lower()
[2990]1730 if (colorby in validtypes):
1731 stype = colorby[0]
1732 elif len(colorby) > 0:
[2991]1733 raise ValueError(col_msg)
[2990]1734 if not stype:
[2991]1735 raise ValueError(col_msg)
[2992]1736 # Selection and sort order
1737 basesel = scan.get_selection()
1738 if colorby in misc_types: misc_types.pop(misc_types.index(colorby))
1739 sel_lbl = ""
1740 for meta in misc_types:
1741 idx = getattr(scan,'get'+meta+'nos')()
1742 if len(idx) > 1: getattr(basesel, 'set_'+meta+'s')([idx[0]])
1743 sel_lbl += ("%s%d, " % (meta.upper(), idx[0]))
1744 sel_lbl = sel_lbl.rstrip(', ')
1745 scan.set_selection(basesel)
1746 if len(sel_lbl) > 0:
1747 asaplog.push("Selection contains multiple IFs/Pols/Beams. Plotting the first ones: %s" % sel_lbl)
1748 asaplog.post("WARN")
1749 if stype == 't':
[2990]1750 selIds = range(15)
1751 sellab = "src type "
1752 else:
1753 selIds = getattr(scan,'get'+colorby+'nos')()
1754 sellab = colorby.upper()
1755 selFunc = "set_"+colorby+"s"
[2992]1756 basesel.set_order(["TIME"])
1757 # define axes labels
1758 xlab = self._abcissa or 'Time (UTC)'
1759 ylab = self._ordinate or scan._get_ordinate_label()
1760 self._plotter.set_axes('xlabel',xlab)
1761 self._plotter.set_axes('ylabel',ylab)
1762 # define the panel title
1763 if len(sel_lbl) > 0: lbl = sel_lbl
1764 else: lbl = self._get_label(scan, r, 's', self._title)
1765 if isinstance(lbl, list) or isinstance(lbl, tuple):
1766 # get default label
1767 lbl = self._get_label(scan, r, self._panelling, None)
1768 self._plotter.set_axes('title',lbl)
1769 # linestyle
1770 lstyle = '' if colorby in time_types else ':'
[2990]1771 alldates = []
1772 for idx in selIds:
1773 sel = selector() + basesel
[2991]1774 bid = getattr(basesel,'get_'+colorby+"s")()
1775 if (len(bid) > 0) and (not idx in bid):
1776 # base selection doesn't contain idx
1777 # Note summation of selector is logical sum if
1778 continue
1779 getattr(sel, selFunc)([idx])
[2990]1780 if not sel.is_empty():
1781 try:
1782 scan.set_selection(sel)
1783 except RuntimeError, instance:
1784 if stype == 't' and str(instance).startswith("Selection contains no data."):
1785 continue
1786 else:
1787 scan.set_selection(basesel)
1788 raise RuntimeError, instance
1789 if scan.nrow() == 0:
1790 scan.set_selection(basesel)
1791 continue
1792 y=array(scan._get_column(scan._getspectrum,-1))
1793 m = array(scan._get_column(scan._getmask,-1))
1794 y = ma.masked_array(y,mask=logical_not(array(m,copy=False)))
1795 # try to handle spectral data somewhat...
[2991]1796 try:
1797 l,m = y.shape
1798 except ValueError, e:
[2992]1799 raise ValueError(str(e)+" This error usually occurs when you select multiple spws with different number of channels. Try selecting single spw and retry.")
[2990]1800 if m > 1:
1801 y=y.mean(axis=1)
1802 # flag handling
1803 m = [ scan._is_all_chan_flagged(i) for i in range(scan.nrow()) ]
1804 y = ma.masked_array(y,mask=m)
1805 if len(y) == 0: continue
[2992]1806 # line label
1807 llbl=sellab+str(idx)
[2991]1808 from matplotlib.dates import date2num
1809 from pytz import timezone
1810 dates = self._data.get_time(asdatetime=True)
1811 alldates += list(dates)
1812 x = date2num(dates)
1813 tz = timezone('UTC')
[2992]1814 # get color
1815 lc = self._plotter.colormap[self._plotter.color]
1816 self._plotter.palette( (self._plotter.color+1) % len(self._plotter.colormap) )
1817 # actual plotting
1818 self._plotter.axes.plot_date(x,y,tz=tz,label=llbl,linestyle=lstyle,color=lc,
1819 marker='o',markersize=3,markeredgewidth=0)
[2991]1820
[2990]1821 # legend and axis formatting
[2991]1822 ax = self.gca()
[3038]1823 (dstr, timefmt, majloc, minloc) = self._get_date_axis_setup(alldates, ax.get_xlim())
[2991]1824 ax.xaxis.set_major_formatter(timefmt)
1825 ax.xaxis.set_major_locator(majloc)
1826 ax.xaxis.set_minor_locator(minloc)
[2992]1827 self._plotter.axes.legend(loc=self._legendloc)
[2990]1828
[1819]1829 def _plottp(self,scan):
1830 """
1831 private method for plotting total power data
1832 """
1833 from numpy import ma, array, arange, logical_not
1834 r=0
1835 nr = scan.nrow()
1836 a0,b0 = -1,-1
1837 allxlim = []
1838 allylim = []
1839 y=[]
1840 self._plotter.set_panels()
1841 self._plotter.palette(0)
1842 #title
1843 #xlab = self._abcissa and self._abcissa[panelcount] \
1844 # or scan._getabcissalabel()
1845 #ylab = self._ordinate and self._ordinate[panelcount] \
1846 # or scan._get_ordinate_label()
1847 xlab = self._abcissa or 'row number' #or Time
1848 ylab = self._ordinate or scan._get_ordinate_label()
1849 self._plotter.set_axes('xlabel',xlab)
1850 self._plotter.set_axes('ylabel',ylab)
1851 lbl = self._get_label(scan, r, 's', self._title)
1852 if isinstance(lbl, list) or isinstance(lbl, tuple):
1853 # if 0 <= panelcount < len(lbl):
1854 # lbl = lbl[panelcount]
1855 # else:
1856 # get default label
1857 lbl = self._get_label(scan, r, self._panelling, None)
1858 self._plotter.set_axes('title',lbl)
1859 y=array(scan._get_column(scan._getspectrum,-1))
1860 m = array(scan._get_column(scan._getmask,-1))
1861 y = ma.masked_array(y,mask=logical_not(array(m,copy=False)))
1862 x = arange(len(y))
1863 # try to handle spectral data somewhat...
[2992]1864 try:
1865 l,m = y.shape
1866 except ValueError, e:
1867 raise ValueError(str(e)+" This error usually occurs when you select multiple spws with different number of channels. Try selecting single spw and retry.")
[1819]1868 if m > 1:
1869 y=y.mean(axis=1)
[2953]1870 # flag handling
1871 m = [ scan._is_all_chan_flagged(i) for i in range(scan.nrow()) ]
1872 y = ma.masked_array(y,mask=m)
[1819]1873 plotit = self._plotter.plot
1874 llbl = self._get_label(scan, r, self._stacking, None)
1875 self._plotter.set_line(label=llbl)
1876 if len(x) > 0:
1877 plotit(x,y)
1878
1879
1880 # printing header information
[1862]1881 @asaplog_post_dec
[2053]1882 def print_header(self, plot=True, fontsize=9, logger=False, selstr='', extrastr=''):
[1819]1883 """
1884 print data (scantable) header on the plot and/or logger.
[2056]1885 To plot the header on the plot, this method should be called after
1886 plotting spectra by the method, asapplotter.plot.
[1819]1887 Parameters:
[1824]1888 plot: whether or not print header info on the plot.
[2053]1889 fontsize: header font size (valid only plot=True)
[1819]1890 logger: whether or not print header info on the logger.
1891 selstr: additional selection string (not verified)
[2053]1892 extrastr: additional string to print at the beginning (not verified)
[1819]1893 """
[1859]1894 if not plot and not logger:
1895 return
1896 if not self._data:
1897 raise RuntimeError("No scantable has been set yet.")
[1824]1898 # Now header will be printed on plot and/or logger.
1899 # Get header information and format it.
[2112]1900 ssum=self._data._list_header()
[1819]1901 # Print Observation header to the upper-left corner of plot
[2290]1902 headstr=[ssum[0:ssum.find('Obs. Type:')]]
1903 headstr.append(ssum[ssum.find('Obs. Type:'):ssum.find('Flux Unit:')])
[2053]1904 if extrastr != '':
1905 headstr[0]=extrastr+'\n'+headstr[0]
1906 self._headtext['extrastr'] = extrastr
[2112]1907 if selstr != '':
1908 selstr += '\n'
1909 self._headtext['selstr'] = selstr
[2944]1910 #ssel=(selstr+self._data.get_selection().__str__()+self._selection.__str__() or 'none')
[2945]1911 curr_selstr = selstr+self._data.get_selection().__str__() or "none"
1912 ssel=(curr_selstr+"\n" +self._selection.__str__())
[2927]1913 headstr.append('\n\n***Selections***\n'+ssel.replace('$','\$'))
[1824]1914
[2051]1915 if plot:
[2451]1916 errmsg = "Can plot header only after the first call to plot()."
[2453]1917 self._assert_plotter(action="halt",errmsg=errmsg)
[1819]1918 self._plotter.hold()
[2053]1919 self._header_plot(headstr,fontsize=fontsize)
[2697]1920 #import time
1921 #self._plotter.figure.text(0.99,0.01,
1922 # time.strftime("%a %d %b %Y %H:%M:%S %Z"),
1923 # horizontalalignment='right',
1924 # verticalalignment='bottom',fontsize=8)
[1819]1925 self._plotter.release()
1926 if logger:
[2053]1927 selstr = "Selections: "+ssel
[1819]1928 asaplog.push("----------------\n Plot Summary\n----------------")
[2053]1929 asaplog.push(extrastr)
[2290]1930 asaplog.push(ssum[0:ssum.find('Selection:')]\
[2112]1931 + selstr)
[2053]1932 self._headtext['string'] = headstr
1933 del ssel, ssum, headstr
[2051]1934
[2053]1935 def _header_plot(self, texts, fontsize=9):
1936 self._headtext['textobj']=[]
1937 nstcol=len(texts)
1938 for i in range(nstcol):
1939 self._headtext['textobj'].append(
1940 self._plotter.figure.text(0.03+float(i)/nstcol,0.98,
1941 texts[i],
1942 horizontalalignment='left',
1943 verticalalignment='top',
1944 fontsize=fontsize))
1945
1946 def clear_header(self):
1947 if not self._headtext['textobj']:
1948 asaplog.push("No header has been plotted. Exit without any operation")
1949 asaplog.post("WARN")
[2453]1950 elif self._assert_plotter(action="status"):
[2053]1951 self._plotter.hold()
1952 for textobj in self._headtext['textobj']:
1953 #if textobj.get_text() in self._headstring:
1954 try:
1955 textobj.remove()
1956 except NotImplementedError:
1957 self._plotter.figure.texts.pop(self._plotter.figure.texts.index(textobj))
1958 self._plotter.release()
1959 self._reset_header()
[2576]1960
1961 # plot spectra by pointing
1962 @asaplog_post_dec
[2717]1963 def plotgrid(self, scan=None,center="",spacing=[],rows=None,cols=None):
[2576]1964 """
1965 Plot spectra based on direction.
1966
1967 Parameters:
1968 scan: a scantable to plot
[2717]1969 center: the grid center direction (a string)
[2576]1970 (default) the center of map region
[2717]1971 (example) 'J2000 19h30m00s -25d00m00s'
[2576]1972 spacing: a list of horizontal (R.A.) and vertical (Dec.)
[2717]1973 spacing.
[2576]1974 (default) Calculated by the extent of map region and
[2717]1975 (example) ['1arcmin', '1arcmin']
[2576]1976 the number of rows and cols to cover
1977 rows: number of panels (grid points) in horizontal direction
1978 cols: number of panels (grid points) in vertical direction
1979
1980 Note:
1981 - Only the first IFNO, POLNO, and BEAM in the scantable will be
1982 plotted.
1983 - This method doesn't re-grid and average spectra in scantable. Use
1984 asapgrid module to re-grid spectra before plotting with this method.
1985 Only the first spectrum is plotted in case there are multiple
1986 spectra which belong to a grid.
1987 """
[2704]1988 self._plotmode = "grid"
[2576]1989 from asap import scantable
[2607]1990 from numpy import array, ma, cos
[2576]1991 if not self._data and not scan:
1992 msg = "No scantable is specified to plot"
1993 raise TypeError(msg)
[2604]1994 if scan:
1995 self.set_data(scan, refresh=False)
1996 del scan
1997
[2576]1998 # Rows and cols
[2717]1999 if (self._rows is None):
2000 rows = max(1, rows)
2001 if (self._cols is None):
2002 cols = max(1, cols)
2003 self.set_layout(rows,cols,False)
[2576]2004
[2717]2005 # Select the first IF, POL, and BEAM for plotting
[2576]2006 ntotpl = self._rows * self._cols
2007 ifs = self._data.getifnos()
2008 if len(ifs) > 1:
2009 msg = "Found multiple IFs in scantable. Only the first IF (IFNO=%d) will be plotted." % ifs[0]
2010 asaplog.post()
2011 asaplog.push(msg)
2012 asaplog.post("WARN")
2013 pols = self._data.getpolnos()
2014 if len(pols) > 1:
2015 msg = "Found multiple POLs in scantable. Only the first POL (POLNO=%d) will be plotted." % pols[0]
2016 asaplog.post()
2017 asaplog.push(msg)
2018 asaplog.post("WARN")
2019 beams = self._data.getbeamnos()
2020 if len(beams) > 1:
2021 msg = "Found multiple BEAMs in scantable. Only the first BEAM (BEAMNO=%d) will be plotted." % beams[0]
2022 asaplog.post()
2023 asaplog.push(msg)
2024 asaplog.post("WARN")
2025 self._data.set_selection(ifs=[ifs[0]],pols=[pols[0]],beams=[beams[0]])
2026 if self._data.nrow() > ntotpl:
2027 msg = "Scantable is finely sampled than plotting grids. "\
2028 + "Only the first spectrum is plotted in each grid."
2029 asaplog.post()
2030 asaplog.push(msg)
2031 asaplog.post("WARN")
[2717]2032
2033 # Prepare plotter
[2576]2034 self._assert_plotter(action="reload")
2035 self._plotter.hold()
[2697]2036 self._reset_counter()
[2604]2037 self._plotter.legend()
[2691]2038
[2576]2039 # Adjust subplot margins
2040 if not self._margins or len(self._margins) !=6:
2041 self.set_margin(refresh=False)
2042 self._plotter.set_panels(rows=self._rows,cols=self._cols,
[2693]2043 nplots=ntotpl,margin=self._margins,ganged=True)
[2603]2044 if self.casabar_exists():
2045 self._plotter.figmgr.casabar.enable_button()
[2691]2046 # Plot helper
2047 from asap._asap import plothelper as plhelper
2048 ph = plhelper(self._data)
[2717]2049 #ph.set_gridval(self._cols, self._rows, spacing[0], spacing[1],
2050 # center[0], center[1], epoch="J2000", projname="SIN")
2051 if type(spacing) in (list, tuple, array):
2052 if len(spacing) == 0:
2053 spacing = ["", ""]
2054 elif len(spacing) == 1:
2055 spacing = [spacing[0], spacing[0]]
2056 else:
2057 spacing = [spacing, spacing]
2058 ph.set_grid(self._cols, self._rows, spacing[0], spacing[1], \
2059 center, projname="SIN")
2060
[2576]2061 # Actual plot
2062 npl = 0
2063 for irow in range(self._data.nrow()):
[2691]2064 (ix, iy) = ph.get_gpos(irow)
2065 #print("asapplotter.plotgrid: (ix, iy) = (%f, %f)" % (ix, iy))
[2576]2066 if ix < 0 or ix >= self._cols:
[2602]2067 #print "Row %d : Out of X-range (x = %f) ... skipped" % (irow, pos[0])
[2576]2068 continue
[2691]2069 ix = int(ix)
2070 if iy < 0 or iy >= self._rows:
[2602]2071 #print "Row %d : Out of Y-range (y = %f) ... skipped" % (irow,pos[1])
[2576]2072 continue
[2691]2073 iy = int(iy)
2074 ipanel = ix + iy*self._rows
2075 #print("Resolved panel Id (%d, %d): %d" % (ix, iy, ipanel))
[2576]2076 if len(self._plotter.subplots[ipanel]['lines']) > 0:
[2602]2077 #print "Row %d : panel %d lready plotted ... skipped" % (irow,ipanel)
[2576]2078 # a spectrum already plotted in the panel
2079 continue
2080 # Plotting this row
[2602]2081 #print "PLOTTING row %d (panel=%d)" % (irow, ipanel)
[2576]2082 npl += 1
2083 self._plotter.subplot(ipanel)
[2602]2084 self._plotter.palette(0,colormap=self._colormap, \
2085 linestyle=0,linestyles=self._linestyles)
[2576]2086 xlab = self._abcissa and self._abcissa[ipanel] \
[2603]2087 or self._data._getabcissalabel(irow)
[2576]2088 if self._offset and not self._abcissa:
2089 xlab += " (relative)"
2090 ylab = self._ordinate and self._ordinate[ipanel] \
[2603]2091 or self._data._get_ordinate_label()
[2576]2092 self._plotter.set_axes('xlabel', xlab)
2093 self._plotter.set_axes('ylabel', ylab)
2094 lbl = self._data.get_direction(irow)
2095 self._plotter.set_axes('title',lbl)
2096
[2603]2097 y = self._data._getspectrum(irow)
[2576]2098 # flag application
[2603]2099 mr = self._data._getflagrow(irow)
[2576]2100 if mr: # FLAGROW=True
2101 y = ma.masked_array(y,mask=mr)
2102 else:
[2603]2103 m = self._data._getmask(irow)
[2576]2104 from numpy import logical_not, logical_and
2105 ### user mask is not available so far
2106 #if self._maskselection and len(self._usermask) == len(m):
2107 # if d[self._stacking](irow) in self._maskselection[self._stacking]:
2108 # m = logical_and(m, self._usermask)
2109 y = ma.masked_array(y,mask=logical_not(array(m,copy=False)))
2110
[2603]2111 x = array(self._data._getabcissa(irow))
[2576]2112 if self._offset:
2113 x += self._offset
2114 if self._minmaxx is not None:
2115 s,e = self._slice_indeces(x)
2116 x = x[s:e]
2117 y = y[s:e]
2118 if len(x) > 1024 and rcParams['plotter.decimate']:
2119 fac = len(x)/1024
2120 x = x[::fac]
2121 y = y[::fac]
2122 self._plotter.set_line(label=lbl)
2123 plotit = self._plotter.plot
2124 if self._hist: plotit = self._plotter.hist
2125 if len(x) > 0 and not mr:
2126 plotit(x,y)
2127# xlim= self._minmaxx or [min(x),max(x)]
2128# allxlim += xlim
2129# ylim= self._minmaxy or [ma.minimum(y),ma.maximum(y)]
2130# allylim += ylim
2131# else:
2132# xlim = self._minmaxx or []
2133# allxlim += xlim
2134# ylim= self._minmaxy or []
2135# allylim += ylim
2136
2137 if npl >= ntotpl:
2138 break
2139
2140 if self._minmaxy is not None:
2141 self._plotter.set_limits(ylim=self._minmaxy)
2142 self._plotter.release()
2143 self._plotter.tidy()
2144 self._plotter.show(hardrefresh=False)
2145 return
Note: See TracBrowser for help on using the repository browser.