diff --git a/Python_script/PostPlot.py b/Python_script/PostPlot.py index c47b26e42c429ea36256cbaeb136818549cf4cc3..e52205a35e3238d1523f7d3a1251bafb20c5815e 100644 --- a/Python_script/PostPlot.py +++ b/Python_script/PostPlot.py @@ -9,8 +9,9 @@ import pandas as pd import sys from pathlib import Path import os -import MeasurementPlot -import curvefit_and_correlation +from MeasurementPlot import MeasurementPlot +import numpy as np + # after measurement has finished from stored csv-data a post plot of all temperature steps is plotted and store in @@ -18,18 +19,22 @@ import curvefit_and_correlation # oftional correclation and regression can be calculated and plotted in results, Michael # option is configureable via ext_sens_data.json, Michael class PostPlot: - def __init__(self, env_cond_sensors = ''): + def __init__(self, env_cond_sensors = '', legend_loc = 'upper left', \ + legend_bbox_to_anchor = (1.09, 1)): # set python for opening an separate plot window if 'ipykernel' in sys.modules: from IPython import get_ipython get_ipython().run_line_magic('matplotlib', 'qt') - self.measplot_obj = MeasurementPlot.MeasurementPlot(env_cond_sensors = env_cond_sensors,\ - legend_loc = 'upper left', legend_bbox_to_anchor = (1.09, 1)) + self.measplot = MeasurementPlot(env_cond_sensors = env_cond_sensors,\ + legend_loc = legend_loc, legend_bbox_to_anchor = legend_bbox_to_anchor) + + self.legend_loc = legend_loc + self.legend_bbox_to_anchor = legend_bbox_to_anchor # set parameter figure of class to object parameter figure - self.fig = self.measplot_obj.fig + self.fig = self.measplot.fig # read csv-file and import data to data frame def import_csv(self, csv_file): @@ -48,7 +53,7 @@ class PostPlot: data_frame.reset_index(inplace=True, drop=True) # set y-Achlabel in all subplots to Time an in square brackets the selected time unit - for element in self.measplot_obj.ax1: + for element in self.measplot.ax1: element.set_xlabel("Time [%s]" %time_unit) # make a copy of data_frame in parameterlist without changing original during modification @@ -67,7 +72,7 @@ class PostPlot: postplot_data_frame.update(time_vals) # refresh subflots with data in data frame - self.measplot_obj.draw(postplot_data_frame, pdf_name = '') + self.measplot.draw(postplot_data_frame, pdf_name = '') # cal PK2PK values of magnitude and phase PK2PK = self.calc_mag_phase_pkpk_values(data_frame) @@ -78,13 +83,12 @@ class PostPlot: def edit_annotation_in_plot(self, annotate_string ='', anno_fontsize = 16): - self.fig - # update text of annotation in first subplot - self.measplot_obj.annotation.set_text(annotate_string) + self.measplot.annotation.set_text(annotate_string) # edit annotation fontsize in first subplot - self.measplot_obj.annotation.set_fontsize(anno_fontsize) + self.measplot.annotation.set_fontsize(anno_fontsize) + def calc_mag_phase_pkpk_values(self, data_frame): @@ -98,7 +102,38 @@ class PostPlot: return delta_vals_string - + + def add_curvefit_to_plot(self, y_lim = None , xvals = [], yvals = [], \ + trace_color = 'None', trace_label = ''): + + if y_lim != None: + # set axis for phaseplot to min, max values + self.measplot.ax1[0].set_ylim(y_lim) + + # set color of trace for curvefit result to green (trace is visible) + self.measplot.path_collection_fit.set_color(trace_color) + + # set label of trace curvefit results to name of fit function name + self.measplot.path_collection_fit.set_label(trace_label) + + # refrest data in meas plot + self.measplot.path_collection_fit.set_offsets(np.c_[xvals, yvals]) + + # get legend handles and labels y-axes from subplot magnitude, phase + handles_phase, labels_phase = self.measplot.ax1[0].get_legend_handles_labels() + handles_mag, labels_mag = self.measplot.magnitude_axis.get_legend_handles_labels() + handles_equi0, labels_eqi0 = self.measplot.equi_axis0.get_legend_handles_labels() + + handles = handles_phase + handles_mag + handles_equi0 + labels = labels_phase + labels_mag + labels_eqi0 + + # update legend subplot phase, magnitude + self.measplot.ax1[0].legend(handles, labels, loc = self.legend_loc, \ + bbox_to_anchor = self.legend_bbox_to_anchor) + + # refresh plot window + self.measplot.fig.canvas.flush_events() + # save figure under the given storepath in parameterlist with the given filename in parameter list, Michael # file extension is part of filename, Michael def save_fig(self, storepath, filename): @@ -140,26 +175,17 @@ if __name__ == '__main__': time_unit = 'min' # set storepath for the post plots, Michael - storepath = Results_Path + '\\Plots' + storepath = Results_Path + '\\PostPlots' # search all csv files in results folder csv_file_list = list(Path(Results_Path).glob("**/*.csv")) - # choose annotation option - plot_correlation_coeff = False - plot_regression_coeff = False - - # activate plot curvefitting - - plot_trace_curvefit = False trace_selection = "" # create postplot object, Michael plot_obj = PostPlot(env_cond_sensors= trace_selection) - - fit_corr_obj = curvefit_and_correlation.reg_and_corr(plot_obj) # empty data frame for concat the data frames from csv import to plot full transistion concat_data_frame = pd.DataFrame() @@ -178,34 +204,9 @@ if __name__ == '__main__': # plot frame data - plot_obj.plot_frame_data(data_frame, title, time_unit) + plot_obj.plot_frame_data(data_frame, title, time_unit) - if plot_correlation_coeff == True: - - # determine correlation coefficient between func 1 and func 2 - corr_coeff =fit_corr_obj.calc_correlation(func_1 = data_frame.S21_PHASE , \ - func_2 = data_frame.TEMP_DUT) - - # plot correlation coefficient - plot_obj.edit_annotation_in_plot(annotate_string = corr_coeff) - - elif plot_regression_coeff == True: - - # start curvefit and determine coefficients best fit function - reg_coeff = fit_corr_obj.calc_regression_coeff_phase_S21(data_frame, time_unit = 'min') - - # plot regression coefficients - plot_obj.edit_annotation_in_plot(annotate_string = reg_coeff) - - plot_obj.edit_annotation_in_plot(annotate_string = reg_coeff) - - if plot_trace_curvefit == True: - - fit_corr_obj.plot_phase_curve_fit(data_frame = data_frame, \ - postplot_obj = plot_obj.measplot_obj, \ - time_unit = time_unit, state = True) - # set filename of post plot, Michael filename = str(csv_file.stem) + '.pdf' @@ -217,10 +218,6 @@ if __name__ == '__main__': # title of this plot will be always full transistion, Michel plot_obj.plot_frame_data(concat_data_frame, 'Full Transistion', time_unit) - fit_corr_obj.plot_phase_curve_fit(data_frame = concat_data_frame, \ - postplot_obj = plot_obj.measplot_obj, \ - time_unit = time_unit, state = False) - # filename of plot that contains all steps of sweep is set to FullTransistion, Michael filename = 'Full_Transistion' + '.pdf' diff --git a/Python_script/TestData_JBY240/AnalysisPlots/2023_07_29-15_38_40_results_25.0deg_55.0rh.pdf b/Python_script/TestData_JBY240/AnalysisPlots/2023_07_29-15_38_40_results_25.0deg_55.0rh.pdf new file mode 100644 index 0000000000000000000000000000000000000000..2a9de5b0c267cde31d0d3563dd0045d6445ceeeb Binary files /dev/null and b/Python_script/TestData_JBY240/AnalysisPlots/2023_07_29-15_38_40_results_25.0deg_55.0rh.pdf differ diff --git a/Python_script/TestData_JBY240/AnalysisPlots/2023_07_29-15_38_40_results_30.0deg_55.0rh.pdf b/Python_script/TestData_JBY240/AnalysisPlots/2023_07_29-15_38_40_results_30.0deg_55.0rh.pdf new file mode 100644 index 0000000000000000000000000000000000000000..360b2329549b34a6b6a6291dbc0d07c058e261a7 Binary files /dev/null and b/Python_script/TestData_JBY240/AnalysisPlots/2023_07_29-15_38_40_results_30.0deg_55.0rh.pdf differ diff --git a/Python_script/TestData_JBY240/AnalysisPlots/Full_Transistion.pdf b/Python_script/TestData_JBY240/AnalysisPlots/Full_Transistion.pdf new file mode 100644 index 0000000000000000000000000000000000000000..34d70956506dac45a0c658afed71dd01631faadc Binary files /dev/null and b/Python_script/TestData_JBY240/AnalysisPlots/Full_Transistion.pdf differ diff --git a/Python_script/TestData_JBY240/PostPlots/2023_07_29-15_38_40_results_25.0deg_55.0rh.pdf b/Python_script/TestData_JBY240/PostPlots/2023_07_29-15_38_40_results_25.0deg_55.0rh.pdf new file mode 100644 index 0000000000000000000000000000000000000000..e421d41f24670877fbb65c29c0ad25f92ddd64ab Binary files /dev/null and b/Python_script/TestData_JBY240/PostPlots/2023_07_29-15_38_40_results_25.0deg_55.0rh.pdf differ diff --git a/Python_script/TestData_JBY240/PostPlots/2023_07_29-15_38_40_results_30.0deg_55.0rh.pdf b/Python_script/TestData_JBY240/PostPlots/2023_07_29-15_38_40_results_30.0deg_55.0rh.pdf new file mode 100644 index 0000000000000000000000000000000000000000..10ceaecee41bea660d6866757f62ddc02e3a9e91 Binary files /dev/null and b/Python_script/TestData_JBY240/PostPlots/2023_07_29-15_38_40_results_30.0deg_55.0rh.pdf differ diff --git a/Python_script/TestData_JBY240/PostPlots/Full_Transistion.pdf b/Python_script/TestData_JBY240/PostPlots/Full_Transistion.pdf new file mode 100644 index 0000000000000000000000000000000000000000..5b7d83c0bd11bedf0df1c900a49c82cb8a6add7a Binary files /dev/null and b/Python_script/TestData_JBY240/PostPlots/Full_Transistion.pdf differ diff --git a/Python_script/curvefit_and_correlation.py b/Python_script/curvefit_and_correlation.py index 9952f9221418c6a2c6928b8dade1b965165f0ccc..7a4d3c7d17f4e338a7d5a7bdd5e4d42bf0b096ee 100644 --- a/Python_script/curvefit_and_correlation.py +++ b/Python_script/curvefit_and_correlation.py @@ -6,56 +6,65 @@ Created on Thu Jul 27 08:53:36 2023 """ import numpy as np from scipy.optimize import curve_fit - - +from PostPlot import PostPlot +import pandas as pd +from pathlib import Path class reg_and_corr: - def __init__(self, post_plot_obj, legend_loc = 'upper left', \ + def __init__(self, env_cond_sensors = '', legend_loc = 'upper left', \ legend_bbox_to_anchor = (1.09, 1)): - self.post_plot_obj = post_plot_obj + self.postplot = PostPlot(env_cond_sensors = env_cond_sensors) self.K_phases = None self.phase_t0 = None self.legend_loc = legend_loc self.legend_bbox_to_anchor = legend_bbox_to_anchor + def calc_correlation(self, func_1 , func_2 , state = 'False'): - # calulate correlation between two parameter from data frame - corr_coeff= np.corrcoef(func_1, func_2)[0][1] - - annotate_string = "$R_{\phi(S_{21}),Temp_{DUT}}$ = %.3f" % corr_coeff - return annotate_string + if state == True: + + # calulate correlation between two parameter from data frame + corr_coeff= np.corrcoef(func_1, func_2)[0][1] + + annotate_string_corr_coeff = "$R_{\phi(S_{21}),Temp_{DUT}}$ = %.3f" % corr_coeff + + self.postplot.edit_annotation_in_plot(annotate_string_corr_coeff) def calc_regression_coeff_phase_S21(self, data_frame, time_unit = 'min', state = False): - phases = data_frame.S21_PHASE.tolist() - self.phase_t0 = phases[0] - - self.K_phases = np.median(data_frame.S21_PHASE) - - # time stamp of index = 0 is the start point of time axis, Michael - # substract all other timestamps with time stamp of index zero to get time scale in - # seconds, Michael - - time_sec = data_frame.TIMESTAMP - data_frame.TIMESTAMP[0] - - # set scaling of time axis depending on the time unit given in parameter list, Michael - # default unit is minutes, Michael - time_vals = self.scaling_time_axes(time_sec, time_unit) - - func, popt = self.choose_fit(time_vals, data_frame.S21_PHASE) - - annotate_string_fit = self.plot_fitted_func_param(func, *popt, time_unit = time_unit) + if state == True: + phases = data_frame.S21_PHASE.tolist() + self.phase_t0 = phases[0] + + self.K_phases = np.median(data_frame.S21_PHASE) + + # time stamp of index = 0 is the start point of time axis, Michael + # substract all other timestamps with time stamp of index zero to get time scale in + # seconds, Michael + + time_sec = data_frame.TIMESTAMP - data_frame.TIMESTAMP[0] + + # set scaling of time axis depending on the time unit given in parameter list, Michael + # default unit is minutes, Michael + time_vals = self.scaling_time_axes(time_sec, time_unit) + + func, popt = self.choose_fit(time_vals, data_frame.S21_PHASE) + + annotate_string_reg_coeff = self.plot_fitted_func_param(func, *popt, time_unit = time_unit) + + self.postplot.edit_annotation_in_plot(annotate_string_reg_coeff) - return annotate_string_fit - def plot_phase_curve_fit(self, data_frame, postplot_obj, time_unit = 'min', state = False): + + + def plot_phase_curve_fit(self, data_frame, time_unit = 'min', state = False): if state == True: - + phases = data_frame.S21_PHASE.tolist() self.phase_t0 = phases[0] @@ -90,41 +99,18 @@ class reg_and_corr: # determine max of measured phases and max of curvefit maximum = max(max_phases, max_fit_phases) - # set axis for phaseplot to min, max values - postplot_obj.ax1[0].set_ylim(minimum, maximum) - - # set color of trace for curvefit result to green (trace is visible) - postplot_obj.path_collection_fit.set_color('green') - - # set label of trace curvefit results to name of fit function name - postplot_obj.path_collection_fit.set_label('fitted with\n' + func.__name__) - - - - postplot_obj.path_collection_fit.set_offsets(np.c_[time_vals, func(time_vals, *popt)]) + self.postplot.add_curvefit_to_plot(xvals =time_vals, \ + yvals = func(time_vals, *popt), \ + y_lim =[minimum, maximum], \ + trace_color = 'green', \ + trace_label = 'fitted by\n' + func.__name__) else: - # set color of trace for curvefit result to None (trace is invisible) - postplot_obj.path_collection_fit.set_color('None') - # set label of trace curvefit results to '' (no label) - postplot_obj.path_collection_fit.set_label('') - - # get legend handles and labels y-axes from subplot magnitude, phase - handles_phase, labels_phase = postplot_obj.ax1[0].get_legend_handles_labels() - handles_mag, labels_mag = postplot_obj.magnitude_axis.get_legend_handles_labels() - handles_equi0, labels_eqi0 = postplot_obj.equi_axis0.get_legend_handles_labels() - - handles = handles_phase + handles_mag + handles_equi0 - labels = labels_phase + labels_mag + labels_eqi0 - - # update legend subplot phase, magnitude - postplot_obj.ax1[0].legend(handles, labels, loc = postplot_obj.legend_loc, \ - bbox_to_anchor = postplot_obj.legend_bbox_to_anchor) - - # refresh plot window - postplot_obj.fig.canvas.draw() - postplot_obj.fig.canvas.flush_events() - + self.postplot.add_curvefit_to_plot(xvals =[], \ + yvals = [], \ + y_lim = None, \ + trace_color = 'None', \ + trace_label = '') @@ -250,5 +236,95 @@ class reg_and_corr: if distance == 0.: distance = 1 return array.min()-0.05*distance, array.max()+0.05*distance + + +# for manually redo post plot after measurement has finished and insert analysis function, Michael +if __name__ == '__main__': + + + # set result path for post plot + Results_Path = r'C:\git\climate-lab-test-stand\Python_script\TestData_JBY240' + + + # set time unit for post post plot + # default is minutes if entry in parameterlist left empty + # possible entries: 'min' for minutes, 'hours' for hours and 'sec' for seconds + time_unit = 'min' + + # set storepath for the post plots, Michael + storepath = Results_Path + '\\AnalysisPlots' + + # search all csv files in results folder + csv_file_list = list(Path(Results_Path).glob("**/*.csv")) + + # choose annotation option + plot_correlation_coeff = False + plot_regression_coeff = False + + # activate plot curvefitting + + plot_trace_curvefit = True + + trace_selection = "" + + + # create postplot object, Michael + analysisplot_obj = reg_and_corr(env_cond_sensors= trace_selection) + + + # empty data frame for concat the data frames from csv import to plot full transistion + concat_data_frame = pd.DataFrame() + + # plot results for each csv-file + for index, csv_file in enumerate(csv_file_list): + + # import csv-data from csv-files in list, Michael + data_frame = analysisplot_obj.postplot.import_csv(str(csv_file)) + + # determine title of plot from csv-filename, Michael + title = csv_file.name + + # concate datesframe for plotting full transistion data + concat_data_frame = pd.concat([concat_data_frame,data_frame],ignore_index=True, sort = False) + + + # plot frame data + analysisplot_obj.postplot.plot_frame_data(data_frame, title, time_unit) + + + # determine correlation coefficient between func 1 and func 2 and plot coefficient + analysisplot_obj.calc_correlation(func_1 = data_frame.S21_PHASE , \ + func_2 = data_frame.TEMP_DUT, state = plot_correlation_coeff ) + + + + + # start curvefit and determine coefficients best fit function and plot coefficients + analysisplot_obj.calc_regression_coeff_phase_S21(data_frame, time_unit = 'min', \ + state = plot_regression_coeff) + + + analysisplot_obj.plot_phase_curve_fit(data_frame = data_frame, time_unit = time_unit, \ + state = plot_trace_curvefit) + + # set filename of post plot, Michael + filename = str(csv_file.stem) + '.pdf' + + # store post plot under the path taht is set in storepath with the earlier defined filename + analysisplot_obj.postplot.save_fig(storepath, filename) + + + # plot of all steps of a sweep is plotted in one diagram, Michael + # title of this plot will be always full transistion, Michel + analysisplot_obj.postplot.plot_frame_data(concat_data_frame, 'Full Transistion', time_unit) + + analysisplot_obj.plot_phase_curve_fit(data_frame = concat_data_frame, time_unit = time_unit, \ + state = False) + + # filename of plot that contains all steps of sweep is set to FullTransistion, Michael + filename = 'Full_Transistion' + '.pdf' + # plot with the results of all steps is store under the predefined storpath with the + # earlier defined filename, Michael + analysisplot_obj.postplot.save_fig(storepath, filename) \ No newline at end of file diff --git a/Python_script/prototype.py b/Python_script/prototype.py index 453b878e46e906fd19287d1f310ece6b3cd17cdd..731a53ca253190a1d7d82ea16863dadbb4358e30 100755 --- a/Python_script/prototype.py +++ b/Python_script/prototype.py @@ -497,7 +497,7 @@ def plot_output(output_basename, measurements_appendices, show_blocking_plot, co list_of_frames = [] # storepath is set to working directory with subfolder Plots, Michael - storepath = os.path.join(os.getcwd(),'Plots') + storepath = os.path.join(os.getcwd(),'PostPlots') # create objet for PostPlot class in PostPlot module, Michael post_plot = PostPlot.PostPlot(env_cond_sensors = config_data['env_cond_sensors']) for index, m in enumerate(measurements_appendices): diff --git a/Python_script/the.pdf b/Python_script/the.pdf index ac526011e9e8b3ca5fbdf2d09f162a6f08e05130..c18b780e37f189477bd2ee1d08699945553a8e2c 100644 Binary files a/Python_script/the.pdf and b/Python_script/the.pdf differ