source: trunk/python/asapplotter.py @ 2712

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

New Development: No (a bug fix)

JIRA Issue: No

Ready for Test: Yes

Interface Changes: No

What Interface Changed:

Test Programs:

invoke asapplotter.plotazel (sdplot with plottype="azel") and
asapplotter.plotpointing (sdplot with plottype="pointing")
before invoking asapplotter.plot (sdplot with plottype="spectra") or
asapplotter.plottp (sdplot with plottype="totalpower") after loading
casapy/asap.

Put in Release Notes: No

Module(s): asapplotter and sdplot

Description:

Fixed a bug which caused azel and pointing plot fail when the plot
commands are invoked before running spectral or totalpower plot at
least once after loading casapy/asap.


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