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

Last change on this file since 1614 was 1614, checked in by Takeshi Nakazato, 15 years ago

New Development: No

JIRA Issue: Yes CAS-729, CAS-1147

Ready to Release: Yes

Interface Changes: No

What Interface Changed: Please list interface changes

Test Programs: List test programs

Put in Release Notes: No

Module(s): Module Names change impacts.

Description: Describe your changes here...

  1. Added level parameter to print_log()
  2. Replaced casalog.post() to asaplog.push() + print_log().


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