source: trunk/python/asapplotter.py@ 2714

Last change on this file since 2714 was 2714, checked in by Kana Sugimoto, 12 years ago

New Development: No

JIRA Issue: No (a minor fix)

Ready for Test: Yes

Interface Changes: No

What Interface Changed:

Test Programs: unit tests of sdplot

Put in Release Notes: No

Module(s): asapplotter and sdplot

Description: more resetting when new scantable is set to plot.


  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 80.6 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
[1819]519 if refresh and self._data: self.plot(self._data)
[377]520 return
521
[1897]522 def set_range(self,xstart=None,xend=None,ystart=None,yend=None,refresh=True, offset=None):
[203]523 """
524 Set the range of interest on the abcissa of the plot
525 Parameters:
[525]526 [x,y]start,[x,y]end: The start and end points of the 'zoom' window
[1819]527 refresh: True (default) or False. If True, the plot is
[1824]528 replotted based on the new parameter setting(s).
[1819]529 Otherwise,the parameter(s) are set without replotting.
[1897]530 offset: shift the abcissa by the given amount. The abcissa label will
531 have '(relative)' appended to it.
[203]532 Note:
533 These become non-sensical when the unit changes.
534 use plotter.set_range() without parameters to reset
535
536 """
[1897]537 self._offset = offset
[525]538 if xstart is None and xend is None:
539 self._minmaxx = None
[600]540 else:
541 self._minmaxx = [xstart,xend]
[525]542 if ystart is None and yend is None:
543 self._minmaxy = None
[600]544 else:
[709]545 self._minmaxy = [ystart,yend]
[1819]546 if refresh and self._data: self.plot(self._data)
[203]547 return
[709]548
[1819]549 def set_legend(self, mp=None, fontsize = None, mode = 0, refresh=True):
[203]550 """
551 Specify a mapping for the legend instead of using the default
552 indices:
553 Parameters:
[1101]554 mp: a list of 'strings'. This should have the same length
555 as the number of elements on the legend and then maps
556 to the indeces in order. It is possible to uses latex
557 math expression. These have to be enclosed in r'',
558 e.g. r'$x^{2}$'
559 fontsize: The font size of the label (default None)
560 mode: where to display the legend
561 Any other value for loc else disables the legend:
[1096]562 0: auto
563 1: upper right
564 2: upper left
565 3: lower left
566 4: lower right
567 5: right
568 6: center left
569 7: center right
570 8: lower center
571 9: upper center
572 10: center
[1819]573 refresh: True (default) or False. If True, the plot is
[1824]574 replotted based on the new parameter setting(s).
[1819]575 Otherwise,the parameter(s) are set without replotting.
[203]576
577 Example:
[485]578 If the data has two IFs/rest frequencies with index 0 and 1
[203]579 for CO and SiO:
580 plotter.set_stacking('i')
[710]581 plotter.set_legend(['CO','SiO'])
[203]582 plotter.plot()
[710]583 plotter.set_legend([r'$^{12}CO$', r'SiO'])
[203]584 """
585 self._lmap = mp
[2451]586 #self._plotter.legend(mode)
587 self._legendloc = mode
[1101]588 if isinstance(fontsize, int):
589 from matplotlib import rc as rcp
590 rcp('legend', fontsize=fontsize)
[1819]591 if refresh and self._data: self.plot(self._data)
[226]592 return
593
[1819]594 def set_title(self, title=None, fontsize=None, refresh=True):
[710]595 """
[2451]596 Set the title of sub-plots. If multiple sub-plots are plotted,
[710]597 multiple titles have to be specified.
[1819]598 Parameters:
[2451]599 title: a list of titles of sub-plots.
600 fontsize: a font size of titles (integer)
[1819]601 refresh: True (default) or False. If True, the plot is
[1824]602 replotted based on the new parameter setting(s).
[1819]603 Otherwise,the parameter(s) are set without replotting.
[710]604 Example:
605 # two panels are visible on the plotter
[2451]606 plotter.set_title(['First Panel','Second Panel'])
[710]607 """
[226]608 self._title = title
[1101]609 if isinstance(fontsize, int):
610 from matplotlib import rc as rcp
611 rcp('axes', titlesize=fontsize)
[1819]612 if refresh and self._data: self.plot(self._data)
[226]613 return
614
[1819]615 def set_ordinate(self, ordinate=None, fontsize=None, refresh=True):
[710]616 """
617 Set the y-axis label of the plot. If multiple panels are plotted,
618 multiple labels have to be specified.
[1021]619 Parameters:
620 ordinate: a list of ordinate labels. None (default) let
621 data determine the labels
[2451]622 fontsize: a font size of vertical axis labels (integer)
[1819]623 refresh: True (default) or False. If True, the plot is
[1824]624 replotted based on the new parameter setting(s).
[1819]625 Otherwise,the parameter(s) are set without replotting.
[710]626 Example:
627 # two panels are visible on the plotter
[2451]628 plotter.set_ordinate(['First Y-Axis','Second Y-Axis'])
[710]629 """
[257]630 self._ordinate = ordinate
[1101]631 if isinstance(fontsize, int):
632 from matplotlib import rc as rcp
633 rcp('axes', labelsize=fontsize)
634 rcp('ytick', labelsize=fontsize)
[1819]635 if refresh and self._data: self.plot(self._data)
[257]636 return
637
[1819]638 def set_abcissa(self, abcissa=None, fontsize=None, refresh=True):
[710]639 """
640 Set the x-axis label of the plot. If multiple panels are plotted,
641 multiple labels have to be specified.
[1021]642 Parameters:
643 abcissa: a list of abcissa labels. None (default) let
644 data determine the labels
[2451]645 fontsize: a font size of horizontal axis labels (integer)
[1819]646 refresh: True (default) or False. If True, the plot is
[1824]647 replotted based on the new parameter setting(s).
[1819]648 Otherwise,the parameter(s) are set without replotting.
[710]649 Example:
650 # two panels are visible on the plotter
[2451]651 plotter.set_ordinate(['First X-Axis','Second X-Axis'])
[710]652 """
[257]653 self._abcissa = abcissa
[1101]654 if isinstance(fontsize, int):
655 from matplotlib import rc as rcp
656 rcp('axes', labelsize=fontsize)
657 rcp('xtick', labelsize=fontsize)
[1819]658 if refresh and self._data: self.plot(self._data)
[257]659 return
660
[2700]661 def set_histogram(self, hist=True, linewidth=None, refresh=True):
662 """
663 Enable/Disable histogram-like plotting.
664 Parameters:
665 hist: True (default) or False. The fisrt default
666 is taken from the .asaprc setting
667 plotter.histogram
668 linewidth: a line width
669 refresh: True (default) or False. If True, the plot is
670 replotted based on the new parameter setting(s).
671 Otherwise,the parameter(s) are set without replotting.
672 """
673 self._hist = hist
674 if isinstance(linewidth, float) or isinstance(linewidth, int):
675 from matplotlib import rc as rcp
676 rcp('lines', linewidth=linewidth)
677 if refresh and self._data: self.plot(self._data)
678
[1819]679 def set_colors(self, colmap, refresh=True):
[377]680 """
[1217]681 Set the colours to be used. The plotter will cycle through
682 these colours when lines are overlaid (stacking mode).
[1021]683 Parameters:
[1217]684 colmap: a list of colour names
[1819]685 refresh: True (default) or False. If True, the plot is
[1824]686 replotted based on the new parameter setting(s).
[1819]687 Otherwise,the parameter(s) are set without replotting.
[710]688 Example:
[2451]689 plotter.set_colors('red green blue')
[710]690 # If for example four lines are overlaid e.g I Q U V
691 # 'I' will be 'red', 'Q' will be 'green', U will be 'blue'
692 # and 'V' will be 'red' again.
693 """
[2451]694 #if isinstance(colmap,str):
695 # colmap = colmap.split()
696 #self._plotter.palette(0, colormap=colmap)
697 self._colormap = colmap
[1819]698 if refresh and self._data: self.plot(self._data)
[710]699
[1217]700 # alias for english speakers
701 set_colours = set_colors
702
[1819]703 def set_linestyles(self, linestyles=None, linewidth=None, refresh=True):
[710]704 """
[734]705 Set the linestyles to be used. The plotter will cycle through
706 these linestyles when lines are overlaid (stacking mode) AND
707 only one color has been set.
[710]708 Parameters:
[2451]709 linestyles: a list of linestyles to use.
[710]710 'line', 'dashed', 'dotted', 'dashdot',
711 'dashdotdot' and 'dashdashdot' are
712 possible
[2451]713 linewidth: a line width
[1819]714 refresh: True (default) or False. If True, the plot is
[1824]715 replotted based on the new parameter setting(s).
[1819]716 Otherwise,the parameter(s) are set without replotting.
[710]717 Example:
[2451]718 plotter.set_colors('black')
719 plotter.set_linestyles('line dashed dotted dashdot')
[710]720 # If for example four lines are overlaid e.g I Q U V
721 # 'I' will be 'solid', 'Q' will be 'dashed',
722 # U will be 'dotted' and 'V' will be 'dashdot'.
723 """
[2451]724 #if isinstance(linestyles,str):
725 # linestyles = linestyles.split()
726 #self._plotter.palette(color=0,linestyle=0,linestyles=linestyles)
727 self._linestyles = linestyles
[1101]728 if isinstance(linewidth, float) or isinstance(linewidth, int):
729 from matplotlib import rc as rcp
730 rcp('lines', linewidth=linewidth)
[1819]731 if refresh and self._data: self.plot(self._data)
[710]732
[1819]733 def set_font(self, refresh=True,**kwargs):
[1101]734 """
735 Set font properties.
736 Parameters:
737 family: one of 'sans-serif', 'serif', 'cursive', 'fantasy', 'monospace'
738 style: one of 'normal' (or 'roman'), 'italic' or 'oblique'
739 weight: one of 'normal or 'bold'
740 size: the 'general' font size, individual elements can be adjusted
741 seperately
[1819]742 refresh: True (default) or False. If True, the plot is
[1824]743 replotted based on the new parameter setting(s).
[1819]744 Otherwise,the parameter(s) are set without replotting.
[1101]745 """
746 from matplotlib import rc as rcp
[1547]747 fdict = {}
748 for k,v in kwargs.iteritems():
749 if v:
750 fdict[k] = v
[1556]751 self._fp = FontProperties(**fdict)
[1819]752 if refresh and self._data: self.plot(self._data)
[1101]753
[2037]754 def set_margin(self,margin=[],refresh=True):
[1819]755 """
[2037]756 Set margins between subplots and plot edges.
[1819]757 Parameters:
[2037]758 margin: a list of margins in figure coordinate (0-1),
[1824]759 i.e., fraction of the figure width or height.
[1819]760 The order of elements should be:
761 [left, bottom, right, top, horizontal space btw panels,
[1824]762 vertical space btw panels].
[1819]763 refresh: True (default) or False. If True, the plot is
[1824]764 replotted based on the new parameter setting(s).
[1819]765 Otherwise,the parameter(s) are set without replotting.
766 Note
[2037]767 * When margin is not specified, the values are reset to the defaults
[1819]768 of matplotlib.
[1824]769 * If any element is set to be None, the current value is adopted.
[1819]770 """
[2037]771 if margin == []: self._margins=self._reset_margin()
[1824]772 else:
[2037]773 self._margins=[None]*6
774 self._margins[0:len(margin)]=margin
775 #print "panel margin set to ",self._margins
[1819]776 if refresh and self._data: self.plot(self._data)
777
[2037]778 def _reset_margin(self):
[1819]779 ks=map(lambda x: 'figure.subplot.'+x,
780 ['left','bottom','right','top','hspace','wspace'])
781 return map(matplotlib.rcParams.get,ks)
782
[1259]783 def plot_lines(self, linecat=None, doppler=0.0, deltachan=10, rotate=90.0,
[1146]784 location=None):
785 """
[1158]786 Plot a line catalog.
787 Parameters:
788 linecat: the linecatalog to plot
[1168]789 doppler: the velocity shift to apply to the frequencies
[1158]790 deltachan: the number of channels to include each side of the
791 line to determine a local maximum/minimum
[1927]792 rotate: the rotation (in degrees) for the text label (default 90.0)
[1158]793 location: the location of the line annotation from the 'top',
794 'bottom' or alternate (None - the default)
[1165]795 Notes:
796 If the spectrum is flagged no line will be drawn in that location.
[1146]797 """
[2451]798 errmsg = "Cannot plot spectral lines. Need to plot scantable first."
[2453]799 self._assert_plotter(action="halt",errmsg=errmsg)
[1259]800 if not self._data:
801 raise RuntimeError("No scantable has been plotted yet.")
[1146]802 from asap._asap import linecatalog
[1259]803 if not isinstance(linecat, linecatalog):
804 raise ValueError("'linecat' isn't of type linecatalog.")
805 if not self._data.get_unit().endswith("Hz"):
806 raise RuntimeError("Can only overlay linecatalogs when data is in frequency.")
[1739]807 from numpy import ma
[1146]808 for j in range(len(self._plotter.subplots)):
809 self._plotter.subplot(j)
810 lims = self._plotter.axes.get_xlim()
[1153]811 for row in range(linecat.nrow()):
[1259]812 # get_frequency returns MHz
813 base = { "GHz": 1000.0, "MHz": 1.0, "Hz": 1.0e-6 }
814 restf = linecat.get_frequency(row)/base[self._data.get_unit()]
[1165]815 c = 299792.458
[1174]816 freq = restf*(1.0-doppler/c)
[1146]817 if lims[0] < freq < lims[1]:
818 if location is None:
819 loc = 'bottom'
[1153]820 if row%2: loc='top'
[1146]821 else: loc = location
[1153]822 maxys = []
823 for line in self._plotter.axes.lines:
824 v = line._x
825 asc = v[0] < v[-1]
826
827 idx = None
828 if not asc:
829 if v[len(v)-1] <= freq <= v[0]:
830 i = len(v)-1
831 while i>=0 and v[i] < freq:
832 idx = i
833 i-=1
834 else:
835 if v[0] <= freq <= v[len(v)-1]:
836 i = 0
837 while i<len(v) and v[i] < freq:
838 idx = i
839 i+=1
840 if idx is not None:
841 lower = idx - deltachan
842 upper = idx + deltachan
843 if lower < 0: lower = 0
844 if upper > len(v): upper = len(v)
845 s = slice(lower, upper)
[1167]846 y = line._y[s]
[1165]847 maxy = ma.maximum(y)
848 if isinstance( maxy, float):
849 maxys.append(maxy)
[1164]850 if len(maxys):
851 peak = max(maxys)
[1165]852 if peak > self._plotter.axes.get_ylim()[1]:
853 loc = 'bottom'
[1164]854 else:
855 continue
[1157]856 self._plotter.vline_with_label(freq, peak,
857 linecat.get_name(row),
858 location=loc, rotate=rotate)
[1153]859 self._plotter.show(hardrefresh=False)
[1146]860
[1153]861
[2698]862 def set_selection(self, selection=None, refresh=True, **kw):
[710]863 """
[377]864 Parameters:
[2698]865 selection: a selector object (default unset the selection)
866 refresh: True (default) or False. If True, the plot is
867 replotted based on the new parameter setting(s).
868 Otherwise,the parameter(s) are set without replotting.
[377]869 """
[2698]870 if selection is None:
871 # reset
872 if len(kw) == 0:
873 self._selection = selector()
874 else:
875 # try keywords
876 for k in kw:
877 if k not in selector.fields:
878 raise KeyError("Invalid selection key '%s', valid keys are %s" % (k, selector.fields))
879 self._selection = selector(**kw)
880 elif isinstance(selection, selector):
881 self._selection = selection
882 else:
883 raise TypeError("'selection' is not of type selector")
[709]884
[2698]885 order = self._get_sortstring([self._panelling,self._stacking])
886 if order:
887 self._selection.set_order(order)
888 if refresh and self._data:
889 self.plot()
890
[1862]891 @asaplog_post_dec
[1819]892 def set_mask(self, mask=None, selection=None, refresh=True):
[525]893 """
[734]894 Set a plotting mask for a specific polarization.
[2451]895 This is useful for masking out 'noise' Pangle outside a source.
[734]896 Parameters:
[920]897 mask: a mask from scantable.create_mask
898 selection: the spectra to apply the mask to.
[1819]899 refresh: True (default) or False. If True, the plot is
[1824]900 replotted based on the new parameter setting(s).
[1819]901 Otherwise,the parameter(s) are set without replotting.
[734]902 Example:
[920]903 select = selector()
[2451]904 select.setpolstrings('Pangle')
[920]905 plotter.set_mask(mymask, select)
[734]906 """
[710]907 if not self._data:
[920]908 msg = "Can only set mask after a first call to plot()"
[1859]909 raise RuntimeError(msg)
[2714]910 if (mask is not None) and len(mask):
[920]911 if isinstance(mask, list) or isinstance(mask, tuple):
912 self._usermask = array(mask)
[710]913 else:
[920]914 self._usermask = mask
915 if mask is None and selection is None:
916 self._usermask = []
917 self._maskselection = None
918 if isinstance(selection, selector):
[947]919 self._maskselection = {'b': selection.get_beams(),
920 's': selection.get_scans(),
921 'i': selection.get_ifs(),
922 'p': selection.get_pols(),
[920]923 't': [] }
[710]924 else:
[920]925 self._maskselection = None
[1819]926 if refresh: self.plot(self._data)
[710]927
[709]928
[2699]929 ### Reset methods ###
[710]930 def _reset(self):
[2714]931 """Reset method called when new data is set"""
932 # reset selections and masks
933 self.set_selection(None, False)
934 self.set_mask(None, None, False)
935 # reset offset
[1897]936 self._offset = None
[2714]937 # reset header
[2051]938 self._reset_header()
[2714]939 # reset labels
940 self._lmap = None # related to stack
941 self.set_title(None, None, False)
942 self.set_ordinate(None, None, False)
943 self.set_abcissa(None, None, False)
[920]944
[2051]945 def _reset_header(self):
[2053]946 self._headtext={'string': None, 'textobj': None}
[2051]947
[2697]948 def _reset_counter(self):
949 self._startrow = 0
950 self._ipanel = -1
951 self._reset_header()
952 self._panelrows = []
953 if self.casabar_exists():
954 self._plotter.figmgr.casabar.set_pagecounter(1)
955
[2698]956 def _reset_counters(self):
957 self._startrow = 0
958 self._ipanel = -1
959 self._panelrows = []
960
[2699]961
962 ### Actual scantable plot methods ###
[2698]963 @asaplog_post_dec
964 def plot(self, scan=None):
965 """
966 Plot a scantable.
967 Parameters:
968 scan: a scantable
969 Note:
970 If a scantable was specified in a previous call
971 to plot, no argument has to be given to 'replot'
972 NO checking is done that the abcissas of the scantable
973 are consistent e.g. all 'channel' or all 'velocity' etc.
974 """
[2704]975 self._plotmode = "spectra"
[2698]976 if not self._data and not scan:
977 msg = "Input is not a scantable"
978 raise TypeError(msg)
979
980 self._assert_plotter(action="reload")
981 self._plotter.hold()
982 self._reset_counter()
983 #self._plotter.clear()
984 if scan:
985 self.set_data(scan, refresh=False)
986 self._plotter.palette(color=0,colormap=self._colormap,
987 linestyle=0,linestyles=self._linestyles)
988 self._plotter.legend(self._legendloc)
989 self._plot(self._data)
990 if self._minmaxy is not None:
991 self._plotter.set_limits(ylim=self._minmaxy)
992 if self.casabar_exists(): self._plotter.figmgr.casabar.enable_button()
993 self._plotter.release()
994 self._plotter.tidy()
995 self._plotter.show(hardrefresh=False)
996 return
997
[920]998 def _plot(self, scan):
[947]999 savesel = scan.get_selection()
1000 sel = savesel + self._selection
[1910]1001 order = self._get_sortstring([self._panelling,self._stacking])
1002 if order:
1003 sel.set_order(order)
[947]1004 scan.set_selection(sel)
[920]1005 d = {'b': scan.getbeam, 's': scan.getscan,
[1949]1006 'i': scan.getif, 'p': scan.getpol, 't': scan.get_time,
[1989]1007 'r': int}#, '_r': int}
[920]1008
[2650]1009 polmodes = dict(zip(sel.get_pols(), sel.get_poltypes()))
[1148]1010 # this returns either a tuple of numbers or a length (ncycles)
1011 # convert this into lengths
1012 n0,nstack0 = self._get_selected_n(scan)
1013 if isinstance(n0, int): n = n0
[1175]1014 else: n = len(n0)
[1148]1015 if isinstance(nstack0, int): nstack = nstack0
[1175]1016 else: nstack = len(nstack0)
[1989]1017 # In case of row stacking
1018 rowstack = False
1019 titlemode = self._panelling
1020 if self._stacking == "r" and self._panelling != "r":
1021 rowstack = True
1022 titlemode = '_r'
[1913]1023 nptot = n
[1582]1024 maxpanel, maxstack = 16,16
[1913]1025 if nstack > maxstack:
1026 msg ="Scan to be overlayed contains more than %d selections.\n" \
1027 "Selecting first %d selections..." % (maxstack, maxstack)
[920]1028 asaplog.push(msg)
[1861]1029 asaplog.post('WARN')
[998]1030 nstack = min(nstack,maxstack)
[2038]1031 #n = min(n-self._ipanel-1,maxpanel)
1032 n = n-self._ipanel-1
[2697]1033 # the number of panels in this page
1034 if self._rows and self._cols:
1035 n = min(n,self._rows*self._cols)
1036 else:
1037 n = min(n,maxpanel)
[2011]1038
[2697]1039 firstpage = (self._ipanel < 0)
1040 #ganged = False
1041 ganged = rcParams['plotter.ganged']
1042 if self._panelling == 'i':
1043 ganged = False
1044 if not firstpage:
1045 # not the first page just clear the axis
1046 nx = self._plotter.cols
1047 ipaxx = n - nx - 1 #the max panel id to supress x-label
1048 for ip in xrange(len(self._plotter.subplots)):
1049 self._plotter.subplot(ip)
1050 self._plotter.clear()
1051 self._plotter.axes.set_visible((ip<n))
1052 if ganged:
1053 self._plotter.axes.xaxis.label.set_visible((ip > ipaxx))
1054 if ip <= ipaxx:
1055 map(lambda x: x.set_visible(False), \
1056 self._plotter.axes.get_xticklabels())
1057 self._plotter.axes.yaxis.label.set_visible((ip % nx)==0)
1058 if ip % nx:
1059 map(lambda y: y.set_visible(False), \
1060 self._plotter.axes.get_yticklabels())
1061 elif (n > 1 and self._rows and self._cols):
[920]1062 self._plotter.set_panels(rows=self._rows,cols=self._cols,
[2650]1063 nplots=n,margin=self._margins,
1064 ganged=ganged)
[920]1065 else:
[2697]1066 self._plotter.set_panels(rows=n,cols=0,nplots=n,
1067 margin=self._margins,ganged=ganged)
[1913]1068 #r = 0
[1981]1069 r = self._startrow
[920]1070 nr = scan.nrow()
1071 a0,b0 = -1,-1
1072 allxlim = []
[1018]1073 allylim = []
[1981]1074 #newpanel=True
1075 newpanel=False
[920]1076 panelcount,stackcount = 0,0
[1981]1077 # If this is not the first page
1078 if r > 0:
1079 # panelling value of the prev page
1080 a0 = d[self._panelling](r-1)
1081 # set the initial stackcount large not to plot
1082 # the start row automatically
1083 stackcount = nstack
1084
[1002]1085 while r < nr:
[920]1086 a = d[self._panelling](r)
1087 b = d[self._stacking](r)
1088 if a > a0 and panelcount < n:
1089 if n > 1:
1090 self._plotter.subplot(panelcount)
1091 self._plotter.palette(0)
1092 #title
1093 xlab = self._abcissa and self._abcissa[panelcount] \
1094 or scan._getabcissalabel()
[1897]1095 if self._offset and not self._abcissa:
1096 xlab += " (relative)"
[920]1097 ylab = self._ordinate and self._ordinate[panelcount] \
1098 or scan._get_ordinate_label()
[1547]1099 self._plotter.set_axes('xlabel', xlab)
1100 self._plotter.set_axes('ylabel', ylab)
[1989]1101 #lbl = self._get_label(scan, r, self._panelling, self._title)
1102 lbl = self._get_label(scan, r, titlemode, self._title)
[920]1103 if isinstance(lbl, list) or isinstance(lbl, tuple):
1104 if 0 <= panelcount < len(lbl):
1105 lbl = lbl[panelcount]
1106 else:
1107 # get default label
[1989]1108 #lbl = self._get_label(scan, r, self._panelling, None)
1109 lbl = self._get_label(scan, r, titlemode, None)
[920]1110 self._plotter.set_axes('title',lbl)
1111 newpanel = True
[1913]1112 stackcount = 0
[920]1113 panelcount += 1
[1981]1114 # save the start row to plot this panel for future revisit.
1115 if self._panelling != 'r' and \
1116 len(self._panelrows) < self._ipanel+1+panelcount:
1117 self._panelrows += [r]
1118
[1944]1119 #if (b > b0 or newpanel) and stackcount < nstack:
[2650]1120 if stackcount < nstack and (newpanel or \
1121 rowstack or (a == a0 and b > b0)):
[920]1122 y = []
1123 if len(polmodes):
1124 y = scan._getspectrum(r, polmodes[scan.getpol(r)])
1125 else:
1126 y = scan._getspectrum(r)
[1995]1127 # flag application
1128 mr = scan._getflagrow(r)
[1739]1129 from numpy import ma, array
[1995]1130 if mr:
1131 y = ma.masked_array(y,mask=mr)
1132 else:
1133 m = scan._getmask(r)
1134 from numpy import logical_not, logical_and
1135 if self._maskselection and len(self._usermask) == len(m):
[2277]1136 if d[self._stacking](r) in self._maskselection[self._stacking]:
[1995]1137 m = logical_and(m, self._usermask)
[2277]1138 y = ma.masked_array(y,mask=logical_not(array(m,copy=False)))
[1995]1139
[1897]1140 x = array(scan._getabcissa(r))
1141 if self._offset:
1142 x += self._offset
[920]1143 if self._minmaxx is not None:
1144 s,e = self._slice_indeces(x)
1145 x = x[s:e]
1146 y = y[s:e]
[1096]1147 if len(x) > 1024 and rcParams['plotter.decimate']:
1148 fac = len(x)/1024
[920]1149 x = x[::fac]
1150 y = y[::fac]
1151 llbl = self._get_label(scan, r, self._stacking, self._lmap)
1152 if isinstance(llbl, list) or isinstance(llbl, tuple):
1153 if 0 <= stackcount < len(llbl):
1154 # use user label
1155 llbl = llbl[stackcount]
1156 else:
1157 # get default label
1158 llbl = self._get_label(scan, r, self._stacking, None)
1159 self._plotter.set_line(label=llbl)
[1023]1160 plotit = self._plotter.plot
1161 if self._hist: plotit = self._plotter.hist
[1995]1162 if len(x) > 0 and not mr:
[1146]1163 plotit(x,y)
1164 xlim= self._minmaxx or [min(x),max(x)]
1165 allxlim += xlim
1166 ylim= self._minmaxy or [ma.minimum(y),ma.maximum(y)]
1167 allylim += ylim
[1819]1168 else:
1169 xlim = self._minmaxx or []
1170 allxlim += xlim
1171 ylim= self._minmaxy or []
1172 allylim += ylim
[920]1173 stackcount += 1
[1981]1174 a0=a
1175 b0=b
[920]1176 # last in colour stack -> autoscale x
[1819]1177 if stackcount == nstack and len(allxlim) > 0:
[920]1178 allxlim.sort()
[1819]1179 self._plotter.subplots[panelcount-1]['axes'].set_xlim([allxlim[0],allxlim[-1]])
[1989]1180 if ganged:
1181 allxlim = [allxlim[0],allxlim[-1]]
1182 else:
1183 # clear
1184 allxlim =[]
[920]1185
1186 newpanel = False
[1981]1187 #a0=a
1188 #b0=b
[920]1189 # ignore following rows
[1981]1190 if (panelcount == n and stackcount == nstack) or (r == nr-1):
[1018]1191 # last panel -> autoscale y if ganged
[1989]1192 #if rcParams['plotter.ganged'] and len(allylim) > 0:
1193 if ganged and len(allylim) > 0:
[1018]1194 allylim.sort()
1195 self._plotter.set_limits(ylim=[allylim[0],allylim[-1]])
[998]1196 break
[920]1197 r+=1 # next row
[1981]1198
1199 # save the current counter for multi-page plotting
1200 self._startrow = r+1
1201 self._ipanel += panelcount
[2147]1202 if self.casabar_exists():
[1981]1203 if self._ipanel >= nptot-1:
[1913]1204 self._plotter.figmgr.casabar.disable_next()
1205 else:
1206 self._plotter.figmgr.casabar.enable_next()
[1981]1207 if self._ipanel + 1 - panelcount > 0:
1208 self._plotter.figmgr.casabar.enable_prev()
1209 else:
1210 self._plotter.figmgr.casabar.disable_prev()
1211
[947]1212 #reset the selector to the scantable's original
1213 scan.set_selection(savesel)
[1824]1214
[1819]1215 #temporary switch-off for older matplotlib
1216 #if self._fp is not None:
[2698]1217 if self._fp is not None and \
1218 getattr(self._plotter.figure,'findobj',False):
[1556]1219 for o in self._plotter.figure.findobj(Text):
[2697]1220 if not self._headtext['textobj'] or \
1221 not (o in self._headtext['textobj']):
1222 o.set_fontproperties(self._fp)
[920]1223
[1910]1224 def _get_sortstring(self, lorders):
1225 d0 = {'s': 'SCANNO', 'b': 'BEAMNO', 'i':'IFNO',
1226 'p': 'POLNO', 'c': 'CYCLENO', 't' : 'TIME', 'r':None, '_r':None }
[1944]1227 if not (type(lorders) == list) and not (type(lorders) == tuple):
[1910]1228 return None
1229 if len(lorders) > 0:
1230 lsorts = []
1231 for order in lorders:
[1989]1232 if order == "r":
1233 # don't sort if row panelling/stacking
1234 return None
[1910]1235 ssort = d0[order]
1236 if ssort:
1237 lsorts.append(ssort)
1238 return lsorts
1239 return None
1240
[920]1241 def _get_selected_n(self, scan):
[1148]1242 d1 = {'b': scan.getbeamnos, 's': scan.getscannos,
[1910]1243 'i': scan.getifnos, 'p': scan.getpolnos, 't': scan.ncycle,
[1989]1244 'r': scan.nrow}#, '_r': False}
[1148]1245 d2 = { 'b': self._selection.get_beams(),
1246 's': self._selection.get_scans(),
1247 'i': self._selection.get_ifs(),
1248 'p': self._selection.get_pols(),
[1910]1249 't': self._selection.get_cycles(),
[1989]1250 'r': False}#, '_r': 1}
[920]1251 n = d2[self._panelling] or d1[self._panelling]()
1252 nstack = d2[self._stacking] or d1[self._stacking]()
[1989]1253 # handle row panelling/stacking
1254 if self._panelling == 'r':
1255 nstack = 1
1256 elif self._stacking == 'r':
1257 n = 1
[920]1258 return n,nstack
1259
1260 def _get_label(self, scan, row, mode, userlabel=None):
[1153]1261 if isinstance(userlabel, list) and len(userlabel) == 0:
1262 userlabel = " "
[947]1263 pms = dict(zip(self._selection.get_pols(),self._selection.get_poltypes()))
[920]1264 if len(pms):
1265 poleval = scan._getpollabel(scan.getpol(row),pms[scan.getpol(row)])
1266 else:
1267 poleval = scan._getpollabel(scan.getpol(row),scan.poltype())
1268 d = {'b': "Beam "+str(scan.getbeam(row)),
[1819]1269 #'s': scan._getsourcename(row),
1270 's': "Scan "+str(scan.getscan(row))+\
1271 " ("+str(scan._getsourcename(row))+")",
[920]1272 'i': "IF"+str(scan.getif(row)),
[964]1273 'p': poleval,
[1910]1274 't': str(scan.get_time(row)),
1275 'r': "row "+str(row),
[1913]1276 #'_r': str(scan.get_time(row))+",\nIF"+str(scan.getif(row))+", "+poleval+", Beam"+str(scan.getbeam(row)) }
1277 '_r': "" }
[920]1278 return userlabel or d[mode]
[1153]1279
[2700]1280 def _slice_indeces(self, data):
1281 mn = self._minmaxx[0]
1282 mx = self._minmaxx[1]
1283 asc = data[0] < data[-1]
1284 start=0
1285 end = len(data)-1
1286 inc = 1
1287 if not asc:
1288 start = len(data)-1
1289 end = 0
1290 inc = -1
1291 # find min index
1292 #while start > 0 and data[start] < mn:
1293 # start+= inc
1294 minind=start
1295 for ind in xrange(start,end+inc,inc):
1296 if data[ind] > mn: break
1297 minind=ind
1298 # find max index
1299 #while end > 0 and data[end] > mx:
1300 # end-=inc
1301 #if end > 0: end +=1
1302 maxind=end
1303 for ind in xrange(end,start-inc,-inc):
1304 if data[ind] < mx: break
1305 maxind=ind
1306 start=minind
1307 end=maxind
1308 if start > end:
1309 return end,start+1
1310 elif start < end:
1311 return start,end+1
1312 else:
1313 return start,end
1314
[1819]1315 def plotazel(self, scan=None, outfile=None):
[1391]1316 """
[1696]1317 plot azimuth and elevation versus time of a scantable
[1391]1318 """
[2704]1319 self._plotmode = "azel"
[1923]1320 visible = rcParams['plotter.gui']
[1696]1321 from matplotlib import pylab as PL
[2586]1322 from matplotlib.dates import DateFormatter
1323 from pytz import timezone
[1696]1324 from matplotlib.dates import HourLocator, MinuteLocator,SecondLocator, DayLocator
[1391]1325 from matplotlib.ticker import MultipleLocator
[1739]1326 from numpy import array, pi
[2704]1327 if self._plotter and (PL.gcf() == self._plotter.figure):
[2699]1328 # the current figure is ASAP plotter. Use mpl plotter
1329 figids = PL.get_fignums()
[2704]1330 PL.figure(max(figids[-1],1))
1331
[1923]1332 if not visible or not self._visible:
1333 PL.ioff()
1334 from matplotlib.backends.backend_agg import FigureCanvasAgg
1335 PL.gcf().canvas.switch_backends(FigureCanvasAgg)
[1819]1336 self._data = scan
[1556]1337 dates = self._data.get_time(asdatetime=True)
[1391]1338 t = PL.date2num(dates)
1339 tz = timezone('UTC')
1340 PL.cla()
1341 PL.ioff()
1342 PL.clf()
[2037]1343 # Adjust subplot margins
[2576]1344 if not self._margins or len(self._margins) != 6:
[2037]1345 self.set_margin(refresh=False)
1346 lef, bot, rig, top, wsp, hsp = self._margins
[1819]1347 PL.gcf().subplots_adjust(left=lef,bottom=bot,right=rig,top=top,
1348 wspace=wsp,hspace=hsp)
[1824]1349
[1391]1350 tdel = max(t) - min(t)
1351 ax = PL.subplot(2,1,1)
1352 el = array(self._data.get_elevation())*180./pi
1353 PL.ylabel('El [deg.]')
1354 dstr = dates[0].strftime('%Y/%m/%d')
1355 if tdel > 1.0:
1356 dstr2 = dates[len(dates)-1].strftime('%Y/%m/%d')
1357 dstr = dstr + " - " + dstr2
1358 majloc = DayLocator()
1359 minloc = HourLocator(range(0,23,12))
1360 timefmt = DateFormatter("%b%d")
[1696]1361 elif tdel > 24./60.:
1362 timefmt = DateFormatter('%H:%M')
1363 majloc = HourLocator()
1364 minloc = MinuteLocator(30)
[1391]1365 else:
[1696]1366 timefmt = DateFormatter('%H:%M')
1367 majloc = MinuteLocator(interval=5)
1368 minloc = SecondLocator(30)
1369
[1391]1370 PL.title(dstr)
[1819]1371 if tdel == 0.0:
1372 th = (t - PL.floor(t))*24.0
1373 PL.plot(th,el,'o',markersize=2, markerfacecolor='b', markeredgecolor='b')
1374 else:
1375 PL.plot_date(t,el,'o', markersize=2, markerfacecolor='b', markeredgecolor='b',tz=tz)
1376 #ax.grid(True)
1377 ax.xaxis.set_major_formatter(timefmt)
1378 ax.xaxis.set_major_locator(majloc)
1379 ax.xaxis.set_minor_locator(minloc)
[1391]1380 ax.yaxis.grid(True)
[1819]1381 yloc = MultipleLocator(30)
1382 ax.set_ylim(0,90)
1383 ax.yaxis.set_major_locator(yloc)
[1391]1384 if tdel > 1.0:
1385 labels = ax.get_xticklabels()
1386 # PL.setp(labels, fontsize=10, rotation=45)
1387 PL.setp(labels, fontsize=10)
[1819]1388
[1391]1389 # Az plot
1390 az = array(self._data.get_azimuth())*180./pi
1391 if min(az) < 0:
1392 for irow in range(len(az)):
1393 if az[irow] < 0: az[irow] += 360.0
1394
[1819]1395 ax2 = PL.subplot(2,1,2)
1396 #PL.xlabel('Time (UT [hour])')
1397 PL.ylabel('Az [deg.]')
1398 if tdel == 0.0:
1399 PL.plot(th,az,'o',markersize=2, markeredgecolor='b',markerfacecolor='b')
1400 else:
1401 PL.plot_date(t,az,'o', markersize=2,markeredgecolor='b',markerfacecolor='b',tz=tz)
1402 ax2.xaxis.set_major_formatter(timefmt)
1403 ax2.xaxis.set_major_locator(majloc)
1404 ax2.xaxis.set_minor_locator(minloc)
1405 #ax2.grid(True)
1406 ax2.set_ylim(0,360)
[1696]1407 ax2.yaxis.grid(True)
[1819]1408 #hfmt = DateFormatter('%H')
1409 #hloc = HourLocator()
1410 yloc = MultipleLocator(60)
1411 ax2.yaxis.set_major_locator(yloc)
1412 if tdel > 1.0:
1413 labels = ax2.get_xticklabels()
1414 PL.setp(labels, fontsize=10)
1415 PL.xlabel('Time (UT [day])')
1416 else:
1417 PL.xlabel('Time (UT [hour])')
1418
[1391]1419 PL.ion()
1420 PL.draw()
[2416]1421 if matplotlib.get_backend() == 'Qt4Agg': PL.gcf().show()
[2576]1422 if (outfile is not None):
1423 PL.savefig(outfile)
[1391]1424
[2693]1425
1426 def plotpointing2(self, scan=None, colorby='', showline=False, projection=''):
1427 """
1428 plot telescope pointings
1429 Parameters:
1430 infile : input filename or scantable instance
1431 colorby : change color by either
1432 'type'(source type)|'scan'|'if'|'pol'|'beam'
1433 showline : show dotted line
1434 projection : projection type either
1435 ''(no projection [deg])|'coord'(not implemented)
1436 """
[2704]1437 self._plotmode = "pointing"
[2693]1438 from numpy import array, pi
1439 from asap import scantable
1440 # check for scantable
1441 if isinstance(scan, scantable):
1442 if self._data is not None:
1443 if scan != self._data:
1444 self._data = scan
1445 # reset
1446 self._reset()
1447 else:
1448 self._data = scan
1449 self._reset()
1450 if not self._data:
1451 msg = "Input is not a scantable"
1452 raise TypeError(msg)
1453 # check for color mode
1454 validtypes=['type','scan','if','pol', 'beam']
1455 stype = None
1456 if (colorby in validtypes):
1457 stype = colorby[0]
1458 elif len(colorby) > 0:
1459 msg = "Invalid choice of 'colorby' (choices: %s)" % str(validtypes)
1460 raise ValueError(msg)
1461 self._assert_plotter(action="reload")
1462 self._plotter.hold()
[2697]1463 self._reset_counter()
[2694]1464 if self.casabar_exists():
1465 self._plotter.figmgr.casabar.disable_button()
[2693]1466 # for now, only one plot
1467 self._plotter.set_panels(rows=1,cols=1)
1468 # first panel
1469 self._plotter.subplot(0)
1470 # first color and linestyles
1471 self._plotter.palette(0)
1472 self.gca().set_aspect('equal')
1473 basesel = scan.get_selection()
[2694]1474 attrback = self._plotter.get_line()
1475 marker = "o"
[2693]1476 if showline:
1477 basesel.set_order(["TIME"])
1478 scan.set_selection(basesel)
1479 if not (stype in ["t", "s"]):
[2694]1480 marker += ":"
1481 self._plotter.set_line(markersize=3, markeredgewidth=0)
1482
[2693]1483 if not stype:
1484 selIds = [""] # cheating
1485 sellab = "all points"
1486 elif stype == 't':
1487 selIds = range(15)
1488 sellab = "src type "
1489 else:
1490 selIds = getattr(self._data,'get'+colorby+'nos')()
1491 sellab = colorby.upper()
1492 selFunc = "set_"+colorby+"s"
1493 for idx in selIds:
1494 sel = selector() + basesel
1495 if stype:
1496 bid = getattr(basesel,'get_'+colorby+"s")()
1497 if (len(bid) > 0) and (not idx in bid):
1498 # base selection doesn't contain idx
1499 # Note summation of selector is logical sum if
1500 continue
1501 getattr(sel, selFunc)([idx])
1502 if not sel.is_empty():
1503 try:
1504 self._data.set_selection(sel)
1505 except RuntimeError, instance:
1506 if stype == 't' and str(instance).startswith("Selection contains no data."):
1507 continue
1508 else:
1509 self._data.set_selection(basesel)
1510 raise RuntimeError, instance
1511 if self._data.nrow() == 0:
1512 self._data.set_selection(basesel)
1513 continue
1514 print "Plotting direction of %s = %s" % (colorby, str(idx))
[2694]1515 # getting data to plot
[2693]1516 dir = array(self._data.get_directionval()).transpose()
1517 ra = dir[0]*180./pi
1518 dec = dir[1]*180./pi
[2694]1519 # actual plot
[2693]1520 self._plotter.set_line(label=(sellab+str(idx)))
1521 self._plotter.plot(ra,dec,marker)
1522
1523 # restore original selection
1524 self._data.set_selection(basesel)
1525 # need to plot scan pattern explicitly
1526 if showline and (stype in ["t", "s"]):
1527 dir = array(self._data.get_directionval()).transpose()
1528 ra = dir[0]*180./pi
1529 dec = dir[1]*180./pi
1530 self._plotter.set_line(label="scan pattern")
1531 self._plotter.plot(ra,dec,":")
[2694]1532 # set color for only this line
1533 self._plotter.lines[-1][0].set_color("gray")
1534
[2693]1535 xlab = 'RA [deg.]'
1536 ylab = 'Declination [deg.]'
1537 self._plotter.set_axes('xlabel', xlab)
1538 self._plotter.set_axes('ylabel', ylab)
1539 self._plotter.set_axes('title', 'Telescope pointings')
1540 if stype: self._plotter.legend(self._legendloc)
1541 else: self._plotter.legend(None)
1542 # reverse x-axis
1543 xmin, xmax = self.gca().get_xlim()
1544 self._plotter.set_limits(xlim=[xmax,xmin])
1545
1546 self._plotter.release()
1547 self._plotter.show(hardrefresh=False)
[2694]1548 # reset line settings
1549 self._plotter.set_line(**attrback)
[2693]1550 return
1551
[1819]1552 def plotpointing(self, scan=None, outfile=None):
[1391]1553 """
1554 plot telescope pointings
1555 """
[1923]1556 visible = rcParams['plotter.gui']
[1696]1557 from matplotlib import pylab as PL
[1819]1558 from numpy import array, pi
[2704]1559 if self._plotter and (PL.gcf() == self._plotter.figure):
[2699]1560 # the current figure is ASAP plotter. Use mpl plotter
1561 figids = PL.get_fignums()
[2704]1562 PL.figure(max(figids[-1],1))
1563
[1923]1564 if not visible or not self._visible:
1565 PL.ioff()
1566 from matplotlib.backends.backend_agg import FigureCanvasAgg
1567 PL.gcf().canvas.switch_backends(FigureCanvasAgg)
[1819]1568 self._data = scan
[1391]1569 dir = array(self._data.get_directionval()).transpose()
1570 ra = dir[0]*180./pi
1571 dec = dir[1]*180./pi
1572 PL.cla()
[1819]1573 #PL.ioff()
[1391]1574 PL.clf()
[2037]1575 # Adjust subplot margins
[2576]1576 if not self._margins or len(self._margins) != 6:
[2037]1577 self.set_margin(refresh=False)
1578 lef, bot, rig, top, wsp, hsp = self._margins
[1819]1579 PL.gcf().subplots_adjust(left=lef,bottom=bot,right=rig,top=top,
1580 wspace=wsp,hspace=hsp)
1581 ax = PL.gca()
1582 #ax = PL.axes([0.1,0.1,0.8,0.8])
1583 #ax = PL.axes([0.1,0.1,0.8,0.8])
[1391]1584 ax.set_aspect('equal')
[1696]1585 PL.plot(ra, dec, 'b,')
[1391]1586 PL.xlabel('RA [deg.]')
1587 PL.ylabel('Declination [deg.]')
1588 PL.title('Telescope pointings')
1589 [xmin,xmax,ymin,ymax] = PL.axis()
1590 PL.axis([xmax,xmin,ymin,ymax])
[2416]1591 PL.ion()
[1391]1592 PL.draw()
[2416]1593 if matplotlib.get_backend() == 'Qt4Agg': PL.gcf().show()
[2576]1594 if (outfile is not None):
1595 PL.savefig(outfile)
[1819]1596
1597 # plot total power data
1598 # plotting in time is not yet implemented..
[1862]1599 @asaplog_post_dec
[2576]1600 def plottp(self, scan=None):
[2704]1601 self._plotmode = "totalpower"
[1819]1602 from asap import scantable
1603 if not self._data and not scan:
1604 msg = "Input is not a scantable"
1605 raise TypeError(msg)
1606 if isinstance(scan, scantable):
1607 if self._data is not None:
1608 if scan != self._data:
1609 self._data = scan
1610 # reset
1611 self._reset()
1612 else:
1613 self._data = scan
1614 self._reset()
1615 # ranges become invalid when abcissa changes?
1616 #if self._abcunit and self._abcunit != self._data.get_unit():
1617 # self._minmaxx = None
1618 # self._minmaxy = None
1619 # self._abcunit = self._data.get_unit()
1620
[2693]1621 self._assert_plotter(action="reload")
1622 self._plotter.hold()
1623 self._plotter.clear()
[2037]1624 # Adjust subplot margins
[2576]1625 if not self._margins or len(self._margins) !=6:
1626 self.set_margin(refresh=False)
[2037]1627 lef, bot, rig, top, wsp, hsp = self._margins
[1819]1628 self._plotter.figure.subplots_adjust(
1629 left=lef,bottom=bot,right=rig,top=top,wspace=wsp,hspace=hsp)
[2147]1630 if self.casabar_exists(): self._plotter.figmgr.casabar.disable_button()
[1819]1631 self._plottp(self._data)
1632 if self._minmaxy is not None:
1633 self._plotter.set_limits(ylim=self._minmaxy)
1634 self._plotter.release()
1635 self._plotter.tidy()
1636 self._plotter.show(hardrefresh=False)
1637 return
1638
1639 def _plottp(self,scan):
1640 """
1641 private method for plotting total power data
1642 """
1643 from numpy import ma, array, arange, logical_not
1644 r=0
1645 nr = scan.nrow()
1646 a0,b0 = -1,-1
1647 allxlim = []
1648 allylim = []
1649 y=[]
1650 self._plotter.set_panels()
1651 self._plotter.palette(0)
1652 #title
1653 #xlab = self._abcissa and self._abcissa[panelcount] \
1654 # or scan._getabcissalabel()
1655 #ylab = self._ordinate and self._ordinate[panelcount] \
1656 # or scan._get_ordinate_label()
1657 xlab = self._abcissa or 'row number' #or Time
1658 ylab = self._ordinate or scan._get_ordinate_label()
1659 self._plotter.set_axes('xlabel',xlab)
1660 self._plotter.set_axes('ylabel',ylab)
1661 lbl = self._get_label(scan, r, 's', self._title)
1662 if isinstance(lbl, list) or isinstance(lbl, tuple):
1663 # if 0 <= panelcount < len(lbl):
1664 # lbl = lbl[panelcount]
1665 # else:
1666 # get default label
1667 lbl = self._get_label(scan, r, self._panelling, None)
1668 self._plotter.set_axes('title',lbl)
1669 y=array(scan._get_column(scan._getspectrum,-1))
1670 m = array(scan._get_column(scan._getmask,-1))
1671 y = ma.masked_array(y,mask=logical_not(array(m,copy=False)))
1672 x = arange(len(y))
1673 # try to handle spectral data somewhat...
1674 l,m = y.shape
1675 if m > 1:
1676 y=y.mean(axis=1)
1677 plotit = self._plotter.plot
1678 llbl = self._get_label(scan, r, self._stacking, None)
1679 self._plotter.set_line(label=llbl)
1680 if len(x) > 0:
1681 plotit(x,y)
1682
1683
1684 # printing header information
[1862]1685 @asaplog_post_dec
[2053]1686 def print_header(self, plot=True, fontsize=9, logger=False, selstr='', extrastr=''):
[1819]1687 """
1688 print data (scantable) header on the plot and/or logger.
[2056]1689 To plot the header on the plot, this method should be called after
1690 plotting spectra by the method, asapplotter.plot.
[1819]1691 Parameters:
[1824]1692 plot: whether or not print header info on the plot.
[2053]1693 fontsize: header font size (valid only plot=True)
[1819]1694 logger: whether or not print header info on the logger.
1695 selstr: additional selection string (not verified)
[2053]1696 extrastr: additional string to print at the beginning (not verified)
[1819]1697 """
[1859]1698 if not plot and not logger:
1699 return
1700 if not self._data:
1701 raise RuntimeError("No scantable has been set yet.")
[1824]1702 # Now header will be printed on plot and/or logger.
1703 # Get header information and format it.
[2112]1704 ssum=self._data._list_header()
[1819]1705 # Print Observation header to the upper-left corner of plot
[2290]1706 headstr=[ssum[0:ssum.find('Obs. Type:')]]
1707 headstr.append(ssum[ssum.find('Obs. Type:'):ssum.find('Flux Unit:')])
[2053]1708 if extrastr != '':
1709 headstr[0]=extrastr+'\n'+headstr[0]
1710 self._headtext['extrastr'] = extrastr
[2112]1711 if selstr != '':
1712 selstr += '\n'
1713 self._headtext['selstr'] = selstr
[2056]1714 ssel=(selstr+self._data.get_selection().__str__()+self._selection.__str__() or 'none')
[2053]1715 headstr.append('***Selections***\n'+ssel)
[1824]1716
[2051]1717 if plot:
[2451]1718 errmsg = "Can plot header only after the first call to plot()."
[2453]1719 self._assert_plotter(action="halt",errmsg=errmsg)
[1819]1720 self._plotter.hold()
[2053]1721 self._header_plot(headstr,fontsize=fontsize)
[2697]1722 #import time
1723 #self._plotter.figure.text(0.99,0.01,
1724 # time.strftime("%a %d %b %Y %H:%M:%S %Z"),
1725 # horizontalalignment='right',
1726 # verticalalignment='bottom',fontsize=8)
[1819]1727 self._plotter.release()
1728 if logger:
[2053]1729 selstr = "Selections: "+ssel
[1819]1730 asaplog.push("----------------\n Plot Summary\n----------------")
[2053]1731 asaplog.push(extrastr)
[2290]1732 asaplog.push(ssum[0:ssum.find('Selection:')]\
[2112]1733 + selstr)
[2053]1734 self._headtext['string'] = headstr
1735 del ssel, ssum, headstr
[2051]1736
[2053]1737 def _header_plot(self, texts, fontsize=9):
1738 self._headtext['textobj']=[]
1739 nstcol=len(texts)
1740 for i in range(nstcol):
1741 self._headtext['textobj'].append(
1742 self._plotter.figure.text(0.03+float(i)/nstcol,0.98,
1743 texts[i],
1744 horizontalalignment='left',
1745 verticalalignment='top',
1746 fontsize=fontsize))
1747
1748 def clear_header(self):
1749 if not self._headtext['textobj']:
1750 asaplog.push("No header has been plotted. Exit without any operation")
1751 asaplog.post("WARN")
[2453]1752 elif self._assert_plotter(action="status"):
[2053]1753 self._plotter.hold()
1754 for textobj in self._headtext['textobj']:
1755 #if textobj.get_text() in self._headstring:
1756 try:
1757 textobj.remove()
1758 except NotImplementedError:
1759 self._plotter.figure.texts.pop(self._plotter.figure.texts.index(textobj))
1760 self._plotter.release()
1761 self._reset_header()
[2576]1762
1763 # plot spectra by pointing
1764 @asaplog_post_dec
1765 def plotgrid(self, scan=None,center=None,spacing=None,rows=None,cols=None):
1766 """
1767 Plot spectra based on direction.
1768
1769 Parameters:
1770 scan: a scantable to plot
1771 center: the grid center direction (a list) of plots in the
1772 unit of DIRECTION column.
1773 (default) the center of map region
1774 spacing: a list of horizontal (R.A.) and vertical (Dec.)
1775 spacing in the unit of DIRECTION column.
1776 (default) Calculated by the extent of map region and
1777 the number of rows and cols to cover
1778 rows: number of panels (grid points) in horizontal direction
1779 cols: number of panels (grid points) in vertical direction
1780
1781 Note:
1782 - Only the first IFNO, POLNO, and BEAM in the scantable will be
1783 plotted.
1784 - This method doesn't re-grid and average spectra in scantable. Use
1785 asapgrid module to re-grid spectra before plotting with this method.
1786 Only the first spectrum is plotted in case there are multiple
1787 spectra which belong to a grid.
1788 """
[2704]1789 self._plotmode = "grid"
[2576]1790 from asap import scantable
[2607]1791 from numpy import array, ma, cos
[2576]1792 if not self._data and not scan:
1793 msg = "No scantable is specified to plot"
1794 raise TypeError(msg)
[2604]1795 if scan:
1796 self.set_data(scan, refresh=False)
1797 del scan
1798
[2576]1799 # Rows and cols
1800 if rows:
1801 self._rows = int(rows)
1802 else:
1803 msg = "Number of rows to plot are not specified. "
1804 if self._rows:
1805 msg += "Using previous value = %d" % (self._rows)
1806 asaplog.push(msg)
1807 else:
1808 self._rows = 1
1809 msg += "Setting rows = %d" % (self._rows)
1810 asaplog.post()
1811 asaplog.push(msg)
1812 asaplog.post("WARN")
1813 if cols:
1814 self._cols = int(cols)
1815 else:
1816 msg = "Number of cols to plot are not specified. "
1817 if self._cols:
1818 msg += "Using previous value = %d" % (self._cols)
1819 asaplog.push(msg)
1820 else:
1821 self._cols = 1
1822 msg += "Setting cols = %d" % (self._cols)
1823 asaplog.post()
1824 asaplog.push(msg)
1825 asaplog.post("WARN")
1826
1827 # Center and spacing
[2691]1828 dirarr = array(self._data.get_directionval()).transpose()
1829 print "Pointing range: (x, y) = (%f - %f, %f - %f)" %\
1830 (dirarr[0].min(),dirarr[0].max(),dirarr[1].min(),dirarr[1].max())
1831 dircent = [0.5*(dirarr[0].max() + dirarr[0].min()),
1832 0.5*(dirarr[1].max() + dirarr[1].min())]
1833 del dirarr
[2607]1834 if center is None:
1835 #asaplog.post()
[2576]1836 asaplog.push("Grid center is not specified. Automatically calculated from pointing center.")
[2607]1837 #asaplog.post("WARN")
[2576]1838 #center = [dirarr[0].mean(), dirarr[1].mean()]
[2691]1839 center = dircent
[2607]1840 elif (type(center) in (list, tuple)) and len(center) > 1:
[2691]1841 from numpy import pi
1842 # make sure center_x is in +-pi of pointing center
1843 # (assumes dirs are in rad)
1844 rotnum = round(abs(center[0] - dircent[0])/(2*pi))
1845 if center[0] < dircent[0]: rotnum *= -1
1846 cenx = center[0] - rotnum*2*pi
1847 center = [cenx, center[1]]
[2607]1848 else:
1849 msg = "Direction of grid center should be a list of float (R.A., Dec.)"
1850 raise ValueError, msg
[2576]1851 asaplog.push("Grid center: (%f, %f) " % (center[0],center[1]))
1852
1853 if spacing is None:
[2607]1854 #asaplog.post()
[2576]1855 asaplog.push("Grid spacing not specified. Automatically calculated from map coverage")
[2607]1856 #asaplog.post("WARN")
[2576]1857 # automatically get spacing
1858 dirarr = array(self._data.get_directionval()).transpose()
1859 wx = 2. * max(abs(dirarr[0].max()-center[0]),
1860 abs(dirarr[0].min()-center[0]))
1861 wy = 2. * max(abs(dirarr[1].max()-center[1]),
1862 abs(dirarr[1].min()-center[1]))
[2607]1863 ## slightly expand area to plot the edges
[2691]1864 #wx *= 1.1
1865 #wy *= 1.1
[2607]1866 xgrid = wx/max(self._cols-1.,1.)
[2691]1867 #xgrid = wx/float(max(self._cols,1.))
1868 xgrid *= cos(center[1])
[2607]1869 ygrid = wy/max(self._rows-1.,1.)
[2691]1870 #ygrid = wy/float(max(self._rows,1.))
1871 # single pointing (identical R.A. and/or Dec. for all spectra.)
[2576]1872 if xgrid == 0:
1873 xgrid = 1.
1874 if ygrid == 0:
1875 ygrid = 1.
1876 # spacing should be negative to transpose plot
1877 spacing = [- xgrid, - ygrid]
1878 del dirarr, xgrid, ygrid
1879 #elif isinstance(spacing, str):
1880 # # spacing is a quantity
[2607]1881 elif (type(spacing) in (list, tuple)) and len(spacing) > 1:
[2602]1882 for i in xrange(2):
1883 val = spacing[i]
1884 if not isinstance(val, float):
[2576]1885 raise TypeError("spacing should be a list of float")
[2602]1886 if val > 0.:
1887 spacing[i] = -val
[2576]1888 spacing = spacing[0:2]
1889 else:
1890 msg = "Invalid spacing."
1891 raise TypeError(msg)
[2607]1892 asaplog.push("Spacing: (%f, %f) (projected)" % (spacing[0],spacing[1]))
[2576]1893
1894 ntotpl = self._rows * self._cols
1895 ifs = self._data.getifnos()
1896 if len(ifs) > 1:
1897 msg = "Found multiple IFs in scantable. Only the first IF (IFNO=%d) will be plotted." % ifs[0]
1898 asaplog.post()
1899 asaplog.push(msg)
1900 asaplog.post("WARN")
1901 pols = self._data.getpolnos()
1902 if len(pols) > 1:
1903 msg = "Found multiple POLs in scantable. Only the first POL (POLNO=%d) will be plotted." % pols[0]
1904 asaplog.post()
1905 asaplog.push(msg)
1906 asaplog.post("WARN")
1907 beams = self._data.getbeamnos()
1908 if len(beams) > 1:
1909 msg = "Found multiple BEAMs in scantable. Only the first BEAM (BEAMNO=%d) will be plotted." % beams[0]
1910 asaplog.post()
1911 asaplog.push(msg)
1912 asaplog.post("WARN")
1913 self._data.set_selection(ifs=[ifs[0]],pols=[pols[0]],beams=[beams[0]])
1914 if self._data.nrow() > ntotpl:
1915 msg = "Scantable is finely sampled than plotting grids. "\
1916 + "Only the first spectrum is plotted in each grid."
1917 asaplog.post()
1918 asaplog.push(msg)
1919 asaplog.post("WARN")
1920
1921 self._assert_plotter(action="reload")
1922 self._plotter.hold()
[2697]1923 self._reset_counter()
[2604]1924 self._plotter.legend()
[2691]1925
[2576]1926 # Adjust subplot margins
1927 if not self._margins or len(self._margins) !=6:
1928 self.set_margin(refresh=False)
1929 self._plotter.set_panels(rows=self._rows,cols=self._cols,
[2693]1930 nplots=ntotpl,margin=self._margins,ganged=True)
[2603]1931 if self.casabar_exists():
1932 self._plotter.figmgr.casabar.enable_button()
[2691]1933 # Plot helper
1934 from asap._asap import plothelper as plhelper
1935 ph = plhelper(self._data)
1936 ph.set_gridval(self._cols, self._rows, spacing[0], spacing[1],
1937 center[0], center[1], epoch="J2000", projname="SIN")
[2576]1938 # Actual plot
1939 npl = 0
1940 for irow in range(self._data.nrow()):
[2691]1941 (ix, iy) = ph.get_gpos(irow)
1942 #print("asapplotter.plotgrid: (ix, iy) = (%f, %f)" % (ix, iy))
[2576]1943 if ix < 0 or ix >= self._cols:
[2602]1944 #print "Row %d : Out of X-range (x = %f) ... skipped" % (irow, pos[0])
[2576]1945 continue
[2691]1946 ix = int(ix)
1947 if iy < 0 or iy >= self._rows:
[2602]1948 #print "Row %d : Out of Y-range (y = %f) ... skipped" % (irow,pos[1])
[2576]1949 continue
[2691]1950 iy = int(iy)
1951 ipanel = ix + iy*self._rows
1952 #print("Resolved panel Id (%d, %d): %d" % (ix, iy, ipanel))
[2576]1953 if len(self._plotter.subplots[ipanel]['lines']) > 0:
[2602]1954 #print "Row %d : panel %d lready plotted ... skipped" % (irow,ipanel)
[2576]1955 # a spectrum already plotted in the panel
1956 continue
1957 # Plotting this row
[2602]1958 #print "PLOTTING row %d (panel=%d)" % (irow, ipanel)
[2576]1959 npl += 1
1960 self._plotter.subplot(ipanel)
[2602]1961 self._plotter.palette(0,colormap=self._colormap, \
1962 linestyle=0,linestyles=self._linestyles)
[2576]1963 xlab = self._abcissa and self._abcissa[ipanel] \
[2603]1964 or self._data._getabcissalabel(irow)
[2576]1965 if self._offset and not self._abcissa:
1966 xlab += " (relative)"
1967 ylab = self._ordinate and self._ordinate[ipanel] \
[2603]1968 or self._data._get_ordinate_label()
[2576]1969 self._plotter.set_axes('xlabel', xlab)
1970 self._plotter.set_axes('ylabel', ylab)
1971 lbl = self._data.get_direction(irow)
1972 self._plotter.set_axes('title',lbl)
1973
[2603]1974 y = self._data._getspectrum(irow)
[2576]1975 # flag application
[2603]1976 mr = self._data._getflagrow(irow)
[2576]1977 if mr: # FLAGROW=True
1978 y = ma.masked_array(y,mask=mr)
1979 else:
[2603]1980 m = self._data._getmask(irow)
[2576]1981 from numpy import logical_not, logical_and
1982 ### user mask is not available so far
1983 #if self._maskselection and len(self._usermask) == len(m):
1984 # if d[self._stacking](irow) in self._maskselection[self._stacking]:
1985 # m = logical_and(m, self._usermask)
1986 y = ma.masked_array(y,mask=logical_not(array(m,copy=False)))
1987
[2603]1988 x = array(self._data._getabcissa(irow))
[2576]1989 if self._offset:
1990 x += self._offset
1991 if self._minmaxx is not None:
1992 s,e = self._slice_indeces(x)
1993 x = x[s:e]
1994 y = y[s:e]
1995 if len(x) > 1024 and rcParams['plotter.decimate']:
1996 fac = len(x)/1024
1997 x = x[::fac]
1998 y = y[::fac]
1999 self._plotter.set_line(label=lbl)
2000 plotit = self._plotter.plot
2001 if self._hist: plotit = self._plotter.hist
2002 if len(x) > 0 and not mr:
2003 plotit(x,y)
2004# xlim= self._minmaxx or [min(x),max(x)]
2005# allxlim += xlim
2006# ylim= self._minmaxy or [ma.minimum(y),ma.maximum(y)]
2007# allylim += ylim
2008# else:
2009# xlim = self._minmaxx or []
2010# allxlim += xlim
2011# ylim= self._minmaxy or []
2012# allylim += ylim
2013
2014 if npl >= ntotpl:
2015 break
2016
2017 if self._minmaxy is not None:
2018 self._plotter.set_limits(ylim=self._minmaxy)
2019 self._plotter.release()
2020 self._plotter.tidy()
2021 self._plotter.show(hardrefresh=False)
2022 return
Note: See TracBrowser for help on using the repository browser.