source: branches/casa-prerelease/pre-asap/python/asapplotter.py @ 2113

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

merged a fix in trunk (r2112)

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