source: branches/alma/python/asapplotter.py @ 1562

Last change on this file since 1562 was 1562, checked in by Kana Sugimoto, 15 years ago

New Development: No

JIRA Issue: Yes (CAS-1298)

Ready to Release: Yes

Interface Changes: No

What Interface Changed:

Test Programs: run sdplot() with wrong 'sprange' or 'flrange' selections

Put in Release Notes: No

Module(s): tools and tasks which calls sd.plotter.plot()

Description:

Methods plot() and _slice_indeces() are modified to fix bugs in ASAP plotter.
The method _slice_indeces() is modified to avoid index referencing error and
to return precise 'slice indices'.
The method plot() is modified to avoid invalid index referencing when setting
plot range. The y-range of the plot will be set to the default plot range of
Matplotlib, i.e., [0,1], if flrange is not set and the selected sprange is out
of range.


  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 36.9 KB
Line 
1from asap import rcParams, print_log, selector
2import matplotlib.axes
3import re
4
5class asapplotter:
6    """
7    The ASAP plotter.
8    By default the plotter is set up to plot polarisations
9    'colour stacked' and scantables across panels.
10    Note:
11        Currenly it only plots 'spectra' not Tsys or
12        other variables.
13    """
14    def __init__(self, visible=None):
15        self._visible = rcParams['plotter.gui']
16        if visible is not None:
17            self._visible = visible
18        self._plotter = self._newplotter()
19
20        self._panelling = None
21        self._stacking = None
22        self.set_panelling()
23        self.set_stacking()
24        self._rows = None
25        self._cols = None
26        self._autoplot = False
27        self._minmaxx = None
28        self._minmaxy = None
29        self._datamask = None
30        self._data = None
31        self._lmap = None
32        self._title = None
33        self._ordinate = None
34        self._abcissa = None
35        self._abcunit = None
36        self._usermask = []
37        self._maskselection = None
38        self._selection = selector()
39        self._hist = rcParams['plotter.histogram']
40
41    def _translate(self, instr):
42        keys = "s b i p t".split()
43        if isinstance(instr, str):
44            for key in keys:
45                if instr.lower().startswith(key):
46                    return key
47        return None
48
49    def _newplotter(self):
50        if self._visible:
51            from asap.asaplotgui import asaplotgui as asaplot
52        else:
53            from asap.asaplot import asaplot
54        return asaplot()
55
56
57    def plot(self, scan=None):
58        """
59        Plot a scantable.
60        Parameters:
61            scan:   a scantable
62        Note:
63            If a scantable was specified in a previous call
64            to plot, no argument has to be given to 'replot'
65            NO checking is done that the abcissas of the scantable
66            are consistent e.g. all 'channel' or all 'velocity' etc.
67        """
68        if self._plotter.is_dead:
69            self._plotter = self._newplotter()
70        self._plotter.hold()
71        self._plotter.clear()
72        from asap import scantable
73        if not self._data and not scan:
74            msg = "Input is not a scantable"
75            if rcParams['verbose']:
76                print msg
77                return
78            raise TypeError(msg)
79        if isinstance(scan, scantable):
80            if self._data is not None:
81                if scan != self._data:
82                    self._data = scan
83                    # reset
84                    self._reset()
85            else:
86                self._data = scan
87                self._reset()
88        # ranges become invalid when unit changes
89        if self._abcunit and self._abcunit != self._data.get_unit():
90            self._minmaxx = None
91            self._minmaxy = None
92            self._abcunit = self._data.get_unit()
93            self._datamask = None
94        self._plot(self._data)
95        if self._minmaxy is not None:
96            self._plotter.set_limits(ylim=self._minmaxy)
97        self._plotter.release()
98        self._plotter.tidy()
99        self._plotter.show(hardrefresh=False)
100        print_log()
101        return
102
103
104    # forwards to matplotlib axes
105    def text(self, *args, **kwargs):
106        self._axes_callback("text", *args, **kwargs)
107    text.__doc__ = matplotlib.axes.Axes.text.__doc__
108    def arrow(self, *args, **kwargs):
109        self._axes_callback("arrow", *args, **kwargs)
110    arrow.__doc__ = matplotlib.axes.Axes.arrow.__doc__
111    def axvline(self, *args, **kwargs):
112        self._axes_callback("axvline", *args, **kwargs)
113    axvline.__doc__ = matplotlib.axes.Axes.axvline.__doc__
114    def axhline(self, *args, **kwargs):
115        self._axes_callback("axhline", *args, **kwargs)
116    axhline.__doc__ = matplotlib.axes.Axes.axhline.__doc__
117    def axvspan(self, *args, **kwargs):
118        self._axes_callback("axvspan", *args, **kwargs)
119        # hack to preventy mpl from redrawing the patch
120        # it seem to convert the patch into lines on every draw.
121        # This doesn't happen in a test script???
122        del self._plotter.axes.patches[-1]
123    axvspan.__doc__ = matplotlib.axes.Axes.axvspan.__doc__
124
125    def axhspan(self, *args, **kwargs):
126        self._axes_callback("axhspan", *args, **kwargs)
127        # hack to preventy mpl from redrawing the patch
128        # it seem to convert the patch into lines on every draw.
129        # This doesn't happen in a test script???
130        del self._plotter.axes.patches[-1]
131    axhspan.__doc__ = matplotlib.axes.Axes.axhspan.__doc__
132
133    def _axes_callback(self, axesfunc, *args, **kwargs):
134        panel = 0
135        if kwargs.has_key("panel"):
136            panel = kwargs.pop("panel")
137        coords = None
138        if kwargs.has_key("coords"):
139            coords = kwargs.pop("coords")
140            if coords.lower() == 'world':
141                kwargs["transform"] = self._plotter.axes.transData
142            elif coords.lower() == 'relative':
143                kwargs["transform"] = self._plotter.axes.transAxes
144        self._plotter.subplot(panel)
145        self._plotter.axes.set_autoscale_on(False)
146        getattr(self._plotter.axes, axesfunc)(*args, **kwargs)
147        self._plotter.show(False)
148        self._plotter.axes.set_autoscale_on(True)
149    # end matplotlib.axes fowarding functions
150
151    def set_mode(self, stacking=None, panelling=None):
152        """
153        Set the plots look and feel, i.e. what you want to see on the plot.
154        Parameters:
155            stacking:     tell the plotter which variable to plot
156                          as line colour overlays (default 'pol')
157            panelling:    tell the plotter which variable to plot
158                          across multiple panels (default 'scan'
159        Note:
160            Valid modes are:
161                 'beam' 'Beam' 'b':     Beams
162                 'if' 'IF' 'i':         IFs
163                 'pol' 'Pol' 'p':       Polarisations
164                 'scan' 'Scan' 's':     Scans
165                 'time' 'Time' 't':     Times
166        """
167        msg = "Invalid mode"
168        if not self.set_panelling(panelling) or \
169               not self.set_stacking(stacking):
170            if rcParams['verbose']:
171                print msg
172                return
173            else:
174                raise TypeError(msg)
175        if self._data: self.plot(self._data)
176        return
177
178    def set_panelling(self, what=None):
179        mode = what
180        if mode is None:
181             mode = rcParams['plotter.panelling']
182        md = self._translate(mode)
183        if md:
184            self._panelling = md
185            self._title = None
186            return True
187        return False
188
189    def set_layout(self,rows=None,cols=None):
190        """
191        Set the multi-panel layout, i.e. how many rows and columns plots
192        are visible.
193        Parameters:
194             rows:   The number of rows of plots
195             cols:   The number of columns of plots
196        Note:
197             If no argument is given, the potter reverts to its auto-plot
198             behaviour.
199        """
200        self._rows = rows
201        self._cols = cols
202        if self._data: self.plot(self._data)
203        return
204
205    def set_stacking(self, what=None):
206        mode = what
207        if mode is None:
208             mode = rcParams['plotter.stacking']
209        md = self._translate(mode)
210        if md:
211            self._stacking = md
212            self._lmap = None
213            return True
214        return False
215
216    def set_range(self,xstart=None,xend=None,ystart=None,yend=None):
217        """
218        Set the range of interest on the abcissa of the plot
219        Parameters:
220            [x,y]start,[x,y]end:  The start and end points of the 'zoom' window
221        Note:
222            These become non-sensical when the unit changes.
223            use plotter.set_range() without parameters to reset
224
225        """
226        if xstart is None and xend is None:
227            self._minmaxx = None
228        else:
229            self._minmaxx = [xstart,xend]
230        if ystart is None and yend is None:
231            self._minmaxy = None
232        else:
233            self._minmaxy = [ystart,yend]
234        if self._data: self.plot(self._data)
235        return
236
237    def set_legend(self, mp=None, fontsize = None, mode = 0):
238        """
239        Specify a mapping for the legend instead of using the default
240        indices:
241        Parameters:
242            mp:        a list of 'strings'. This should have the same length
243                       as the number of elements on the legend and then maps
244                       to the indeces in order. It is possible to uses latex
245                       math expression. These have to be enclosed in r'',
246                       e.g. r'$x^{2}$'
247            fontsize:  The font size of the label (default None)
248            mode:      where to display the legend
249                       Any other value for loc else disables the legend:
250                        0: auto
251                        1: upper right
252                        2: upper left
253                        3: lower left
254                        4: lower right
255                        5: right
256                        6: center left
257                        7: center right
258                        8: lower center
259                        9: upper center
260                        10: center
261
262        Example:
263             If the data has two IFs/rest frequencies with index 0 and 1
264             for CO and SiO:
265             plotter.set_stacking('i')
266             plotter.set_legend(['CO','SiO'])
267             plotter.plot()
268             plotter.set_legend([r'$^{12}CO$', r'SiO'])
269        """
270        self._lmap = mp
271        self._plotter.legend(mode)
272        if isinstance(fontsize, int):
273            from matplotlib import rc as rcp
274            rcp('legend', fontsize=fontsize)
275        if self._data:
276            self.plot(self._data)
277        return
278
279    def set_title(self, title=None, fontsize=None):
280        """
281        Set the title of the plot. If multiple panels are plotted,
282        multiple titles have to be specified.
283        Example:
284             # two panels are visible on the plotter
285             plotter.set_title(["First Panel","Second Panel"])
286        """
287        self._title = title
288        if isinstance(fontsize, int):
289            from matplotlib import rc as rcp
290            rcp('axes', titlesize=fontsize)
291        if self._data: self.plot(self._data)
292        return
293
294    def set_ordinate(self, ordinate=None, fontsize=None):
295        """
296        Set the y-axis label of the plot. If multiple panels are plotted,
297        multiple labels have to be specified.
298        Parameters:
299            ordinate:    a list of ordinate labels. None (default) let
300                         data determine the labels
301        Example:
302             # two panels are visible on the plotter
303             plotter.set_ordinate(["First Y-Axis","Second Y-Axis"])
304        """
305        self._ordinate = ordinate
306        if isinstance(fontsize, int):
307            from matplotlib import rc as rcp
308            rcp('axes', labelsize=fontsize)
309            rcp('ytick', labelsize=fontsize)
310        if self._data: self.plot(self._data)
311        return
312
313    def set_abcissa(self, abcissa=None, fontsize=None):
314        """
315        Set the x-axis label of the plot. If multiple panels are plotted,
316        multiple labels have to be specified.
317        Parameters:
318            abcissa:     a list of abcissa labels. None (default) let
319                         data determine the labels
320        Example:
321             # two panels are visible on the plotter
322             plotter.set_ordinate(["First X-Axis","Second X-Axis"])
323        """
324        self._abcissa = abcissa
325        if isinstance(fontsize, int):
326            from matplotlib import rc as rcp
327            rcp('axes', labelsize=fontsize)
328            rcp('xtick', labelsize=fontsize)
329        if self._data: self.plot(self._data)
330        return
331
332    def set_colors(self, colmap):
333        """
334        Set the colours to be used. The plotter will cycle through
335        these colours when lines are overlaid (stacking mode).
336        Parameters:
337            colmap:     a list of colour names
338        Example:
339             plotter.set_colors("red green blue")
340             # If for example four lines are overlaid e.g I Q U V
341             # 'I' will be 'red', 'Q' will be 'green', U will be 'blue'
342             # and 'V' will be 'red' again.
343        """
344        if isinstance(colmap,str):
345            colmap = colmap.split()
346        self._plotter.palette(0, colormap=colmap)
347        if self._data: self.plot(self._data)
348
349    # alias for english speakers
350    set_colours = set_colors
351
352    def set_histogram(self, hist=True, linewidth=None):
353        """
354        Enable/Disable histogram-like plotting.
355        Parameters:
356            hist:        True (default) or False. The fisrt default
357                         is taken from the .asaprc setting
358                         plotter.histogram
359        """
360        self._hist = hist
361        if isinstance(linewidth, float) or isinstance(linewidth, int):
362            from matplotlib import rc as rcp
363            rcp('lines', linewidth=linewidth)
364        if self._data: self.plot(self._data)
365
366    def set_linestyles(self, linestyles=None, linewidth=None):
367        """
368        Set the linestyles to be used. The plotter will cycle through
369        these linestyles when lines are overlaid (stacking mode) AND
370        only one color has been set.
371        Parameters:
372             linestyles:     a list of linestyles to use.
373                             'line', 'dashed', 'dotted', 'dashdot',
374                             'dashdotdot' and 'dashdashdot' are
375                             possible
376
377        Example:
378             plotter.set_colors("black")
379             plotter.set_linestyles("line dashed dotted dashdot")
380             # If for example four lines are overlaid e.g I Q U V
381             # 'I' will be 'solid', 'Q' will be 'dashed',
382             # U will be 'dotted' and 'V' will be 'dashdot'.
383        """
384        if isinstance(linestyles,str):
385            linestyles = linestyles.split()
386        self._plotter.palette(color=0,linestyle=0,linestyles=linestyles)
387        if isinstance(linewidth, float) or isinstance(linewidth, int):
388            from matplotlib import rc as rcp
389            rcp('lines', linewidth=linewidth)
390        if self._data: self.plot(self._data)
391
392    def set_font(self, family=None, style=None, weight=None, size=None):
393        """
394        Set font properties.
395        Parameters:
396            family:    one of 'sans-serif', 'serif', 'cursive', 'fantasy', 'monospace'
397            style:     one of 'normal' (or 'roman'), 'italic'  or 'oblique'
398            weight:    one of 'normal or 'bold'
399            size:      the 'general' font size, individual elements can be adjusted
400                       seperately
401        """
402        from matplotlib import rc as rcp
403        if isinstance(family, str):
404            rcp('font', family=family)
405        if isinstance(style, str):
406            rcp('font', style=style)
407        if isinstance(weight, str):
408            rcp('font', weight=weight)
409        if isinstance(size, float) or isinstance(size, int):
410            rcp('font', size=size)
411        if self._data: self.plot(self._data)
412
413    def plot_lines(self, linecat=None, doppler=0.0, deltachan=10, rotate=90.0,
414                   location=None):
415        """
416        Plot a line catalog.
417        Parameters:
418            linecat:      the linecatalog to plot
419            doppler:      the velocity shift to apply to the frequencies
420            deltachan:    the number of channels to include each side of the
421                          line to determine a local maximum/minimum
422            rotate:       the rotation (in degrees) )for the text label (default 90.0)
423            location:     the location of the line annotation from the 'top',
424                          'bottom' or alternate (None - the default)
425        Notes:
426        If the spectrum is flagged no line will be drawn in that location.
427        """
428        if not self._data:
429            raise RuntimeError("No scantable has been plotted yet.")
430        from asap._asap import linecatalog
431        if not isinstance(linecat, linecatalog):
432            raise ValueError("'linecat' isn't of type linecatalog.")
433        if not self._data.get_unit().endswith("Hz"):
434            raise RuntimeError("Can only overlay linecatalogs when data is in frequency.")
435        from matplotlib.numerix import ma
436        for j in range(len(self._plotter.subplots)):
437            self._plotter.subplot(j)
438            lims = self._plotter.axes.get_xlim()
439            for row in range(linecat.nrow()):
440                # get_frequency returns MHz
441                base = { "GHz": 1000.0, "MHz": 1.0, "Hz": 1.0e-6 }
442                restf = linecat.get_frequency(row)/base[self._data.get_unit()]
443                c = 299792.458
444                freq = restf*(1.0-doppler/c)
445                if lims[0] < freq < lims[1]:
446                    if location is None:
447                        loc = 'bottom'
448                        if row%2: loc='top'
449                    else: loc = location
450                    maxys = []
451                    for line in self._plotter.axes.lines:
452                        v = line._x
453                        asc = v[0] < v[-1]
454
455                        idx = None
456                        if not asc:
457                            if v[len(v)-1] <= freq <= v[0]:
458                                i = len(v)-1
459                                while i>=0 and v[i] < freq:
460                                    idx = i
461                                    i-=1
462                        else:
463                           if v[0] <= freq <= v[len(v)-1]:
464                                i = 0
465                                while  i<len(v) and v[i] < freq:
466                                    idx = i
467                                    i+=1
468                        if idx is not None:
469                            lower = idx - deltachan
470                            upper = idx + deltachan
471                            if lower < 0: lower = 0
472                            if upper > len(v): upper = len(v)
473                            s = slice(lower, upper)
474                            y = line._y[s]
475                            maxy = ma.maximum(y)
476                            if isinstance( maxy, float):
477                                maxys.append(maxy)
478                    if len(maxys):
479                        peak = max(maxys)
480                        if peak > self._plotter.axes.get_ylim()[1]:
481                            loc = 'bottom'
482                    else:
483                        continue
484                    self._plotter.vline_with_label(freq, peak,
485                                                   linecat.get_name(row),
486                                                   location=loc, rotate=rotate)
487        self._plotter.show(hardrefresh=False)
488
489
490    def save(self, filename=None, orientation=None, dpi=None):
491        """
492        Save the plot to a file. The know formats are 'png', 'ps', 'eps'.
493        Parameters:
494             filename:    The name of the output file. This is optional
495                          and autodetects the image format from the file
496                          suffix. If non filename is specified a file
497                          called 'yyyymmdd_hhmmss.png' is created in the
498                          current directory.
499             orientation: optional parameter for postscript only (not eps).
500                          'landscape', 'portrait' or None (default) are valid.
501                          If None is choosen for 'ps' output, the plot is
502                          automatically oriented to fill the page.
503             dpi:         The dpi of the output non-ps plot
504        """
505        self._plotter.save(filename,orientation,dpi)
506        return
507
508
509    def set_mask(self, mask=None, selection=None):
510        """
511        Set a plotting mask for a specific polarization.
512        This is useful for masking out "noise" Pangle outside a source.
513        Parameters:
514             mask:           a mask from scantable.create_mask
515             selection:      the spectra to apply the mask to.
516        Example:
517             select = selector()
518             select.setpolstrings("Pangle")
519             plotter.set_mask(mymask, select)
520        """
521        if not self._data:
522            msg = "Can only set mask after a first call to plot()"
523            if rcParams['verbose']:
524                print msg
525                return
526            else:
527                raise RuntimeError(msg)
528        if len(mask):
529            if isinstance(mask, list) or isinstance(mask, tuple):
530                self._usermask = array(mask)
531            else:
532                self._usermask = mask
533        if mask is None and selection is None:
534            self._usermask = []
535            self._maskselection = None
536        if isinstance(selection, selector):
537            self._maskselection = {'b': selection.get_beams(),
538                                   's': selection.get_scans(),
539                                   'i': selection.get_ifs(),
540                                   'p': selection.get_pols(),
541                                   't': [] }
542        else:
543            self._maskselection = None
544        self.plot(self._data)
545
546    def _slice_indeces(self, data):
547        mn = self._minmaxx[0]
548        mx = self._minmaxx[1]
549        asc = data[0] < data[-1]
550        start=0
551        end = len(data)-1
552        inc = 1
553        if not asc:
554            start = len(data)-1
555            end = 0
556            inc = -1
557        # find min index
558        #while start > 0 and data[start] < mn:
559        #    start+= inc
560        minind=start
561        for ind in xrange(start,end+inc,inc):
562            if data[ind] > mn: break
563            minind=ind
564        # find max index
565        #while end > 0 and data[end] > mx:
566        #    end-=inc
567        #if end > 0: end +=1
568        maxind=end
569        for ind in xrange(end,start-inc,-inc):
570            if data[ind] < mx: break
571            maxind=ind
572        start=minind
573        end=maxind
574        if start > end:
575            return end,start+1
576        elif start < end:
577            return start,end+1
578        else:
579            return start,end
580
581    def _reset(self):
582        self._usermask = []
583        self._usermaskspectra = None
584        self.set_selection(None, False)
585
586    def _plot(self, scan):
587        savesel = scan.get_selection()
588        sel = savesel +  self._selection
589        d0 = {'s': 'SCANNO', 'b': 'BEAMNO', 'i':'IFNO',
590              'p': 'POLNO', 'c': 'CYCLENO', 't' : 'TIME' }
591        order = [d0[self._panelling],d0[self._stacking]]
592        sel.set_order(order)
593        scan.set_selection(sel)
594        d = {'b': scan.getbeam, 's': scan.getscan,
595             'i': scan.getif, 'p': scan.getpol, 't': scan._gettime }
596
597        polmodes = dict(zip(self._selection.get_pols(),
598                            self._selection.get_poltypes()))
599        # this returns either a tuple of numbers or a length  (ncycles)
600        # convert this into lengths
601        n0,nstack0 = self._get_selected_n(scan)
602        if isinstance(n0, int): n = n0
603        else: n = len(n0)
604        if isinstance(nstack0, int): nstack = nstack0
605        else: nstack = len(nstack0)
606        maxpanel, maxstack = 16,8
607        if n > maxpanel or nstack > maxstack:
608            from asap import asaplog
609            maxn = 0
610            if nstack > maxstack: maxn = maxstack
611            if n > maxpanel: maxn = maxpanel
612            msg ="Scan to be plotted contains more than %d selections.\n" \
613                  "Selecting first %d selections..." % (maxn, maxn)
614            asaplog.push(msg)
615            print_log()
616            n = min(n,maxpanel)
617            nstack = min(nstack,maxstack)
618        if n > 1:
619            ganged = rcParams['plotter.ganged']
620            if self._panelling == 'i':
621                ganged = False
622            if self._rows and self._cols:
623                n = min(n,self._rows*self._cols)
624                self._plotter.set_panels(rows=self._rows,cols=self._cols,
625                                         nplots=n,ganged=ganged)
626            else:
627                self._plotter.set_panels(rows=n,cols=0,nplots=n,ganged=ganged)
628        else:
629            self._plotter.set_panels()
630        r=0
631        nr = scan.nrow()
632        a0,b0 = -1,-1
633        allxlim = []
634        allylim = []
635        newpanel=True
636        panelcount,stackcount = 0,0
637        while r < nr:
638            a = d[self._panelling](r)
639            b = d[self._stacking](r)
640            if a > a0 and panelcount < n:
641                if n > 1:
642                    self._plotter.subplot(panelcount)
643                self._plotter.palette(0)
644                #title
645                xlab = self._abcissa and self._abcissa[panelcount] \
646                       or scan._getabcissalabel()
647                ylab = self._ordinate and self._ordinate[panelcount] \
648                       or scan._get_ordinate_label()
649                self._plotter.set_axes('xlabel',xlab)
650                self._plotter.set_axes('ylabel',ylab)
651                lbl = self._get_label(scan, r, self._panelling, self._title)
652                if isinstance(lbl, list) or isinstance(lbl, tuple):
653                    if 0 <= panelcount < len(lbl):
654                        lbl = lbl[panelcount]
655                    else:
656                        # get default label
657                        lbl = self._get_label(scan, r, self._panelling, None)
658                self._plotter.set_axes('title',lbl)
659                newpanel = True
660                stackcount =0
661                panelcount += 1
662            if (b > b0 or newpanel) and stackcount < nstack:
663                y = []
664                if len(polmodes):
665                    y = scan._getspectrum(r, polmodes[scan.getpol(r)])
666                else:
667                    y = scan._getspectrum(r)
668                m = scan._getmask(r)
669                from matplotlib.numerix import logical_not, logical_and
670                if self._maskselection and len(self._usermask) == len(m):
671                    if d[self._stacking](r) in self._maskselection[self._stacking]:
672                        m = logical_and(m, self._usermask)
673                x = scan._getabcissa(r)
674                from matplotlib.numerix import ma, array
675                y = ma.masked_array(y,mask=logical_not(array(m,copy=False)))
676                if self._minmaxx is not None:
677                    s,e = self._slice_indeces(x)
678                    x = x[s:e]
679                    y = y[s:e]
680                if len(x) > 1024 and rcParams['plotter.decimate']:
681                    fac = len(x)/1024
682                    x = x[::fac]
683                    y = y[::fac]
684                llbl = self._get_label(scan, r, self._stacking, self._lmap)
685                if isinstance(llbl, list) or isinstance(llbl, tuple):
686                    if 0 <= stackcount < len(llbl):
687                        # use user label
688                        llbl = llbl[stackcount]
689                    else:
690                        # get default label
691                        llbl = self._get_label(scan, r, self._stacking, None)
692                self._plotter.set_line(label=llbl)
693                plotit = self._plotter.plot
694                if self._hist: plotit = self._plotter.hist
695                if len(x) > 0:
696                    plotit(x,y)
697                    xlim= self._minmaxx or [min(x),max(x)]
698                    allxlim += xlim
699                    ylim= self._minmaxy or [ma.minimum(y),ma.maximum(y)]
700                    allylim += ylim
701                else:
702                    xlim = self._minmaxx or []
703                    allxlim += xlim
704                    ylim= self._minmaxy or []
705                    allylim += ylim
706                stackcount += 1
707                # last in colour stack -> autoscale x
708                if stackcount == nstack and len(allxlim) > 0:
709                    allxlim.sort()
710                    self._plotter.subplots[panelcount-1]['axes'].set_xlim([allxlim[0],allxlim[-1]])
711                    # clear
712                    allxlim =[]
713
714            newpanel = False
715            a0=a
716            b0=b
717            # ignore following rows
718            if (panelcount == n) and (stackcount == nstack):
719                # last panel -> autoscale y if ganged
720                if rcParams['plotter.ganged'] and len(allylim) > 0:
721                    allylim.sort()
722                    self._plotter.set_limits(ylim=[allylim[0],allylim[-1]])
723                break
724            r+=1 # next row
725        #reset the selector to the scantable's original
726        scan.set_selection(savesel)
727
728    def set_selection(self, selection=None, refresh=True):
729        self._selection = isinstance(selection,selector) and selection or selector()
730        d0 = {'s': 'SCANNO', 'b': 'BEAMNO', 'i':'IFNO',
731              'p': 'POLNO', 'c': 'CYCLENO', 't' : 'TIME' }
732        order = [d0[self._panelling],d0[self._stacking]]
733        self._selection.set_order(order)
734        if self._data and refresh: self.plot(self._data)
735
736    def _get_selected_n(self, scan):
737        d1 = {'b': scan.getbeamnos, 's': scan.getscannos,
738             'i': scan.getifnos, 'p': scan.getpolnos, 't': scan.ncycle }
739        d2 = { 'b': self._selection.get_beams(),
740               's': self._selection.get_scans(),
741               'i': self._selection.get_ifs(),
742               'p': self._selection.get_pols(),
743               't': self._selection.get_cycles() }
744        n =  d2[self._panelling] or d1[self._panelling]()
745        nstack = d2[self._stacking] or d1[self._stacking]()
746        return n,nstack
747
748    def _get_label(self, scan, row, mode, userlabel=None):
749        if isinstance(userlabel, list) and len(userlabel) == 0:
750            userlabel = " "
751        pms = dict(zip(self._selection.get_pols(),self._selection.get_poltypes()))
752        if len(pms):
753            poleval = scan._getpollabel(scan.getpol(row),pms[scan.getpol(row)])
754        else:
755            poleval = scan._getpollabel(scan.getpol(row),scan.poltype())
756        d = {'b': "Beam "+str(scan.getbeam(row)),
757             's': scan._getsourcename(row),
758             'i': "IF"+str(scan.getif(row)),
759             'p': poleval,
760             't': str(scan.get_time(row)) }
761        return userlabel or d[mode]
762
763    def plotazel(self, scan=None, outfile=None):
764        """
765        plot azimuth and elevation  versus time of a scantable
766        """
767        import pylab as PL
768        from matplotlib.dates import DateFormatter, timezone, HourLocator, MinuteLocator, DayLocator
769        from matplotlib.ticker import MultipleLocator
770        from matplotlib.numerix import array, pi
771        self._data = scan
772        self._outfile = outfile
773        dates = self._data.get_time(asdatetime=True)
774        t = PL.date2num(dates)
775        tz = timezone('UTC')
776        PL.cla()
777        #PL.ioff()
778        PL.clf()
779        tdel = max(t) - min(t)
780        ax = PL.subplot(2,1,1)
781        el = array(self._data.get_elevation())*180./pi
782        PL.ylabel('El [deg.]')
783        dstr = dates[0].strftime('%Y/%m/%d')
784        if tdel > 1.0:
785            dstr2 = dates[len(dates)-1].strftime('%Y/%m/%d')
786            dstr = dstr + " - " + dstr2
787            majloc = DayLocator()
788            minloc = HourLocator(range(0,23,12))
789            timefmt = DateFormatter("%b%d")
790        else:
791            timefmt = DateFormatter('%H')
792            majloc = HourLocator()
793            minloc = MinuteLocator(20)
794        PL.title(dstr)
795
796        if tdel == 0.0:
797            th = (t - PL.floor(t))*24.0
798            PL.plot(th,el,'o',markersize=2, markerfacecolor='b', markeredgecolor='b')
799        else:
800            PL.plot_date(t,el,'o', markersize=2, markerfacecolor='b', markeredgecolor='b',tz=tz)
801            #ax.grid(True)
802            ax.xaxis.set_major_formatter(timefmt)
803            ax.xaxis.set_major_locator(majloc)
804            ax.xaxis.set_minor_locator(minloc)
805        ax.yaxis.grid(True)
806        yloc = MultipleLocator(30)
807        ax.set_ylim(0,90)
808        ax.yaxis.set_major_locator(yloc)
809        if tdel > 1.0:
810            labels = ax.get_xticklabels()
811        #    PL.setp(labels, fontsize=10, rotation=45)
812            PL.setp(labels, fontsize=10)
813
814        # Az plot
815        az = array(self._data.get_azimuth())*180./pi
816        if min(az) < 0:
817            for irow in range(len(az)):
818                if az[irow] < 0: az[irow] += 360.0
819
820        ax = PL.subplot(2,1,2)
821        #PL.xlabel('Time (UT [hour])')
822        PL.ylabel('Az [deg.]')
823        if tdel == 0.0:
824            PL.plot(th,az,'o',markersize=2, markeredgecolor='b',markerfacecolor='b')
825        else:
826            PL.plot_date(t,az,'o', markersize=2,markeredgecolor='b',markerfacecolor='b',tz=tz)
827            ax.xaxis.set_major_formatter(timefmt)
828            ax.xaxis.set_major_locator(majloc)
829            ax.xaxis.set_minor_locator(minloc)
830        #ax.grid(True)
831        ax.set_ylim(0,360)
832        ax.yaxis.grid(True)
833        #hfmt = DateFormatter('%H')
834        #hloc = HourLocator()
835        yloc = MultipleLocator(60)
836        ax.yaxis.set_major_locator(yloc)
837        if tdel > 1.0:
838            labels = ax.get_xticklabels()
839            PL.setp(labels, fontsize=10)
840            PL.xlabel('Time (UT [day])')
841        else:
842            PL.xlabel('Time (UT [hour])')
843
844        #PL.ion()
845        PL.draw()
846        if (self._outfile is not None):
847           PL.savefig(self._outfile)
848
849    def plotpointing(self, scan=None, outfile=None):
850        """
851        plot telescope pointings
852        """
853        import pylab as PL
854        from matplotlib.dates import DateFormatter, timezone
855        from matplotlib.ticker import MultipleLocator
856        from matplotlib.numerix import array, pi, zeros
857        self._data = scan
858        self._outfile = outfile
859        dir = array(self._data.get_directionval()).transpose()
860        ra = dir[0]*180./pi
861        dec = dir[1]*180./pi
862        PL.cla()
863        #PL.ioff()
864        PL.clf()
865        ax = PL.axes([0.1,0.1,0.8,0.8])
866        ax = PL.axes([0.1,0.1,0.8,0.8])
867        ax.set_aspect('equal')
868        PL.plot(ra,dec, 'b,')
869        PL.xlabel('RA [deg.]')
870        PL.ylabel('Declination [deg.]')
871        PL.title('Telescope pointings')
872        [xmin,xmax,ymin,ymax] = PL.axis()
873        PL.axis([xmax,xmin,ymin,ymax])
874        #PL.ion()
875        PL.draw()
876        if (self._outfile is not None):
877           PL.savefig(self._outfile)
878
879    # plot total power data
880    # plotting in time is not yet implemented..
881    def plottp(self, scan=None, outfile=None):
882        if self._plotter.is_dead:
883            self._plotter = self._newplotter()
884        self._plotter.hold()
885        self._plotter.clear()
886        from asap import scantable
887        if not self._data and not scan:
888            msg = "Input is not a scantable"
889            if rcParams['verbose']:
890                print msg
891                return
892            raise TypeError(msg)
893        if isinstance(scan, scantable):
894            if self._data is not None:
895                if scan != self._data:
896                    self._data = scan
897                    # reset
898                    self._reset()
899            else:
900                self._data = scan
901                self._reset()
902        # ranges become invalid when abcissa changes?
903        #if self._abcunit and self._abcunit != self._data.get_unit():
904        #    self._minmaxx = None
905        #    self._minmaxy = None
906        #    self._abcunit = self._data.get_unit()
907        #    self._datamask = None
908        self._plottp(self._data)
909        if self._minmaxy is not None:
910            self._plotter.set_limits(ylim=self._minmaxy)
911        self._plotter.release()
912        self._plotter.tidy()
913        self._plotter.show(hardrefresh=False)
914        print_log()
915        return
916
917    def _plottp(self,scan):
918        """
919        private method for plotting total power data
920        """
921        from matplotlib.numerix import ma, array, arange, logical_not
922        r=0
923        nr = scan.nrow()
924        a0,b0 = -1,-1
925        allxlim = []
926        allylim = []
927        y=[]
928        self._plotter.set_panels()
929        self._plotter.palette(0)
930        #title
931        #xlab = self._abcissa and self._abcissa[panelcount] \
932        #       or scan._getabcissalabel()
933        #ylab = self._ordinate and self._ordinate[panelcount] \
934        #       or scan._get_ordinate_label()
935        xlab = self._abcissa or 'row number' #or Time
936        ylab = self._ordinate or scan._get_ordinate_label()
937        self._plotter.set_axes('xlabel',xlab)
938        self._plotter.set_axes('ylabel',ylab)
939        lbl = self._get_label(scan, r, 's', self._title)
940        if isinstance(lbl, list) or isinstance(lbl, tuple):
941        #    if 0 <= panelcount < len(lbl):
942        #        lbl = lbl[panelcount]
943        #    else:
944                # get default label
945             lbl = self._get_label(scan, r, self._panelling, None)
946        self._plotter.set_axes('title',lbl)
947        y=array(scan._get_column(scan._getspectrum,-1))
948        m = array(scan._get_column(scan._getmask,-1))
949        y = ma.masked_array(y,mask=logical_not(array(m,copy=False)))
950        x = arange(len(y))
951        # try to handle spectral data somewhat...
952        l,m = y.shape
953        if m > 1:
954            y=y.mean(axis=1)
955        plotit = self._plotter.plot
956        llbl = self._get_label(scan, r, self._stacking, None)
957        self._plotter.set_line(label=llbl)
958        if len(x) > 0:
959            plotit(x,y)
960
961
962    # forwards to matplotlib.Figure.text
963    def figtext(self, *args, **kwargs):
964        """
965        Add text to figure at location x,y (relative 0-1 coords).
966        This method forwards *args and **kwargs to a Matplotlib method,
967        matplotlib.Figure.text.
968        See the method help for detailed information.
969        """
970        self._plotter.text(*args, **kwargs)
971    # end matplotlib.Figure.text forwarding function
972
Note: See TracBrowser for help on using the repository browser.