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

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

Module(s): Module Names change impacts.

Description: Describe your changes here...

I have changed that almost all log messages are output to casapy.log,
not to the terminal window. After this change, asap becomes to depend on casapy
and is not running in standalone, because asap have to import taskinit module
to access casalogger.


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