source: trunk/python/asapplotter.py @ 2699

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

New Development: No

JIRA Issue: No (bug fixes)

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:

Fixed a bug which caused failure of plots by user defined linestyles.
Made sure data is plotted on mpl plotter (not on ASAP plotter) by
plotpointing and plotazel.


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