source: trunk/python/asapplotter.py @ 2155

Last change on this file since 2155 was 2155, checked in by Kana Sugimoto, 13 years ago

New Development: Yes

JIRA Issue: No (reorganization of modules)

Ready for Test: Yes

Interface Changes: Yes

What Interface Changed: the modules casatoolbar, flagtoolbar, notaionwindow, were reorganized as customgui_base, customgui_tkagg, and customgui_qt4agg, based on backend

Test Programs: List test programs

Put in Release Notes: Yes/No?

Module(s): Module Names change impacts.

Description: Describe your changes here...


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