import numpy as np
import math as m
import matplotlib.pyplot as plt
import matplotlib.transforms as transforms
import matplotlib.colors as mcolors
import matplotlib.patches as mpatches
from cycler import cycler
from matplotlib.legend_handler import HandlerLine2D, HandlerTuple
import pandas as pd
from decimal import Decimal
from sklearn.linear_model import LinearRegression
import statistics
from pathlib import Path
from numpy.polynomial import Chebyshev, Legendre, Polynomial, Laguerre, Hermite, HermiteE
import os
import cv2
from scipy.optimize import curve_fit

def get_run_names(Log_file):
    Run = []
    file = open(Log_file,'r')
    for line in file:
        if 'Run' in line:
            Run.append(str(line.split()[3]))
    return Run
def get_settings(Settings, Sheet_name):
    Found = False
    for j in range(len(Settings)):
        if Settings.iloc[j, 0] == Sheet_name:
            Found = True
        if Found == True:
            if Settings.iloc[j, 0] == 'Speed':
                Speed = str(Settings.iloc[j, 1])
            if Settings.iloc[j, 0] == 'Sweep Delay':
                Sweep_Delay = str(Settings.iloc[j, 1])
            if Settings.iloc[j, 0] == 'Hold Time':
                Hold_Time = str(Settings.iloc[j, 1])
            if Settings.iloc[j, 0] == 'Last Executed':
                Last_Executed = str(Settings.iloc[j, 1])
            if Settings.iloc[j, 0] == 'Execution Time':
                Execution_Time = str(Settings.iloc[j, 1])
            if Settings.iloc[j, 0] == 'Current Range':
                Current_Range = str(Settings.iloc[j, 1])
            if Settings.iloc[j, 0] == 'Voltage Range':
                Voltage_Range = str(Settings.iloc[j, 1])
            if Settings.iloc[j, 0] == 'CVU Path':
                Found = False

    Settings_Data = []
    Settings_Data.append('Speed')
    Settings_Data.append(Speed)
    Settings_Data.append('Sweep Delay')
    Settings_Data.append(Sweep_Delay)
    Settings_Data.append('Hold Time')
    Settings_Data.append(Hold_Time)
    Settings_Data.append('Last Executed')
    Settings_Data.append(Last_Executed)
    Settings_Data.append('Execution Time')
    Settings_Data.append(Execution_Time)
    Settings_Data.append('Current Range')
    Settings_Data.append(Current_Range)
    Settings_Data.append('Voltage Range')
    Settings_Data.append(Voltage_Range)
    return Settings_Data
def read_LabBook(LabBook):
    Channel_Length = LabBook._get_value(Num_ID, 'Channel_length')
    Channel_Width = LabBook._get_value(Num_ID, 'Channel_width')
    Dielectric_Thickness = LabBook._get_value(Num_ID, 'Dielectric_thickness')
    Dielectric_Constant = LabBook._get_value(Num_ID, 'Dielectric_constant')
    Areal_Capacitance = (Dielectric_Constant * Vacuum_Permittivity_Constant) / Dielectric_Thickness

    print('\n----Current device properties----')
    print('Channel Length: ' + str(Channel_Length))
    print('Channel Width: ' + str(Channel_Width))
    print('Dielectric Thickness: ' + str(Dielectric_Thickness))
    print('Dielectric Costant: ' + str(Dielectric_Constant))
    print('Vacuum Permittivity Costant: ' + str(Vacuum_Permittivity_Constant))
    print('Areal Capacitance: ' + str(Areal_Capacitance))
    print('---------------------------------')

    return Channel_Length, Channel_Width, Dielectric_Thickness, Dielectric_Constant, Areal_Capacitance
def write_to_png(Text):
    fig, ax = plt.subplots(figsize=(7/9,8), dpi=300, edgecolor='black', frameon=True)
    ax.axis('off')
    ax.text(0, 1, Text, transform=ax.transAxes, fontsize=18, verticalalignment='top')
    return fig
def Device_short(Data_File, threshold_ratio, threshold_residual_upper, threshold_residual_lower):
    #This function filters out devices that are not working and considered short.
    print('Checking if Device is short...')

    Short = False

    #The first criteria is the ratio between the gate and the source current, if the ratio is smaller than the defined threshold the device is considered short, because the gate current is too high.
    ratio = max(abs(Data_File[I_Source]))/max(abs(Data_File[I_Gate]))
    if ratio < threshold_ratio:
        Short = True

    print('\tSource/Gate ratio = ' + str(ratio))

    # The second criteria is that the on/off ratio exceeds 2
    if max(abs(Data_File[I_Source]))/min(abs(Data_File[I_Source])) < 2:
        Short = True
    print('\tI_on/off ratio = ' + str(max(abs(Data_File[I_Source]))/min(abs(Data_File[I_Source]))))

    #The third criteria is, that the current should exceed a certain value
    if max(abs(Data_File[I_Source])) < 5*pow(10,-9):
        Short = True
    print('\tmax I = ' + str(max(abs(Data_File[I_Source]))))

    #The fourth criteria is, that the linear transfer plot of a working transistor should be fairly well fitted by a 2nd degree polynom. Therefore r^2 of the fit has to be inside a defined range for the device to be considered working.
    #Polynomial fit
    I_DS_forward = []
    V_GS_forward = []
    for i in range(0, int(len(Data_File[I_Source])/2)):
        I_DS_forward.append(Data_File._get_value(i,I_Source))
        V_GS_forward.append(Data_File._get_value(i,V_Gate))

    poly_coefficients, residuals= Chebyshev.fit(V_GS_forward, I_DS_forward, deg=2, full=True)
    if float(residuals[0][0]) >= threshold_residual_upper or float(residuals[0][0]) <= threshold_residual_lower:
        Short = True
    print('\tPolyfit residual = ' + str(float(residuals[0][0])))

    if Short:
        print('\t--> Device is short')
    if not Short:
        print('\t--> Device is not short')


    '''fig, ax = plt.subplots(dpi=300, edgecolor='black', frameon=True)
    p1, = ax.plot(Data_File['V_Gate'], Data_File['I_Source'], color='blue')
    p2, = ax.plot(Data_File['V_Gate'], poly_coefficients(Data_File['V_Gate']), color='red')'''

    return Short #, fig
def linear_fit(x_data,y_data,I_threshold, fitting_intercept):
    #Define the x intervall, in which the data should be fitted
    x_range = []
    y_range = []
    for i in range(len(x_data)):
        if abs(y_data[i]) >= I_threshold:
            x_range.append(x_data[i])
            y_range.append(y_data[i])

    # Linear regression
    x = np.array(x_range).reshape(-1, 1)
    y = np.array(y_range)

    model = LinearRegression(fit_intercept=fitting_intercept).fit(x,y)

    fit_range = [max(x_range), min(x_range)]

    return model.coef_, model.intercept_, model.score(x,y), fit_range
def quadratic_function(x,a):
    return a*x**2
def cut_off_noise(I_forward, V_forward, I_backward, V_backward):
    diff_forward = []
    diff_backward = []
    Upper_Bound_forward = 0
    Upper_Bound_backward = 0
    for i in range(len(V_forward)-1):
        diff_forward.append(I_forward[i+1] - I_forward[i])
    for i in range(len(V_backward)-1):
        diff_backward.append(I_backward[i+1] - I_backward[i])

    n = 5
    for i in range(n, len(diff_forward)):
        if all(diff_forward[i - n:i + n][j] > 0 for j in range(len(diff_forward[i - n:i + n]))) and abs(I_forward[i]) >= pow(10, -9) or all(diff_forward[i - n:i + n][j] < 0 for j in range(len(diff_forward[i - n:i + n]))) and abs(I_forward[i]) >= pow(10, -9):
            if i > 150:
                Upper_Bound_forward = i-150
            if i <= 150:
                Upper_Bound_forward = 0
            break
    for i in range(n, len(diff_backward)):
        if all(diff_backward[i - n:i + n][j] > 0 for j in range(len(diff_backward[i - n:i + n]))) and abs(I_backward[i]) >= 5*pow(10, -9) or all(diff_backward[i - n:i + n][j] < 0 for j in range(len(diff_backward[i - n:i + n]))) and abs(I_backward[i]) >= pow(10, -9):
            if i > 150:
                Upper_Bound_backward = i-150
            if i <= 150:
                Upper_Bound_backward = 0
            break

    return Upper_Bound_forward, Upper_Bound_backward
def calculate_SS(V_GS_forward_fit, V_GS_backward_fit, c_forward, c_backward):
    log_c_forward = []
    log_c_backward = []

    for i in range(len(V_GS_forward_fit)):
            log_c_forward.append(m.log(abs(c_forward(V_GS_forward_fit[i])), 10))
    for i in range(len(V_GS_backward_fit)):
            log_c_backward.append(m.log(abs(c_backward(V_GS_backward_fit[i])), 10))

    diff_log_c_forward = []
    diff_log_c_backward = []

    for i in range(len(V_GS_forward_fit) - 1):
        diff_log_c_forward.append((log_c_forward[i+1] - log_c_forward[i])/(V_GS_forward_fit[i+1] - V_GS_forward_fit[i]))
    for i in range(len(V_GS_backward_fit) - 1):
        diff_log_c_backward.append((log_c_backward[i+1] - log_c_backward[i])/(V_GS_backward_fit[i+1] - V_GS_backward_fit[i]))

    n = 4
    diff_log_median_forward = [0] * n
    diff_log_median_backward = [0] * n

    for i in range (n,len(diff_log_c_forward)):
        diff_log_median_forward.append(abs(sum(diff_log_c_forward[i - n:i + n])/(len(diff_log_c_forward[i - n:i + n]))))
    for i in range(n, len(diff_log_c_backward)):
        diff_log_median_backward.append(abs(sum(diff_log_c_backward[i - n:i + n])/(len(diff_log_c_backward[i - n:i + n]))))

    max_slope_forward = -1*max(diff_log_median_forward)
    SS_forward = -1 / max_slope_forward
    V_GS_point_of_max_slope_forward = V_GS_forward_fit[np.argmax(diff_log_median_forward)]
    b_forward = log_c_forward[np.argmax(diff_log_median_forward)]-(max_slope_forward * V_GS_point_of_max_slope_forward)

    max_slope_backward = -1*max(diff_log_median_backward)
    SS_backward = -1 / max_slope_backward
    V_GS_point_of_max_slope_backward = V_GS_backward_fit[np.argmax(diff_log_median_backward)]
    b_backward = log_c_backward[np.argmax(diff_log_median_backward)] - (max_slope_backward * V_GS_point_of_max_slope_backward)

    return max_slope_forward, SS_forward, V_GS_point_of_max_slope_forward, b_forward, max_slope_backward, SS_backward, V_GS_point_of_max_slope_backward, b_backward
def Output_plot_legend(Exceldata_Sheet, ax, j, n_Step, p1, p2):
    Legend_Ends = True
    if j == 0 or j == int(int(len(Exceldata_Sheet.columns) / n_Variables) - 1):
        leg = ax.legend([(p1, p2)], [str('$V_{GS}$:' + str('%.0f' % Exceldata_Sheet._get_value(1, str(V_Gate + n_Step))).rjust(3) + ' V').rjust(10)],numpoints=1, handler_map={tuple: HandlerTuple(ndivide=None)},bbox_to_anchor=((0.7), (0.15 + (j * 0.03))), loc='upper left', frameon=False)
        Legend_Ends = False
    if j == int((int(len(Exceldata_Sheet.columns) / 5) - 1) / 2):
        leg = ax.legend([(p1, p2)], [str('+' + str('%.0f' % abs(Exceldata_Sheet._get_value(1, str(V_Gate + '(1)')) - Exceldata_Sheet._get_value(1,str(V_Gate + '(2)'))) + ' V')).rjust(7)],numpoints=1, handler_map={tuple: HandlerTuple(ndivide=None)},bbox_to_anchor=((0.7), (0.15 + (j * 0.03))), loc='upper left', frameon=False)
        Legend_Ends = False
    if Legend_Ends:
        leg = ax.legend([(p1, p2)], [str('').rjust(10)], numpoints=1, handler_map={tuple: HandlerTuple(ndivide=None)},bbox_to_anchor=((0.7), (0.15 + (j * 0.03))), loc='upper left', frameon=False)
    ax.add_artist(leg)
    return
def plot_output_gate_cleaned(Exceldata_Sheet, Settings_Data, Run_Name, Short, n_Variables, Text):
    I_pinch_off = []
    V_pinch_off = []
    min_I_DS_gate_cleaned = 0

    fig, ax = plt.subplots(figsize=(7, 5), dpi=300, edgecolor='black', frameon=True)
    ax2 = ax.twinx()
    ax3 = ax.twinx()
    for j in range(int(len(Exceldata_Sheet.columns) / n_Variables)):
        n_Step = str('(' + str(j + 1) + ')')
        I_DS_gate_cleaned = []
        for i in range(len(Exceldata_Sheet[str(I_Source + n_Step)])):
            I_DS_gate_cleaned.append(Exceldata_Sheet._get_value(i,str(I_Source + n_Step)) + Exceldata_Sheet._get_value(i,str(I_Gate + n_Step)))

        p1, = ax.plot(Exceldata_Sheet[str(V_Source + '(1)')], I_DS_gate_cleaned,color=str(color_tableau[j]))
        p2, = ax2.plot(Exceldata_Sheet[str(V_Source + '(1)')], Exceldata_Sheet[str(I_Gate + n_Step)], '--',color=str(color_tableau[j]), alpha=0.3)

        Output_plot_legend(Exceldata_Sheet, ax, j, n_Step, p1, p2)

        if not Short:
            #Linear fit the output curves to get the pinch off point and determine the linear region. Only the forward scan is fitted
            I_DS_fit = []
            V_DS_fit = []
            for i in range(int(len(Exceldata_Sheet[str(V_Source + '(1)')]) / 2)):
                I_DS_fit.append(I_DS_gate_cleaned[i])
                V_DS_fit.append(Exceldata_Sheet._get_value(i, str(V_Source + n_Step)))
                if i >= 3:
                    Slope,  Intercept, R_sq, fit_range = linear_fit(V_DS_fit, I_DS_fit, 0, fitting_intercept=False)
                    if R_sq < 0.98 and abs(Slope[0]) >= 1*pow(10,-7):
                        I_pinch_off.append(I_DS_fit[i])
                        V_pinch_off.append(V_DS_fit[i])
                        break
                    if R_sq >= 0.98 and abs(Slope[0]) >= 1*pow(10,-7) and i == int(len(Exceldata_Sheet[str(V_Source + '(1)')])/2-1) :
                        I_pinch_off.append(I_DS_fit[i])
                        V_pinch_off.append(V_DS_fit[i])

            '''x_forward = np.linspace(min(V_DS_fit), max(V_DS_fit))
            y_forward = Slope[0] * x_forward + Intercept
            p3, = ax.plot(x_forward, y_forward, color='limegreen', alpha=0.8)'''

        #Get minimal current overall for coloring the plot in the next step.
        if min(I_DS_gate_cleaned) <= min_I_DS_gate_cleaned:
            min_I_DS_gate_cleaned = min(I_DS_gate_cleaned)

    if not Short:
        #Calculate the border between saturation and linear regime as fit of 2nd degree and color the plot accordingly.
        regime_border, _ = curve_fit(quadratic_function, V_pinch_off, I_pinch_off)
        x = np.linspace(min(Exceldata_Sheet[str(V_Source + '(1)')])-10,max(Exceldata_Sheet[str(V_Source + '(1)')])+10)
        ax3.fill_between(x,quadratic_function(x, *regime_border), 1, color='blue', alpha=0.1 )
        ax3.fill_between(x, quadratic_function(x, *regime_border), ax.get_ylim()[0], color='red', alpha=0.1)
        ax3.set_ylim(ax.get_ylim()[0],ax.get_ylim()[1])
        ax3.set_xlim(min(Exceldata_Sheet[str(V_Source + '(1)')])-1, max(Exceldata_Sheet[str(V_Source + '(1)')]))
        ax3.axis('off')
        print('\tFound border between linear and saturation regime')

        V_th_output_list = []
        #Start a second loop over all output curves, because we need to calculate the cross points of the curves with the regime border to get the threshold voltage
        for j in range(int(len(Exceldata_Sheet.columns) / n_Variables)):
            n_Step = str('(' + str(j + 1) + ')')
            I_DS_gate_cleaned2 = []
            V_DS_forward = []
            for i in range(int(len(Exceldata_Sheet[str(V_Source + '(1)')])/2)):
                I_DS_gate_cleaned2.append(Exceldata_Sheet._get_value(i,str(I_Source + n_Step)) + Exceldata_Sheet._get_value(i,str(I_Gate + n_Step)))
                V_DS_forward.append(Exceldata_Sheet._get_value(i,str(V_Source + '(1)')))

            C_output_forward = Chebyshev.fit(V_DS_forward, I_DS_gate_cleaned2, deg=20)

            #p6, = ax.plot(V_DS_forward, C_output_forward(V_DS_forward), color='orange', alpha= 1)
            diff_fit_border = []
            for i in range(1,len(V_DS_forward)):
                diff_fit_border.append(C_output_forward(V_DS_forward[i]) - quadratic_function(V_DS_forward[i], *regime_border))
                if i > 2 and np.sign(diff_fit_border[i-1]) != np.sign(diff_fit_border[i-2]) and abs(C_output_forward(V_DS_forward[i])) >= abs(I_pinch_off[0]/100) and V_DS_forward[i] > min(V_DS_forward)+3:
                    V_th_output_list.append(Exceldata_Sheet._get_value(1,str(V_Gate + n_Step)) - V_DS_forward[i])

        V_th_output = np.mean(V_th_output_list)

    if Short:
        V_th_output = 0

    if Text:
        ax.set_title(Run_Name, loc='center')
    ax.set_ylabel('$I_{DS}$ $[A]$')
    ax2.set_ylabel('$I_{GS}$ $[A]$')
    ax.ticklabel_format(style='sci', axis='y', scilimits=(0, 0), useMathText=True)
    ax2.ticklabel_format(style='sci', axis='y', scilimits=(0, 0), useMathText=True)
    ax.set_xlabel('$V_{DS}$ $[V]$')
    arrow = mpatches.FancyArrowPatch((0.82, 0.115), (0.82, (0.1 + int(len(Exceldata_Sheet.columns) / 5) * 0.021)), arrowstyle='->', mutation_scale=10, transform=ax.transAxes)
    ax.add_patch(arrow)

    #Write the measurement settings next to the plot
    if Text:
        Settings_text = ''
        for j in range(0,len(Settings_Data),2):
            Settings_text = str(Settings_text + Settings_Data[j] + ': ' + Settings_Data[j+1] + '\n')
        ax.text(1.2, 1, Settings_text, transform=ax.transAxes, fontsize=12, verticalalignment='top')

    return fig, V_th_output
def plot_output(Exceldata_Sheet, Settings_Data, Run_Name, Short, n_Variables, Text):
    fig, ax = plt.subplots(figsize=(7, 5), dpi=300, edgecolor='black', frameon=True)
    ax2 = ax.twinx()
    for j in range(int(len(Exceldata_Sheet.columns) / n_Variables)):
        n_Step = str('(' + str(j + 1) + ')')
        p1, = ax.plot(Exceldata_Sheet[str(V_Source + '(1)')], Exceldata_Sheet[str(I_Source + n_Step)],color=str(color_tableau[j]))
        p2, = ax2.plot(Exceldata_Sheet[str(V_Source + '(1)')], Exceldata_Sheet[str(I_Gate + n_Step)], '--',color=str(color_tableau[j]), alpha=0.3)

        Output_plot_legend(Exceldata_Sheet, ax, j, n_Step, p1, p2)

    if Text:
        ax.set_title(Run_Name, loc='center')
    ax.set_ylabel('$I_{DS}$ $[A]$')
    ax2.set_ylabel('$I_{GS}$ $[A]$')
    ax.ticklabel_format(style='sci', axis='y', scilimits=(0, 0), useMathText=True)
    ax2.ticklabel_format(style='sci', axis='y', scilimits=(0, 0), useMathText=True)
    ax.set_xlabel('$V_{DS}$ $[V]$')
    arrow = mpatches.FancyArrowPatch((0.82, 0.115), (0.82, (0.1 + int(len(Exceldata_Sheet.columns) / 5) * 0.021)), arrowstyle='->', mutation_scale=10, transform=ax.transAxes)
    ax.add_patch(arrow)

    #Write the measurement settings next to the plot
    if Text:
        Settings_text = ''
        for j in range(0,len(Settings_Data),2):
            Settings_text = str(Settings_text + Settings_Data[j] + ': ' + Settings_Data[j+1] + '\n')
        ax.text(1.2, 1, Settings_text, transform=ax.transAxes, fontsize=12, verticalalignment='top')

    return fig
def plot_transfer_lin_scale(Exceldata_Sheet, Settings_Data, Run_Name, Short, V_th_output , Text, CG):
    mu_lin_forward = 0
    mu_lin_backward = 0
    V_th_lin_forward = 0
    V_th_lin_backward = 0

    I_DS_forward = []
    I_DS_backward = []
    V_GS_forward = []
    V_GS_backward = []
    I_GS_forward = []
    I_GS_backward = []
    for i in range(0, int(len(Exceldata_Sheet[I_Source]) / 2)):
        if not CG:
            I_DS_forward.append(Exceldata_Sheet._get_value(i, I_Source))
        if CG:
            I_DS_forward.append(Exceldata_Sheet._get_value(i, I_Source) + Exceldata_Sheet._get_value(i,I_Gate))
        V_GS_forward.append(Exceldata_Sheet._get_value(i, V_Gate))
        I_GS_forward.append(Exceldata_Sheet._get_value(i,I_Gate))

    for i in range(len(Exceldata_Sheet[I_Source])-1, int((len(Exceldata_Sheet[I_Source]) / 2)-1), -1):
        if not CG:
            I_DS_backward.append(Exceldata_Sheet._get_value(i, I_Source))
        if CG:
            I_DS_backward.append(Exceldata_Sheet._get_value(i, I_Source) + Exceldata_Sheet._get_value(i,I_Gate))
        V_GS_backward.append(Exceldata_Sheet._get_value(i, V_Gate))
        I_GS_backward.append(Exceldata_Sheet._get_value(i, I_Gate))

    fig, ax = plt.subplots(figsize=(7, 5), dpi=300, edgecolor='black', frameon=True)
    ax2 = ax.twinx()
    ax3 = ax.twinx()
    p1, = ax.plot(V_GS_forward, I_DS_forward, color=str(color_names[119 + 3]))
    p2, = ax2.plot(V_GS_forward, I_GS_forward, color=str(color_names[18 + 3]), alpha=0.3)
    p3, = ax.plot(V_GS_backward, I_DS_backward, color=str(color_names[119 + 7]))
    p4, = ax2.plot(V_GS_backward, I_GS_backward, color=str(color_names[18 + 7]), alpha=0.3)

    if Text:
        ax.set_title(str(Run_Name), loc='center')
    ax.legend([(p1, p2), (p3, p4)], ['Forward', 'Backward'], numpoints=1,handler_map={tuple: HandlerTuple(ndivide=None)}, bbox_to_anchor=((0.65), (0.4)), loc='upper left',frameon=False)
    ax.set_ylabel('$I_{DS}$ $[A]$', color=str(color_names[119]))
    ax2.set_ylabel('$I_{GS}$ $[A]$', color=str(color_names[18]))
    ax.ticklabel_format(style='sci', axis='y', scilimits=(0, 0), useMathText=True)
    ax2.ticklabel_format(style='sci', axis='y', scilimits=(0, 0), useMathText=True)
    ax.set_xlabel('$V_{GS}$ $[V]$')
    ax.text(0.67, 0.1, str('$V_{DS}$ = ' + str('%.0f' % Exceldata_Sheet._get_value(1,'V_Source')) + ' V'), transform=ax.transAxes)
    ax.hlines(0, min(Exceldata_Sheet[V_Gate]), max(Exceldata_Sheet[V_Gate]), color='black', alpha=0.8)
    ax3.axis('off')

    #Calculate max I_DS and On/Off ratio
    I_DS_forward_abs = []
    I_DS_backward_abs = []
    for i in range (len(I_DS_forward)):
        I_DS_forward_abs.append(abs(I_DS_forward[i]))
        I_DS_backward_abs.append(abs(I_DS_backward[i]))
    max_I_DS_forward = max(I_DS_forward_abs)
    min_I_DS_forward = min(I_DS_forward_abs)
    max_I_DS_backward = max(I_DS_backward_abs)
    min_I_DS_backward = min(I_DS_backward_abs)
    On_off_ratio_forward = max_I_DS_forward / min_I_DS_forward
    On_off_ratio_backward = max_I_DS_backward / min_I_DS_backward

    #Polynomial fit
    c_forward = []
    c_backward = []
    I_DS_forward_fit = []
    I_DS_backward_fit = []
    V_GS_forward_fit = []
    V_GS_backward_fit = []
    n = 5
    if not Short:
        Upper_bound_forward, Upper_bound_backward = cut_off_noise(I_DS_forward, V_GS_forward, I_DS_backward, V_GS_backward)
        for i in range(Upper_bound_forward,len(V_GS_forward)):
            V_GS_forward_fit.append(V_GS_forward[i])
            I_DS_forward_fit.append(I_DS_forward[i])
        for i in range(Upper_bound_backward,len(V_GS_backward)):
            V_GS_backward_fit.append(V_GS_backward[i])
            I_DS_backward_fit.append(I_DS_backward[i])

        c_forward = Chebyshev.fit(V_GS_forward_fit, I_DS_forward_fit, deg=200)
        c_backward = Chebyshev.fit(V_GS_backward_fit, I_DS_backward_fit, deg=200)

        # Cut of the edge of the fit
        if Upper_bound_forward > 0:
            del V_GS_forward_fit[0:150]
        if Upper_bound_backward > 0:
            del V_GS_backward_fit[0:150]

        p5, = ax.plot(V_GS_forward_fit, c_forward(V_GS_forward_fit), color='#005F73', alpha=1)
        p6, = ax.plot(V_GS_backward_fit, c_backward(V_GS_backward_fit), color='#BB3E03', alpha=1)

        #Linear fit in linear regime
        c_forward_lin_regime = []
        V_GS_lin_regime = []
        for i in range(len(V_GS_forward_fit)):
            if V_GS_forward_fit[i] <= float(Exceldata_Sheet._get_value(1, V_Source) + V_th_output):
                c_forward_lin_regime.append(c_forward(V_GS_forward_fit[i]))
                V_GS_lin_regime.append(V_GS_forward_fit[i])

        c_backward_lin_regime = []
        for i in range(len(V_GS_backward_fit)):
            if V_GS_backward_fit[i] <= float(Exceldata_Sheet._get_value(1, V_Source) + V_th_output):
                c_backward_lin_regime.append(c_backward(V_GS_backward_fit[i]))

        if not len(V_GS_lin_regime) == 0:
            Slope_forward_lin_regime, Intercept_forward_lin_regime, R_sq_forward_lin_regime, fit_range_forward_lin_regime = linear_fit(V_GS_lin_regime, c_forward_lin_regime, 0, fitting_intercept=True)
            x_forward_lin_regime = np.linspace(min(V_GS_forward), max(V_GS_forward))
            y_forward_lin_regime = Slope_forward_lin_regime[0] * x_forward_lin_regime + Intercept_forward_lin_regime
            p7, = ax3.plot(x_forward_lin_regime, y_forward_lin_regime, color='#0A9396', alpha=0.8)

            Slope_backward_lin_regime, Intercept_backward_lin_regime, R_sq_backward_lin_regime, fit_range_backward_lin_regime = linear_fit(V_GS_lin_regime, c_backward_lin_regime,0,fitting_intercept=True)
            x_backward_lin_regime = np.linspace(min(V_GS_backward), max(V_GS_backward))
            y_backward_lin_regime = Slope_backward_lin_regime[0] * x_backward_lin_regime + Intercept_backward_lin_regime
            p8, = ax3.plot(x_backward_lin_regime, y_backward_lin_regime, color='#FFA630', alpha=0.8)

            ax.axvspan(min(V_GS_forward), float(Exceldata_Sheet._get_value(1, 'V_Source') + V_th_output),facecolor='red', alpha=0.1)
            ax.legend([(p1, p2), (p3, p4), (p5, p7), (p6,p8)], ['Forward scan', 'Backward scan', 'Fit (forward)', 'Fit (backward)'],numpoints=1, handler_map={tuple: HandlerTuple(ndivide=None)}, bbox_to_anchor=((0.65), (0.4)),loc='upper left', frameon=False)
            ax3.set_ylim(ax.get_ylim())
            ax3.axis('off')

            #Calculate performance parameter
            mu_factor = Channel_Length/(Channel_Width * Areal_Capacitance * Exceldata_Sheet._get_value(1, V_Source))
            mu_lin_forward = abs(mu_factor * Slope_forward_lin_regime[0] *10000)
            mu_lin_backward = abs(mu_factor * Slope_backward_lin_regime[0] *10000)
            V_th_lin_forward = (-1*Intercept_forward_lin_regime) / Slope_forward_lin_regime[0]
            V_th_lin_backward = (-1 * Intercept_backward_lin_regime) / Slope_backward_lin_regime[0]

            if V_th_lin_forward <= max(V_GS_forward):
                ax.vlines(V_th_lin_forward, 0, min(I_DS_forward_fit)*0.5, color='steelblue')
                ax.text(V_th_lin_forward, min(I_DS_forward_fit)*0.5,str('$V_{th}$(forward)\n' + str('%.2f' % V_th_lin_forward) + 'V'), fontsize=8, horizontalalignment='left',verticalalignment='top')
            if V_th_lin_backward <= max(V_GS_forward):
                ax.vlines(V_th_lin_backward, 0, min(I_DS_backward_fit)*0.3, color='steelblue')
                ax.text(V_th_lin_backward, min(I_DS_backward_fit)*0.3,str('$V_{th}$(backward)\n' + str('%.2f' % V_th_lin_backward) + 'V'), fontsize=8,horizontalalignment='left', verticalalignment='top')

    # Write the measurement settings next to the plot
    if Text:
        Settings_text = ''
        for j in range(0, len(Settings_Data), 2):
            Settings_text = str(Settings_text + Settings_Data[j] + ': ' + Settings_Data[j + 1] + '\n')
        ax.text(1.2, 1, Settings_text, transform=ax.transAxes, fontsize=12, verticalalignment='top')

    return fig, c_forward, c_backward, V_GS_forward_fit, V_GS_backward_fit, mu_lin_forward, V_th_lin_forward, mu_lin_backward, V_th_lin_backward, max_I_DS_forward, max_I_DS_backward, min_I_DS_forward, min_I_DS_backward, On_off_ratio_forward, On_off_ratio_backward
def plot_transfer_log_scale(Exceldata_Sheet, Settings_Data, Run_Name, c_forward, c_backward, V_GS_forward_fit, V_GS_backward_fit, Short, Text, CG):

    I_DS_forward_abs = []
    I_DS_backward_abs = []
    V_GS_forward = []
    V_GS_backward = []
    I_GS_forward_abs = []
    I_GS_backward_abs = []
    for i in range(0, int(len(Exceldata_Sheet[I_Source]) / 2)):
        if not CG:
            I_DS_forward_abs.append(abs(Exceldata_Sheet._get_value(i, I_Source)))
        if CG:
            I_DS_forward_abs.append(abs(Exceldata_Sheet._get_value(i, I_Source) + Exceldata_Sheet._get_value(i, I_Gate)))
        V_GS_forward.append(Exceldata_Sheet._get_value(i, V_Gate))
        I_GS_forward_abs.append(abs(Exceldata_Sheet._get_value(i, I_Gate)))

    for i in range(int(len(Exceldata_Sheet[I_Source]) / 2), len(Exceldata_Sheet[I_Source])):
        if not CG:
            I_DS_backward_abs.append(abs(Exceldata_Sheet._get_value(i, I_Source)))
        if CG:
            I_DS_backward_abs.append(abs(Exceldata_Sheet._get_value(i, I_Source) + Exceldata_Sheet._get_value(i, I_Gate)))
        V_GS_backward.append(Exceldata_Sheet._get_value(i, V_Gate))
        I_GS_backward_abs.append(abs(Exceldata_Sheet._get_value(i, I_Gate)))

    fig, ax = plt.subplots(figsize=(7, 5), dpi=300, edgecolor='black', frameon=True)
    ax2 = ax.twinx()
    ax3 = ax.twinx()
    ax3.axis('off')
    p1, = ax.semilogy(V_GS_forward, I_DS_forward_abs, color=str(color_names[119+3]))
    p2, = ax2.semilogy(V_GS_forward, I_GS_forward_abs, color=str(color_names[18+3]), alpha=0.3)
    p3, = ax.semilogy(V_GS_backward, I_DS_backward_abs, color=str(color_names[119 + 7]))
    p4, = ax2.semilogy(V_GS_backward, I_GS_backward_abs, color=str(color_names[18 + 7]), alpha=0.3)

    ax.legend([(p1, p2), (p3, p4)], ['Forward', 'Backward'], numpoints=1,handler_map={tuple: HandlerTuple(ndivide=None)}, bbox_to_anchor=((0), (0.4)), loc='upper left',frameon=False)

    if not Short:
        #Plot the fit function
        p5, = ax.semilogy(V_GS_forward_fit, abs(c_forward(V_GS_forward_fit)), color='#005F73', alpha=1)
        p6, = ax.semilogy(V_GS_backward_fit, abs(c_backward(V_GS_backward_fit)), color='#BB3E03', alpha=1)
        ax.legend([(p1, p2), (p3, p4), p5, p6], ['Forward scan', 'Backward scan', 'Fit (forward)', 'Fit (backward)'],numpoints=1, handler_map={tuple: HandlerTuple(ndivide=None)}, bbox_to_anchor=((0), (0.4)),loc='upper left', frameon=False)

        #Calculate and plot the subthreshold swing
        max_slope_forward, SS_forward, V_GS_max_slope_forward, b_forward, max_slope_backward, SS_backward, V_GS_max_slope_backward, b_backward = calculate_SS(V_GS_forward_fit, V_GS_backward_fit, c_forward, c_backward)
        x = np.linspace(min(V_GS_forward), max(V_GS_forward))
        y = max_slope_forward * x + b_forward
        p7, = ax3.plot(x, y, color='#0A9396', alpha=0.7)
        y1 = max_slope_backward * x + b_backward
        p8, = ax3.plot(x, y1, color='#FFA630', alpha=0.7)
        ax3.set_ylim(m.log(ax.get_ylim()[0], 10), m.log(ax.get_ylim()[1], 10))
        ax3.axis('off')

        ax.legend([(p1, p2), (p3, p4), (p5, p7), (p6, p8)], ['Forward scan', 'Backward scan', 'Fit (forward)', 'Fit (backward)'],numpoints=1, handler_map={tuple: HandlerTuple(ndivide=None)}, bbox_to_anchor=((0), (0.4)),loc='upper left', frameon=False)

    if Short:
        SS_forward = 0
        SS_backward = 0

    if Text:
        ax.set_title(str(Run_Name + '_log'), loc='center')
    ax.set_ylabel('$I_{DS}$ $[A]$', color=str(color_names[119]))
    ax2.set_ylabel('$I_{GS}$ $[A]$', color=str(color_names[18]))
    ax.set_xlabel('$V_{GS}$ $[V]$')
    ax.text(0.02, 0.1, str('$V_{DS}$ = ' + str('%.0f' % Exceldata_Sheet._get_value(1,V_Source)) + ' V'), transform=ax.transAxes)

    # Write the measurement settings next to the plot
    if Text:
        Settings_text = ''
        for j in range(0, len(Settings_Data), 2):
            Settings_text = str(Settings_text + Settings_Data[j] + ': ' + Settings_Data[j + 1] + '\n')
        ax.text(1.2, 1, Settings_text, transform=ax.transAxes, fontsize=12, verticalalignment='top')

    return fig, SS_forward, SS_backward
def plot_sqrt_I_Source(Exceldata_Sheet, Settings_Data, Run_Name, c_forward, c_backward,  V_GS_forward_fit, V_GS_backward_fit, V_th_output, Short, Text, CG):
    V_th_forward = 0
    V_th_backward = 0
    mu_sat_forward = 0
    mu_sat_backward = 0

    sqrt_I_DS_forward_abs = []
    sqrt_I_DS_backward_abs = []
    V_GS_forward = []
    V_GS_backward = []
    for i in range(0, int(len(Exceldata_Sheet[I_Source]) / 2)):
        if not CG:
            sqrt_I_DS_forward_abs.append(pow(abs(Exceldata_Sheet._get_value(i, I_Source)),0.5))
        if CG:
            sqrt_I_DS_forward_abs.append(pow(abs(Exceldata_Sheet._get_value(i, I_Source) + Exceldata_Sheet._get_value(i, I_Gate)), 0.5))
        V_GS_forward.append(Exceldata_Sheet._get_value(i, V_Gate))

    for i in range(len(Exceldata_Sheet[I_Source])-1, int((len(Exceldata_Sheet[I_Source]) / 2)-1), -1):
        if not CG:
            sqrt_I_DS_backward_abs.append(pow(abs(Exceldata_Sheet._get_value(i, I_Source)), 0.5))
        if CG:
            sqrt_I_DS_backward_abs.append(pow(abs(Exceldata_Sheet._get_value(i, I_Source) + Exceldata_Sheet._get_value(i, I_Gate)), 0.5))
        V_GS_backward.append(Exceldata_Sheet._get_value(i, V_Gate))

    fig, ax = plt.subplots(figsize=(7, 5),dpi=300, edgecolor='black', frameon=True)
    p1, = ax.plot(V_GS_forward, sqrt_I_DS_forward_abs, color=str(color_names[119+3]))
    p2, = ax.plot(V_GS_backward, sqrt_I_DS_backward_abs, color=str(color_names[119+7]))
    ax.legend([p1, p2], ['Forward scan', 'Backward scan'], numpoints=1,handler_map={tuple: HandlerTuple(ndivide=None)}, bbox_to_anchor=((0), (0.4)), loc='upper left',frameon=False)

    #Linear fit
    if not Short:
        I_threshold = 0 #Define a threshold current which has to be overcome by a value, to be considered trully measured
        C_forward_sat_sqrt = []
        C_backward_sat_sqrt = []
        V_GS_sat_regime_forward = []
        V_GS_sat_regime_backward = []
        Found_upper_forward = False
        Found_upper_backward = False
        n = 10

        for i in range(10,len(V_GS_forward_fit)-10):
            I_DS_upper_bound_forward = []
            V_GS_upper_bound_forward = V_GS_forward_fit[i-n:i+n]
            for j in range(2*n):
                I_DS_upper_bound_forward.append(pow(abs(c_forward(V_GS_forward_fit[i-n+j])),0.5))
            if not Found_upper_forward:
                Slope_upper_bound, Intercept_upper_bound, R_sq_upper_bound, fit_range_upper_bound = linear_fit(V_GS_upper_bound_forward, I_DS_upper_bound_forward, 0, fitting_intercept=True)
                if abs(Slope_upper_bound[0]/max(sqrt_I_DS_forward_abs)) > 0.004:
                    Found_upper_forward = True
            if Found_upper_forward and V_GS_forward_fit[i] >= float(Exceldata_Sheet._get_value(1, V_Source) + V_th_output):
                    C_forward_sat_sqrt.append(pow(abs(c_forward(V_GS_forward_fit[i])),0.5))
                    V_GS_sat_regime_forward.append(V_GS_forward_fit[i])

        for i in range(10,len(V_GS_backward_fit)-10):
            I_DS_upper_bound_backward = []
            V_GS_upper_bound_backward = V_GS_backward_fit[i - n:i + n]
            for j in range(2 * n):
                I_DS_upper_bound_backward.append(pow(abs(c_backward(V_GS_backward_fit[i - n + j])), 0.5))
            if not Found_upper_backward:
                Slope_upper_bound, Intercept_upper_bound, R_sq_upper_bound, fit_range_upper_bound = linear_fit(V_GS_upper_bound_backward, I_DS_upper_bound_backward, 0, fitting_intercept=True)
                if abs(Slope_upper_bound[0] / max(sqrt_I_DS_forward_abs)) > 0.004:
                    Found_upper_backward = True
            if Found_upper_backward and V_GS_backward_fit[i] >= float(Exceldata_Sheet._get_value(1, V_Source) + V_th_output):
                C_backward_sat_sqrt.append(pow(abs(c_backward(V_GS_backward_fit[i])), 0.5))
                V_GS_sat_regime_backward.append(V_GS_backward_fit[i])

        if not len(V_GS_sat_regime_forward) == 0:
            Slope_forward, Intercept_forward, R_sq_forward, fit_range_forward = linear_fit(V_GS_sat_regime_forward, C_forward_sat_sqrt, I_threshold, fitting_intercept=True)
            x_forward = np.linspace(min(V_GS_forward),max(V_GS_forward))
            y_forward = Slope_forward[0] * x_forward + Intercept_forward
            p3, = ax.plot(x_forward, y_forward, color='#0A9396', alpha=0.8)  # Plot the linear fit
            p4, = ax.plot(V_GS_sat_regime_forward,C_forward_sat_sqrt, color='#005F73')
            ax.axvspan(min(fit_range_forward), max(fit_range_forward), facecolor='blue',alpha=0.05)  # Color the background in the range of the linear plot
            ax.hlines(0,min(Exceldata_Sheet[V_Gate]), max(Exceldata_Sheet[V_Gate]), color='black', alpha=0.8)  # Plot 0 line

            #Calculation of key parameters
            V_th_forward = (-1*Intercept_forward)/Slope_forward[0] #Threshold Voltage
            if V_th_forward < max(V_GS_forward):
                ax.vlines(V_th_forward,0, statistics.median(C_forward_sat_sqrt),color='steelblue')
                ax.text(V_th_forward,statistics.median(C_forward_sat_sqrt),str('$V_{th}$(forward)\n' + str('%.2f' %V_th_forward) + 'V'), fontsize=8, horizontalalignment='left' ,verticalalignment='bottom')

        if not len(V_GS_sat_regime_backward) == 0:
            Slope_backward, Intercept_backward, R_sq_backward, fit_range_backward = linear_fit(V_GS_sat_regime_backward,C_backward_sat_sqrt,I_threshold,fitting_intercept=True)
            x_backward = np.linspace(min(V_GS_backward), max(V_GS_backward))
            y_backward = Slope_backward[0] * x_backward + Intercept_backward
            p5, = ax.plot(x_backward, y_backward, color='#FFA630', alpha=0.8)  # Plot the linear fit
            p6, = ax.plot(V_GS_sat_regime_backward, C_backward_sat_sqrt, color='#BB3e03')
            ax.axvspan(min(fit_range_backward), max(fit_range_backward), facecolor='blue', alpha=0.05)
            ax.legend([p1, p2, (p4, p3), (p6, p5)],['Forward scan', 'Backward scan', 'Fit (forward)', 'Fit (backward)'], numpoints=1,handler_map={tuple: HandlerTuple(ndivide=None)}, bbox_to_anchor=((0), (0.4)), loc='upper left',frameon=False)

            # Calculation of key parameters
            V_th_backward = (-1 * Intercept_backward) / Slope_backward[0]  # Threshold Voltage
            if V_th_backward < max(V_GS_forward):
                ax.vlines(V_th_backward, 0, statistics.median(C_backward_sat_sqrt)*1.5, color='steelblue')
                ax.text(V_th_backward, statistics.median(C_backward_sat_sqrt)*1.5,str('$V_{th}$(backward)\n' + str('%.2f' % V_th_backward) + 'V'), fontsize=8,horizontalalignment='left', verticalalignment='bottom')

            mu_sat_forward = ((2*Channel_Length)/(Channel_Width*Areal_Capacitance))*pow(Slope_forward[0],2)*10000
            mu_sat_backward = ((2*Channel_Length)/(Channel_Width*Areal_Capacitance))*pow(Slope_backward[0],2)*10000

        # Write the measurement settings next to the plot
        '''if Text:
            Settings_Data.append('Linear fit')
            Settings_Data.append(str('%.2E' % Decimal(str(Slope_forward[0])) + 'x + ' + '%.2E' % Decimal(str(Intercept_forward))))
            Settings_Data.append('$R^{2}$')
            Settings_Data.append('%.2E' % Decimal(str(R_sq_forward)))
            Settings_Data.append('$V_{th}$ (sqrt)')
            Settings_Data.append(str('%.2f' % V_th_forward + ' V'))
            Settings_Data.append('$\\mu_{sat}$ (sqrt)')
            Settings_Data.append(str('%.2f' % mu_sat_forward + ' $\\frac{cm^{2}}{Vs}$'))'''

    if Text:
        ax.set_title(str(Run_Name + '_sqrt'), loc='center')
    ax.tick_params(labelright=True)
    ax.ticklabel_format(style='sci', axis='y', scilimits=(0, 0), useMathText=True)
    ax.set_ylabel('$\\sqrt{|I_{DS}|}$ $[\\sqrt{A}]$', color=str(color_names[119]))
    ax.set_xlabel('$V_{GS}$ $[V]$')
    ax.set_ylim(bottom=-0.0001)
    ax.text(0.02, 0.1, str('$V_{DS}$ = ' + str('%.0f' % Exceldata_Sheet._get_value(1, 'V_Source')) + ' V'),transform=ax.transAxes)


    if Text:
        Settings_text = ''
        for j in range(0, len(Settings_Data), 2):
            Settings_text = str(Settings_text + Settings_Data[j] + ': ' + Settings_Data[j + 1] + '\n')
        ax.text(1.2, 1, Settings_text, transform=ax.transAxes, fontsize=12, verticalalignment='top')

    return fig, V_th_forward, V_th_backward, mu_sat_forward, mu_sat_backward
def calculate_perf_parameters_transfer(Exceldata_Sheet, c_forward, c_backward, V_GS_forward_fit, V_GS_backward_fit):
    I_DS_forward = []
    I_DS_backward = []
    V_GS_forward = []
    V_GS_backward = []
    I_GS_forward = []
    I_GS_backward = []
    I_DS_forward_abs = []
    I_DS_backward_abs = []
    I_DS_forward_CG = []
    I_DS_backward_CG = []

    for i in range(0, int(len(Exceldata_Sheet[I_Source]) / 2)):
        I_DS_forward.append(Exceldata_Sheet._get_value(i, I_Source))
        I_DS_forward_abs.append(abs(Exceldata_Sheet._get_value(i, I_Source)))
        I_DS_forward_CG.append(Exceldata_Sheet._get_value(i, I_Source) + Exceldata_Sheet._get_value(i, I_Gate))
        V_GS_forward.append(Exceldata_Sheet._get_value(i, V_Gate))
        I_GS_forward.append(Exceldata_Sheet._get_value(i, I_Gate))

    for i in range(int(len(Exceldata_Sheet[I_Source]) / 2), len(Exceldata_Sheet[I_Source])):
        I_DS_backward.append(Exceldata_Sheet._get_value(i, I_Source))
        I_DS_backward_abs.append(abs(Exceldata_Sheet._get_value(i, I_Source)))
        I_DS_backward_CG.append(Exceldata_Sheet._get_value(i, I_Source) + Exceldata_Sheet._get_value(i, I_Gate))
        V_GS_backward.append(Exceldata_Sheet._get_value(i, V_Gate))
        I_GS_backward.append(Exceldata_Sheet._get_value(i, I_Gate))

    max_I_DS_forward = max(I_DS_forward_abs)
    min_I_DS_forward = min(I_DS_forward_abs)
    max_I_DS_backward = max(I_DS_backward_abs)
    min_I_DS_backward = min(I_DS_backward_abs)
    max_I_GS_forward = max(I_GS_forward)
    min_I_GS_forward = min(I_GS_forward)
    max_I_GS_backward = max(I_GS_backward)
    min_I_GS_backward = min(I_GS_backward)
    On_off_ratio_forward = max_I_DS_forward/min_I_DS_forward
    On_off_ratio_backward = max_I_DS_backward/min_I_DS_backward

    max_slope_forward, SS_forward, V_GS_max_slope_forward, b_forward, max_slope_backward, SS_backward, V_GS_max_slope_backward, b_backward = calculate_SS(V_GS_forward_fit, V_GS_backward_fit, c_forward, c_backward)

    n1 = 15
    n2 =20

    Performance_parameters = str(str('Performance parameters for B' + str(Batch_Number) + '_' + str(Run_Name)).center(57) + '\n' + str('-').center(57,'-') + '\n' + str(' ').center(17) + str('Forward').center(20) + '|' + str('Backward').center(20) + '\n' + str('-').center(57,'-') + '\n')
    Performance_parameters = str(Performance_parameters + str('V_th (output)').ljust(n1) + '= ' + str('%.2f' % V_th_output + ' V').center(n2) + '|' + str(' ').center(n2) + '\n')
    Performance_parameters = str(Performance_parameters + str(' ').ljust(n1) + '= ' + str(' ').center(n2) + '|' + str(' ').center(n2) + '\n')
    Performance_parameters = str(Performance_parameters + str('max I_DS').ljust(n1) + '= ' + str('%.2E' % Decimal(max_I_DS_forward) + ' A').center(n2) + '|' + str('%.2E' % Decimal(max_I_DS_backward) + ' A').center(n2) + '\n')
    Performance_parameters = str(Performance_parameters + str('min $I_DS').ljust(n1) + '= ' + str('%.2E' % Decimal(min_I_DS_forward) + ' A').center(n2) + '|' + str('%.2E' % Decimal(min_I_DS_backward) + ' A').center(n2) + '\n')
    Performance_parameters = str(Performance_parameters + str('I_on/off').ljust(n1) + '= ' + str('%.2E' % Decimal(On_off_ratio_forward)).center(n2) + '|' + str('%.2E' % Decimal(On_off_ratio_backward)).center(n2) + '\n')
    Performance_parameters = str(Performance_parameters + str('SubS').ljust(n1) + '= ' + str('%.2f' % SS_forward + ' V/dec').center(n2) + '|' + str('%.2f' % SS_backward + ' V/dec').center(n2) + '\n')
    Performance_parameters = str(Performance_parameters + str(' ').ljust(n1) + '= ' + str(' ').center(n2) + '|' + str(' ').center(n2) + '\n')
    Performance_parameters = str(Performance_parameters + str('V_th (sat)').ljust(n1) + '= ' + str('%.2f' %V_th_sat_forward_sqrt + ' V').center(n2) + '|' + str('%.2f' % V_th_sat_backward_sqrt + ' V').center(n2) + '\n')
    Performance_parameters = str(Performance_parameters + str('mu_sat').ljust(n1) + '= ' + str('%.2f' % mu_sat_forward_sqrt + ' cm^2/Vs').center(n2) + '|' + str('%.2f' % mu_sat_backward_sqrt + ' cm^2/Vs').center(n2) + '\n')
    Performance_parameters = str(Performance_parameters + str(' ').ljust(n1) + '= ' + str(' ').center(n2) + '|' + str(' ').center(n2) + '\n')
    Performance_parameters = str(Performance_parameters + str('V_th (lin)').ljust(n1) + '= ' + str('%.2f' % V_th_lin_forward + ' V').center(n2) + '|' + str('%.2f' % V_th_lin_backward + ' V').center(n2) + '\n')
    Performance_parameters = str(Performance_parameters + str('mu_lin').ljust(n1) + '= ' + str('%.2f' % mu_lin_forward + ' cm^2/Vs').center(n2) + '|' + str('%.2f' % mu_lin_backward + ' cm^2/Vs').center(n2) + '\n')

    '''Performance_parameters = str(Performance_parameters + str('SS (CG)').ljust(n1) + '= ' + str('%.2f' % SS_forward_CG + ' V/dec').center(n2) + '|' + str('%.2f' % SS_backward_CG + ' V/dec').center(n2) + '\n')
    Performance_parameters = str(Performance_parameters + str('$V_{th/sat}$ (sqrt,CG)').ljust(n1+6) + '= ' + str('%.2f' % V_th_sat_forward_sqrt_CG + ' V').center(n2) + '|' + str('%.2f' % V_th_sat_backward_sqrt_CG + ' V').center(n2) + '\n')
    Performance_parameters = str(Performance_parameters + str('$\\mu_{sat}$ (sqrt,CG)').ljust(n1+3) + '= ' + str('%.2f' % mu_sat_forward_sqrt_CG + ' $cm^{2}Vs^{-1}$').center(n2+3) + '|' + str('%.2f' % mu_sat_backward_sqrt_CG + ' $cm^{2}Vs^{-1}$').center(n2+3) + '\n')
    Performance_parameters = str(Performance_parameters + str('$V_{th/lin} CG$ ').ljust(n1+6) + '= ' + str('%.2f' % V_th_lin_forward_CG + ' V').center(n2) + '|' + str('%.2f' % V_th_lin_backward_CG + ' V').center(n2) + '\n')
    Performance_parameters = str(Performance_parameters + str('$\\mu_{lin} CG$').ljust(n1+3) + '= ' + str('%.2f' % mu_lin_forward_CG + ' $cm^{2}Vs^{-1}$').center(n2+3) + '|' + str('%.2f' % mu_lin_backward_CG + ' $cm^{2}Vs^{-1}$').center(n2+3) + '\n')'''


    return Performance_parameters
def Plot_overview():
    Output_image = cv2.imread(str(str(Device_Folder) + '/B' + str(Batch_Number) + '_' + str(Run_Name) + '_Output.png'))[...,::-1]

    Output_image_CG = cv2.imread(str(str(Device_Folder) + '/B' + str(Batch_Number) + '_' + str(Run_Name) + '_Output_CG.png'))[..., ::-1]

    Transfer_lin_image = cv2.imread(str(str(Device_Folder) + '/B' + str(Batch_Number) + '_' + str(Run_Name) + '_Transfer_lin_' + str(V_G[k]) + 'V.png'))[...,::-1]

    Transfer_log_image = cv2.imread(str(str(Device_Folder) + '/B' + str(Batch_Number) + '_' + str(Run_Name) + '_Transfer_log_' + str(V_G[k]) + 'V.png'))[...,::-1]

    Transfer_log_image_CG = cv2.imread(str(str(Device_Folder) + '/B' + str(Batch_Number) + '_' + str(Run_Name) + '_Transfer_log_CG_' + str(V_G[k]) + 'V.png'))[..., ::-1]

    Transfer_sqrt_image = cv2.imread(str(str(Device_Folder) + '/B' + str(Batch_Number) + '_' + str(Run_Name) + '_Transfer_sqrt_' + str(V_G[k]) + 'V.png'))[...,::-1]

    Settings_text = str(str('Measurement settings for B' + str(Batch_Number) + '_' + str(Run_Name)).center(57) + '\n' + str('-').center(57,'-') + '\n' + str(' ').center(17) + str('Output').center(20) + '|' + str('Transfer').center(20) + '\n' + str('-').center(57,'-') + '\n')
    for j in range(0, 12, 2):
        Settings_text = str(Settings_text + Settings_Output_Data[j].ljust(15) + ': ' + Settings_Output_Data[j + 1].center(20) + '|' + Settings_Transfer_Data[j + 1].center(20) + '\n')

    Settings_fig = write_to_png(Settings_text)
    Settings_fig.savefig(str(str(Device_Folder) + '/B' + str(Batch_Number) + '_' + str(Run_Name) + '_Measurement_Settings_' + str(V_G[k]) + 'V.png'),bbox_inches='tight')
    Settings_image = cv2.imread(str(str(Device_Folder) + '/B' + str(Batch_Number) + '_' + str(Run_Name) + '_Measurement_Settings_' + str(V_G[k]) + 'V.png'))[..., ::-1]

    if not Short:
        Perf_Parameters = calculate_perf_parameters_transfer(Transfer_Exceldata_Sheet, c_forward, c_backward, V_GS_forward_fit, V_GS_backward_fit)
        Perf_Parameters_fig = write_to_png(Perf_Parameters)
        Perf_Parameters_fig.savefig(str(str(Device_Folder) + '/B' + str(Batch_Number) + '_' + str(Run_Name) + '_Performance_Parameters_' + str(V_G[k]) + 'V.png'),bbox_inches='tight')
        Perf_Parameters_image = cv2.imread(str(str(Device_Folder) + '/B' + str(Batch_Number) + '_' + str(Run_Name) + '_Performance_Parameters_' + str(V_G[k]) + 'V.png'))[..., ::-1]

    fig = plt.figure(figsize=(20, 11), dpi=300)
    rows = 2
    columns = 3
    fig.suptitle(str('B' + str(Batch_Number) + '_' + str(Run_Name) + str('').center(5) + 'V_GS = -' + str(V_G[k]) + 'V'), fontsize = 16)

    '''fig.add_subplot(rows, columns, 1)
    plt.imshow(Output_image)
    plt.axis('off')
    plt.title('Output')'''

    fig.add_subplot(rows, columns, 1)
    plt.imshow(Output_image_CG)
    plt.axis('off')
    plt.title('Output (CG)')

    fig.add_subplot(rows, columns, 2)
    plt.imshow(Transfer_log_image)
    plt.axis('off')
    plt.title('Transfer Log')

    '''fig.add_subplot(rows, columns, 8)
    plt.imshow(Transfer_log_image_CG)
    plt.axis('off')
    plt.title('Transfer Log (CG)')'''

    fig.add_subplot(rows, columns, 6)
    plt.imshow(Settings_image)
    plt.axis('off')

    fig.add_subplot(rows, columns, 4)
    plt.imshow(Transfer_lin_image)
    plt.axis('off')
    plt.title('Transfer Lin')

    fig.add_subplot(rows, columns, 5)
    plt.imshow(Transfer_sqrt_image)
    plt.axis('off')
    plt.title('Transfer Sqrt')

    if not Short:
        fig.add_subplot(rows, columns, 3)
        plt.imshow(Perf_Parameters_image)
        plt.axis('off')

    fig.tight_layout()

    if len(V_G) == 1:
        if Short:
            fig.savefig(str(Short_Folder) + '/B' + str(Batch_Number) + '_' + str(Run_Name) + '_Overview_' + str(V_G[k]) + 'V.png')

        if not Short:
            fig.savefig(str(Working_Folder) + '/B' + str(Batch_Number) + '_' + str(Run_Name) + '_Overview_' + str(V_G[k]) + 'V.png')

    if len(V_G) > 1:
            fig.savefig(str(Device_Folder) + '/B' + str(Batch_Number) + '_' + str(Run_Name) + '_Overview_' + str(V_G[k]) + 'V.png')

    print('\nSaved overview png.')
    return
def Plot_overview_BIG():
    del Short_devices[1]
    del Short_devices[1]
    Short_devices.reverse()
    V_G.reverse()
    for i in range(len(Run_Names)):
        if Short_devices[i] == 0:
            Folder = Working_Folder
            Device_Folder = str(Working_Folder + '/Single_Devices/B'+ str(Batch_Number)+ '_' + str(Run_Names[i]))
        if Short_devices[i] == 1:
            Folder = Short_Folder
            Device_Folder = str(Short_Folder + '/Single_Devices/B'+ str(Batch_Number)+ '_' + str(Run_Names[i]))

        V1_image = cv2.imread(str(str(Device_Folder) + '/B' + str(Batch_Number) + '_' + str(Run_Names[i]) + '_Overview_' + str(V_G[0]) + 'V.png'))[...,::-1]
        V2_image = cv2.imread(str(str(Device_Folder) + '/B' + str(Batch_Number) + '_' + str(Run_Names[i]) + '_Overview_' + str(V_G[1]) + 'V.png'))[..., ::-1]
        V3_image = cv2.imread(str(str(Device_Folder) + '/B' + str(Batch_Number) + '_' + str(Run_Names[i]) + '_Overview_' + str(V_G[2]) + 'V.png'))[..., ::-1]

        fig = plt.figure(figsize=(18, 27), dpi=300)
        rows = 3
        columns = 1

        fig.add_subplot(rows, columns, 1)
        plt.imshow(V1_image)
        plt.axis('off')

        fig.add_subplot(rows, columns, 2)
        plt.imshow(V2_image)
        plt.axis('off')

        fig.add_subplot(rows, columns, 3)
        plt.imshow(V3_image)
        plt.axis('off')

        fig.tight_layout()

        fig.savefig(str(Folder) + '/' + str(Run_Names[i]) + '_Overview.png')

        print('Saved BIG overview for ' + 'B' + str(Batch_Number) + '_' + str(Run_Names[i]))

    return
def Perf_data_to_DataFrame(Perf_Params, Num_ID, Batch_Number, Run_Name, max_I_DS_forward, min_I_DS_forward, On_off_ratio_forward, SS_forward, V_G, V_th_sat_forward_sqrt, mu_sat_forward_sqrt, V_th_lin_forward, mu_lin_forward, max_I_DS_backward, min_I_DS_backward, On_off_ratio_backward, SS_backward, V_th_sat_backward_sqrt, mu_sat_backward_sqrt, V_th_lin_backward, mu_lin_backward):
    Current_Perf_Params = pd.DataFrame(
        {'Num ID': [Num_ID], 'ID': [str('B' + str(Batch_Number) + '_' + str(Run_Name))],
         'max I_DS (' + str(V_G[k]) + 'V) (f)': [max_I_DS_forward], 'min I_DS (' + str(V_G[k]) + 'V) (f)': [min_I_DS_forward], 'I_on/off (' + str(V_G[k]) + 'V) (f)': [On_off_ratio_forward], 'SubS (' + str(V_G[k]) + 'V) (f)': [SS_forward],
         str('V_th (sat) (' + str(V_G[k]) + 'V) (f)'): [V_th_sat_forward_sqrt],
         str('mu_sat (' + str(V_G[k]) + 'V) (f)'): [mu_sat_forward_sqrt],
         str('V_th (lin) (' + str(V_G[k]) + 'V) (f)'): [V_th_lin_forward],
         str('mu_lin (' + str(V_G[k]) + 'V) (f)'): [mu_lin_forward],
         'max I_DS (' + str(V_G[k]) + 'V) (b)': [max_I_DS_backward], 'min I_DS (' + str(V_G[k]) + 'V) (b)': [min_I_DS_backward], 'I_on/off (' + str(V_G[k]) + 'V) (b)': [On_off_ratio_backward], 'SubS (' + str(V_G[k]) + 'V) (b)': [SS_backward],
         str('V_th (sat) (' + str(V_G[k]) + 'V) (b)'): [V_th_sat_backward_sqrt],
         str('mu_sat (' + str(V_G[k]) + 'V) (b)'): [mu_sat_backward_sqrt],
         str('V_th (lin) (' + str(V_G[k]) + 'V) (b)'): [V_th_lin_backward],
         str('mu_lin (' + str(V_G[k]) + 'V) (b)'): [mu_lin_backward]})

    Current_Perf_Params.set_index('Num ID', inplace=True)
    if not Current_Perf_Params.index.to_list()[0] in Perf_Params.index.to_list():
        Perf_Params = pd.concat([Perf_Params, Current_Perf_Params])
    if Current_Perf_Params.index.to_list()[0] in Perf_Params.index.to_list():
        Perf_Params = Current_Perf_Params.combine_first(Perf_Params)

    return Perf_Params

#Set global settings for matplotlib
plt.rcParams['font.family'] = 'monospace'
colors = mcolors.CSS4_COLORS
by_hsv = sorted((tuple(mcolors.rgb_to_hsv(mcolors.to_rgb(color))),name)for name, color in colors.items())
color_names = [name for hsv, name in by_hsv]
#color_tableau=['blue','green','red','purple','orange','gray','olive','pink','brown','cyan']
#color_tableau = ['#006BA4', '#FF800E', '#ABABAB', '#595959', '#5F9ED1', '#C85200', '#898989', '#A2C8EC', '#FFBC79', '#CFCFCF']
color_tableau = ['#AE2012', '#BB3E03', '#CA6702', '#94D2BD', '#0A9396', '#005F73', '#FFA630', '#8D7471', '#A89B9D']

Save_Figs = True
CG = True

#Get the Batch and substrate numbers to find the data files
Batch_Number = input('\nEnter the batch number: ')
S1 = input('Enter Substrate Number in Board 1: ')
S2 = input('Enter Substrate Number in Board 2: ')
S3 = input('Enter Substrate Number in Board 3: ')
S4 = input('Enter Substrate Number in Board 4: ')
S5 = input('Enter Substrate Number in Board 5: ')
Substrates = [S1,S2,S3,S4,S5]

multiple_V_G = input('\nDo you want to analyze multiple gate voltages in the transfer? (y/n)  ')
if multiple_V_G == 'y':
    V_G1 = input('Enter the first gate voltage: ')
    V_G2 = input('Enter the second gate voltage: ')
    V_G3 = input('Enter the third gate voltage: ')
    V_G = [V_G1, V_G2, V_G3]
if multiple_V_G == 'n':
    V_G = [input('Enter the gate voltage for the transfer: ')]
if multiple_V_G != 'y' and multiple_V_G != 'n':
    print('\nINVALID INPUT')
    exit()


#Define the file and all folder names for storing the data
File_Name =str('/Batch' + str(Batch_Number) + '_S' + str(Substrates[0]) + '_S' + str(Substrates[1]) + '_S' + str(Substrates[2]) + '_S' + str(Substrates[3]) + '_S' + str(Substrates[4]))
Batch_Folder = str('Batch' + str(Batch_Number))
Data_Folder = str('Batch' + str(Batch_Number) + '/Data')
Plot_Folder = str('Batch' + str(Batch_Number) + '/Plots')
Working_Folder = str('Batch' + str(Batch_Number) + '/Plots/Working')
Short_Folder = str('Batch' + str(Batch_Number) + '/Plots/Short')
Performance_File = 'Data/Device_Performance_Parameter.txt'
Batch_Performance_File = str('Batch' + str(Batch_Number) + '/Batch' + str(Batch_Number) + '_Performance_Parameter.txt')
LabBook_File = 'Data/LabBook.xlsx'

#Checking if the folders already exist, if not create them
if not os.path.exists(Plot_Folder):
    os.makedirs(Plot_Folder)
if not os.path.exists(Working_Folder):
    os.makedirs(Working_Folder)
if not os.path.exists(Short_Folder):
    os.makedirs(Short_Folder)

#Defining the path to the multiple data files
Log_file = str(str(Data_Folder) + str(File_Name) + '_log_file.txt')
Output_file = str(str(Data_Folder) + str(File_Name) + '_Output.xlsx')
Transfer_file = []
V_G.reverse()
for i in range(len(V_G)):
    Transfer_file.append(str(str(Data_Folder) + str(File_Name) + '_Transfer_' + str(V_G[i]) + 'V.xlsx'))

#Define parameters for the data evaluation
Vacuum_Permittivity_Constant = 8.8541878188*pow(10,-12)
#Parameters for filtering out short devices
Short_filter_threshold_ratio = 10
Short_filter_threshold_residual_upper = pow(10, -8)
Short_filter_threshold_residual_lower = pow(10, -13)

#Define the variable names given in Clarius
Time = 'Time'
V_Gate = 'V_Gate'
I_Gate = 'I_Gate'
V_Source = 'V_Source'
I_Source = 'I_Source'
n_Variables = 5 #Number of variables/columns per measurement n=5 if time is measured, n=4 if the time is not measured

#Define the performamce parameters, that are saved
columns = ['ID']
V_G.reverse()
for i in range(len(V_G)):
    columns.append(str('max I_DS (' + str(V_G[i]) + 'V)'))
    columns.append(str('min I_DS (' + str(V_G[i]) + 'V)'))
    columns.append(str('I_on/off (' + str(V_G[i]) + 'V)'))
    columns.append(str('SubS (' + str(V_G[i]) + 'V)'))
    columns.append(str('V_th (sat) (' + str(V_G[i]) + 'V)'))
    columns.append(str('mu_sat (' + str(V_G[i]) + 'V)'))
    columns.append(str('V_th (lin) (' + str(V_G[i]) + 'V)'))
    columns.append(str('mu_lin (' + str(V_G[i]) + 'V)'))
for i in range(1, len(columns)):
    columns.append(str(str(columns[i]) + ' (b)'))
    columns[i] = str(str(columns[i]) + ' (f)')

#Check if the performance files already exists. If it does read the data from it.
if os.path.isfile(Performance_File):
    Perf_Params = pd.read_csv(Performance_File, sep=',', header=0)
    Perf_Params.set_index('Num ID', inplace=True)

if not os.path.isfile(Performance_File):
    Perf_Params = pd.DataFrame(columns=columns)

if os.path.isfile(Batch_Performance_File):
    Batch_Perf_Params = pd.read_csv(Batch_Performance_File, sep=',', header=0)
    Batch_Perf_Params.set_index('Num ID', inplace=True)

if not os.path.isfile(Batch_Performance_File):
    Batch_Perf_Params = pd.DataFrame(columns=columns)

#Read the Log file from the measurement to understand which measurement run corresponds to which substrate/device
Run_Names = get_run_names(Log_file)
Short_devices = [0]*(len(Run_Names)+2)

#Import the data from the Excel files to pd dataframes
Output_Exceldata_Workbook = pd.ExcelFile(Output_file)
Output_Settings = pd.read_excel(Output_file, sheet_name=2)
LabBook = pd.read_excel(LabBook_File, sheet_name=str('Batch' + str(Batch_Number)))
LabBook.set_index('Num ID', inplace=True)

V_G.reverse()

#Checking which devices are short
print('\n' + str('Checking for short devices').center(50, '-'))
for k in range(len(Transfer_file)):
    Transfer_Exceldata_Workbook = pd.ExcelFile(Transfer_file[k])
    print('\n' + str('\nTransfer File: ' + Transfer_file[k]).center(50, '-'))
    for i in range(len(Transfer_Exceldata_Workbook.sheet_names)): #Loop over all sheets in the Excel file
        if i != 1 and i != 2:
            Run_Name = Run_Names[int(Transfer_Exceldata_Workbook.sheet_names[i].strip('Run')) - 1]
            print('\n' + str('Run_Name: ' + Run_Name).center(50, '-'))
            Transfer_Exceldata_Sheet = pd.read_excel(Transfer_file[k], sheet_name=i)
            Short = Device_short(Transfer_Exceldata_Sheet, Short_filter_threshold_ratio,Short_filter_threshold_residual_upper, Short_filter_threshold_residual_lower)
            if Short:
                Short_devices[i] = 1

print('\n' + str('Results of short filter').center(50, '-'))
if Short_devices[0] == 1:
    print(str('\n' +Run_Names[-1] + ': ' + str(Short_devices[0]) + ' -> short'))
if Short_devices[0] == 0:
    print(str('\n' +Run_Names[-1] + ': ' + str(Short_devices[0]) + ' -> not short'))
for i in range(len(Run_Names)-2,-1,-1):
    if Short_devices[-i-1] == 1:
        print(str(Run_Names[i] + ': ' + str(Short_devices[-i-1]) + ' -> short'))
    if Short_devices[-i-1] == 0:
        print(str(Run_Names[i] + ': ' + str(Short_devices[-i-1]) + ' -> not short'))
print('\n' + str('-').center(50, '-'))

for k in range(len(Transfer_file)):
    Transfer_Exceldata_Workbook = pd.ExcelFile(Transfer_file[k])
    Transfer_Settings = pd.read_excel(Transfer_file[k], sheet_name=2)
    print('\n' + str('-').center(200, '-'))
    print('\nOpened Output file: ' + str(Output_file))
    print('Opened Transfer file: ' + str(Transfer_file[k]))
    print('\n' + str('-').center(200, '-'))

    for i in range(len(Transfer_Exceldata_Workbook.sheet_names)): #Loop over all sheets in the Excel file
        if i != 1 and i != 2:
            if 'Run' in Transfer_Exceldata_Workbook.sheet_names[i]: #Combine the name from the log file with the excel data to get the right data to the corresponding device
                Run_Name = Run_Names[int(Transfer_Exceldata_Workbook.sheet_names[i].strip('Run'))-1]
                Num_ID = int(str(Batch_Number).rjust(3,'0') + str(Run_Name).split('_')[0].strip('S').rjust(3,'0') + str(Run_Name).split('_')[1].strip('D').rjust(3,'0'))
                print('\n' + str('Analyzing ' + str(Run_Name)).center(50,'-'))

                # Read device parameters from LabBook
                Channel_Length, Channel_Width, Dielectric_Thickness, Dielectric_Constant, Areal_Capacitance = read_LabBook(LabBook)

                # Reading the settings of the measurement
                print('\nReading measurement settings for: ' + str(Run_Name))
                Settings_Transfer_Data = get_settings(Transfer_Settings, Transfer_Exceldata_Workbook.sheet_names[i])
                Settings_Output_Data = get_settings(Output_Settings, Output_Exceldata_Workbook.sheet_names[i])

                # Reading the data of the current transfer/output sheet/run to a DataFrame
                print('\nReading data for: ' + str(Run_Name))
                Transfer_Exceldata_Sheet = pd.read_excel(Transfer_file[k], sheet_name=i)
                Output_Exceldata_Sheet = pd.read_excel(Output_file, sheet_name=i)

                # Checking if the current device was short
                if Short_devices[i] == 0:
                    Short = False
                if Short_devices[i] == 1:
                    Short = True

                if Short:
                    Device_Folder = str(Short_Folder + '/Single_Devices/B' + str(Batch_Number) + '_' + str(Run_Name))
                if not Short:
                    Device_Folder = str(Working_Folder + '/Single_Devices/B' + str(Batch_Number) + '_' + str(Run_Name))
                if not os.path.exists(Device_Folder):
                    os.makedirs(Device_Folder)
                #Filter_plot.savefig(str(str(Device_Folder) + '/B' + str(Batch_Number) + '_' + str(Run_Name) + '_Short_Filter.png'),bbox_inches='tight')

                #Analyzing the Output data
                print('\nAnalyzing output data...')

                #PLotting the gate cleaned version of the output, from which the saturation and linear regime, as well as a threshold voltage are calculated.
                Output_plot_gate_cleaned, V_th_output = plot_output_gate_cleaned(Output_Exceldata_Sheet,Settings_Output_Data, Run_Name, Short, n_Variables, Text=False)
                print('\tV_th (output) = ' + str(V_th_output))

                Output_plot = plot_output(Output_Exceldata_Sheet, Settings_Output_Data, Run_Name, Short, n_Variables, Text=False)
                print('\tDone with plotting output')

                # Plotting the transfer data
                print('\nAnalyzing transfer data...')

                Transfer_plot_lin, c_forward, c_backward, V_GS_forward_fit, V_GS_backward_fit, mu_lin_forward, V_th_lin_forward, mu_lin_backward, V_th_lin_backward, max_I_DS_forward, max_I_DS_backward, min_I_DS_forward, min_I_DS_backward, On_off_ratio_forward, On_off_ratio_backward = plot_transfer_lin_scale(Transfer_Exceldata_Sheet, Settings_Transfer_Data, Run_Name, Short, V_th_output, Text=False, CG=False)
                print('\tV_th (lin) = ' + str(V_th_lin_forward))
                print('\tmu (lin) = ' + str(mu_lin_forward))
                print('\tDone with plotting transfer on linear scale')

                Transfer_plot_log, SS_forward, SS_backward = plot_transfer_log_scale(Transfer_Exceldata_Sheet, Settings_Transfer_Data, Run_Name,c_forward, c_backward, V_GS_forward_fit, V_GS_backward_fit,Short, Text=False, CG=False)
                print('\tSubS = ' + str(SS_forward))
                print('\tDone with plotting transfer on logarithmic scale')

                Transfer_plot_sqrt, V_th_sat_forward_sqrt, V_th_sat_backward_sqrt, mu_sat_forward_sqrt, mu_sat_backward_sqrt = plot_sqrt_I_Source(Transfer_Exceldata_Sheet, Settings_Transfer_Data, Run_Name, c_forward, c_backward, V_GS_forward_fit,V_GS_backward_fit, V_th_output, Short, Text=False, CG=False)
                print('\tV_th (sat) = ' + str(V_th_sat_forward_sqrt))
                print('\tmu (sat) = ' + str(mu_sat_forward_sqrt))
                print('\tDone with plotting the square root of transfer')

                # Plotting the transfer data gate cleaned
                if CG:
                    print('\nAnalyzing transfer data gate cleaned...')

                    Transfer_plot_lin_CG, c_forward_CG, c_backward_CG, V_GS_forward_fit_CG, V_GS_backward_fit_CG, mu_lin_forward_CG, V_th_lin_forward_CG, mu_lin_backward_CG, V_th_lin_backward_CG, max_I_DS_forward_CG, max_I_DS_backward_CG, min_I_DS_forward_CG, min_I_DS_backward_CG, On_off_ratio_forward_CG, On_off_ratio_backward_CG  = plot_transfer_lin_scale(Transfer_Exceldata_Sheet, Settings_Transfer_Data, Run_Name, Short, V_th_output, Text=False, CG=True)
                    print('\tV_th (lin) CG = ' + str(V_th_lin_forward_CG))
                    print('\tmu (lin) CG = ' + str(mu_lin_forward_CG))
                    print('\tDone with plotting transfer on linear scale gate cleaned')

                    Transfer_plot_log_CG, SS_forward_CG, SS_backward_CG = plot_transfer_log_scale(Transfer_Exceldata_Sheet, Settings_Transfer_Data, Run_Name, c_forward_CG, c_backward_CG, V_GS_forward_fit_CG, V_GS_backward_fit_CG, Short, Text=False, CG=True)
                    print('\tSubS CG = ' + str(SS_forward_CG))
                    print('\tDone with plotting transfer on logarithmic scale')

                    Transfer_plot_sqrt_CG, V_th_sat_forward_sqrt_CG, V_th_sat_backward_sqrt_CG, mu_sat_forward_sqrt_CG, mu_sat_backward_sqrt_CG = plot_sqrt_I_Source(Transfer_Exceldata_Sheet, Settings_Transfer_Data, Run_Name, c_forward_CG, c_backward_CG, V_GS_forward_fit_CG,V_GS_backward_fit_CG, V_th_output, Short, Text=False, CG=True)
                    print('\tV_th (sat) CG = ' + str(V_th_sat_forward_sqrt_CG))
                    print('\tmu (sat) CG = ' + str(mu_sat_forward_sqrt_CG))
                    print('\tDone with plotting the square root of transfer')

                if not Short:
                   Perf_Params = Perf_data_to_DataFrame(Perf_Params, Num_ID, Batch_Number, Run_Name, max_I_DS_forward, min_I_DS_forward, On_off_ratio_forward, SS_forward, V_G, V_th_sat_forward_sqrt, mu_sat_forward_sqrt, V_th_lin_forward, mu_lin_forward, max_I_DS_backward, min_I_DS_backward, On_off_ratio_backward, SS_backward, V_th_sat_backward_sqrt, mu_sat_backward_sqrt, V_th_lin_backward, mu_lin_backward)
                   Batch_Perf_Params = Perf_data_to_DataFrame(Batch_Perf_Params, Num_ID, Batch_Number, Run_Name, max_I_DS_forward,min_I_DS_forward, On_off_ratio_forward, SS_forward, V_G,V_th_sat_forward_sqrt, mu_sat_forward_sqrt, V_th_lin_forward,mu_lin_forward, max_I_DS_backward, min_I_DS_backward,On_off_ratio_backward, SS_backward, V_th_sat_backward_sqrt,mu_sat_backward_sqrt, V_th_lin_backward, mu_lin_backward)


                if Save_Figs:
                    Output_plot_gate_cleaned.savefig(str(str(Device_Folder) + '/B' + str(Batch_Number) + '_' + str(Run_Name) + '_Output_CG.png'),bbox_inches='tight')
                    Output_plot.savefig(str(str(Device_Folder) + '/B' + str(Batch_Number) + '_' + str(Run_Name) + '_Output.png'),bbox_inches='tight')
                    Transfer_plot_lin.savefig(str(str(Device_Folder) + '/B' + str(Batch_Number) + '_' + str(Run_Name) + '_Transfer_lin_' + str(V_G[k]) + 'V.png'), bbox_inches='tight')
                    Transfer_plot_log.savefig(str(str(Device_Folder) + '/B' + str(Batch_Number) + '_' + str(Run_Name) + '_Transfer_log_' + str(V_G[k]) + 'V.png'), bbox_inches='tight')
                    Transfer_plot_sqrt.savefig(str(str(Device_Folder) + '/B' + str(Batch_Number) + '_' + str(Run_Name) + '_Transfer_sqrt_' + str(V_G[k]) + 'V.png'), bbox_inches='tight')
                    if CG:
                        Transfer_plot_lin_CG.savefig(str(str(Device_Folder) + '/B' + str(Batch_Number) + '_' + str(Run_Name) + '_Transfer_lin_CG_' + str(V_G[k]) + 'V.png'), bbox_inches='tight')
                        Transfer_plot_log_CG.savefig(str(str(Device_Folder) + '/B' + str(Batch_Number) + '_' + str(Run_Name) + '_Transfer_log_CG_' + str(V_G[k]) + 'V.png'), bbox_inches='tight')
                        Transfer_plot_sqrt_CG.savefig(str(str(Device_Folder) + '/B' + str(Batch_Number) + '_' + str(Run_Name) + '_Transfer_sqrt_CG_' + str(V_G[k]) + 'V.png'), bbox_inches='tight')

                    Plot_overview()

                print('\n' + str('-').center(50, '-'))

if len(V_G) > 1 and Save_Figs:
    Plot_overview_BIG()

Perf_Params.to_csv(Performance_File)
Batch_Perf_Params.to_csv(Batch_Performance_File)
print('\n Wrote data to performance files')
print('\n' + str('-').center(200, '-'))