source: trunk/python/asapplotter.py @ 1982

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

New Development: Yes

JIRA Issue: Yes (CAS-1822/ASAP-204)

Ready for Test: Yes

Interface Changes: Yes

What Interface Changed: Added "-" page button and page counter to the ASAP plotter

Test Programs: plot spectra and press Page: "+" and "-" button to go

back and forth between the pages

Put in Release Notes: Yes

Module(s): asapplotter and sdplot (CASA)

Description:

Added "-" page button and page counter to the ASAP plotter.
Renamed "+ page" button to "+" button.
You can plot multi-page plots and move back and forth between pages.

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