source: trunk/python/asapplotter.py@ 2451

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

New Development: No

JIRA Issue: Yes (CAS-3749)

Ready for Test: Yes

Interface Changes: No

What Interface Changed:

Test Programs: unit tests of sdplot

Put in Release Notes: No

Module(s): sdplot, sdfit, sdstat, sdflag, sdcal, sdreduce

Description:

Made asapplotter not to generate plotter window at start-up, but the window is
only generated at the first invokation of plotting operation.


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