def do_pca(data, cov=False): tolerance = 1.0E-5 Nobj, Mattr = data.shape if cov: colmean = (np.sum(data,0)/Nobj)[:,np.newaxis] temp = np.ones((Nobj,1)) X = data - np.dot(temp,colmean.T) else: msgs.bug("PCA without cov=True is not implemented") msgs.error("Unable to continue") A = np.dot(X.T,X) eigva, eigve = np.linalg.eig(A) indx = np.where(np.abs(eigva) <= tolerance*np.max(eigva))[0] if np.size(indx) != 0: eigva[indx] = 0.0 indx = np.where(np.abs(eigve) <= tolerance*np.max(eigve))[0] if np.size(indx) != 0: eigve[indx] = 0.0 # Sort by increasing eigenvalue indx = np.argsort(eigva) eigva = eigva[indx] eigve = eigve[:,indx] eigva = eigva[::-1] eigve = eigve.T[::-1,:] return eigva, eigve
def fitsol_deriv(self, xfit=None, idx=None): """Calculate the dispersion as a function of wavelength Args: xfit (ndarray, float): Pixel values that the user wishes to evaluate the wavelength idx (int): Index of the arc line detections that the user wishes to evaluate the wavelength Returns: disp (ndarray, float, None): The dispersion (Angstroms/pixel) as a function of wavelength """ if xfit is None: xfit = self._detns if self._fitdict['coeff'] is not None: cder = np.polyder(self._fitdict["coeff"]) if idx is None: return np.polyval( cder, xfit / self._fitdict["scale"]) / self._fitdict["scale"] else: return np.polyval( cder, xfit[idx] / self._fitdict["scale"]) / self._fitdict["scale"] else: msgs.bug( "Cannot predict wavelength value - no fit has been performed") return None
def polyfit2d_general(x, y, z, deg, w=None, function='polynomial', minx=None, maxx=None, miny=None, maxy=None): """ 2D Polynomimal fit Args: x (`numpy.ndarray`_): y (`numpy.ndarray`_): z (`numpy.ndarray`_): value of data at each (x,y) coordinate deg (tuple): degree of polynomial fit in the form [nx,ny] w (`numpy.ndarray`_): function: minx: maxx: miny: maxy: Returns: `numpy.ndarray`_: """ x = np.asarray(x) y = np.asarray(y) z = np.asarray(z) deg = np.asarray(deg) # Vander if function == 'polynomial': vander = np.polynomial.polynomial.polyvander2d(x, y, deg) elif function == 'legendre' or function == 'chebyshev': xv, minx, maxx = scale_minmax(x, minx=minx, maxx=maxx) yv, miny, maxy = scale_minmax(y, minx=miny, maxx=maxy) vander = np.polynomial.legendre.legvander2d(xv, yv, deg) if function == 'legendre' \ else np.polynomial.chebyshev.chebvander2d(xv, yv, deg) else: msgs.error("Not ready for this type of {:s}".format(function)) # Weights if w is not None: w = np.asarray(w) + 0.0 if w.ndim != 1: msgs.bug("fitting.polyfit2d - Expected 1D vector for weights") if len(x) != len(w) or len(y) != len(w) or len(x) != len(y): msgs.bug( "fitting.polyfit2d - Expected x, y and weights to have same length" ) z = z * w vander = vander * w[:, np.newaxis] # Reshape vander = vander.reshape((-1, vander.shape[-1])) z = z.reshape((vander.shape[0], )) c = np.linalg.lstsq(vander, z, rcond=None)[0] return c.reshape(deg + 1), minx, maxx, miny, maxy
def robust_regression(x, y, ordr, outfrac, maxiter=100, function='polynomial', min=None, max=None): """ Deprecated """ msgs.bug("PypeIt using deprecated function") msgs.error("Please contact the authors") xsize=x.size infrac = 1.0-outfrac if infrac < 0.5: infrac = 0.5 slct = int(xsize*infrac) if slct == xsize: slct = xsize-1 if ordr+1 >= slct: if xsize <= 1: msgs.error("At least 2 points are required for a statistical fit") elif xsize == 2: msgs.warn("Only a constant can be fit to 2 points") msgs.info("Fitting a constant instead") return func_fit(x,y,function,0) elif ordr+1 >= xsize: msgs.warn("Not enough points ({0:d}) for a {1:d}th order fit".format(xsize,ordr)) ordr = xsize-3 slct = ordr+2 msgs.info("Changing order to a {0:d} order {1:s} fucntion".format(ordr,function)) else: slct = ordr indx = np.arange(xsize) np.random.shuffle(indx) ind = indx[:slct] i=0 while True: tc = func_fit(x[ind],y[ind],function,ordr) diff = np.abs(y[ind]-func_val(tc,x[ind],function)) mad = np.median(diff) w=np.argsort(diff) inds=-1 for j in range(0,xsize-slct): temp = ind[w[-1]] ind[w[-1]] = indx[slct+j] indx[slct+j] = temp diff = np.abs(y[ind]-func_val(tc,x[ind],function)) if np.median(diff) < mad: inds = j mad = np.median(diff) # Switch it back temp = ind[w[-1]] ind[w[-1]] = indx[slct+j] indx[slct+j] = temp if inds == -1 or i>maxiter: break temp = ind[w[-1]] ind[w[-1]] = indx[slct+inds] indx[slct+inds] = temp i += 1 return tc
def key_list(strlist): """ Check that a keyword argument is a list. Set the appropriate type of the list based on the supplied values. Parameters ---------- v : str value of a keyword argument Returns ------- v : list A value used by the settings dictionary """ # Check if the input array is a null list if strlist == "[]" or strlist == "()": return [] # Remove outer brackets and split by commas temp = strlist.lstrip('([').rstrip(')]').split(',') addarr = [] # Find the type of the array elements for i in temp: if i.lower() == 'none': # None type addarr += [None] elif i.lower() == 'true' or i.lower() == 'false': # bool type addarr += [i.lower() in ['true']] elif ',' in i: # a list addarr += i.lstrip('([').rstrip('])').split(',') msgs.bug( "nested lists could cause trouble if elements are not strings!" ) elif '.' in i: try: # Might be a float addarr += [float(i)] except ValueError: # Must be a string addarr += [i] else: try: # Could be an integer addarr += [int(i)] except ValueError: # Must be a string addarr += [i] return addarr
def fitsol_value(self, xfit=None, idx=None): """Calculate the wavelength at a pixel Args: xfit (ndarray, float): Pixel values that the user wishes to evaluate the wavelength idx (int): Index of the arc line detections that the user wishes to evaluate the wavelength Returns: disp (ndarray, float, None): The wavelength (Angstroms) of the requested pixels """ if xfit is None: xfit = self._detns if self._fitdict['coeff'] is not None: if idx is None: return np.polyval(self._fitdict["coeff"], xfit / self._fitdict["scale"]) else: return np.polyval(self._fitdict["coeff"], xfit[idx] / self._fitdict["scale"]) else: msgs.bug( "Cannot predict wavelength value - no fit has been performed") return None
def operations(self, key, axisID): """Canvas operations Args: key (str): Which key has been pressed axisID (int): The index of the axis where the key has been pressed (see get_axisID) """ # Check if the user really wants to quit if key == 'q' and self._qconf: if self._changes: self.update_infobox(message="WARNING: There are unsaved changes!!\nPress q again to exit", yesno=False) self._qconf = True else: msgs.bug("Need to change this to kill and return the results to PypeIt") plt.close() elif self._qconf: self.update_infobox(default=True) self._qconf = False # Manage responses from questions posed to the user. if self._respreq[0]: if key != "y" and key != "n": return else: # Switch off the required response self._respreq[0] = False # Deal with the response if self._respreq[1] == "delete_object" and key == "y": self.delete_object() elif self._respreq[1] == "clear_anchors" and key == "y": self.empty_mantrace() self.replot() elif self._respreq[1] == "exit_update" and key == "y": self._use_updates = True self.print_pypeit_info() self.operations("qu", None) elif self._respreq[1] == "exit_restore" and key == "y": self._use_updates = False self.operations("qr", None) else: return # Reset the info box self.update_infobox(default=True) return if key == '?': self.print_help() elif key == 'a': self.add_object() elif key == 'c': if axisID == 0: # If this is pressed on the main window self.recenter() # elif key == 'c': # self._respreq = [True, "clear_anchors"] # self.update_infobox(message="Are you sure you want to clear the anchors", yesno=True) elif key == 'd': if self._obj_idx != -1: self._respreq = [True, "delete_object"] self.update_infobox(message="Are you sure you want to delete this object trace", yesno=True) # elif key == 'm': # if self._trcmthd != 'manual': # self.update_infobox(message="To add an anchor point, set the 'manual' trace method", yesno=False) # else: # self.add_anchor() # elif key == 'n': # self.remove_anchor() elif key == 'qu' or key == 'qr': if self._changes: self.update_infobox(message="WARNING: There are unsaved changes!!\nPress q again to exit", yesno=False) self._qconf = True else: plt.close() # elif key == '+': # if self._mantrace["polyorder"] < 10: # self._mantrace["polyorder"] += 1 # self.update_infobox(message="Polynomial order = {0:d}".format(self._mantrace["polyorder"]), yesno=False) # self.fit_anchors() # else: # self.update_infobox(message="Polynomial order must be <= 10", yesno=False) # elif key == '-': # if self._mantrace["polyorder"] > 1: # self._mantrace["polyorder"] -= 1 # self.update_infobox(message="Polynomial order = {0:d}".format(self._mantrace["polyorder"]), yesno=False) # self.fit_anchors() # else: # self.update_infobox(message="Polynomial order must be >= 1", yesno=False) self.replot()
def operations(self, key, axisID): """Canvas operations Args: key (str): Which key has been pressed axisID (int): The index of the axis where the key has been pressed (see get_axisID) """ # Check if the user really wants to quit if key == 'q' and self._qconf: if self._changes: self.update_infobox( message= "WARNING: There are unsaved changes!!\nPress q again to exit", yesno=False) self._qconf = True else: msgs.bug( "Need to change this to kill and return the results to PypeIt" ) plt.close() elif self._qconf: self.update_infobox(default=True) self._qconf = False # Manage responses from questions posed to the user. if self._respreq[0]: if key != "y" and key != "n": return else: # Switch off the required response self._respreq[0] = False # Deal with the response if self._respreq[1] == "write": # First remove the old file, and save the new one msgs.work("Not implemented yet!") self.write() else: return # Reset the info box self.update_infobox(default=True) return if key == '?': self.print_help() elif key == 'a': if self._fitdict['coeff'] is not None: self.auto_id() else: msgs.info("You must identify a few lines first") elif key == 'c': wclr = np.where((self._lineflg == 2) | (self._lineflg == 3)) self._lineflg[wclr] = 0 self.replot() elif key == 'd': self._lineflg *= 0 self._lineids *= 0.0 self._fitdict['coeff'] = None self.replot() elif key == 'f': self.fitsol_fit() self.replot() elif key == 'l': self.load_IDs() elif key == 'q': if self._changes: self.update_infobox( message= "WARNING: There are unsaved changes!!\nPress q again to exit", yesno=False) self._qconf = True else: plt.close() elif key == 'r': if self._detns_idx == -1: msgs.info("You must select a line first") elif self._fitr is None: msgs.info("You must select a fitting region first") else: msgs.work("Feature not yet implemented") elif key == 's': self.save_IDs() elif key == 'w': self.toggle_wavepix(toggled=True) self.replot() elif key == 'z': self.delete_line_id() elif key == '+': if self._fitdict["polyorder"] < 10: self._fitdict["polyorder"] += 1 self.update_infobox(message="Polynomial order = {0:d}".format( self._fitdict["polyorder"]), yesno=False) self.fitsol_fit() self.replot() else: self.update_infobox(message="Polynomial order must be <= 10", yesno=False) elif key == '-': if self._fitdict["polyorder"] > 1: self._fitdict["polyorder"] -= 1 self.update_infobox(message="Polynomial order = {0:d}".format( self._fitdict["polyorder"]), yesno=False) self.fitsol_fit() self.replot() else: self.update_infobox(message="Polynomial order must be >= 1", yesno=False) self.canvas.draw()
def operations(self, key, axisID): """Canvas operations Args: key : str Which key has been pressed axisID : int The index of the axis where the key has been pressed (see get_axisID) """ # Check if the user really wants to quit if key == 'q' and self._qconf: if self._changes: self.update_infobox( message='WARNING: There are unsaved changes!!\nPress q ' 'again to exit', yesno=False) self._qconf = True else: msgs.bug( "Need to change this to kill and return the results to PypeIt" ) plt.close() elif self._qconf: self.update_infobox(default=True) self._qconf = False # Manage responses from questions posed to the user. if self._respreq[0]: if key != "y" and key != "n": return else: # Switch off the required response self._respreq[0] = False # Deal with the response if self._respreq[1] == "exit_update" and key == "y": self._use_updates = True self.operations("qu", None) elif self._respreq[1] == "exit_restore" and key == "y": self._use_updates = False self.operations("qr", None) else: return # Reset the info box self.update_infobox(default=True) return if key == '?': self.print_help() elif key == 'd': if axisID == 0: # If this is pressed on the main window self.reset_regions() elif key == 'c': if axisID == 0: # If this is pressed on the main window self.recenter() elif key == 'qu' or key == 'qr': if self._changes: self.update_infobox( message='WARNING: There are unsaved changes!!\nPress q ' 'again to exit', yesno=False) self._qconf = True else: plt.close() self.replot()
def polyfit_integral(x, y, dx, deg, rcond=None, full=False, w=None): order = int(deg) + 1 x = np.asarray(x) y = np.asarray(y) # check arguments. if deg < 0: msgs.bug("Expected deg >= 0") msgs.error("Input of function arutils.polyfit_integral is incorrect") if x.ndim != 1: msgs.bug("Expected 1D vector for x") msgs.error("Input of function arutils.polyfit_integral is incorrect") if x.size == 0: msgs.bug("Expected non-empty vector for x") msgs.error("Input of function arutils.polyfit_integral is incorrect") if y.ndim < 1 or y.ndim > 2: msgs.bug("Expected 1D or 2D array for y") msgs.error("Input of function arutils.polyfit_integral is incorrect") if len(x) != len(y): msgs.bug("Expected x and y to have same length") msgs.error("Input of function arutils.polyfit_integral is incorrect") # set up the least squares matrices in transposed form lhst = np.polynomial.polynomial.polyvander( x + dx / 2.0, deg + 1) - np.polynomial.polynomial.polyvander( x - dx / 2.0, deg + 1) div = np.arange(1., deg + 2.).reshape(1, deg + 1).repeat(x.size, axis=0) lhs = (lhst[:, 1:] / (dx.reshape(dx.size, 1).repeat(deg + 1, axis=1) * div)).T rhs = y.T if w is not None: w = np.asarray(w) if w.ndim != 1: msgs.bug("Expected 1D vector for weights in arutils.polyfit2d") if len(x) != len(w): msgs.bug( "Expected x and weights to have same length in arutils.polyfit2d" ) # apply weights. Don't use inplace operations as they # can cause problems with NA. lhs = lhs * w rhs = rhs * w # set rcond if rcond is None: rcond = len(x) * np.finfo(x.dtype).eps # Determine the norms of the design matrix columns. if issubclass(lhs.dtype.type, np.complexfloating): scl = np.sqrt((np.square(lhs.real) + np.square(lhs.imag)).sum(1)) else: scl = np.sqrt(np.square(lhs).sum(1)) scl[scl == 0] = 1 # Solve the least squares problem. c, resids, rank, s = np.linalg.lstsq(lhs.T / scl, rhs.T, rcond) c = (c.T / scl).T # warn on rank reduction if rank != order and not full: msgs.warn( "The fit result of the function arutils.polyfit_integral may be poorly conditioned" ) if full: return c, [resids, rank, s, rcond] else: return c