source: trunk/python/asapplotter.py @ 2698

Last change on this file since 2698 was 2698, 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:

Put in Release Notes: No

Module(s):

Description:

perparation for refactoring. chaged order of methods in code.


  • 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        # 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    # forwards to matplotlib axes
277    def text(self, *args, **kwargs):
278        self._assert_plotter(action="reload")
279        if kwargs.has_key("interactive"):
280            if kwargs.pop("interactive"):
281                pos = self._plotter.get_point()
282                args = tuple(pos)+args
283        self._axes_callback("text", *args, **kwargs)
284
285    text.__doc__ = matplotlib.axes.Axes.text.__doc__
286
287    def arrow(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_region()
292                dpos = (pos[0][0], pos[0][1],
293                        pos[1][0]-pos[0][0],
294                        pos[1][1] - pos[0][1])
295                args = dpos + args
296        self._axes_callback("arrow", *args, **kwargs)
297
298    arrow.__doc__ = matplotlib.axes.Axes.arrow.__doc__
299
300    def annotate(self, text, xy=None, xytext=None, **kwargs):
301        self._assert_plotter(action="reload")
302        if kwargs.has_key("interactive"):
303            if kwargs.pop("interactive"):
304                xy = self._plotter.get_point()
305                xytext = self._plotter.get_point()
306        if not kwargs.has_key("arrowprops"):
307            kwargs["arrowprops"] = dict(arrowstyle="->")
308        self._axes_callback("annotate", text, xy, xytext, **kwargs)
309
310    annotate.__doc__ = matplotlib.axes.Axes.annotate.__doc__
311
312    def axvline(self, *args, **kwargs):
313        self._assert_plotter(action="reload")
314        if kwargs.has_key("interactive"):
315            if kwargs.pop("interactive"):
316                pos = self._plotter.get_point()
317                args = (pos[0],)+args
318        self._axes_callback("axvline", *args, **kwargs)
319
320    axvline.__doc__ = matplotlib.axes.Axes.axvline.__doc__
321
322    def axhline(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[1],)+args
328        self._axes_callback("axhline", *args, **kwargs)
329
330    axhline.__doc__ = matplotlib.axes.Axes.axhline.__doc__
331
332    def axvspan(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_region()
337                dpos = (pos[0][0], pos[1][0])
338                args = dpos + args
339        self._axes_callback("axvspan", *args, **kwargs)
340        # hack to preventy mpl from redrawing the patch
341        # it seem to convert the patch into lines on every draw.
342        # This doesn't happen in a test script???
343        #del self._plotter.axes.patches[-1]
344
345    axvspan.__doc__ = matplotlib.axes.Axes.axvspan.__doc__
346
347    def axhspan(self, *args, **kwargs):
348        self._assert_plotter(action="reload")
349        if kwargs.has_key("interactive"):
350            if kwargs.pop("interactive"):
351                pos = self._plotter.get_region()
352                dpos = (pos[0][1], pos[1][1])
353                args = dpos + args
354        self._axes_callback("axhspan", *args, **kwargs)
355        # hack to preventy mpl from redrawing the patch
356        # it seem to convert the patch into lines on every draw.
357        # This doesn't happen in a test script???
358        #del self._plotter.axes.patches[-1]
359
360    axhspan.__doc__ = matplotlib.axes.Axes.axhspan.__doc__
361
362    def _axes_callback(self, axesfunc, *args, **kwargs):
363        self._assert_plotter(action="reload")
364        panel = 0
365        if kwargs.has_key("panel"):
366            panel = kwargs.pop("panel")
367        coords = None
368        if kwargs.has_key("coords"):
369            coords = kwargs.pop("coords")
370            if coords.lower() == 'world':
371                kwargs["transform"] = self._plotter.axes.transData
372            elif coords.lower() == 'relative':
373                kwargs["transform"] = self._plotter.axes.transAxes
374        self._plotter.subplot(panel)
375        self._plotter.axes.set_autoscale_on(False)
376        getattr(self._plotter.axes, axesfunc)(*args, **kwargs)
377        self._plotter.show(False)
378        self._plotter.axes.set_autoscale_on(True)
379    # end matplotlib.axes fowarding functions
380
381    # forwards to matplotlib.Figure.text
382    def figtext(self, *args, **kwargs):
383        """
384        Add text to figure at location x,y (relative 0-1 coords).
385        This method forwards *args and **kwargs to a Matplotlib method,
386        matplotlib.Figure.text.
387        See the method help for detailed information.
388        """
389        self._assert_plotter(action="reload")
390        self._plotter.text(*args, **kwargs)
391    # end matplotlib.Figure.text forwarding function
392
393    # plot setttings
394    @asaplog_post_dec
395    def set_data(self, scan, refresh=True):
396        """
397        Set a scantable to plot.
398        Parameters:
399            scan:      a scantable
400            refresh:   True (default) or False. If True, the plot is
401                       replotted based on the new parameter setting(s).
402                       Otherwise,the parameter(s) are set without replotting.
403        Note:
404           The user specified masks and data selections will be reset
405           if a new scantable is set. This method should be called before
406           setting data selections (set_selection) and/or masks (set_mask).
407        """
408        from asap import scantable
409        if isinstance(scan, scantable):
410            if (self._data is not None) and (scan != self._data):
411                del self._data
412                msg = "A new scantable is set to the plotter. "\
413                      "The masks and data selections are reset."
414                asaplog.push( msg )
415            self._data = scan
416            # reset
417            self._reset()
418        else:
419            msg = "Input is not a scantable"
420            raise TypeError(msg)
421
422        # ranges become invalid when unit changes
423        if self._abcunit and self._abcunit != self._data.get_unit():
424            self._minmaxx = None
425            self._minmaxy = None
426            self._abcunit = self._data.get_unit()
427        if refresh: self.plot()
428
429    @asaplog_post_dec
430    def set_mode(self, stacking=None, panelling=None, refresh=True):
431        """
432        Set the plots look and feel, i.e. what you want to see on the plot.
433        Parameters:
434            stacking:     tell the plotter which variable to plot
435                          as line colour overlays (default 'pol')
436            panelling:    tell the plotter which variable to plot
437                          across multiple panels (default 'scan'
438            refresh:      True (default) or False. If True, the plot is
439                          replotted based on the new parameter setting(s).
440                          Otherwise,the parameter(s) are set without replotting.
441        Note:
442            Valid modes are:
443                 'beam' 'Beam' 'b':     Beams
444                 'if' 'IF' 'i':         IFs
445                 'pol' 'Pol' 'p':       Polarisations
446                 'scan' 'Scan' 's':     Scans
447                 'time' 'Time' 't':     Times
448                 'row' 'Row' 'r':       Rows
449            When either 'stacking' or 'panelling' is set to 'row',
450            the other parameter setting is ignored.
451        """
452        msg = "Invalid mode"
453        if not self.set_panelling(panelling) or \
454               not self.set_stacking(stacking):
455            raise TypeError(msg)
456        #if self._panelling == 'r':
457        #    self._stacking = '_r'
458        #if self._stacking == 'r':
459        #    self._panelling = '_r'
460        if refresh and self._data: self.plot(self._data)
461        return
462
463    def set_stacking(self, what=None):
464        """Set the 'stacking' mode i.e. which type of spectra should be
465        overlayed.
466        """
467        mode = what
468        if mode is None:
469             mode = rcParams['plotter.stacking']
470        md = self._translate(mode)
471        if md:
472            self._stacking = md
473            self._lmap = None
474            # new mode is set. need to reset counters for multi page plotting
475            self._reset_counters()
476            return True
477        return False
478
479    def set_panelling(self, what=None):
480        """Set the 'panelling' mode i.e. which type of spectra should be
481        spread across different panels.
482        """
483
484        mode = what
485        if mode is None:
486             mode = rcParams['plotter.panelling']
487        md = self._translate(mode)
488        if md:
489            self._panelling = md
490            self._title = None
491            # new mode is set. need to reset counters for multi page plotting
492            self._reset_counters()
493            return True
494        return False
495
496    def set_layout(self,rows=None,cols=None,refresh=True):
497        """
498        Set the multi-panel layout, i.e. how many rows and columns plots
499        are visible.
500        Parameters:
501             rows:   The number of rows of plots
502             cols:   The number of columns of plots
503             refresh:  True (default) or False. If True, the plot is
504                       replotted based on the new parameter setting(s).
505                       Otherwise,the parameter(s) are set without replotting.
506        Note:
507             If no argument is given, the potter reverts to its auto-plot
508             behaviour.
509        """
510        self._rows = rows
511        self._cols = cols
512        if refresh and self._data: self.plot(self._data)
513        return
514
515    def set_range(self,xstart=None,xend=None,ystart=None,yend=None,refresh=True, offset=None):
516        """
517        Set the range of interest on the abcissa of the plot
518        Parameters:
519            [x,y]start,[x,y]end:  The start and end points of the 'zoom' window
520            refresh:  True (default) or False. If True, the plot is
521                      replotted based on the new parameter setting(s).
522                      Otherwise,the parameter(s) are set without replotting.
523            offset:   shift the abcissa by the given amount. The abcissa label will
524                      have '(relative)' appended to it.
525        Note:
526            These become non-sensical when the unit changes.
527            use plotter.set_range() without parameters to reset
528
529        """
530        self._offset = offset
531        if xstart is None and xend is None:
532            self._minmaxx = None
533        else:
534            self._minmaxx = [xstart,xend]
535        if ystart is None and yend is None:
536            self._minmaxy = None
537        else:
538            self._minmaxy = [ystart,yend]
539        if refresh and self._data: self.plot(self._data)
540        return
541
542    def set_legend(self, mp=None, fontsize = None, mode = 0, refresh=True):
543        """
544        Specify a mapping for the legend instead of using the default
545        indices:
546        Parameters:
547            mp:        a list of 'strings'. This should have the same length
548                       as the number of elements on the legend and then maps
549                       to the indeces in order. It is possible to uses latex
550                       math expression. These have to be enclosed in r'',
551                       e.g. r'$x^{2}$'
552            fontsize:  The font size of the label (default None)
553            mode:      where to display the legend
554                       Any other value for loc else disables the legend:
555                        0: auto
556                        1: upper right
557                        2: upper left
558                        3: lower left
559                        4: lower right
560                        5: right
561                        6: center left
562                        7: center right
563                        8: lower center
564                        9: upper center
565                        10: center
566            refresh:    True (default) or False. If True, the plot is
567                        replotted based on the new parameter setting(s).
568                        Otherwise,the parameter(s) are set without replotting.
569
570        Example:
571             If the data has two IFs/rest frequencies with index 0 and 1
572             for CO and SiO:
573             plotter.set_stacking('i')
574             plotter.set_legend(['CO','SiO'])
575             plotter.plot()
576             plotter.set_legend([r'$^{12}CO$', r'SiO'])
577        """
578        self._lmap = mp
579        #self._plotter.legend(mode)
580        self._legendloc = mode
581        if isinstance(fontsize, int):
582            from matplotlib import rc as rcp
583            rcp('legend', fontsize=fontsize)
584        if refresh and self._data: self.plot(self._data)
585        return
586
587    def set_title(self, title=None, fontsize=None, refresh=True):
588        """
589        Set the title of sub-plots. If multiple sub-plots are plotted,
590        multiple titles have to be specified.
591        Parameters:
592            title:      a list of titles of sub-plots.
593            fontsize:   a font size of titles (integer)
594            refresh:    True (default) or False. If True, the plot is
595                        replotted based on the new parameter setting(s).
596                        Otherwise,the parameter(s) are set without replotting.
597        Example:
598             # two panels are visible on the plotter
599             plotter.set_title(['First Panel','Second Panel'])
600        """
601        self._title = title
602        if isinstance(fontsize, int):
603            from matplotlib import rc as rcp
604            rcp('axes', titlesize=fontsize)
605        if refresh and self._data: self.plot(self._data)
606        return
607
608    def set_ordinate(self, ordinate=None, fontsize=None, refresh=True):
609        """
610        Set the y-axis label of the plot. If multiple panels are plotted,
611        multiple labels have to be specified.
612        Parameters:
613            ordinate:    a list of ordinate labels. None (default) let
614                         data determine the labels
615            fontsize:    a font size of vertical axis labels (integer)
616            refresh:     True (default) or False. If True, the plot is
617                         replotted based on the new parameter setting(s).
618                         Otherwise,the parameter(s) are set without replotting.
619        Example:
620             # two panels are visible on the plotter
621             plotter.set_ordinate(['First Y-Axis','Second Y-Axis'])
622        """
623        self._ordinate = ordinate
624        if isinstance(fontsize, int):
625            from matplotlib import rc as rcp
626            rcp('axes', labelsize=fontsize)
627            rcp('ytick', labelsize=fontsize)
628        if refresh and self._data: self.plot(self._data)
629        return
630
631    def set_abcissa(self, abcissa=None, fontsize=None, refresh=True):
632        """
633        Set the x-axis label of the plot. If multiple panels are plotted,
634        multiple labels have to be specified.
635        Parameters:
636            abcissa:     a list of abcissa labels. None (default) let
637                         data determine the labels
638            fontsize:    a font size of horizontal axis labels (integer)
639            refresh:     True (default) or False. If True, the plot is
640                         replotted based on the new parameter setting(s).
641                         Otherwise,the parameter(s) are set without replotting.
642        Example:
643             # two panels are visible on the plotter
644             plotter.set_ordinate(['First X-Axis','Second X-Axis'])
645        """
646        self._abcissa = abcissa
647        if isinstance(fontsize, int):
648            from matplotlib import rc as rcp
649            rcp('axes', labelsize=fontsize)
650            rcp('xtick', labelsize=fontsize)
651        if refresh and self._data: self.plot(self._data)
652        return
653
654    def set_colors(self, colmap, refresh=True):
655        """
656        Set the colours to be used. The plotter will cycle through
657        these colours when lines are overlaid (stacking mode).
658        Parameters:
659            colmap:     a list of colour names
660            refresh:    True (default) or False. If True, the plot is
661                        replotted based on the new parameter setting(s).
662                        Otherwise,the parameter(s) are set without replotting.
663        Example:
664             plotter.set_colors('red green blue')
665             # If for example four lines are overlaid e.g I Q U V
666             # 'I' will be 'red', 'Q' will be 'green', U will be 'blue'
667             # and 'V' will be 'red' again.
668        """
669        #if isinstance(colmap,str):
670        #    colmap = colmap.split()
671        #self._plotter.palette(0, colormap=colmap)
672        self._colormap = colmap
673        if refresh and self._data: self.plot(self._data)
674
675    # alias for english speakers
676    set_colours = set_colors
677
678    def set_histogram(self, hist=True, linewidth=None, refresh=True):
679        """
680        Enable/Disable histogram-like plotting.
681        Parameters:
682            hist:        True (default) or False. The fisrt default
683                         is taken from the .asaprc setting
684                         plotter.histogram
685            linewidth:   a line width
686            refresh:     True (default) or False. If True, the plot is
687                         replotted based on the new parameter setting(s).
688                         Otherwise,the parameter(s) are set without replotting.
689        """
690        self._hist = hist
691        if isinstance(linewidth, float) or isinstance(linewidth, int):
692            from matplotlib import rc as rcp
693            rcp('lines', linewidth=linewidth)
694        if refresh and self._data: self.plot(self._data)
695
696    def set_linestyles(self, linestyles=None, linewidth=None, refresh=True):
697        """
698        Set the linestyles to be used. The plotter will cycle through
699        these linestyles when lines are overlaid (stacking mode) AND
700        only one color has been set.
701        Parameters:
702            linestyles:      a list of linestyles to use.
703                             'line', 'dashed', 'dotted', 'dashdot',
704                             'dashdotdot' and 'dashdashdot' are
705                             possible
706            linewidth:       a line width
707            refresh:         True (default) or False. If True, the plot is
708                             replotted based on the new parameter setting(s).
709                             Otherwise,the parameter(s) are set without replotting.
710        Example:
711             plotter.set_colors('black')
712             plotter.set_linestyles('line dashed dotted dashdot')
713             # If for example four lines are overlaid e.g I Q U V
714             # 'I' will be 'solid', 'Q' will be 'dashed',
715             # U will be 'dotted' and 'V' will be 'dashdot'.
716        """
717        #if isinstance(linestyles,str):
718        #    linestyles = linestyles.split()
719        #self._plotter.palette(color=0,linestyle=0,linestyles=linestyles)
720        self._linestyles = linestyles
721        if isinstance(linewidth, float) or isinstance(linewidth, int):
722            from matplotlib import rc as rcp
723            rcp('lines', linewidth=linewidth)
724        if refresh and self._data: self.plot(self._data)
725
726    def set_font(self, refresh=True,**kwargs):
727        """
728        Set font properties.
729        Parameters:
730            family:    one of 'sans-serif', 'serif', 'cursive', 'fantasy', 'monospace'
731            style:     one of 'normal' (or 'roman'), 'italic'  or 'oblique'
732            weight:    one of 'normal or 'bold'
733            size:      the 'general' font size, individual elements can be adjusted
734                       seperately
735            refresh:   True (default) or False. If True, the plot is
736                       replotted based on the new parameter setting(s).
737                       Otherwise,the parameter(s) are set without replotting.
738        """
739        from matplotlib import rc as rcp
740        fdict = {}
741        for k,v in kwargs.iteritems():
742            if v:
743                fdict[k] = v
744        self._fp = FontProperties(**fdict)
745        if refresh and self._data: self.plot(self._data)
746
747    def set_margin(self,margin=[],refresh=True):
748        """
749        Set margins between subplots and plot edges.
750        Parameters:
751            margin:   a list of margins in figure coordinate (0-1),
752                      i.e., fraction of the figure width or height.
753                      The order of elements should be:
754                      [left, bottom, right, top, horizontal space btw panels,
755                      vertical space btw panels].
756            refresh:  True (default) or False. If True, the plot is
757                      replotted based on the new parameter setting(s).
758                      Otherwise,the parameter(s) are set without replotting.
759        Note
760        * When margin is not specified, the values are reset to the defaults
761          of matplotlib.
762        * If any element is set to be None, the current value is adopted.
763        """
764        if margin == []: self._margins=self._reset_margin()
765        else:
766            self._margins=[None]*6
767            self._margins[0:len(margin)]=margin
768        #print "panel margin set to ",self._margins
769        if refresh and self._data: self.plot(self._data)
770
771    def _reset_margin(self):
772        ks=map(lambda x: 'figure.subplot.'+x,
773               ['left','bottom','right','top','hspace','wspace'])
774        return map(matplotlib.rcParams.get,ks)
775
776    def plot_lines(self, linecat=None, doppler=0.0, deltachan=10, rotate=90.0,
777                   location=None):
778        """
779        Plot a line catalog.
780        Parameters:
781            linecat:      the linecatalog to plot
782            doppler:      the velocity shift to apply to the frequencies
783            deltachan:    the number of channels to include each side of the
784                          line to determine a local maximum/minimum
785            rotate:       the rotation (in degrees) for the text label (default 90.0)
786            location:     the location of the line annotation from the 'top',
787                          'bottom' or alternate (None - the default)
788        Notes:
789        If the spectrum is flagged no line will be drawn in that location.
790        """
791        errmsg = "Cannot plot spectral lines. Need to plot scantable first."
792        self._assert_plotter(action="halt",errmsg=errmsg)
793        if not self._data:
794            raise RuntimeError("No scantable has been plotted yet.")
795        from asap._asap import linecatalog
796        if not isinstance(linecat, linecatalog):
797            raise ValueError("'linecat' isn't of type linecatalog.")
798        if not self._data.get_unit().endswith("Hz"):
799            raise RuntimeError("Can only overlay linecatalogs when data is in frequency.")
800        from numpy import ma
801        for j in range(len(self._plotter.subplots)):
802            self._plotter.subplot(j)
803            lims = self._plotter.axes.get_xlim()
804            for row in range(linecat.nrow()):
805                # get_frequency returns MHz
806                base = { "GHz": 1000.0, "MHz": 1.0, "Hz": 1.0e-6 }
807                restf = linecat.get_frequency(row)/base[self._data.get_unit()]
808                c = 299792.458
809                freq = restf*(1.0-doppler/c)
810                if lims[0] < freq < lims[1]:
811                    if location is None:
812                        loc = 'bottom'
813                        if row%2: loc='top'
814                    else: loc = location
815                    maxys = []
816                    for line in self._plotter.axes.lines:
817                        v = line._x
818                        asc = v[0] < v[-1]
819
820                        idx = None
821                        if not asc:
822                            if v[len(v)-1] <= freq <= v[0]:
823                                i = len(v)-1
824                                while i>=0 and v[i] < freq:
825                                    idx = i
826                                    i-=1
827                        else:
828                           if v[0] <= freq <= v[len(v)-1]:
829                                i = 0
830                                while  i<len(v) and v[i] < freq:
831                                    idx = i
832                                    i+=1
833                        if idx is not None:
834                            lower = idx - deltachan
835                            upper = idx + deltachan
836                            if lower < 0: lower = 0
837                            if upper > len(v): upper = len(v)
838                            s = slice(lower, upper)
839                            y = line._y[s]
840                            maxy = ma.maximum(y)
841                            if isinstance( maxy, float):
842                                maxys.append(maxy)
843                    if len(maxys):
844                        peak = max(maxys)
845                        if peak > self._plotter.axes.get_ylim()[1]:
846                            loc = 'bottom'
847                    else:
848                        continue
849                    self._plotter.vline_with_label(freq, peak,
850                                                   linecat.get_name(row),
851                                                   location=loc, rotate=rotate)
852        self._plotter.show(hardrefresh=False)
853
854
855    def set_selection(self, selection=None, refresh=True, **kw):
856        """
857        Parameters:
858            selection:  a selector object (default unset the selection)
859            refresh:    True (default) or False. If True, the plot is
860                        replotted based on the new parameter setting(s).
861                        Otherwise,the parameter(s) are set without replotting.
862        """
863        if selection is None:
864            # reset
865            if len(kw) == 0:
866                self._selection = selector()
867            else:
868                # try keywords
869                for k in kw:
870                    if k not in selector.fields:
871                        raise KeyError("Invalid selection key '%s', valid keys are %s" % (k, selector.fields))
872                self._selection = selector(**kw)
873        elif isinstance(selection, selector):
874            self._selection = selection
875        else:
876            raise TypeError("'selection' is not of type selector")
877
878        order = self._get_sortstring([self._panelling,self._stacking])
879        if order:
880            self._selection.set_order(order)
881        if refresh and self._data:
882            self.plot()
883
884    @asaplog_post_dec
885    def set_mask(self, mask=None, selection=None, refresh=True):
886        """
887        Set a plotting mask for a specific polarization.
888        This is useful for masking out 'noise' Pangle outside a source.
889        Parameters:
890             mask:           a mask from scantable.create_mask
891             selection:      the spectra to apply the mask to.
892             refresh:        True (default) or False. If True, the plot is
893                             replotted based on the new parameter setting(s).
894                             Otherwise,the parameter(s) are set without replotting.
895        Example:
896             select = selector()
897             select.setpolstrings('Pangle')
898             plotter.set_mask(mymask, select)
899        """
900        if not self._data:
901            msg = "Can only set mask after a first call to plot()"
902            raise RuntimeError(msg)
903        if len(mask):
904            if isinstance(mask, list) or isinstance(mask, tuple):
905                self._usermask = array(mask)
906            else:
907                self._usermask = mask
908        if mask is None and selection is None:
909            self._usermask = []
910            self._maskselection = None
911        if isinstance(selection, selector):
912            self._maskselection = {'b': selection.get_beams(),
913                                   's': selection.get_scans(),
914                                   'i': selection.get_ifs(),
915                                   'p': selection.get_pols(),
916                                   't': [] }
917        else:
918            self._maskselection = None
919        if refresh: self.plot(self._data)
920
921    def _slice_indeces(self, data):
922        mn = self._minmaxx[0]
923        mx = self._minmaxx[1]
924        asc = data[0] < data[-1]
925        start=0
926        end = len(data)-1
927        inc = 1
928        if not asc:
929            start = len(data)-1
930            end = 0
931            inc = -1
932        # find min index
933        #while start > 0 and data[start] < mn:
934        #    start+= inc
935        minind=start
936        for ind in xrange(start,end+inc,inc):
937            if data[ind] > mn: break
938            minind=ind
939        # find max index
940        #while end > 0 and data[end] > mx:
941        #    end-=inc
942        #if end > 0: end +=1
943        maxind=end
944        for ind in xrange(end,start-inc,-inc):
945            if data[ind] < mx: break
946            maxind=ind
947        start=minind
948        end=maxind
949        if start > end:
950            return end,start+1
951        elif start < end:
952            return start,end+1
953        else:
954            return start,end
955
956    # reset methods
957    def _reset(self):
958        self._usermask = []
959        self._usermaskspectra = None
960        self._offset = None
961        self.set_selection(None, False)
962        self._reset_header()
963
964    def _reset_header(self):
965        self._headtext={'string': None, 'textobj': None}
966
967    def _reset_counter(self):
968        self._startrow = 0
969        self._ipanel = -1
970        self._reset_header()
971        self._panelrows = []
972        if self.casabar_exists():
973            self._plotter.figmgr.casabar.set_pagecounter(1)
974
975    def _reset_counters(self):
976        self._startrow = 0
977        self._ipanel = -1
978        self._panelrows = []
979
980    # scantable plot methods
981    @asaplog_post_dec
982    def plot(self, scan=None):
983        """
984        Plot a scantable.
985        Parameters:
986            scan:   a scantable
987        Note:
988            If a scantable was specified in a previous call
989            to plot, no argument has to be given to 'replot'
990            NO checking is done that the abcissas of the scantable
991            are consistent e.g. all 'channel' or all 'velocity' etc.
992        """
993        if not self._data and not scan:
994            msg = "Input is not a scantable"
995            raise TypeError(msg)
996
997        self._assert_plotter(action="reload")
998        self._plotter.hold()
999        self._reset_counter()
1000        #self._plotter.clear()
1001        if scan:
1002            self.set_data(scan, refresh=False)
1003        self._plotter.palette(color=0,colormap=self._colormap,
1004                              linestyle=0,linestyles=self._linestyles)
1005        self._plotter.legend(self._legendloc)
1006        self._plot(self._data)
1007        if self._minmaxy is not None:
1008            self._plotter.set_limits(ylim=self._minmaxy)
1009        if self.casabar_exists(): self._plotter.figmgr.casabar.enable_button()
1010        self._plotter.release()
1011        self._plotter.tidy()
1012        self._plotter.show(hardrefresh=False)
1013        return
1014
1015    def _plot(self, scan):
1016        savesel = scan.get_selection()
1017        sel = savesel +  self._selection
1018        order = self._get_sortstring([self._panelling,self._stacking])
1019        if order:
1020            sel.set_order(order)
1021        scan.set_selection(sel)
1022        d = {'b': scan.getbeam, 's': scan.getscan,
1023             'i': scan.getif, 'p': scan.getpol, 't': scan.get_time,
1024             'r': int}#, '_r': int}
1025
1026        polmodes = dict(zip(sel.get_pols(), sel.get_poltypes()))
1027        # this returns either a tuple of numbers or a length  (ncycles)
1028        # convert this into lengths
1029        n0,nstack0 = self._get_selected_n(scan)
1030        if isinstance(n0, int): n = n0
1031        else: n = len(n0)
1032        if isinstance(nstack0, int): nstack = nstack0
1033        else: nstack = len(nstack0)
1034        # In case of row stacking
1035        rowstack = False
1036        titlemode = self._panelling
1037        if self._stacking == "r" and self._panelling != "r":
1038            rowstack = True
1039            titlemode = '_r'
1040        nptot = n
1041        maxpanel, maxstack = 16,16
1042        if nstack > maxstack:
1043            msg ="Scan to be overlayed contains more than %d selections.\n" \
1044                  "Selecting first %d selections..." % (maxstack, maxstack)
1045            asaplog.push(msg)
1046            asaplog.post('WARN')
1047            nstack = min(nstack,maxstack)
1048        #n = min(n-self._ipanel-1,maxpanel)
1049        n = n-self._ipanel-1
1050        # the number of panels in this page
1051        if self._rows and self._cols:
1052            n = min(n,self._rows*self._cols)
1053        else:
1054            n = min(n,maxpanel)
1055
1056        firstpage = (self._ipanel < 0)
1057        #ganged = False
1058        ganged = rcParams['plotter.ganged']
1059        if self._panelling == 'i':
1060            ganged = False
1061        if not firstpage:
1062            # not the first page just clear the axis
1063            nx = self._plotter.cols
1064            ipaxx = n - nx - 1 #the max panel id to supress x-label
1065            for ip in xrange(len(self._plotter.subplots)):
1066                self._plotter.subplot(ip)
1067                self._plotter.clear()
1068                self._plotter.axes.set_visible((ip<n))
1069                if ganged:
1070                    self._plotter.axes.xaxis.label.set_visible((ip > ipaxx))
1071                    if ip <= ipaxx:
1072                        map(lambda x: x.set_visible(False), \
1073                            self._plotter.axes.get_xticklabels())
1074                    self._plotter.axes.yaxis.label.set_visible((ip % nx)==0)
1075                    if ip % nx:
1076                        map(lambda y: y.set_visible(False), \
1077                            self._plotter.axes.get_yticklabels())
1078        elif (n > 1 and self._rows and self._cols):
1079                self._plotter.set_panels(rows=self._rows,cols=self._cols,
1080                                         nplots=n,margin=self._margins,
1081                                         ganged=ganged)
1082        else:
1083            self._plotter.set_panels(rows=n,cols=0,nplots=n,
1084                                     margin=self._margins,ganged=ganged)
1085        #r = 0
1086        r = self._startrow
1087        nr = scan.nrow()
1088        a0,b0 = -1,-1
1089        allxlim = []
1090        allylim = []
1091        #newpanel=True
1092        newpanel=False
1093        panelcount,stackcount = 0,0
1094        # If this is not the first page
1095        if r > 0:
1096            # panelling value of the prev page
1097            a0 = d[self._panelling](r-1)
1098            # set the initial stackcount large not to plot
1099            # the start row automatically
1100            stackcount = nstack
1101
1102        while r < nr:
1103            a = d[self._panelling](r)
1104            b = d[self._stacking](r)
1105            if a > a0 and panelcount < n:
1106                if n > 1:
1107                    self._plotter.subplot(panelcount)
1108                self._plotter.palette(0)
1109                #title
1110                xlab = self._abcissa and self._abcissa[panelcount] \
1111                       or scan._getabcissalabel()
1112                if self._offset and not self._abcissa:
1113                    xlab += " (relative)"
1114                ylab = self._ordinate and self._ordinate[panelcount] \
1115                       or scan._get_ordinate_label()
1116                self._plotter.set_axes('xlabel', xlab)
1117                self._plotter.set_axes('ylabel', ylab)
1118                #lbl = self._get_label(scan, r, self._panelling, self._title)
1119                lbl = self._get_label(scan, r, titlemode, self._title)
1120                if isinstance(lbl, list) or isinstance(lbl, tuple):
1121                    if 0 <= panelcount < len(lbl):
1122                        lbl = lbl[panelcount]
1123                    else:
1124                        # get default label
1125                        #lbl = self._get_label(scan, r, self._panelling, None)
1126                        lbl = self._get_label(scan, r, titlemode, None)
1127                self._plotter.set_axes('title',lbl)
1128                newpanel = True
1129                stackcount = 0
1130                panelcount += 1
1131                # save the start row to plot this panel for future revisit.
1132                if self._panelling != 'r' and \
1133                       len(self._panelrows) < self._ipanel+1+panelcount:
1134                    self._panelrows += [r]
1135                   
1136            #if (b > b0 or newpanel) and stackcount < nstack:
1137            if stackcount < nstack and (newpanel or \
1138                                            rowstack or (a == a0 and b > b0)):
1139                y = []
1140                if len(polmodes):
1141                    y = scan._getspectrum(r, polmodes[scan.getpol(r)])
1142                else:
1143                    y = scan._getspectrum(r)
1144                # flag application
1145                mr = scan._getflagrow(r)
1146                from numpy import ma, array
1147                if mr:
1148                    y = ma.masked_array(y,mask=mr)
1149                else:
1150                    m = scan._getmask(r)
1151                    from numpy import logical_not, logical_and
1152                    if self._maskselection and len(self._usermask) == len(m):
1153                        if d[self._stacking](r) in self._maskselection[self._stacking]:
1154                            m = logical_and(m, self._usermask)
1155                    y = ma.masked_array(y,mask=logical_not(array(m,copy=False)))
1156
1157                x = array(scan._getabcissa(r))
1158                if self._offset:
1159                    x += self._offset
1160                if self._minmaxx is not None:
1161                    s,e = self._slice_indeces(x)
1162                    x = x[s:e]
1163                    y = y[s:e]
1164                if len(x) > 1024 and rcParams['plotter.decimate']:
1165                    fac = len(x)/1024
1166                    x = x[::fac]
1167                    y = y[::fac]
1168                llbl = self._get_label(scan, r, self._stacking, self._lmap)
1169                if isinstance(llbl, list) or isinstance(llbl, tuple):
1170                    if 0 <= stackcount < len(llbl):
1171                        # use user label
1172                        llbl = llbl[stackcount]
1173                    else:
1174                        # get default label
1175                        llbl = self._get_label(scan, r, self._stacking, None)
1176                self._plotter.set_line(label=llbl)
1177                plotit = self._plotter.plot
1178                if self._hist: plotit = self._plotter.hist
1179                if len(x) > 0 and not mr:
1180                    plotit(x,y)
1181                    xlim= self._minmaxx or [min(x),max(x)]
1182                    allxlim += xlim
1183                    ylim= self._minmaxy or [ma.minimum(y),ma.maximum(y)]
1184                    allylim += ylim
1185                else:
1186                    xlim = self._minmaxx or []
1187                    allxlim += xlim
1188                    ylim= self._minmaxy or []
1189                    allylim += ylim
1190                stackcount += 1
1191                a0=a
1192                b0=b
1193                # last in colour stack -> autoscale x
1194                if stackcount == nstack and len(allxlim) > 0:
1195                    allxlim.sort()
1196                    self._plotter.subplots[panelcount-1]['axes'].set_xlim([allxlim[0],allxlim[-1]])
1197                    if ganged:
1198                        allxlim = [allxlim[0],allxlim[-1]]
1199                    else:
1200                        # clear
1201                        allxlim =[]
1202
1203            newpanel = False
1204            #a0=a
1205            #b0=b
1206            # ignore following rows
1207            if (panelcount == n and stackcount == nstack) or (r == nr-1):
1208                # last panel -> autoscale y if ganged
1209                #if rcParams['plotter.ganged'] and len(allylim) > 0:
1210                if ganged and len(allylim) > 0:
1211                    allylim.sort()
1212                    self._plotter.set_limits(ylim=[allylim[0],allylim[-1]])
1213                break
1214            r+=1 # next row
1215
1216        # save the current counter for multi-page plotting
1217        self._startrow = r+1
1218        self._ipanel += panelcount
1219        if self.casabar_exists():
1220            if self._ipanel >= nptot-1:
1221                self._plotter.figmgr.casabar.disable_next()
1222            else:
1223                self._plotter.figmgr.casabar.enable_next()
1224            if self._ipanel + 1 - panelcount > 0:
1225                self._plotter.figmgr.casabar.enable_prev()
1226            else:
1227                self._plotter.figmgr.casabar.disable_prev()
1228
1229        #reset the selector to the scantable's original
1230        scan.set_selection(savesel)
1231
1232        #temporary switch-off for older matplotlib
1233        #if self._fp is not None:
1234        if self._fp is not None and \
1235               getattr(self._plotter.figure,'findobj',False):
1236            for o in self._plotter.figure.findobj(Text):
1237                if not self._headtext['textobj'] or \
1238                   not (o in self._headtext['textobj']):
1239                    o.set_fontproperties(self._fp)
1240
1241    def _get_sortstring(self, lorders):
1242        d0 = {'s': 'SCANNO', 'b': 'BEAMNO', 'i':'IFNO',
1243              'p': 'POLNO', 'c': 'CYCLENO', 't' : 'TIME', 'r':None, '_r':None }
1244        if not (type(lorders) == list) and not (type(lorders) == tuple):
1245            return None
1246        if len(lorders) > 0:
1247            lsorts = []
1248            for order in lorders:
1249                if order == "r":
1250                    # don't sort if row panelling/stacking
1251                    return None
1252                ssort = d0[order]
1253                if ssort:
1254                    lsorts.append(ssort)
1255            return lsorts
1256        return None
1257
1258    def _get_selected_n(self, scan):
1259        d1 = {'b': scan.getbeamnos, 's': scan.getscannos,
1260             'i': scan.getifnos, 'p': scan.getpolnos, 't': scan.ncycle,
1261             'r': scan.nrow}#, '_r': False}
1262        d2 = { 'b': self._selection.get_beams(),
1263               's': self._selection.get_scans(),
1264               'i': self._selection.get_ifs(),
1265               'p': self._selection.get_pols(),
1266               't': self._selection.get_cycles(),
1267               'r': False}#, '_r': 1}
1268        n =  d2[self._panelling] or d1[self._panelling]()
1269        nstack = d2[self._stacking] or d1[self._stacking]()
1270        # handle row panelling/stacking
1271        if self._panelling == 'r':
1272            nstack = 1
1273        elif self._stacking == 'r':
1274            n = 1
1275        return n,nstack
1276
1277    def _get_label(self, scan, row, mode, userlabel=None):
1278        if isinstance(userlabel, list) and len(userlabel) == 0:
1279            userlabel = " "
1280        pms = dict(zip(self._selection.get_pols(),self._selection.get_poltypes()))
1281        if len(pms):
1282            poleval = scan._getpollabel(scan.getpol(row),pms[scan.getpol(row)])
1283        else:
1284            poleval = scan._getpollabel(scan.getpol(row),scan.poltype())
1285        d = {'b': "Beam "+str(scan.getbeam(row)),
1286             #'s': scan._getsourcename(row),
1287             's': "Scan "+str(scan.getscan(row))+\
1288                  " ("+str(scan._getsourcename(row))+")",
1289             'i': "IF"+str(scan.getif(row)),
1290             'p': poleval,
1291             't': str(scan.get_time(row)),
1292             'r': "row "+str(row),
1293             #'_r': str(scan.get_time(row))+",\nIF"+str(scan.getif(row))+", "+poleval+", Beam"+str(scan.getbeam(row)) }
1294             '_r': "" }
1295        return userlabel or d[mode]
1296
1297    def plotazel(self, scan=None, outfile=None):
1298        """
1299        plot azimuth and elevation versus time of a scantable
1300        """
1301        visible = rcParams['plotter.gui']
1302        from matplotlib import pylab as PL
1303        from matplotlib.dates import DateFormatter
1304        from pytz import timezone
1305        from matplotlib.dates import HourLocator, MinuteLocator,SecondLocator, DayLocator
1306        from matplotlib.ticker import MultipleLocator
1307        from numpy import array, pi
1308        if not visible or not self._visible:
1309            PL.ioff()
1310            from matplotlib.backends.backend_agg import FigureCanvasAgg
1311            PL.gcf().canvas.switch_backends(FigureCanvasAgg)
1312        self._data = scan
1313        dates = self._data.get_time(asdatetime=True)
1314        t = PL.date2num(dates)
1315        tz = timezone('UTC')
1316        PL.cla()
1317        PL.ioff()
1318        PL.clf()
1319        # Adjust subplot margins
1320        if not self._margins or len(self._margins) != 6:
1321            self.set_margin(refresh=False)
1322        lef, bot, rig, top, wsp, hsp = self._margins
1323        PL.gcf().subplots_adjust(left=lef,bottom=bot,right=rig,top=top,
1324                                 wspace=wsp,hspace=hsp)
1325
1326        tdel = max(t) - min(t)
1327        ax = PL.subplot(2,1,1)
1328        el = array(self._data.get_elevation())*180./pi
1329        PL.ylabel('El [deg.]')
1330        dstr = dates[0].strftime('%Y/%m/%d')
1331        if tdel > 1.0:
1332            dstr2 = dates[len(dates)-1].strftime('%Y/%m/%d')
1333            dstr = dstr + " - " + dstr2
1334            majloc = DayLocator()
1335            minloc = HourLocator(range(0,23,12))
1336            timefmt = DateFormatter("%b%d")
1337        elif tdel > 24./60.:
1338            timefmt = DateFormatter('%H:%M')
1339            majloc = HourLocator()
1340            minloc = MinuteLocator(30)
1341        else:
1342            timefmt = DateFormatter('%H:%M')
1343            majloc = MinuteLocator(interval=5)
1344            minloc = SecondLocator(30)
1345
1346        PL.title(dstr)
1347        if tdel == 0.0:
1348            th = (t - PL.floor(t))*24.0
1349            PL.plot(th,el,'o',markersize=2, markerfacecolor='b', markeredgecolor='b')
1350        else:
1351            PL.plot_date(t,el,'o', markersize=2, markerfacecolor='b', markeredgecolor='b',tz=tz)
1352            #ax.grid(True)
1353            ax.xaxis.set_major_formatter(timefmt)
1354            ax.xaxis.set_major_locator(majloc)
1355            ax.xaxis.set_minor_locator(minloc)
1356        ax.yaxis.grid(True)
1357        yloc = MultipleLocator(30)
1358        ax.set_ylim(0,90)
1359        ax.yaxis.set_major_locator(yloc)
1360        if tdel > 1.0:
1361            labels = ax.get_xticklabels()
1362        #    PL.setp(labels, fontsize=10, rotation=45)
1363            PL.setp(labels, fontsize=10)
1364
1365        # Az plot
1366        az = array(self._data.get_azimuth())*180./pi
1367        if min(az) < 0:
1368            for irow in range(len(az)):
1369                if az[irow] < 0: az[irow] += 360.0
1370
1371        ax2 = PL.subplot(2,1,2)
1372        #PL.xlabel('Time (UT [hour])')
1373        PL.ylabel('Az [deg.]')
1374        if tdel == 0.0:
1375            PL.plot(th,az,'o',markersize=2, markeredgecolor='b',markerfacecolor='b')
1376        else:
1377            PL.plot_date(t,az,'o', markersize=2,markeredgecolor='b',markerfacecolor='b',tz=tz)
1378            ax2.xaxis.set_major_formatter(timefmt)
1379            ax2.xaxis.set_major_locator(majloc)
1380            ax2.xaxis.set_minor_locator(minloc)
1381        #ax2.grid(True)
1382        ax2.set_ylim(0,360)
1383        ax2.yaxis.grid(True)
1384        #hfmt = DateFormatter('%H')
1385        #hloc = HourLocator()
1386        yloc = MultipleLocator(60)
1387        ax2.yaxis.set_major_locator(yloc)
1388        if tdel > 1.0:
1389            labels = ax2.get_xticklabels()
1390            PL.setp(labels, fontsize=10)
1391            PL.xlabel('Time (UT [day])')
1392        else:
1393            PL.xlabel('Time (UT [hour])')
1394
1395        PL.ion()
1396        PL.draw()
1397        if matplotlib.get_backend() == 'Qt4Agg': PL.gcf().show()
1398        if (outfile is not None):
1399           PL.savefig(outfile)
1400
1401
1402    def plotpointing2(self, scan=None, colorby='', showline=False, projection=''):
1403        """
1404        plot telescope pointings
1405        Parameters:
1406            infile  : input filename or scantable instance
1407            colorby : change color by either
1408                      'type'(source type)|'scan'|'if'|'pol'|'beam'
1409            showline : show dotted line
1410            projection : projection type either
1411                         ''(no projection [deg])|'coord'(not implemented)
1412        """
1413        from numpy import array, pi
1414        from asap import scantable
1415        # check for scantable
1416        if isinstance(scan, scantable):
1417            if self._data is not None:
1418                if scan != self._data:
1419                    self._data = scan
1420                    # reset
1421                    self._reset()
1422            else:
1423                self._data = scan
1424                self._reset()
1425        if not self._data:
1426            msg = "Input is not a scantable"
1427            raise TypeError(msg)
1428        # check for color mode
1429        validtypes=['type','scan','if','pol', 'beam']
1430        stype = None
1431        if (colorby in validtypes):
1432            stype = colorby[0]
1433        elif len(colorby) > 0:
1434            msg = "Invalid choice of 'colorby' (choices: %s)" % str(validtypes)
1435            raise ValueError(msg)
1436        self._assert_plotter(action="reload")
1437        self._plotter.hold()
1438        self._reset_counter()
1439        if self.casabar_exists():
1440            self._plotter.figmgr.casabar.disable_button()
1441        # for now, only one plot
1442        self._plotter.set_panels(rows=1,cols=1)
1443        # first panel
1444        self._plotter.subplot(0)
1445        # first color and linestyles
1446        self._plotter.palette(0)
1447        self.gca().set_aspect('equal')
1448        basesel = scan.get_selection()
1449        attrback = self._plotter.get_line()
1450        marker = "o"
1451        if showline:
1452            basesel.set_order(["TIME"])
1453            scan.set_selection(basesel)
1454            if not (stype in ["t", "s"]):
1455                marker += ":"
1456        self._plotter.set_line(markersize=3, markeredgewidth=0)
1457
1458        if not stype:
1459            selIds = [""] # cheating
1460            sellab = "all points"
1461        elif stype == 't':
1462            selIds = range(15)
1463            sellab = "src type "
1464        else:
1465            selIds = getattr(self._data,'get'+colorby+'nos')()
1466            sellab = colorby.upper()
1467        selFunc = "set_"+colorby+"s"
1468        for idx in selIds:
1469            sel = selector() + basesel
1470            if stype:
1471                bid = getattr(basesel,'get_'+colorby+"s")()
1472                if (len(bid) > 0) and (not idx in bid):
1473                    # base selection doesn't contain idx
1474                    # Note summation of selector is logical sum if
1475                    continue
1476                getattr(sel, selFunc)([idx])
1477            if not sel.is_empty():
1478                try:
1479                    self._data.set_selection(sel)
1480                except RuntimeError, instance:
1481                    if stype == 't' and str(instance).startswith("Selection contains no data."):
1482                        continue
1483                    else:
1484                        self._data.set_selection(basesel)
1485                        raise RuntimeError, instance
1486            if self._data.nrow() == 0:
1487                self._data.set_selection(basesel)
1488                continue
1489            print "Plotting direction of %s = %s" % (colorby, str(idx))
1490            # getting data to plot
1491            dir = array(self._data.get_directionval()).transpose()
1492            ra = dir[0]*180./pi
1493            dec = dir[1]*180./pi
1494            # actual plot
1495            self._plotter.set_line(label=(sellab+str(idx)))
1496            self._plotter.plot(ra,dec,marker)
1497
1498        # restore original selection
1499        self._data.set_selection(basesel)
1500        # need to plot scan pattern explicitly
1501        if showline and (stype in ["t", "s"]):
1502            dir = array(self._data.get_directionval()).transpose()
1503            ra = dir[0]*180./pi
1504            dec = dir[1]*180./pi
1505            self._plotter.set_line(label="scan pattern")
1506            self._plotter.plot(ra,dec,":")
1507            # set color for only this line
1508            self._plotter.lines[-1][0].set_color("gray")
1509
1510        xlab = 'RA [deg.]'
1511        ylab = 'Declination [deg.]'
1512        self._plotter.set_axes('xlabel', xlab)
1513        self._plotter.set_axes('ylabel', ylab)
1514        self._plotter.set_axes('title', 'Telescope pointings')
1515        if stype: self._plotter.legend(self._legendloc)
1516        else: self._plotter.legend(None)
1517        # reverse x-axis
1518        xmin, xmax = self.gca().get_xlim()
1519        self._plotter.set_limits(xlim=[xmax,xmin])
1520
1521        self._plotter.release()
1522        self._plotter.show(hardrefresh=False)
1523        # reset line settings
1524        self._plotter.set_line(**attrback)
1525        return
1526
1527    def plotpointing(self, scan=None, outfile=None):
1528        """
1529        plot telescope pointings
1530        """
1531        visible = rcParams['plotter.gui']
1532        from matplotlib import pylab as PL
1533        from numpy import array, pi
1534        if not visible or not self._visible:
1535            PL.ioff()
1536            from matplotlib.backends.backend_agg import FigureCanvasAgg
1537            PL.gcf().canvas.switch_backends(FigureCanvasAgg)
1538        self._data = scan
1539        dir = array(self._data.get_directionval()).transpose()
1540        ra = dir[0]*180./pi
1541        dec = dir[1]*180./pi
1542        PL.cla()
1543        #PL.ioff()
1544        PL.clf()
1545        # Adjust subplot margins
1546        if not self._margins or len(self._margins) != 6:
1547            self.set_margin(refresh=False)
1548        lef, bot, rig, top, wsp, hsp = self._margins
1549        PL.gcf().subplots_adjust(left=lef,bottom=bot,right=rig,top=top,
1550                                 wspace=wsp,hspace=hsp)
1551        ax = PL.gca()
1552        #ax = PL.axes([0.1,0.1,0.8,0.8])
1553        #ax = PL.axes([0.1,0.1,0.8,0.8])
1554        ax.set_aspect('equal')
1555        PL.plot(ra, dec, 'b,')
1556        PL.xlabel('RA [deg.]')
1557        PL.ylabel('Declination [deg.]')
1558        PL.title('Telescope pointings')
1559        [xmin,xmax,ymin,ymax] = PL.axis()
1560        PL.axis([xmax,xmin,ymin,ymax])
1561        PL.ion()
1562        PL.draw()
1563        if matplotlib.get_backend() == 'Qt4Agg': PL.gcf().show()
1564        if (outfile is not None):
1565           PL.savefig(outfile)
1566
1567    # plot total power data
1568    # plotting in time is not yet implemented..
1569    @asaplog_post_dec
1570    def plottp(self, scan=None):
1571        from asap import scantable
1572        if not self._data and not scan:
1573            msg = "Input is not a scantable"
1574            raise TypeError(msg)
1575        if isinstance(scan, scantable):
1576            if self._data is not None:
1577                if scan != self._data:
1578                    self._data = scan
1579                    # reset
1580                    self._reset()
1581            else:
1582                self._data = scan
1583                self._reset()
1584        # ranges become invalid when abcissa changes?
1585        #if self._abcunit and self._abcunit != self._data.get_unit():
1586        #    self._minmaxx = None
1587        #    self._minmaxy = None
1588        #    self._abcunit = self._data.get_unit()
1589
1590        self._assert_plotter(action="reload")
1591        self._plotter.hold()
1592        self._plotter.clear()
1593        # Adjust subplot margins
1594        if not self._margins or len(self._margins) !=6:
1595            self.set_margin(refresh=False)
1596        lef, bot, rig, top, wsp, hsp = self._margins
1597        self._plotter.figure.subplots_adjust(
1598            left=lef,bottom=bot,right=rig,top=top,wspace=wsp,hspace=hsp)
1599        if self.casabar_exists(): self._plotter.figmgr.casabar.disable_button()
1600        self._plottp(self._data)
1601        if self._minmaxy is not None:
1602            self._plotter.set_limits(ylim=self._minmaxy)
1603        self._plotter.release()
1604        self._plotter.tidy()
1605        self._plotter.show(hardrefresh=False)
1606        return
1607
1608    def _plottp(self,scan):
1609        """
1610        private method for plotting total power data
1611        """
1612        from numpy import ma, array, arange, logical_not
1613        r=0
1614        nr = scan.nrow()
1615        a0,b0 = -1,-1
1616        allxlim = []
1617        allylim = []
1618        y=[]
1619        self._plotter.set_panels()
1620        self._plotter.palette(0)
1621        #title
1622        #xlab = self._abcissa and self._abcissa[panelcount] \
1623        #       or scan._getabcissalabel()
1624        #ylab = self._ordinate and self._ordinate[panelcount] \
1625        #       or scan._get_ordinate_label()
1626        xlab = self._abcissa or 'row number' #or Time
1627        ylab = self._ordinate or scan._get_ordinate_label()
1628        self._plotter.set_axes('xlabel',xlab)
1629        self._plotter.set_axes('ylabel',ylab)
1630        lbl = self._get_label(scan, r, 's', self._title)
1631        if isinstance(lbl, list) or isinstance(lbl, tuple):
1632        #    if 0 <= panelcount < len(lbl):
1633        #        lbl = lbl[panelcount]
1634        #    else:
1635                # get default label
1636             lbl = self._get_label(scan, r, self._panelling, None)
1637        self._plotter.set_axes('title',lbl)
1638        y=array(scan._get_column(scan._getspectrum,-1))
1639        m = array(scan._get_column(scan._getmask,-1))
1640        y = ma.masked_array(y,mask=logical_not(array(m,copy=False)))
1641        x = arange(len(y))
1642        # try to handle spectral data somewhat...
1643        l,m = y.shape
1644        if m > 1:
1645            y=y.mean(axis=1)
1646        plotit = self._plotter.plot
1647        llbl = self._get_label(scan, r, self._stacking, None)
1648        self._plotter.set_line(label=llbl)
1649        if len(x) > 0:
1650            plotit(x,y)
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.