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

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

merged a bug fix in trunk(r2051)

  • 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 = []
[2052]57        self._headstring = None
58        self._headsize = None
[1023]59
[920]60    def _translate(self, instr):
[1910]61        keys = "s b i p t r".split()
[920]62        if isinstance(instr, str):
63            for key in keys:
64                if instr.lower().startswith(key):
65                    return key
66        return None
67
[1563]68    def _newplotter(self, **kwargs):
[1819]69        backend=matplotlib.get_backend()
70        if not self._visible:
71            from asap.asaplot import asaplot
72        elif backend == 'TkAgg':
[710]73            from asap.asaplotgui import asaplotgui as asaplot
[1819]74        elif backend == 'Qt4Agg':
75            from asap.asaplotgui_qt4 import asaplotgui as asaplot
76        elif backend == 'GTkAgg':
77            from asap.asaplotgui_gtk import asaplotgui as asaplot
[710]78        else:
79            from asap.asaplot import asaplot
[1563]80        return asaplot(**kwargs)
[710]81
[1819]82    def _newcasabar(self):
83        backend=matplotlib.get_backend()
84        if self._visible and backend == "TkAgg":
85            from asap.casatoolbar import CustomToolbarTkAgg
86            return CustomToolbarTkAgg(self)
[1989]87            #from asap.casatoolbar import CustomFlagToolbarTkAgg
88            #return CustomFlagToolbarTkAgg(self)
[1995]89        return None
[1819]90
[1862]91    @asaplog_post_dec
[935]92    def plot(self, scan=None):
[203]93        """
[920]94        Plot a scantable.
[203]95        Parameters:
[920]96            scan:   a scantable
[203]97        Note:
[920]98            If a scantable was specified in a previous call
[203]99            to plot, no argument has to be given to 'replot'
[920]100            NO checking is done that the abcissas of the scantable
[203]101            are consistent e.g. all 'channel' or all 'velocity' etc.
102        """
[1981]103        self._startrow = 0
104        self._ipanel = -1
[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):
849        self._headsize = None
850        self._headstring = None
851
[920]852    def _plot(self, scan):
[947]853        savesel = scan.get_selection()
854        sel = savesel +  self._selection
[1910]855        order = self._get_sortstring([self._panelling,self._stacking])
856        if order:
857            sel.set_order(order)
[947]858        scan.set_selection(sel)
[920]859        d = {'b': scan.getbeam, 's': scan.getscan,
[1949]860             'i': scan.getif, 'p': scan.getpol, 't': scan.get_time,
[1989]861             'r': int}#, '_r': int}
[920]862
[1148]863        polmodes = dict(zip(self._selection.get_pols(),
864                            self._selection.get_poltypes()))
865        # this returns either a tuple of numbers or a length  (ncycles)
866        # convert this into lengths
867        n0,nstack0 = self._get_selected_n(scan)
868        if isinstance(n0, int): n = n0
[1175]869        else: n = len(n0)
[1148]870        if isinstance(nstack0, int): nstack = nstack0
[1175]871        else: nstack = len(nstack0)
[1989]872        # In case of row stacking
873        rowstack = False
874        titlemode = self._panelling
875        if self._stacking == "r" and self._panelling != "r":
876            rowstack = True
877            titlemode = '_r'
[1913]878        nptot = n
[1582]879        maxpanel, maxstack = 16,16
[1913]880        if nstack > maxstack:
881            msg ="Scan to be overlayed contains more than %d selections.\n" \
882                  "Selecting first %d selections..." % (maxstack, maxstack)
[920]883            asaplog.push(msg)
[1861]884            asaplog.post('WARN')
[998]885            nstack = min(nstack,maxstack)
[2038]886        #n = min(n-self._ipanel-1,maxpanel)
887        n = n-self._ipanel-1
[2011]888
889        ganged = False
[920]890        if n > 1:
891            ganged = rcParams['plotter.ganged']
[1819]892            if self._panelling == 'i':
893                ganged = False
[920]894            if self._rows and self._cols:
895                n = min(n,self._rows*self._cols)
896                self._plotter.set_panels(rows=self._rows,cols=self._cols,
[2037]897                                         nplots=n,margin=self._margins,ganged=ganged)
[920]898            else:
[2038]899                n = min(n,maxpanel)
[2037]900                self._plotter.set_panels(rows=n,cols=0,nplots=n,margin=self._margins,ganged=ganged)
[920]901        else:
[2037]902            self._plotter.set_panels(margin=self._margins)
[1913]903        #r = 0
[1981]904        r = self._startrow
[920]905        nr = scan.nrow()
906        a0,b0 = -1,-1
907        allxlim = []
[1018]908        allylim = []
[1981]909        #newpanel=True
910        newpanel=False
[920]911        panelcount,stackcount = 0,0
[1981]912        # If this is not the first page
913        if r > 0:
914            # panelling value of the prev page
915            a0 = d[self._panelling](r-1)
916            # set the initial stackcount large not to plot
917            # the start row automatically
918            stackcount = nstack
919
[1002]920        while r < nr:
[920]921            a = d[self._panelling](r)
922            b = d[self._stacking](r)
923            if a > a0 and panelcount < n:
924                if n > 1:
925                    self._plotter.subplot(panelcount)
926                self._plotter.palette(0)
927                #title
928                xlab = self._abcissa and self._abcissa[panelcount] \
929                       or scan._getabcissalabel()
[1897]930                if self._offset and not self._abcissa:
931                    xlab += " (relative)"
[920]932                ylab = self._ordinate and self._ordinate[panelcount] \
933                       or scan._get_ordinate_label()
[1547]934                self._plotter.set_axes('xlabel', xlab)
935                self._plotter.set_axes('ylabel', ylab)
[1989]936                #lbl = self._get_label(scan, r, self._panelling, self._title)
937                lbl = self._get_label(scan, r, titlemode, self._title)
[920]938                if isinstance(lbl, list) or isinstance(lbl, tuple):
939                    if 0 <= panelcount < len(lbl):
940                        lbl = lbl[panelcount]
941                    else:
942                        # get default label
[1989]943                        #lbl = self._get_label(scan, r, self._panelling, None)
944                        lbl = self._get_label(scan, r, titlemode, None)
[920]945                self._plotter.set_axes('title',lbl)
946                newpanel = True
[1913]947                stackcount = 0
[920]948                panelcount += 1
[1981]949                # save the start row to plot this panel for future revisit.
950                if self._panelling != 'r' and \
951                       len(self._panelrows) < self._ipanel+1+panelcount:
952                    self._panelrows += [r]
953                   
[1944]954            #if (b > b0 or newpanel) and stackcount < nstack:
[1989]955            if stackcount < nstack and (newpanel or rowstack or (a == a0 and b > b0)):
[920]956                y = []
957                if len(polmodes):
958                    y = scan._getspectrum(r, polmodes[scan.getpol(r)])
959                else:
960                    y = scan._getspectrum(r)
[1995]961                # flag application
962                mr = scan._getflagrow(r)
[1739]963                from numpy import ma, array
[1995]964                if mr:
965                    y = ma.masked_array(y,mask=mr)
966                else:
967                    m = scan._getmask(r)
968                    from numpy import logical_not, logical_and
969                    if self._maskselection and len(self._usermask) == len(m):
970                        if d[self._stacking](r) in self._maskselection[self._stacking]:
971                            m = logical_and(m, self._usermask)
972                    y = ma.masked_array(y,mask=logical_not(array(m,copy=False)))
973
[1897]974                x = array(scan._getabcissa(r))
975                if self._offset:
976                    x += self._offset
[920]977                if self._minmaxx is not None:
978                    s,e = self._slice_indeces(x)
979                    x = x[s:e]
980                    y = y[s:e]
[1096]981                if len(x) > 1024 and rcParams['plotter.decimate']:
982                    fac = len(x)/1024
[920]983                    x = x[::fac]
984                    y = y[::fac]
985                llbl = self._get_label(scan, r, self._stacking, self._lmap)
986                if isinstance(llbl, list) or isinstance(llbl, tuple):
987                    if 0 <= stackcount < len(llbl):
988                        # use user label
989                        llbl = llbl[stackcount]
990                    else:
991                        # get default label
992                        llbl = self._get_label(scan, r, self._stacking, None)
993                self._plotter.set_line(label=llbl)
[1023]994                plotit = self._plotter.plot
995                if self._hist: plotit = self._plotter.hist
[1995]996                if len(x) > 0 and not mr:
[1146]997                    plotit(x,y)
998                    xlim= self._minmaxx or [min(x),max(x)]
999                    allxlim += xlim
1000                    ylim= self._minmaxy or [ma.minimum(y),ma.maximum(y)]
1001                    allylim += ylim
[1819]1002                else:
1003                    xlim = self._minmaxx or []
1004                    allxlim += xlim
1005                    ylim= self._minmaxy or []
1006                    allylim += ylim
[920]1007                stackcount += 1
[1981]1008                a0=a
1009                b0=b
[920]1010                # last in colour stack -> autoscale x
[1819]1011                if stackcount == nstack and len(allxlim) > 0:
[920]1012                    allxlim.sort()
[1819]1013                    self._plotter.subplots[panelcount-1]['axes'].set_xlim([allxlim[0],allxlim[-1]])
[1989]1014                    if ganged:
1015                        allxlim = [allxlim[0],allxlim[-1]]
1016                    else:
1017                        # clear
1018                        allxlim =[]
[920]1019
1020            newpanel = False
[1981]1021            #a0=a
1022            #b0=b
[920]1023            # ignore following rows
[1981]1024            if (panelcount == n and stackcount == nstack) or (r == nr-1):
[1018]1025                # last panel -> autoscale y if ganged
[1989]1026                #if rcParams['plotter.ganged'] and len(allylim) > 0:
1027                if ganged and len(allylim) > 0:
[1018]1028                    allylim.sort()
1029                    self._plotter.set_limits(ylim=[allylim[0],allylim[-1]])
[998]1030                break
[920]1031            r+=1 # next row
[1981]1032
1033        # save the current counter for multi-page plotting
1034        self._startrow = r+1
1035        self._ipanel += panelcount
[1913]1036        if self._plotter.figmgr.casabar:
[1981]1037            if self._ipanel >= nptot-1:
[1913]1038                self._plotter.figmgr.casabar.disable_next()
1039            else:
1040                self._plotter.figmgr.casabar.enable_next()
[1981]1041            if self._ipanel + 1 - panelcount > 0:
1042                self._plotter.figmgr.casabar.enable_prev()
1043            else:
1044                self._plotter.figmgr.casabar.disable_prev()
1045
[947]1046        #reset the selector to the scantable's original
1047        scan.set_selection(savesel)
[1824]1048
[1819]1049        #temporary switch-off for older matplotlib
1050        #if self._fp is not None:
1051        if self._fp is not None and getattr(self._plotter.figure,'findobj',False):
[1556]1052            for o in self._plotter.figure.findobj(Text):
1053                o.set_fontproperties(self._fp)
[920]1054
[1910]1055    def _get_sortstring(self, lorders):
1056        d0 = {'s': 'SCANNO', 'b': 'BEAMNO', 'i':'IFNO',
1057              'p': 'POLNO', 'c': 'CYCLENO', 't' : 'TIME', 'r':None, '_r':None }
[1944]1058        if not (type(lorders) == list) and not (type(lorders) == tuple):
[1910]1059            return None
1060        if len(lorders) > 0:
1061            lsorts = []
1062            for order in lorders:
[1989]1063                if order == "r":
1064                    # don't sort if row panelling/stacking
1065                    return None
[1910]1066                ssort = d0[order]
1067                if ssort:
1068                    lsorts.append(ssort)
1069            return lsorts
1070        return None
1071
[1582]1072    def set_selection(self, selection=None, refresh=True, **kw):
[1819]1073        """
1074        Parameters:
1075            selection:  a selector object (default unset the selection)
1076            refresh:    True (default) or False. If True, the plot is
[1824]1077                        replotted based on the new parameter setting(s).
[1819]1078                        Otherwise,the parameter(s) are set without replotting.
1079        """
[1582]1080        if selection is None:
1081            # reset
1082            if len(kw) == 0:
1083                self._selection = selector()
1084            else:
1085                # try keywords
1086                for k in kw:
1087                    if k not in selector.fields:
1088                        raise KeyError("Invalid selection key '%s', valid keys are %s" % (k, selector.fields))
1089                self._selection = selector(**kw)
1090        elif isinstance(selection, selector):
1091            self._selection = selection
1092        else:
1093            raise TypeError("'selection' is not of type selector")
1094
[1910]1095        order = self._get_sortstring([self._panelling,self._stacking])
1096        if order:
1097            self._selection.set_order(order)
[1819]1098        if refresh and self._data: self.plot(self._data)
[920]1099
1100    def _get_selected_n(self, scan):
[1148]1101        d1 = {'b': scan.getbeamnos, 's': scan.getscannos,
[1910]1102             'i': scan.getifnos, 'p': scan.getpolnos, 't': scan.ncycle,
[1989]1103             'r': scan.nrow}#, '_r': False}
[1148]1104        d2 = { 'b': self._selection.get_beams(),
1105               's': self._selection.get_scans(),
1106               'i': self._selection.get_ifs(),
1107               'p': self._selection.get_pols(),
[1910]1108               't': self._selection.get_cycles(),
[1989]1109               'r': False}#, '_r': 1}
[920]1110        n =  d2[self._panelling] or d1[self._panelling]()
1111        nstack = d2[self._stacking] or d1[self._stacking]()
[1989]1112        # handle row panelling/stacking
1113        if self._panelling == 'r':
1114            nstack = 1
1115        elif self._stacking == 'r':
1116            n = 1
[920]1117        return n,nstack
1118
1119    def _get_label(self, scan, row, mode, userlabel=None):
[1153]1120        if isinstance(userlabel, list) and len(userlabel) == 0:
1121            userlabel = " "
[947]1122        pms = dict(zip(self._selection.get_pols(),self._selection.get_poltypes()))
[920]1123        if len(pms):
1124            poleval = scan._getpollabel(scan.getpol(row),pms[scan.getpol(row)])
1125        else:
1126            poleval = scan._getpollabel(scan.getpol(row),scan.poltype())
1127        d = {'b': "Beam "+str(scan.getbeam(row)),
[1819]1128             #'s': scan._getsourcename(row),
1129             's': "Scan "+str(scan.getscan(row))+\
1130                  " ("+str(scan._getsourcename(row))+")",
[920]1131             'i': "IF"+str(scan.getif(row)),
[964]1132             'p': poleval,
[1910]1133             't': str(scan.get_time(row)),
1134             'r': "row "+str(row),
[1913]1135             #'_r': str(scan.get_time(row))+",\nIF"+str(scan.getif(row))+", "+poleval+", Beam"+str(scan.getbeam(row)) }
1136             '_r': "" }
[920]1137        return userlabel or d[mode]
[1153]1138
[1819]1139    def plotazel(self, scan=None, outfile=None):
[1391]1140        """
[1696]1141        plot azimuth and elevation versus time of a scantable
[1391]1142        """
[1923]1143        visible = rcParams['plotter.gui']
[1696]1144        from matplotlib import pylab as PL
1145        from matplotlib.dates import DateFormatter, timezone
1146        from matplotlib.dates import HourLocator, MinuteLocator,SecondLocator, DayLocator
[1391]1147        from matplotlib.ticker import MultipleLocator
[1739]1148        from numpy import array, pi
[1923]1149        if not visible or not self._visible:
1150            PL.ioff()
1151            from matplotlib.backends.backend_agg import FigureCanvasAgg
1152            PL.gcf().canvas.switch_backends(FigureCanvasAgg)
[1819]1153        self._data = scan
1154        self._outfile = outfile
[1556]1155        dates = self._data.get_time(asdatetime=True)
[1391]1156        t = PL.date2num(dates)
1157        tz = timezone('UTC')
1158        PL.cla()
1159        PL.ioff()
1160        PL.clf()
[2037]1161        # Adjust subplot margins
1162        if len(self._margins) != 6:
1163            self.set_margin(refresh=False)
1164        lef, bot, rig, top, wsp, hsp = self._margins
[1819]1165        PL.gcf().subplots_adjust(left=lef,bottom=bot,right=rig,top=top,
1166                                 wspace=wsp,hspace=hsp)
[1824]1167
[1391]1168        tdel = max(t) - min(t)
1169        ax = PL.subplot(2,1,1)
1170        el = array(self._data.get_elevation())*180./pi
1171        PL.ylabel('El [deg.]')
1172        dstr = dates[0].strftime('%Y/%m/%d')
1173        if tdel > 1.0:
1174            dstr2 = dates[len(dates)-1].strftime('%Y/%m/%d')
1175            dstr = dstr + " - " + dstr2
1176            majloc = DayLocator()
1177            minloc = HourLocator(range(0,23,12))
1178            timefmt = DateFormatter("%b%d")
[1696]1179        elif tdel > 24./60.:
1180            timefmt = DateFormatter('%H:%M')
1181            majloc = HourLocator()
1182            minloc = MinuteLocator(30)
[1391]1183        else:
[1696]1184            timefmt = DateFormatter('%H:%M')
1185            majloc = MinuteLocator(interval=5)
1186            minloc = SecondLocator(30)
1187
[1391]1188        PL.title(dstr)
[1819]1189        if tdel == 0.0:
1190            th = (t - PL.floor(t))*24.0
1191            PL.plot(th,el,'o',markersize=2, markerfacecolor='b', markeredgecolor='b')
1192        else:
1193            PL.plot_date(t,el,'o', markersize=2, markerfacecolor='b', markeredgecolor='b',tz=tz)
1194            #ax.grid(True)
1195            ax.xaxis.set_major_formatter(timefmt)
1196            ax.xaxis.set_major_locator(majloc)
1197            ax.xaxis.set_minor_locator(minloc)
[1391]1198        ax.yaxis.grid(True)
[1819]1199        yloc = MultipleLocator(30)
1200        ax.set_ylim(0,90)
1201        ax.yaxis.set_major_locator(yloc)
[1391]1202        if tdel > 1.0:
1203            labels = ax.get_xticklabels()
1204        #    PL.setp(labels, fontsize=10, rotation=45)
1205            PL.setp(labels, fontsize=10)
[1819]1206
[1391]1207        # Az plot
1208        az = array(self._data.get_azimuth())*180./pi
1209        if min(az) < 0:
1210            for irow in range(len(az)):
1211                if az[irow] < 0: az[irow] += 360.0
1212
[1819]1213        ax2 = PL.subplot(2,1,2)
1214        #PL.xlabel('Time (UT [hour])')
1215        PL.ylabel('Az [deg.]')
1216        if tdel == 0.0:
1217            PL.plot(th,az,'o',markersize=2, markeredgecolor='b',markerfacecolor='b')
1218        else:
1219            PL.plot_date(t,az,'o', markersize=2,markeredgecolor='b',markerfacecolor='b',tz=tz)
1220            ax2.xaxis.set_major_formatter(timefmt)
1221            ax2.xaxis.set_major_locator(majloc)
1222            ax2.xaxis.set_minor_locator(minloc)
1223        #ax2.grid(True)
1224        ax2.set_ylim(0,360)
[1696]1225        ax2.yaxis.grid(True)
[1819]1226        #hfmt = DateFormatter('%H')
1227        #hloc = HourLocator()
1228        yloc = MultipleLocator(60)
1229        ax2.yaxis.set_major_locator(yloc)
1230        if tdel > 1.0:
1231            labels = ax2.get_xticklabels()
1232            PL.setp(labels, fontsize=10)
1233            PL.xlabel('Time (UT [day])')
1234        else:
1235            PL.xlabel('Time (UT [hour])')
1236
[1391]1237        PL.ion()
1238        PL.draw()
[1819]1239        if (self._outfile is not None):
1240           PL.savefig(self._outfile)
[1391]1241
[1819]1242    def plotpointing(self, scan=None, outfile=None):
[1391]1243        """
1244        plot telescope pointings
1245        """
[1923]1246        visible = rcParams['plotter.gui']
[1696]1247        from matplotlib import pylab as PL
[1819]1248        from numpy import array, pi
[1923]1249        if not visible or not self._visible:
1250            PL.ioff()
1251            from matplotlib.backends.backend_agg import FigureCanvasAgg
1252            PL.gcf().canvas.switch_backends(FigureCanvasAgg)
[1819]1253        self._data = scan
1254        self._outfile = outfile
[1391]1255        dir = array(self._data.get_directionval()).transpose()
1256        ra = dir[0]*180./pi
1257        dec = dir[1]*180./pi
1258        PL.cla()
[1819]1259        #PL.ioff()
[1391]1260        PL.clf()
[2037]1261        # Adjust subplot margins
1262        if len(self._margins) != 6:
1263            self.set_margin(refresh=False)
1264        lef, bot, rig, top, wsp, hsp = self._margins
[1819]1265        PL.gcf().subplots_adjust(left=lef,bottom=bot,right=rig,top=top,
1266                                 wspace=wsp,hspace=hsp)
1267        ax = PL.gca()
1268        #ax = PL.axes([0.1,0.1,0.8,0.8])
1269        #ax = PL.axes([0.1,0.1,0.8,0.8])
[1391]1270        ax.set_aspect('equal')
[1696]1271        PL.plot(ra, dec, 'b,')
[1391]1272        PL.xlabel('RA [deg.]')
1273        PL.ylabel('Declination [deg.]')
1274        PL.title('Telescope pointings')
1275        [xmin,xmax,ymin,ymax] = PL.axis()
1276        PL.axis([xmax,xmin,ymin,ymax])
[1819]1277        #PL.ion()
[1391]1278        PL.draw()
[1819]1279        if (self._outfile is not None):
1280           PL.savefig(self._outfile)
1281
1282    # plot total power data
1283    # plotting in time is not yet implemented..
[1862]1284    @asaplog_post_dec
[1819]1285    def plottp(self, scan=None, outfile=None):
1286        if self._plotter.is_dead:
1287            if hasattr(self._plotter.figmgr,'casabar'):
1288                del self._plotter.figmgr.casabar
1289            self._plotter = self._newplotter()
1290            self._plotter.figmgr.casabar=self._newcasabar()
1291        self._plotter.hold()
1292        self._plotter.clear()
1293        from asap import scantable
1294        if not self._data and not scan:
1295            msg = "Input is not a scantable"
1296            raise TypeError(msg)
1297        if isinstance(scan, scantable):
1298            if self._data is not None:
1299                if scan != self._data:
1300                    self._data = scan
1301                    # reset
1302                    self._reset()
1303            else:
1304                self._data = scan
1305                self._reset()
1306        # ranges become invalid when abcissa changes?
1307        #if self._abcunit and self._abcunit != self._data.get_unit():
1308        #    self._minmaxx = None
1309        #    self._minmaxy = None
1310        #    self._abcunit = self._data.get_unit()
1311        #    self._datamask = None
1312
[2037]1313        # Adjust subplot margins
1314        if len(self._margins) !=6: self.set_margin(refresh=False)
1315        lef, bot, rig, top, wsp, hsp = self._margins
[1819]1316        self._plotter.figure.subplots_adjust(
1317            left=lef,bottom=bot,right=rig,top=top,wspace=wsp,hspace=hsp)
1318        if self._plotter.figmgr.casabar: self._plotter.figmgr.casabar.disable_button()
1319        self._plottp(self._data)
1320        if self._minmaxy is not None:
1321            self._plotter.set_limits(ylim=self._minmaxy)
1322        self._plotter.release()
1323        self._plotter.tidy()
1324        self._plotter.show(hardrefresh=False)
1325        return
1326
1327    def _plottp(self,scan):
1328        """
1329        private method for plotting total power data
1330        """
1331        from numpy import ma, array, arange, logical_not
1332        r=0
1333        nr = scan.nrow()
1334        a0,b0 = -1,-1
1335        allxlim = []
1336        allylim = []
1337        y=[]
1338        self._plotter.set_panels()
1339        self._plotter.palette(0)
1340        #title
1341        #xlab = self._abcissa and self._abcissa[panelcount] \
1342        #       or scan._getabcissalabel()
1343        #ylab = self._ordinate and self._ordinate[panelcount] \
1344        #       or scan._get_ordinate_label()
1345        xlab = self._abcissa or 'row number' #or Time
1346        ylab = self._ordinate or scan._get_ordinate_label()
1347        self._plotter.set_axes('xlabel',xlab)
1348        self._plotter.set_axes('ylabel',ylab)
1349        lbl = self._get_label(scan, r, 's', self._title)
1350        if isinstance(lbl, list) or isinstance(lbl, tuple):
1351        #    if 0 <= panelcount < len(lbl):
1352        #        lbl = lbl[panelcount]
1353        #    else:
1354                # get default label
1355             lbl = self._get_label(scan, r, self._panelling, None)
1356        self._plotter.set_axes('title',lbl)
1357        y=array(scan._get_column(scan._getspectrum,-1))
1358        m = array(scan._get_column(scan._getmask,-1))
1359        y = ma.masked_array(y,mask=logical_not(array(m,copy=False)))
1360        x = arange(len(y))
1361        # try to handle spectral data somewhat...
1362        l,m = y.shape
1363        if m > 1:
1364            y=y.mean(axis=1)
1365        plotit = self._plotter.plot
1366        llbl = self._get_label(scan, r, self._stacking, None)
1367        self._plotter.set_line(label=llbl)
1368        if len(x) > 0:
1369            plotit(x,y)
1370
1371
1372    # forwards to matplotlib.Figure.text
1373    def figtext(self, *args, **kwargs):
1374        """
1375        Add text to figure at location x,y (relative 0-1 coords).
1376        This method forwards *args and **kwargs to a Matplotlib method,
1377        matplotlib.Figure.text.
1378        See the method help for detailed information.
1379        """
1380        self._plotter.text(*args, **kwargs)
1381    # end matplotlib.Figure.text forwarding function
1382
1383
1384    # printing header information
[1862]1385    @asaplog_post_dec
[2052]1386    def print_header(self, plot=True, fontsize=None, logger=False, selstr='', extrastr=''):
[1819]1387        """
1388        print data (scantable) header on the plot and/or logger.
1389        Parameters:
[1824]1390            plot:      whether or not print header info on the plot.
[2052]1391            fontsize:  header font size (valid only plot=True) default: 9
[1819]1392            logger:    whether or not print header info on the logger.
1393            selstr:    additional selection string (not verified)
1394            extrastr:  additional string to print (not verified)
1395        """
[1859]1396        if not plot and not logger:
1397            return
1398        if not self._data:
1399            raise RuntimeError("No scantable has been set yet.")
[1824]1400        # Now header will be printed on plot and/or logger.
1401        # Get header information and format it.
[1819]1402        ssum=self._data.__str__()
1403        # Print Observation header to the upper-left corner of plot
[2052]1404        if self._headstring:
1405            headstr = self._headstring
1406            if extrastr != '': headstr[0]=extrastr+'\n'+headstr[0]
1407            if selstr != '': headstr[2] += selstr
1408            fontsize = fontsize or self._headsize
1409        else:
[1819]1410            headstr=[ssum[ssum.find('Observer:'):ssum.find('Flux Unit:')]]
1411            headstr.append(ssum[ssum.find('Beams:'):ssum.find('Observer:')]
[2052]1412                           +ssum[ssum.find('Rest Freqs:'):ssum.find('Abcissa:')])
[1819]1413            if extrastr != '': headstr[0]=extrastr+'\n'+headstr[0]
1414            ssel='***Selections***\n'+(selstr+self._data.get_selection().__str__() or 'none')
1415            headstr.append(ssel)
[2052]1416            del ssel
1417        fontsize = fontsize or 9
1418        self._headsize = fontsize
1419        self._headstring = headstr
[1824]1420
[2052]1421        if plot:
[1819]1422            self._plotter.hold()
[2052]1423            nstcol=len(headstr)
[1819]1424            for i in range(nstcol):
1425                self._plotter.figure.text(0.03+float(i)/nstcol,0.98,
1426                             headstr[i],
1427                             horizontalalignment='left',
1428                             verticalalignment='top',
1429                             fontsize=fontsize)
1430            import time
1431            self._plotter.figure.text(0.99,0.0,
1432                            time.strftime("%a %d %b %Y  %H:%M:%S %Z"),
1433                            horizontalalignment='right',
1434                            verticalalignment='bottom',fontsize=8)
1435            self._plotter.release()
1436        if logger:
[2052]1437            sextra = headstr[0][0:headstr[0].find('Observer:')].rstrip('\n')
1438            selstr = "Selections:    "+(headstr[2].lstrip('***Selections***\n') or 'none')+"\n \n"
1439               
[1819]1440            asaplog.push("----------------\n  Plot Summary\n----------------")
[2052]1441            asaplog.push(sextra)
1442            asaplog.push(ssum[ssum.find('Beams:'):ssum.find('Selection:')]\
1443                         + selstr + ssum[ssum.find('Scan Source'):])
1444        del ssum, headstr
1445
1446#     def clear_header(self):
1447#         if not self._headstring or len(self._plotter.figure.texts) == 0:
1448#             asaplog.push("No header has been plotted. Exit without any operation")
1449#             asaplog.post("WARN")
1450#         else:
1451#             self._plotter.hold()
1452#             for textobj in self._plotter.figure.texts:
1453#                 if textobj.get_text() in self._headstring:
1454#                     try:
1455#                         textobj.remove()
1456#                     except NotImplementedError:
1457#                         self._plotter.figure.texts.pop(self._plotter.figure.texts.index(textobj))
1458#             self._plotter.release()
1459#         self._reset_header()
Note: See TracBrowser for help on using the repository browser.