source: trunk/python/asapplotter.py @ 1563

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

fix for ticket #160: allow user to select the size of plotter and also honour matplotlib.rcParams

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