source: trunk/python/asapplotter.py @ 1555

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

handle timeouts and general None returns in ginput

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