source: trunk/python/asapplotter.py @ 1582

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

Increased maxstack to 16; added simple selection to plotter (refer to #169)

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