source: trunk/python/asapplotter.py @ 1549

Last change on this file since 1549 was 1549, checked in by Malte Marquarding, 15 years ago

add alittle bit of room, so masks can be created past the first/last channel

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