source: trunk/python/asapplotter.py @ 2704

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

New Development: No (a bug fix)

JIRA Issue: No

Ready for Test: Yes

Interface Changes: No

What Interface Changed:

Test Programs:

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

Put in Release Notes: No

Module(s): asapplotter and sdplot

Description:

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


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