source: trunk/python/asapplotter.py@ 2695

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

New Development: No

JIRA Issue: Yes (TRAC-287)

Ready for Test: Yes

Interface Changes: No

What Interface Changed:

Test Programs:

Put in Release Notes: No

Module(s): asapplotter and sdplot

Description: bug fixes to asapplotter.plotpoining2


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