def plot(self, *expr_pairs, save=None, xunit=None, yunit=None, xrange=None, yrange=None, ignore_dim=False): """ Plots data or functions Args: expr_pairs: one or more pair of quantity on x-axis and on y-axis. e.g. ["p","V"] y-axis can also be a function. e.g. ["t", "7*exp(t/t0)"] save: string of file name without extension. if specified, plot will be saved to '<save>.png' xunit: unit on x-axis. if not given, will find unit on its own yunit: unit on y-axis. if not given, will find unit on its own xrange: pair of x-axis range, e.g. [-5,10] yrange: pair of y-axis range ignore_dim: if True, will skip dimension check """ if len(expr_pairs) == 0:# raise ValueError("nothing to plot specified.") expr_pairs_obj = [] for expr_pair in expr_pairs: # parse expressions expr_pairs_obj.append( (quantities.parse_expr(expr_pair[0], self.data), quantities.parse_expr(expr_pair[1], self.data)) ) if not xunit is None: xunit = units.parse_unit(xunit)[2] if not yunit is None: yunit = units.parse_unit(yunit)[2] if not xrange is None: xrange = [quantities.get_value(quantities.parse_expr(xrange[0], self.data)), quantities.get_value(quantities.parse_expr(xrange[1], self.data))] if not yrange is None: yrange = [quantities.get_value(quantities.parse_expr(yrange[0], self.data)), quantities.get_value(quantities.parse_expr(yrange[1], self.data))] return plotting.plot(expr_pairs_obj, self.config, save=save, xunit=xunit, yunit=yunit, xrange=xrange, yrange=yrange, ignore_dim=ignore_dim)
def plot(self, *expr_pairs, save=None, xunit=None, yunit=None, xrange=None, yrange=None, ignore_dim=False): """ Plots data or functions Args: expr_pairs: one or more pair of quantity on x-axis and on y-axis. e.g. ["p","V"] y-axis can also be a function. e.g. ["t", "7*exp(t/t0)"] save: string of file name without extension. if specified, plot will be saved to '<save>.png' xunit: unit on x-axis. if not given, will find unit on its own yunit: unit on y-axis. if not given, will find unit on its own xrange: pair of x-axis range, e.g. [-5,10] yrange: pair of y-axis range ignore_dim: if True, will skip dimension check """ if len(expr_pairs) == 0: # raise ValueError("nothing to plot specified.") expr_pairs_obj = [] for expr_pair in expr_pairs: # parse expressions expr_pairs_obj.append( (quantities.parse_expr(expr_pair[0], self.data), quantities.parse_expr(expr_pair[1], self.data))) if not xunit is None: xunit = units.parse_unit(xunit)[2] if not yunit is None: yunit = units.parse_unit(yunit)[2] if not xrange is None: xrange = [ quantities.get_value( quantities.parse_expr(xrange[0], self.data)), quantities.get_value( quantities.parse_expr(xrange[1], self.data)) ] if not yrange is None: yrange = [ quantities.get_value( quantities.parse_expr(yrange[0], self.data)), quantities.get_value( quantities.parse_expr(yrange[1], self.data)) ] return plotting.plot(expr_pairs_obj, self.config, save=save, xunit=xunit, yunit=yunit, xrange=xrange, yrange=yrange, ignore_dim=ignore_dim)
def fit(self, fit_function, xydata, parameters, weighted=None, plot=False, ignore_dim=False): """ fits function to data Args: fit_function: function to fit, e.g. "n*t**2 + m*t + b" xydata: pair of x-quantity and y-quantity of data to fit to, e.g. ["t","U"] parameters: list of parameters in fit function, e.g. ["n","m","b"] weighted: if True, will weight fit by errors (returns error if not possible) if False, will not weight fit by errors if None, will try to weight fit, but if at least one error is not given, will not weight it plot: Bool, if data and fit function should be plotted ignore_dim: if True, will ignore dimensions and just calculate in base units instead """ if self.config["fit_module"] == "scipy": import errorpro.fit_scipy as fit_module else: raise ValueError("no fit module called '%s'." % self.config["fit_module"]) # get parameter quantities parameters_obj = [] for p in parameters: if isinstance(p, str): if not p in self.data: self.data[p] = quantities.Quantity(p) self.data[p].dim = Dimension() parameters_obj.append(self.data[p]) elif isinstance(p, quantities.Quantity): parameters_obj.append(p) else: raise TypeError("parameters can only be strings or Quantity objects") # parse fit function fit_function = quantities.parse_expr(fit_function, self.data) # get data quantities x_data = quantities.parse_expr(xydata[0], self.data) # if x-data is an expression if not isinstance(x_data, quantities.Quantity): dummy = quantities.Quantity() fit_function = fit_function.subs(x_data,dummy) dummy.value = quantities.get_value(x_data) dummy.error = quantities.get_error(x_data)[0] dummy.dim = quantities.get_dimension(x_data) x_data = dummy y_data = quantities.parse_expr(xydata[1], self.data) # if y-data is an expression if not isinstance(y_data, quantities.Quantity): dummy = quantities.Quantity() dummy.value = quantities.get_value(y_data) dummy.error = quantities.get_error(y_data)[0] dummy.dim = quantities.get_dimension(y_data) y_data = dummy # check if dimension fits if not ignore_dim: try: dim_func = quantities.get_dimension(fit_function) except ValueError: dim_func = None if not dim_func == y_data.dim: # try to solve for dimensionless parameters known_dimensions = {x_data.name: x_data.dim} known_dimensions = dim_solve(fit_function, y_data.dim, known_dimensions) for q_name in known_dimensions: if q_name in self.data: if not self.data[q_name].dim == known_dimensions[q_name]: self.data[q_name].dim = known_dimensions[q_name] self.data[q_name].prefer_unit = None dim_func = quantities.get_dimension(fit_function) # if it still doesn't work, raise error if not dim_func == y_data.dim: raise RuntimeError("Finding dimensions of fit parameters was not sucessful.\n"\ "Check fit function or specify parameter units manually.\n"\ "This error will occur until dimensions are right.") # fit values, errors = fit_module.fit(x_data, y_data, fit_function, parameters_obj, weighted) # save results i = 0 for p in parameters_obj: p.value = values[i] p.value_formula = "fit" p.error = errors[i] p.error_formula = "fit" i += 1 # plot if plot: return plotting.plot([(x_data, y_data), (x_data, fit_function)], self.config, ignore_dim=ignore_dim) else: return self.table(*parameters_obj)
def fit(self, fit_function, xydata, parameters, weighted=None, plot=False, ignore_dim=False): """ fits function to data Args: fit_function: function to fit, e.g. "n*t**2 + m*t + b" xydata: pair of x-quantity and y-quantity of data to fit to, e.g. ["t","U"] parameters: list of parameters in fit function, e.g. ["n","m","b"] weighted: if True, will weight fit by errors (returns error if not possible) if False, will not weight fit by errors if None, will try to weight fit, but if at least one error is not given, will not weight it plot: Bool, if data and fit function should be plotted ignore_dim: if True, will ignore dimensions and just calculate in base units instead """ if self.config["fit_module"] == "scipy": import errorpro.fit_scipy as fit_module else: raise ValueError("no fit module called '%s'." % self.config["fit_module"]) # get parameter quantities parameters_obj = [] for p in parameters: if isinstance(p, str): if not p in self.data: self.data[p] = quantities.Quantity(p) self.data[p].dim = Dimension() parameters_obj.append(self.data[p]) elif isinstance(p, quantities.Quantity): parameters_obj.append(p) else: raise TypeError( "parameters can only be strings or Quantity objects") # parse fit function fit_function = quantities.parse_expr(fit_function, self.data) # get data quantities x_data = quantities.parse_expr(xydata[0], self.data) # if x-data is an expression if not isinstance(x_data, quantities.Quantity): dummy = quantities.Quantity() fit_function = fit_function.subs(x_data, dummy) dummy.value = quantities.get_value(x_data) dummy.error = quantities.get_error(x_data)[0] dummy.dim = quantities.get_dimension(x_data) x_data = dummy y_data = quantities.parse_expr(xydata[1], self.data) # if y-data is an expression if not isinstance(y_data, quantities.Quantity): dummy = quantities.Quantity() dummy.value = quantities.get_value(y_data) dummy.error = quantities.get_error(y_data)[0] dummy.dim = quantities.get_dimension(y_data) y_data = dummy # check if dimension fits if not ignore_dim: try: dim_func = quantities.get_dimension(fit_function) except ValueError: dim_func = None if not dim_func == y_data.dim: # try to solve for dimensionless parameters known_dimensions = {x_data.name: x_data.dim} known_dimensions = dim_solve(fit_function, y_data.dim, known_dimensions) for q_name in known_dimensions: if q_name in self.data: if not self.data[q_name].dim == known_dimensions[ q_name]: self.data[q_name].dim = known_dimensions[q_name] self.data[q_name].prefer_unit = None dim_func = quantities.get_dimension(fit_function) # if it still doesn't work, raise error if not dim_func == y_data.dim: raise RuntimeError("Finding dimensions of fit parameters was not sucessful.\n"\ "Check fit function or specify parameter units manually.\n"\ "This error will occur until dimensions are right.") # fit values, errors = fit_module.fit(x_data, y_data, fit_function, parameters_obj, weighted) # save results i = 0 for p in parameters_obj: p.value = values[i] p.value_formula = "fit" p.error = errors[i] p.error_formula = "fit" i += 1 # plot if plot: return plotting.plot([(x_data, y_data), (x_data, fit_function)], self.config, ignore_dim=ignore_dim) else: return self.table(*parameters_obj)