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

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

New Development: No

JIRA Issue: No

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...

Bug fix.
Removed duplicated 'from asap import asaplog' lines.


  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 37.2 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            maxn = 0
616            if nstack > maxstack: maxn = maxstack
617            if n > maxpanel: maxn = maxpanel
618            msg ="Scan to be plotted contains more than %d selections.\n" \
619                  "Selecting first %d selections..." % (maxn, maxn)
620            asaplog.push(msg)
621            print_log('WARN')
622            n = min(n,maxpanel)
623            nstack = min(nstack,maxstack)
624        if n > 1:
625            ganged = rcParams['plotter.ganged']
626            if self._panelling == 'i':
627                ganged = False
628            if self._rows and self._cols:
629                n = min(n,self._rows*self._cols)
630                self._plotter.set_panels(rows=self._rows,cols=self._cols,
631                                         nplots=n,ganged=ganged)
632            else:
633                self._plotter.set_panels(rows=n,cols=0,nplots=n,ganged=ganged)
634        else:
635            self._plotter.set_panels()
636        r=0
637        nr = scan.nrow()
638        a0,b0 = -1,-1
639        allxlim = []
640        allylim = []
641        newpanel=True
642        panelcount,stackcount = 0,0
643        while r < nr:
644            a = d[self._panelling](r)
645            b = d[self._stacking](r)
646            if a > a0 and panelcount < n:
647                if n > 1:
648                    self._plotter.subplot(panelcount)
649                self._plotter.palette(0)
650                #title
651                xlab = self._abcissa and self._abcissa[panelcount] \
652                       or scan._getabcissalabel()
653                ylab = self._ordinate and self._ordinate[panelcount] \
654                       or scan._get_ordinate_label()
655                self._plotter.set_axes('xlabel',xlab)
656                self._plotter.set_axes('ylabel',ylab)
657                lbl = self._get_label(scan, r, self._panelling, self._title)
658                if isinstance(lbl, list) or isinstance(lbl, tuple):
659                    if 0 <= panelcount < len(lbl):
660                        lbl = lbl[panelcount]
661                    else:
662                        # get default label
663                        lbl = self._get_label(scan, r, self._panelling, None)
664                self._plotter.set_axes('title',lbl)
665                newpanel = True
666                stackcount =0
667                panelcount += 1
668            if (b > b0 or newpanel) and stackcount < nstack:
669                y = []
670                if len(polmodes):
671                    y = scan._getspectrum(r, polmodes[scan.getpol(r)])
672                else:
673                    y = scan._getspectrum(r)
674                m = scan._getmask(r)
675                from matplotlib.numerix import logical_not, logical_and
676                if self._maskselection and len(self._usermask) == len(m):
677                    if d[self._stacking](r) in self._maskselection[self._stacking]:
678                        m = logical_and(m, self._usermask)
679                x = scan._getabcissa(r)
680                from matplotlib.numerix import ma, array
681                y = ma.masked_array(y,mask=logical_not(array(m,copy=False)))
682                if self._minmaxx is not None:
683                    s,e = self._slice_indeces(x)
684                    x = x[s:e]
685                    y = y[s:e]
686                if len(x) > 1024 and rcParams['plotter.decimate']:
687                    fac = len(x)/1024
688                    x = x[::fac]
689                    y = y[::fac]
690                llbl = self._get_label(scan, r, self._stacking, self._lmap)
691                if isinstance(llbl, list) or isinstance(llbl, tuple):
692                    if 0 <= stackcount < len(llbl):
693                        # use user label
694                        llbl = llbl[stackcount]
695                    else:
696                        # get default label
697                        llbl = self._get_label(scan, r, self._stacking, None)
698                self._plotter.set_line(label=llbl)
699                plotit = self._plotter.plot
700                if self._hist: plotit = self._plotter.hist
701                if len(x) > 0:
702                    plotit(x,y)
703                    xlim= self._minmaxx or [min(x),max(x)]
704                    allxlim += xlim
705                    ylim= self._minmaxy or [ma.minimum(y),ma.maximum(y)]
706                    allylim += ylim
707                else:
708                    xlim = self._minmaxx or []
709                    allxlim += xlim
710                    ylim= self._minmaxy or []
711                    allylim += ylim
712                stackcount += 1
713                # last in colour stack -> autoscale x
714                if stackcount == nstack and len(allxlim) > 0:
715                    allxlim.sort()
716                    self._plotter.subplots[panelcount-1]['axes'].set_xlim([allxlim[0],allxlim[-1]])
717                    # clear
718                    allxlim =[]
719
720            newpanel = False
721            a0=a
722            b0=b
723            # ignore following rows
724            if (panelcount == n) and (stackcount == nstack):
725                # last panel -> autoscale y if ganged
726                if rcParams['plotter.ganged'] and len(allylim) > 0:
727                    allylim.sort()
728                    self._plotter.set_limits(ylim=[allylim[0],allylim[-1]])
729                break
730            r+=1 # next row
731        #reset the selector to the scantable's original
732        scan.set_selection(savesel)
733
734    def set_selection(self, selection=None, refresh=True):
735        self._selection = isinstance(selection,selector) and selection or selector()
736        d0 = {'s': 'SCANNO', 'b': 'BEAMNO', 'i':'IFNO',
737              'p': 'POLNO', 'c': 'CYCLENO', 't' : 'TIME' }
738        order = [d0[self._panelling],d0[self._stacking]]
739        self._selection.set_order(order)
740        if self._data and refresh: self.plot(self._data)
741
742    def _get_selected_n(self, scan):
743        d1 = {'b': scan.getbeamnos, 's': scan.getscannos,
744             'i': scan.getifnos, 'p': scan.getpolnos, 't': scan.ncycle }
745        d2 = { 'b': self._selection.get_beams(),
746               's': self._selection.get_scans(),
747               'i': self._selection.get_ifs(),
748               'p': self._selection.get_pols(),
749               't': self._selection.get_cycles() }
750        n =  d2[self._panelling] or d1[self._panelling]()
751        nstack = d2[self._stacking] or d1[self._stacking]()
752        return n,nstack
753
754    def _get_label(self, scan, row, mode, userlabel=None):
755        if isinstance(userlabel, list) and len(userlabel) == 0:
756            userlabel = " "
757        pms = dict(zip(self._selection.get_pols(),self._selection.get_poltypes()))
758        if len(pms):
759            poleval = scan._getpollabel(scan.getpol(row),pms[scan.getpol(row)])
760        else:
761            poleval = scan._getpollabel(scan.getpol(row),scan.poltype())
762        d = {'b': "Beam "+str(scan.getbeam(row)),
763             's': scan._getsourcename(row),
764             'i': "IF"+str(scan.getif(row)),
765             'p': poleval,
766             't': str(scan.get_time(row)) }
767        return userlabel or d[mode]
768
769    def plotazel(self, scan=None, outfile=None):
770        """
771        plot azimuth and elevation  versus time of a scantable
772        """
773        import pylab as PL
774        from matplotlib.dates import DateFormatter, timezone, HourLocator, MinuteLocator, DayLocator
775        from matplotlib.ticker import MultipleLocator
776        from matplotlib.numerix import array, pi
777        self._data = scan
778        self._outfile = outfile
779        dates = self._data.get_time(asdatetime=True)
780        t = PL.date2num(dates)
781        tz = timezone('UTC')
782        PL.cla()
783        #PL.ioff()
784        PL.clf()
785        tdel = max(t) - min(t)
786        ax = PL.subplot(2,1,1)
787        el = array(self._data.get_elevation())*180./pi
788        PL.ylabel('El [deg.]')
789        dstr = dates[0].strftime('%Y/%m/%d')
790        if tdel > 1.0:
791            dstr2 = dates[len(dates)-1].strftime('%Y/%m/%d')
792            dstr = dstr + " - " + dstr2
793            majloc = DayLocator()
794            minloc = HourLocator(range(0,23,12))
795            timefmt = DateFormatter("%b%d")
796        else:
797            timefmt = DateFormatter('%H')
798            majloc = HourLocator()
799            minloc = MinuteLocator(20)
800        PL.title(dstr)
801
802        if tdel == 0.0:
803            th = (t - PL.floor(t))*24.0
804            PL.plot(th,el,'o',markersize=2, markerfacecolor='b', markeredgecolor='b')
805        else:
806            PL.plot_date(t,el,'o', markersize=2, markerfacecolor='b', markeredgecolor='b',tz=tz)
807            #ax.grid(True)
808            ax.xaxis.set_major_formatter(timefmt)
809            ax.xaxis.set_major_locator(majloc)
810            ax.xaxis.set_minor_locator(minloc)
811        ax.yaxis.grid(True)
812        yloc = MultipleLocator(30)
813        ax.set_ylim(0,90)
814        ax.yaxis.set_major_locator(yloc)
815        if tdel > 1.0:
816            labels = ax.get_xticklabels()
817        #    PL.setp(labels, fontsize=10, rotation=45)
818            PL.setp(labels, fontsize=10)
819
820        # Az plot
821        az = array(self._data.get_azimuth())*180./pi
822        if min(az) < 0:
823            for irow in range(len(az)):
824                if az[irow] < 0: az[irow] += 360.0
825
826        ax = PL.subplot(2,1,2)
827        #PL.xlabel('Time (UT [hour])')
828        PL.ylabel('Az [deg.]')
829        if tdel == 0.0:
830            PL.plot(th,az,'o',markersize=2, markeredgecolor='b',markerfacecolor='b')
831        else:
832            PL.plot_date(t,az,'o', markersize=2,markeredgecolor='b',markerfacecolor='b',tz=tz)
833            ax.xaxis.set_major_formatter(timefmt)
834            ax.xaxis.set_major_locator(majloc)
835            ax.xaxis.set_minor_locator(minloc)
836        #ax.grid(True)
837        ax.set_ylim(0,360)
838        ax.yaxis.grid(True)
839        #hfmt = DateFormatter('%H')
840        #hloc = HourLocator()
841        yloc = MultipleLocator(60)
842        ax.yaxis.set_major_locator(yloc)
843        if tdel > 1.0:
844            labels = ax.get_xticklabels()
845            PL.setp(labels, fontsize=10)
846            PL.xlabel('Time (UT [day])')
847        else:
848            PL.xlabel('Time (UT [hour])')
849
850        #PL.ion()
851        PL.draw()
852        if (self._outfile is not None):
853           PL.savefig(self._outfile)
854
855    def plotpointing(self, scan=None, outfile=None):
856        """
857        plot telescope pointings
858        """
859        import pylab as PL
860        from matplotlib.dates import DateFormatter, timezone
861        from matplotlib.ticker import MultipleLocator
862        from matplotlib.numerix import array, pi, zeros
863        self._data = scan
864        self._outfile = outfile
865        dir = array(self._data.get_directionval()).transpose()
866        ra = dir[0]*180./pi
867        dec = dir[1]*180./pi
868        PL.cla()
869        #PL.ioff()
870        PL.clf()
871        ax = PL.axes([0.1,0.1,0.8,0.8])
872        ax = PL.axes([0.1,0.1,0.8,0.8])
873        ax.set_aspect('equal')
874        PL.plot(ra,dec, 'b,')
875        PL.xlabel('RA [deg.]')
876        PL.ylabel('Declination [deg.]')
877        PL.title('Telescope pointings')
878        [xmin,xmax,ymin,ymax] = PL.axis()
879        PL.axis([xmax,xmin,ymin,ymax])
880        #PL.ion()
881        PL.draw()
882        if (self._outfile is not None):
883           PL.savefig(self._outfile)
884
885    # plot total power data
886    # plotting in time is not yet implemented..
887    def plottp(self, scan=None, outfile=None):
888        if self._plotter.is_dead:
889            self._plotter = self._newplotter()
890        self._plotter.hold()
891        self._plotter.clear()
892        from asap import scantable
893        if not self._data and not scan:
894            msg = "Input is not a scantable"
895            if rcParams['verbose']:
896                #print msg
897                asaplog.push( msg )
898                print_log( 'ERROR' )
899                return
900            raise TypeError(msg)
901        if isinstance(scan, scantable):
902            if self._data is not None:
903                if scan != self._data:
904                    self._data = scan
905                    # reset
906                    self._reset()
907            else:
908                self._data = scan
909                self._reset()
910        # ranges become invalid when abcissa changes?
911        #if self._abcunit and self._abcunit != self._data.get_unit():
912        #    self._minmaxx = None
913        #    self._minmaxy = None
914        #    self._abcunit = self._data.get_unit()
915        #    self._datamask = None
916        self._plottp(self._data)
917        if self._minmaxy is not None:
918            self._plotter.set_limits(ylim=self._minmaxy)
919        self._plotter.release()
920        self._plotter.tidy()
921        self._plotter.show(hardrefresh=False)
922        print_log()
923        return
924
925    def _plottp(self,scan):
926        """
927        private method for plotting total power data
928        """
929        from matplotlib.numerix import ma, array, arange, logical_not
930        r=0
931        nr = scan.nrow()
932        a0,b0 = -1,-1
933        allxlim = []
934        allylim = []
935        y=[]
936        self._plotter.set_panels()
937        self._plotter.palette(0)
938        #title
939        #xlab = self._abcissa and self._abcissa[panelcount] \
940        #       or scan._getabcissalabel()
941        #ylab = self._ordinate and self._ordinate[panelcount] \
942        #       or scan._get_ordinate_label()
943        xlab = self._abcissa or 'row number' #or Time
944        ylab = self._ordinate or scan._get_ordinate_label()
945        self._plotter.set_axes('xlabel',xlab)
946        self._plotter.set_axes('ylabel',ylab)
947        lbl = self._get_label(scan, r, 's', self._title)
948        if isinstance(lbl, list) or isinstance(lbl, tuple):
949        #    if 0 <= panelcount < len(lbl):
950        #        lbl = lbl[panelcount]
951        #    else:
952                # get default label
953             lbl = self._get_label(scan, r, self._panelling, None)
954        self._plotter.set_axes('title',lbl)
955        y=array(scan._get_column(scan._getspectrum,-1))
956        m = array(scan._get_column(scan._getmask,-1))
957        y = ma.masked_array(y,mask=logical_not(array(m,copy=False)))
958        x = arange(len(y))
959        # try to handle spectral data somewhat...
960        l,m = y.shape
961        if m > 1:
962            y=y.mean(axis=1)
963        plotit = self._plotter.plot
964        llbl = self._get_label(scan, r, self._stacking, None)
965        self._plotter.set_line(label=llbl)
966        if len(x) > 0:
967            plotit(x,y)
968
969
970    # forwards to matplotlib.Figure.text
971    def figtext(self, *args, **kwargs):
972        """
973        Add text to figure at location x,y (relative 0-1 coords).
974        This method forwards *args and **kwargs to a Matplotlib method,
975        matplotlib.Figure.text.
976        See the method help for detailed information.
977        """
978        self._plotter.text(*args, **kwargs)
979    # end matplotlib.Figure.text forwarding function
980
Note: See TracBrowser for help on using the repository browser.