source: trunk/python/asapplotter.py @ 1556

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

Fix for ticket #158; can' use rc parameters to set fonts dynamically

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