source: trunk/python/asapplotter.py @ 2714

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

New Development: No

JIRA Issue: No (a minor fix)

Ready for Test: Yes

Interface Changes: No

What Interface Changed:

Test Programs: unit tests of sdplot

Put in Release Notes: No

Module(s): asapplotter and sdplot

Description: more resetting when new scantable is set to plot.


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