source: trunk/python/asapplotter.py @ 2697

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

New Development: No

JIRA Issue: No

Ready for Test: Yes

Interface Changes: No

What Interface Changed:

Test Programs: iterate pages

Put in Release Notes: No

Module(s): asapplotter and sdplot

Description: An attempt to speed-up page iterations in ASAP plotter.


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