source: trunk/python/asapplotter.py @ 1550

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