|
| 1 | + |
| 2 | +import numpy as np |
| 3 | +from scipy.optimize import curve_fit |
| 4 | + |
| 5 | +# Class CurveFit: |
| 6 | +# contains all functions used to generate a regression line given a set of data points |
| 7 | +# functions are called in R2byScalePlot and RegressionPlot class functions. |
| 8 | +class CurveFit: |
| 9 | + |
| 10 | + def __init__(self): |
| 11 | + |
| 12 | + # Regression line is determined recursively using the curve_fit function from scipy library. |
| 13 | + # this value can be changed in the Curve Fit dialog by the user. I set the default to be 1000 based on trial and error. |
| 14 | + # this can actually have a significant impact with R^2 values by changing them from undefined / zero all the way to 0.3+ |
| 15 | + # depending on the scale |
| 16 | + self.maxfev = 1000 |
| 17 | + |
| 18 | + # below are the functions for each curve type easy to add new functions or in the future have user defined functions |
| 19 | + # -----------------------------Proportional Fit Functions--------------------------------------------------------------- |
| 20 | + def prop_fit(self, x, a): return a*x |
| 21 | + def prop_data(self, x, y): return curve_fit(self.prop_fit, x, y, maxfev=self.get_maxfev()) |
| 22 | + # ------------------------------Linear Fit Functions-------------------------------------------------------------------- |
| 23 | + def linear_fit(self, x, a, b): return a*x + b |
| 24 | + def linear_data(self, x, y): return curve_fit(self.linear_fit, x, y, maxfev=self.get_maxfev()) |
| 25 | + # ------------------------------Quadratic Fit Functions----------------------------------------------------------------- |
| 26 | + def quad_fit(self, x, a, b, c): return a*x**2 + b*x + c |
| 27 | + def quad_data(self, x, y): return curve_fit(self.quad_fit, x, y, maxfev=self.get_maxfev()) |
| 28 | + # ------------------------------Cubic Fit Functions--------------------------------------------------------------------- |
| 29 | + def cubic_fit(self, x, a, b, c, d): return a*x**3 + b*x**2 + c*x + d |
| 30 | + def cubic_data(self, x, y): return curve_fit(self.cubic_fit, x, y, maxfev=self.get_maxfev()) |
| 31 | + # ---------------------------------Quartic Fit Functions---------------------------------------------------------------- |
| 32 | + def quartic_fit(self, x, a, b, c, d, e): return a*x**4 + b*x**3 + c*x**2 + d*x + e |
| 33 | + def quartic_data(self, x, y): return curve_fit(self.quartic_fit, x, y, maxfev=self.get_maxfev()) |
| 34 | + # ------------------------------- Quintic Fit Functions----------------------------------------------------------------- |
| 35 | + def quintic_fit(self, x, a, b, c, d, e, f): return a*x**5 + b*x**4 + c*x**3 + d*x**2 + e*x + f |
| 36 | + def quintic_data(self, x, y): return curve_fit(self.quintic_fit, x, y, maxfev=self.get_maxfev()) |
| 37 | + # -------------------------------------Power Fit Functions ----------------------------------------------------------- |
| 38 | + def power_fit(self, x, a, b): return a*x**b |
| 39 | + def power_data(self, x, y): return curve_fit(self.power_fit, x, y, maxfev=self.get_maxfev()) |
| 40 | + # -------------------------------------Inverse Fit Functions------------------------------------------------------- |
| 41 | + def inverse_fit(self, x, a): return a/x |
| 42 | + def inverse_data(self, x, y): return curve_fit(self.inverse_fit, x, y, maxfev=self.get_maxfev()) |
| 43 | + # ---------------------------------------Inverse Squared Fit Functions ------------------------------------------------- |
| 44 | + def insq_fit(self, x, a): return a/(x**2) |
| 45 | + def insq_data(self, x, y): return curve_fit(self.insq_fit, x, y, maxfev=self.get_maxfev()) |
| 46 | + # ---------------------------------------------Natural Exponent Fit Functions------------------------------------------- |
| 47 | + def nexp_fit(self, x, a, b, c): return a*np.exp(-1*b*x) + c |
| 48 | + def nexp_data(self, x, y): return curve_fit(self.nexp_fit, x, y, maxfev=self.get_maxfev()) |
| 49 | + # ----------------------------------------Natural Log Fit-------------------------------------------------------------- |
| 50 | + def ln_fit(self, x, a, b): return a*np.log(b*x) # second term is base in log() |
| 51 | + def ln_data(self, x, y): return curve_fit(self.ln_fit, x, y, maxfev=self.get_maxfev()) |
| 52 | + # --------------------------------------Base-10 Exponent---------------------------------------------------------------- |
| 53 | + # doesnt even work smh |
| 54 | + def b10exp_fit(self, x, a, b, c): return a*(10**(b*x)) + c |
| 55 | + def b10exp_data(self, x, y): return curve_fit(self.b10exp_fit, x, y, maxfev=self.get_maxfev()) |
| 56 | + # ---------------------------------------Base-10 Logarithm-------------------------------------------------------------- |
| 57 | + def b10log_fit(self, x, a, b): return a*np.log10(b*x) |
| 58 | + def b10log_data(self, x, y): return curve_fit(self.b10log_fit, x, y, maxfev=self.get_maxfev()) |
| 59 | + # ---------------------------------------Inverse Exponent Fit----------------------------------------------------------- |
| 60 | + def invexp_fit(self, x, a, b, c): return a*(1-np.exp(-1*b*x)) + c |
| 61 | + def invexp_data(self, x, y): return curve_fit(self.invexp_fit, x, y, maxfev=self.get_maxfev()) |
| 62 | + # ---------------------------------------Sine Fit------------------------------------------------------------------ |
| 63 | + def sine_fit(self, x, a, b, c, d): return a*np.sin(b*x + c) + d |
| 64 | + def sine_data(self, x, y): return curve_fit(self.sine_fit, x, y, maxfev=self.get_maxfev()) |
| 65 | + # -------------------------------------Cosine Fit---------------------------------------------------- |
| 66 | + def cosine_fit(self, x, a, b, c, d): return a*np.cos(b*x + c) + d |
| 67 | + def cosine_data(self, x, y): return curve_fit(self.cosine_fit, x, y, maxfev=self.get_maxfev()) |
| 68 | + # -------------------------------------Cosine Squared Fit-------------------------------------------------------- |
| 69 | + # not sure if theres a point to this it doesnt even work smh |
| 70 | + def cossqrd_fit(self, x, a, b, c, d): return a*np.square(np.cos(b*x + c)) + d |
| 71 | + def cossqrd_data(self, x, y): return curve_fit(self.cossqrd_fit, x, y, maxfev=self.get_maxfev()) |
| 72 | + # ---------------------------------- Gaussian Fit ---------------------------------------------------------------- |
| 73 | + def gauss_fit(self, x, a, b, c, d): return a*np.exp(-1*((x-b)**2)/(c**2)) + d |
| 74 | + def gauss_data(self, x, y): return curve_fit(self.gauss_fit, x, y, maxfev=self.get_maxfev()) |
| 75 | + # ---------------------------------------R^2 CALCULATION---------------------------------------------------------------- |
| 76 | + # function to calculate the R^2 value of a regression line |
| 77 | + def r_squared(self, y, func): |
| 78 | + |
| 79 | + # forumla for R^2 calculation |
| 80 | + residuals = y - np.array(func) |
| 81 | + # residual sum of squares |
| 82 | + ss_res = np.sum(residuals**2) |
| 83 | + ss_total = np.sum((y - np.mean(y))**2) |
| 84 | + |
| 85 | + # depending on the data, the regression function can yield results > 1 or ss_total = 0 so R^2 would be undefined |
| 86 | + # this returns nan so in each of these cases the R^2 value is set to be 0 |
| 87 | + if ss_total == 0: |
| 88 | + return 0 |
| 89 | + elif (ss_res / ss_total) > 1: |
| 90 | + return 0 |
| 91 | + else: |
| 92 | + return np.sqrt(1 - (ss_res / ss_total)) |
| 93 | + |
| 94 | + def get_maxfev(self): return self.maxfev |
| 95 | + def set_maxfev(self, maxfev): self.maxfev = maxfev |
0 commit comments