source: trunk/python/asapplotter.py @ 2693

Last change on this file since 2693 was 2693, checked in by Kana Sugimoto, 11 years ago

New Development: Yes

JIRA Issue: Yes (Trac-287)

Ready for Test: Yes

Interface Changes: Yes

What Interface Changed: a new method, asapplotter.plotpointings2

Test Programs:

Put in Release Notes: No

Module(s): asapplotter, sdplot

Description:

a new method, asapplotter.plotpointings2, is created.
This method will be supposed to replace asapplotter.plotpointing
in near future if there's no issue found.
plotpointings2 plots pointing directions of a scantable.
It is possible to plot pointings of different source type, scanno,
ifno, polno, or beamno in different colors by setting the 'colorby'
paramter. When showline=True, the scan pattern is plotted in dotted
line.
This function alway plots pointings on ASAP plotter and works properly
with custom toolbar.


  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 78.1 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()
1402        if self.casabar_exists(): self._plotter.figmgr.casabar.disable_button()
1403        # for now, only one plot
1404        self._plotter.set_panels(rows=1,cols=1)
1405        # first panel
1406        self._plotter.subplot(0)
1407        # first color and linestyles
1408        self._plotter.palette(0)
1409        self.gca().set_aspect('equal')
1410        basesel = scan.get_selection()
1411        marker = "+"
1412        if showline:
1413            basesel.set_order(["TIME"])
1414            scan.set_selection(basesel)
1415            if not (stype in ["t", "s"]):
1416                marker = "+:"
1417        if not stype:
1418            selIds = [""] # cheating
1419            sellab = "all points"
1420        elif stype == 't':
1421            selIds = range(15)
1422            sellab = "src type "
1423        else:
1424            selIds = getattr(self._data,'get'+colorby+'nos')()
1425            sellab = colorby.upper()
1426        selFunc = "set_"+colorby+"s"
1427        for idx in selIds:
1428            sel = selector() + basesel
1429            if stype:
1430                bid = getattr(basesel,'get_'+colorby+"s")()
1431                if (len(bid) > 0) and (not idx in bid):
1432                    # base selection doesn't contain idx
1433                    # Note summation of selector is logical sum if
1434                    continue
1435                getattr(sel, selFunc)([idx])
1436            if not sel.is_empty():
1437                try:
1438                    self._data.set_selection(sel)
1439                except RuntimeError, instance:
1440                    if stype == 't' and str(instance).startswith("Selection contains no data."):
1441                        continue
1442                    else:
1443                        self._data.set_selection(basesel)
1444                        raise RuntimeError, instance
1445            if self._data.nrow() == 0:
1446                self._data.set_selection(basesel)
1447                continue
1448            print "Plotting direction of %s = %s" % (colorby, str(idx))
1449            dir = array(self._data.get_directionval()).transpose()
1450            ra = dir[0]*180./pi
1451            dec = dir[1]*180./pi
1452            self._plotter.set_line(label=(sellab+str(idx)))
1453            self._plotter.plot(ra,dec,marker)
1454
1455        # restore original selection
1456        self._data.set_selection(basesel)
1457        # need to plot scan pattern explicitly
1458        if showline and (stype in ["t", "s"]):
1459            dir = array(self._data.get_directionval()).transpose()
1460            ra = dir[0]*180./pi
1461            dec = dir[1]*180./pi
1462            self._plotter.set_line(label="scan pattern")
1463            self._plotter.plot(ra,dec,":")
1464           
1465        xlab = 'RA [deg.]'
1466        ylab = 'Declination [deg.]'
1467        self._plotter.set_axes('xlabel', xlab)
1468        self._plotter.set_axes('ylabel', ylab)
1469        self._plotter.set_axes('title', 'Telescope pointings')
1470        if stype: self._plotter.legend(self._legendloc)
1471        else: self._plotter.legend(None)
1472        # reverse x-axis
1473        xmin, xmax = self.gca().get_xlim()
1474        self._plotter.set_limits(xlim=[xmax,xmin])
1475
1476        self._plotter.release()
1477        self._plotter.show(hardrefresh=False)
1478        return
1479
[1819]1480    def plotpointing(self, scan=None, outfile=None):
[1391]1481        """
1482        plot telescope pointings
1483        """
[1923]1484        visible = rcParams['plotter.gui']
[1696]1485        from matplotlib import pylab as PL
[1819]1486        from numpy import array, pi
[1923]1487        if not visible or not self._visible:
1488            PL.ioff()
1489            from matplotlib.backends.backend_agg import FigureCanvasAgg
1490            PL.gcf().canvas.switch_backends(FigureCanvasAgg)
[1819]1491        self._data = scan
[1391]1492        dir = array(self._data.get_directionval()).transpose()
1493        ra = dir[0]*180./pi
1494        dec = dir[1]*180./pi
1495        PL.cla()
[1819]1496        #PL.ioff()
[1391]1497        PL.clf()
[2037]1498        # Adjust subplot margins
[2576]1499        if not self._margins or len(self._margins) != 6:
[2037]1500            self.set_margin(refresh=False)
1501        lef, bot, rig, top, wsp, hsp = self._margins
[1819]1502        PL.gcf().subplots_adjust(left=lef,bottom=bot,right=rig,top=top,
1503                                 wspace=wsp,hspace=hsp)
1504        ax = PL.gca()
1505        #ax = PL.axes([0.1,0.1,0.8,0.8])
1506        #ax = PL.axes([0.1,0.1,0.8,0.8])
[1391]1507        ax.set_aspect('equal')
[1696]1508        PL.plot(ra, dec, 'b,')
[1391]1509        PL.xlabel('RA [deg.]')
1510        PL.ylabel('Declination [deg.]')
1511        PL.title('Telescope pointings')
1512        [xmin,xmax,ymin,ymax] = PL.axis()
1513        PL.axis([xmax,xmin,ymin,ymax])
[2416]1514        PL.ion()
[1391]1515        PL.draw()
[2416]1516        if matplotlib.get_backend() == 'Qt4Agg': PL.gcf().show()
[2576]1517        if (outfile is not None):
1518           PL.savefig(outfile)
[1819]1519
1520    # plot total power data
1521    # plotting in time is not yet implemented..
[1862]1522    @asaplog_post_dec
[2576]1523    def plottp(self, scan=None):
[1819]1524        from asap import scantable
1525        if not self._data and not scan:
1526            msg = "Input is not a scantable"
1527            raise TypeError(msg)
1528        if isinstance(scan, scantable):
1529            if self._data is not None:
1530                if scan != self._data:
1531                    self._data = scan
1532                    # reset
1533                    self._reset()
1534            else:
1535                self._data = scan
1536                self._reset()
1537        # ranges become invalid when abcissa changes?
1538        #if self._abcunit and self._abcunit != self._data.get_unit():
1539        #    self._minmaxx = None
1540        #    self._minmaxy = None
1541        #    self._abcunit = self._data.get_unit()
1542        #    self._datamask = None
1543
[2693]1544        self._assert_plotter(action="reload")
1545        self._plotter.hold()
1546        self._plotter.clear()
[2037]1547        # Adjust subplot margins
[2576]1548        if not self._margins or len(self._margins) !=6:
1549            self.set_margin(refresh=False)
[2037]1550        lef, bot, rig, top, wsp, hsp = self._margins
[1819]1551        self._plotter.figure.subplots_adjust(
1552            left=lef,bottom=bot,right=rig,top=top,wspace=wsp,hspace=hsp)
[2147]1553        if self.casabar_exists(): self._plotter.figmgr.casabar.disable_button()
[1819]1554        self._plottp(self._data)
1555        if self._minmaxy is not None:
1556            self._plotter.set_limits(ylim=self._minmaxy)
1557        self._plotter.release()
1558        self._plotter.tidy()
1559        self._plotter.show(hardrefresh=False)
1560        return
1561
1562    def _plottp(self,scan):
1563        """
1564        private method for plotting total power data
1565        """
1566        from numpy import ma, array, arange, logical_not
1567        r=0
1568        nr = scan.nrow()
1569        a0,b0 = -1,-1
1570        allxlim = []
1571        allylim = []
1572        y=[]
1573        self._plotter.set_panels()
1574        self._plotter.palette(0)
1575        #title
1576        #xlab = self._abcissa and self._abcissa[panelcount] \
1577        #       or scan._getabcissalabel()
1578        #ylab = self._ordinate and self._ordinate[panelcount] \
1579        #       or scan._get_ordinate_label()
1580        xlab = self._abcissa or 'row number' #or Time
1581        ylab = self._ordinate or scan._get_ordinate_label()
1582        self._plotter.set_axes('xlabel',xlab)
1583        self._plotter.set_axes('ylabel',ylab)
1584        lbl = self._get_label(scan, r, 's', self._title)
1585        if isinstance(lbl, list) or isinstance(lbl, tuple):
1586        #    if 0 <= panelcount < len(lbl):
1587        #        lbl = lbl[panelcount]
1588        #    else:
1589                # get default label
1590             lbl = self._get_label(scan, r, self._panelling, None)
1591        self._plotter.set_axes('title',lbl)
1592        y=array(scan._get_column(scan._getspectrum,-1))
1593        m = array(scan._get_column(scan._getmask,-1))
1594        y = ma.masked_array(y,mask=logical_not(array(m,copy=False)))
1595        x = arange(len(y))
1596        # try to handle spectral data somewhat...
1597        l,m = y.shape
1598        if m > 1:
1599            y=y.mean(axis=1)
1600        plotit = self._plotter.plot
1601        llbl = self._get_label(scan, r, self._stacking, None)
1602        self._plotter.set_line(label=llbl)
1603        if len(x) > 0:
1604            plotit(x,y)
1605
1606
1607    # forwards to matplotlib.Figure.text
1608    def figtext(self, *args, **kwargs):
1609        """
1610        Add text to figure at location x,y (relative 0-1 coords).
1611        This method forwards *args and **kwargs to a Matplotlib method,
1612        matplotlib.Figure.text.
1613        See the method help for detailed information.
1614        """
[2453]1615        self._assert_plotter(action="reload")
[1819]1616        self._plotter.text(*args, **kwargs)
1617    # end matplotlib.Figure.text forwarding function
1618
1619
1620    # printing header information
[1862]1621    @asaplog_post_dec
[2053]1622    def print_header(self, plot=True, fontsize=9, logger=False, selstr='', extrastr=''):
[1819]1623        """
1624        print data (scantable) header on the plot and/or logger.
[2056]1625        To plot the header on the plot, this method should be called after
1626        plotting spectra by the method, asapplotter.plot.
[1819]1627        Parameters:
[1824]1628            plot:      whether or not print header info on the plot.
[2053]1629            fontsize:  header font size (valid only plot=True)
[1819]1630            logger:    whether or not print header info on the logger.
1631            selstr:    additional selection string (not verified)
[2053]1632            extrastr:  additional string to print at the beginning (not verified)
[1819]1633        """
[1859]1634        if not plot and not logger:
1635            return
1636        if not self._data:
1637            raise RuntimeError("No scantable has been set yet.")
[1824]1638        # Now header will be printed on plot and/or logger.
1639        # Get header information and format it.
[2112]1640        ssum=self._data._list_header()
[1819]1641        # Print Observation header to the upper-left corner of plot
[2290]1642        headstr=[ssum[0:ssum.find('Obs. Type:')]]
1643        headstr.append(ssum[ssum.find('Obs. Type:'):ssum.find('Flux Unit:')])
[2053]1644        if extrastr != '':
1645            headstr[0]=extrastr+'\n'+headstr[0]
1646            self._headtext['extrastr'] = extrastr
[2112]1647        if selstr != '':
1648            selstr += '\n'
1649            self._headtext['selstr'] = selstr
[2056]1650        ssel=(selstr+self._data.get_selection().__str__()+self._selection.__str__() or 'none')
[2053]1651        headstr.append('***Selections***\n'+ssel)
[1824]1652
[2051]1653        if plot:
[2451]1654            errmsg = "Can plot header only after the first call to plot()."
[2453]1655            self._assert_plotter(action="halt",errmsg=errmsg)
[1819]1656            self._plotter.hold()
[2053]1657            self._header_plot(headstr,fontsize=fontsize)
[1819]1658            import time
[2106]1659            self._plotter.figure.text(0.99,0.01,
[1819]1660                            time.strftime("%a %d %b %Y  %H:%M:%S %Z"),
1661                            horizontalalignment='right',
1662                            verticalalignment='bottom',fontsize=8)
1663            self._plotter.release()
1664        if logger:
[2053]1665            selstr = "Selections:    "+ssel
[1819]1666            asaplog.push("----------------\n  Plot Summary\n----------------")
[2053]1667            asaplog.push(extrastr)
[2290]1668            asaplog.push(ssum[0:ssum.find('Selection:')]\
[2112]1669                         + selstr)
[2053]1670        self._headtext['string'] = headstr
1671        del ssel, ssum, headstr
[2051]1672
[2053]1673    def _header_plot(self, texts, fontsize=9):
1674        self._headtext['textobj']=[]
1675        nstcol=len(texts)
1676        for i in range(nstcol):
1677            self._headtext['textobj'].append(
1678                self._plotter.figure.text(0.03+float(i)/nstcol,0.98,
1679                                          texts[i],
1680                                          horizontalalignment='left',
1681                                          verticalalignment='top',
1682                                          fontsize=fontsize))
1683
1684    def clear_header(self):
1685        if not self._headtext['textobj']:
1686            asaplog.push("No header has been plotted. Exit without any operation")
1687            asaplog.post("WARN")
[2453]1688        elif self._assert_plotter(action="status"):
[2053]1689            self._plotter.hold()
1690            for textobj in self._headtext['textobj']:
1691                #if textobj.get_text() in self._headstring:
1692                try:
1693                    textobj.remove()
1694                except NotImplementedError:
1695                    self._plotter.figure.texts.pop(self._plotter.figure.texts.index(textobj))
1696            self._plotter.release()
1697        self._reset_header()
[2576]1698
1699    # plot spectra by pointing
1700    @asaplog_post_dec
1701    def plotgrid(self, scan=None,center=None,spacing=None,rows=None,cols=None):
1702        """
1703        Plot spectra based on direction.
1704       
1705        Parameters:
1706            scan:      a scantable to plot
1707            center:    the grid center direction (a list) of plots in the
1708                       unit of DIRECTION column.
1709                       (default) the center of map region
1710            spacing:   a list of horizontal (R.A.) and vertical (Dec.)
1711                       spacing in the unit of DIRECTION column.
1712                       (default) Calculated by the extent of map region and
1713                       the number of rows and cols to cover
1714            rows:      number of panels (grid points) in horizontal direction
1715            cols:      number of panels (grid points) in vertical direction
1716
1717        Note:
1718        - Only the first IFNO, POLNO, and BEAM in the scantable will be
1719        plotted.
1720        - This method doesn't re-grid and average spectra in scantable. Use
1721        asapgrid module to re-grid spectra before plotting with this method.
1722        Only the first spectrum is plotted in case there are multiple
1723        spectra which belong to a grid.
1724        """
1725        from asap import scantable
[2607]1726        from numpy import array, ma, cos
[2576]1727        if not self._data and not scan:
1728            msg = "No scantable is specified to plot"
1729            raise TypeError(msg)
[2604]1730        if scan:
1731            self.set_data(scan, refresh=False)
1732            del scan
1733
[2576]1734        # Rows and cols
1735        if rows:
1736            self._rows = int(rows)
1737        else:
1738            msg = "Number of rows to plot are not specified. "
1739            if self._rows:
1740                msg += "Using previous value = %d" % (self._rows)
1741                asaplog.push(msg)
1742            else:
1743                self._rows = 1
1744                msg += "Setting rows = %d" % (self._rows)
1745                asaplog.post()
1746                asaplog.push(msg)
1747                asaplog.post("WARN")
1748        if cols:
1749            self._cols = int(cols)
1750        else:
1751            msg = "Number of cols to plot are not specified. "
1752            if self._cols:
1753                msg += "Using previous value = %d" % (self._cols)
1754                asaplog.push(msg)
1755            else:
1756                self._cols = 1
1757                msg += "Setting cols = %d" % (self._cols)
1758                asaplog.post()
1759                asaplog.push(msg)
1760                asaplog.post("WARN")
1761
1762        # Center and spacing
[2691]1763        dirarr = array(self._data.get_directionval()).transpose()
1764        print "Pointing range: (x, y) = (%f - %f, %f - %f)" %\
1765              (dirarr[0].min(),dirarr[0].max(),dirarr[1].min(),dirarr[1].max())
1766        dircent = [0.5*(dirarr[0].max() + dirarr[0].min()),
1767                   0.5*(dirarr[1].max() + dirarr[1].min())]
1768        del dirarr
[2607]1769        if center is None:
1770            #asaplog.post()
[2576]1771            asaplog.push("Grid center is not specified. Automatically calculated from pointing center.")
[2607]1772            #asaplog.post("WARN")
[2576]1773            #center = [dirarr[0].mean(), dirarr[1].mean()]
[2691]1774            center = dircent
[2607]1775        elif (type(center) in (list, tuple)) and len(center) > 1:
[2691]1776            from numpy import pi
1777            # make sure center_x is in +-pi of pointing center
1778            # (assumes dirs are in rad)
1779            rotnum = round(abs(center[0] - dircent[0])/(2*pi))
1780            if center[0] < dircent[0]: rotnum *= -1
1781            cenx = center[0] - rotnum*2*pi
1782            center = [cenx, center[1]]
[2607]1783        else:
1784            msg = "Direction of grid center should be a list of float (R.A., Dec.)"
1785            raise ValueError, msg
[2576]1786        asaplog.push("Grid center: (%f, %f) " % (center[0],center[1]))
1787
1788        if spacing is None:
[2607]1789            #asaplog.post()
[2576]1790            asaplog.push("Grid spacing not specified. Automatically calculated from map coverage")
[2607]1791            #asaplog.post("WARN")
[2576]1792            # automatically get spacing
1793            dirarr = array(self._data.get_directionval()).transpose()
1794            wx = 2. * max(abs(dirarr[0].max()-center[0]),
1795                          abs(dirarr[0].min()-center[0]))
1796            wy = 2. * max(abs(dirarr[1].max()-center[1]),
1797                          abs(dirarr[1].min()-center[1]))
[2607]1798            ## slightly expand area to plot the edges
[2691]1799            #wx *= 1.1
1800            #wy *= 1.1
[2607]1801            xgrid = wx/max(self._cols-1.,1.)
[2691]1802            #xgrid = wx/float(max(self._cols,1.))
1803            xgrid *= cos(center[1])
[2607]1804            ygrid = wy/max(self._rows-1.,1.)
[2691]1805            #ygrid = wy/float(max(self._rows,1.))
1806            # single pointing (identical R.A. and/or Dec. for all spectra.)
[2576]1807            if xgrid == 0:
1808                xgrid = 1.
1809            if ygrid == 0:
1810                ygrid = 1.
1811            # spacing should be negative to transpose plot
1812            spacing = [- xgrid, - ygrid]
1813            del dirarr, xgrid, ygrid
1814        #elif isinstance(spacing, str):
1815        #    # spacing is a quantity
[2607]1816        elif (type(spacing) in (list, tuple)) and len(spacing) > 1:
[2602]1817            for i in xrange(2):
1818                val = spacing[i]
1819                if not isinstance(val, float):
[2576]1820                    raise TypeError("spacing should be a list of float")
[2602]1821                if val > 0.:
1822                    spacing[i] = -val
[2576]1823            spacing = spacing[0:2]
1824        else:
1825            msg = "Invalid spacing."
1826            raise TypeError(msg)
[2607]1827        asaplog.push("Spacing: (%f, %f) (projected)" % (spacing[0],spacing[1]))
[2576]1828
1829        ntotpl = self._rows * self._cols
1830        ifs = self._data.getifnos()
1831        if len(ifs) > 1:
1832            msg = "Found multiple IFs in scantable. Only the first IF (IFNO=%d) will be plotted." % ifs[0]
1833            asaplog.post()
1834            asaplog.push(msg)
1835            asaplog.post("WARN")
1836        pols = self._data.getpolnos()
1837        if len(pols) > 1:
1838            msg = "Found multiple POLs in scantable. Only the first POL (POLNO=%d) will be plotted." % pols[0]
1839            asaplog.post()
1840            asaplog.push(msg)
1841            asaplog.post("WARN")
1842        beams = self._data.getbeamnos()
1843        if len(beams) > 1:
1844            msg = "Found multiple BEAMs in scantable. Only the first BEAM (BEAMNO=%d) will be plotted." % beams[0]
1845            asaplog.post()
1846            asaplog.push(msg)
1847            asaplog.post("WARN")
1848        self._data.set_selection(ifs=[ifs[0]],pols=[pols[0]],beams=[beams[0]])
1849        if self._data.nrow() > ntotpl:
1850            msg = "Scantable is finely sampled than plotting grids. "\
1851                  + "Only the first spectrum is plotted in each grid."
1852            asaplog.post()
1853            asaplog.push(msg)
1854            asaplog.post("WARN")
1855       
1856        self._assert_plotter(action="reload")
1857        self._plotter.hold()
[2693]1858        #self._plotter.clear() #all artists are cleared at set_panels
[2604]1859        self._plotter.legend()
[2691]1860
[2576]1861        # Adjust subplot margins
1862        if not self._margins or len(self._margins) !=6:
1863            self.set_margin(refresh=False)
1864        self._plotter.set_panels(rows=self._rows,cols=self._cols,
[2693]1865                                 nplots=ntotpl,margin=self._margins,ganged=True)       
[2603]1866        if self.casabar_exists():
1867            self._plotter.figmgr.casabar.set_pagecounter(1)
1868            self._plotter.figmgr.casabar.enable_button()
[2691]1869        # Plot helper
1870        from asap._asap import plothelper as plhelper
1871        ph = plhelper(self._data)
1872        ph.set_gridval(self._cols, self._rows, spacing[0], spacing[1],
1873                          center[0], center[1], epoch="J2000", projname="SIN")
[2576]1874        # Actual plot
1875        npl = 0
1876        for irow in range(self._data.nrow()):
[2691]1877            (ix, iy) = ph.get_gpos(irow)
1878            #print("asapplotter.plotgrid: (ix, iy) = (%f, %f)" % (ix, iy))
[2576]1879            if ix < 0 or ix >= self._cols:
[2602]1880                #print "Row %d : Out of X-range (x = %f) ... skipped" % (irow, pos[0])
[2576]1881                continue
[2691]1882            ix = int(ix)
1883            if iy < 0 or iy >= self._rows:
[2602]1884                #print "Row %d : Out of Y-range (y = %f) ... skipped" % (irow,pos[1])
[2576]1885                continue
[2691]1886            iy = int(iy)
1887            ipanel = ix + iy*self._rows
1888            #print("Resolved panel Id (%d, %d): %d" % (ix, iy, ipanel))
[2576]1889            if len(self._plotter.subplots[ipanel]['lines']) > 0:
[2602]1890                #print "Row %d : panel %d lready plotted ... skipped" % (irow,ipanel)
[2576]1891                # a spectrum already plotted in the panel
1892                continue
1893            # Plotting this row
[2602]1894            #print "PLOTTING row %d (panel=%d)" % (irow, ipanel)
[2576]1895            npl += 1
1896            self._plotter.subplot(ipanel)
[2602]1897            self._plotter.palette(0,colormap=self._colormap, \
1898                                  linestyle=0,linestyles=self._linestyles)
[2576]1899            xlab = self._abcissa and self._abcissa[ipanel] \
[2603]1900                   or self._data._getabcissalabel(irow)
[2576]1901            if self._offset and not self._abcissa:
1902                xlab += " (relative)"
1903            ylab = self._ordinate and self._ordinate[ipanel] \
[2603]1904                   or self._data._get_ordinate_label()
[2576]1905            self._plotter.set_axes('xlabel', xlab)
1906            self._plotter.set_axes('ylabel', ylab)
1907            lbl = self._data.get_direction(irow)
1908            self._plotter.set_axes('title',lbl)
1909
[2603]1910            y = self._data._getspectrum(irow)
[2576]1911            # flag application
[2603]1912            mr = self._data._getflagrow(irow)
[2576]1913            if mr:  # FLAGROW=True
1914                y = ma.masked_array(y,mask=mr)
1915            else:
[2603]1916                m = self._data._getmask(irow)
[2576]1917                from numpy import logical_not, logical_and
1918                ### user mask is not available so far
1919                #if self._maskselection and len(self._usermask) == len(m):
1920                #    if d[self._stacking](irow) in self._maskselection[self._stacking]:
1921                #            m = logical_and(m, self._usermask)
1922                y = ma.masked_array(y,mask=logical_not(array(m,copy=False)))
1923
[2603]1924            x = array(self._data._getabcissa(irow))
[2576]1925            if self._offset:
1926                x += self._offset
1927            if self._minmaxx is not None:
1928                s,e = self._slice_indeces(x)
1929                x = x[s:e]
1930                y = y[s:e]
1931            if len(x) > 1024 and rcParams['plotter.decimate']:
1932                fac = len(x)/1024
1933                x = x[::fac]
1934                y = y[::fac]
1935            self._plotter.set_line(label=lbl)
1936            plotit = self._plotter.plot
1937            if self._hist: plotit = self._plotter.hist
1938            if len(x) > 0 and not mr:
1939                plotit(x,y)
1940#                 xlim= self._minmaxx or [min(x),max(x)]
1941#                 allxlim += xlim
1942#                 ylim= self._minmaxy or [ma.minimum(y),ma.maximum(y)]
1943#                 allylim += ylim
1944#             else:
1945#                 xlim = self._minmaxx or []
1946#                 allxlim += xlim
1947#                 ylim= self._minmaxy or []
1948#                 allylim += ylim
1949           
1950            if npl >= ntotpl:
1951                break
1952           
1953        if self._minmaxy is not None:
1954            self._plotter.set_limits(ylim=self._minmaxy)
1955        self._plotter.release()
1956        self._plotter.tidy()
1957        self._plotter.show(hardrefresh=False)
1958        return
Note: See TracBrowser for help on using the repository browser.