source: trunk/python/asapplotter.py @ 1551

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

Add some instuctions to the plot

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