def __repr__(self):
        '''
        Represent as a table
        '''
        out = 'Event Prediction \n'
        out += '-------------------\n'
        out += '\n'.join(
            [key + ': ' + str(self.meta[key])
             for key in self.meta.keys()]) + '\n'
        out += '-------------------\n'
        table = Table(self.info[self.info_cols], meta=self.meta)
        out += table.__repr__()

        return out
Beispiel #2
0
class SpecObjs(object):
    """
    Object to hold a set of SpecObj objects

    Args:
        specobjs (ndarray or list, optional):  One or more SpecObj objects

    Internals:
        summary (astropy.table.Table):


    __getitem__ is overloaded to allow one to pull an attribute or a
                portion of the SpecObjs list
        Args:
            item (str or int (or slice)
        Returns:
            item (object, SpecObj or SpecObjs):  Depends on input item..

    __setitem__ is over-loaded using our custom set() method
        Args:
            name (str):  Item to set
            value (anything) : Value of the item
        Returns:
    __getattr__ is overloaded to generate an array of attribute 'k' from the specobjs
        First attempts to grab data from the Summary table, then the list
    """
    def __init__(self, specobjs=None):
        if specobjs is None:
            self.specobjs = np.array([])
        else:
            if isinstance(specobjs, (list, np.ndarray)):
                specobjs = np.array(specobjs)
            self.specobjs = specobjs

        # Internal summary Table
        self.build_summary()

    @property
    def nobj(self):
        """
        Return the number of SpecObj objects

        Returns:
            int

        """
        return self.specobjs.size

    def get_std(self):
        """
        Return the standard star from this Specobjs. For MultiSlit this
        will be a single specobj in SpecObjs container, for Echelle it
        will be the standard for all the orders.

        Args:

        Returns:
            SpecObj or SpecObjs

        """
        # Is this MultiSlit or Echelle
        pypeline = (self.pypeline)[0]
        if 'MultiSlit' in pypeline:
            nspec = self[0].optimal['COUNTS'].size
            SNR = np.zeros(self.nobj)
            # Have to do a loop to extract the counts for all objects
            for iobj in range(self.nobj):
                SNR[iobj] = np.median(
                    self[iobj].optimal['COUNTS'] *
                    np.sqrt(self[iobj].optimal['COUNTS_IVAR']))
            istd = SNR.argmax()
            return SpecObjs(specobjs=[self[istd]])
        elif 'Echelle' in pypeline:
            uni_objid = np.unique(self.ech_objid)
            uni_order = np.unique(self.ech_orderindx)
            nobj = len(uni_objid)
            norders = len(uni_order)
            SNR = np.zeros((norders, nobj))
            for iobj in range(nobj):
                for iord in range(norders):
                    ind = (self.ech_objid == uni_objid[iobj]) & (
                        self.ech_orderindx == uni_order[iord])
                    spec = self[ind]
                    SNR[iord, iobj] = np.median(
                        spec[0].optimal['COUNTS'] *
                        np.sqrt(spec[0].optimal['COUNTS_IVAR']))
            SNR_all = np.sqrt(np.sum(SNR**2, axis=0))
            objid_std = uni_objid[SNR_all.argmax()]
            indx = self.ech_objid == objid_std
            return SpecObjs(specobjs=self[indx])
        else:
            msgs.error('Unknown pypeline')

    def append_neg(self, sobjs_neg):
        """
        Append negative objects and change the sign of their objids for IR reductions

        Args:
            sobjs_neg (SpecObjs):

        """

        # Assign the sign and the objids
        for spec in sobjs_neg:
            spec.sign = -1.0
            try:
                spec.objid = -spec.objid
            except TypeError:
                pass
            try:
                spec.ech_objid = -spec.ech_objid
            except TypeError:
                pass

        self.add_sobj(sobjs_neg)

        # Sort objects according to their spatial location. Necessary for the extraction to properly work
        if self.nobj > 0:
            spat_pixpos = self.spat_pixpos
            self.specobjs = self.specobjs[spat_pixpos.argsort()]

    def purge_neg(self):
        """
        Purge negative objects from specobjs for IR reductions

        """
        # Assign the sign and the objids
        if self.nobj > 0:
            index = (self.objid < 0) | (self.ech_objid < 0)
            self.remove_sobj(index)

    def add_sobj(self, sobj):
        """
        Add one or more SpecObj
        The summary table is rebuilt

        Args:
            sobj (SpecObj or list or ndarray):  On or more SpecObj objects

        Returns:


        """
        if isinstance(sobj, SpecObj):
            self.specobjs = np.append(self.specobjs, [sobj])
        elif isinstance(sobj, (np.ndarray, list)):
            self.specobjs = np.append(self.specobjs, sobj)
        elif isinstance(sobj, SpecObjs):
            self.specobjs = np.append(self.specobjs, sobj)

        # Rebuild summary table
        self.build_summary()

    def build_summary(self):
        """
        Build the internal Summary Table

        Returns:
            Builds self.summary Table internally

        """
        # Dummy?
        if len(self.specobjs) == 0:
            self.summary = Table()
            return
        #
        atts = self.specobjs[0].__dict__.keys()
        uber_dict = {}
        for key in atts:
            uber_dict[key] = []
            for sobj in self.specobjs:
                uber_dict[key] += [getattr(sobj, key)]
        # Build it
        self.summary = Table(uber_dict)

    def remove_sobj(self, index):
        """
        Remove an object

        Args:
            index: int

        Returns:

        """
        msk = np.ones(self.specobjs.size, dtype=bool)
        msk[index] = False
        # Do it
        self.specobjs = self.specobjs[msk]
        # Update
        self.build_summary()

    def copy(self):
        """
        Generate a copy of self

        Returns:
            SpecObjs

        """
        sobj_copy = SpecObjs()
        for sobj in self.specobjs:
            sobj_copy.add_sobj(sobj.copy())
        sobj_copy.build_summary()
        return sobj_copy

    def set_idx(self):
        """
        Set the idx in all the SpecObj
        Update the summary Table

        Returns:

        """
        for sobj in self.specobjs:
            sobj.set_idx()
        self.build_summary()

    def __getitem__(self, item):
        if isinstance(item, str):
            return self.__getattr__(item)
        elif isinstance(item, (int, np.integer)):
            return self.specobjs[
                item]  # TODO Is this using pointers or creating new data????
        elif (isinstance(item, slice) or  # Stolen from astropy.table
              isinstance(item, np.ndarray) or
              isinstance(item, list) or isinstance(item, tuple)
              and all(isinstance(x, np.ndarray) for x in item)):
            # here for the many ways to give a slice; a tuple of ndarray
            # is produced by np.where, as in t[np.where(t['a'] > 2)]
            # For all, a new table is constructed with slice of all columns
            return SpecObjs(specobjs=self.specobjs[item])

    # TODO this code fails for assignments of this nature sobjs[:].attribute = np.array(5)
    def __setitem__(self, name, value):
        self.set(slice(0, self.nobj), name, value)

    def set(self, islice, attr, value):
        """
        Set the attribute for a slice of the specobjs

        Args:
            islice (int, ndarray of bool, slice):  Indicates SpecObj to affect
            attr (str):
            value (anything) : Value of the item

        Returns:

        """
        sub_sobjs = self.specobjs[islice]
        if isiterable(value):
            if sub_sobjs.size == len(value):  # Assume you want each paired up
                for kk, sobj in enumerate(sub_sobjs):
                    setattr(sobj, attr, value[kk])
                    return
        # Assuming scalar assignment
        if isinstance(sub_sobjs, SpecObj):
            setattr(sub_sobjs, attr, value)
        else:
            for sobj in sub_sobjs:
                setattr(sobj, attr, value)
        return

    def __getattr__(self, k):
        # Overloaded
        self.build_summary()
        # Special case(s)
        if k in self.summary.keys():  # _data
            lst = self.summary[k]
        else:
            lst = None
        # specobjs last!
        if lst is None:
            if len(self.specobjs) == 0:
                raise ValueError("Attribute not available!")
            try:
                lst = [getattr(specobj, k) for specobj in self.specobjs]
            except ValueError:
                raise ValueError("Attribute does not exist")
        # Recast as an array
        return lst_to_array(lst)

    # Printing
    def __repr__(self):
        return self.summary.__repr__()

    def __len__(self):
        return len(self.specobjs)

    def keys(self):
        self.build_summary()
        return self.summary.keys()