From d879a6a6da197531e7194bb6a07c882718adc7b6 Mon Sep 17 00:00:00 2001 From: "nazarchuk.as" Date: Tue, 8 Nov 2022 19:55:59 +0300 Subject: [PATCH] add chart --- Automation/Main.py | 94 ++++++++++++++++++++++------------ Automation/j/.~lock.data.csv# | 1 + Automation/j/Chart.png | Bin 0 -> 11416 bytes Automation/j/data.csv | 6 ++- 4 files changed, 67 insertions(+), 34 deletions(-) create mode 100644 Automation/j/.~lock.data.csv# create mode 100644 Automation/j/Chart.png diff --git a/Automation/Main.py b/Automation/Main.py index d6f3309..28f5640 100644 --- a/Automation/Main.py +++ b/Automation/Main.py @@ -5,6 +5,7 @@ import numpy as np import matplotlib.pyplot as plt from scipy.optimize import curve_fit import time +import pandas as pd from PyQt6 import QtCore from PyQt6.QtGui import QAction, QIcon, QPixmap from PyQt6.QtWidgets import (QHBoxLayout, @@ -176,11 +177,11 @@ class MainExperimentDataWindow(AbstractWindow): self.resize(1400, 800) # make masthead - self.dataname = 'data.csv' + self.parent.dataname = 'data.csv' head_1 = 'I_0,mA' head_2 = 'U_34,mV' head_3 = 't,s' - with open(os.path.join(self.parent.folder, self.dataname), 'w') as file: + with open(os.path.join(self.parent.folder, self.parent.dataname), 'w') as file: wr = csv.writer(file) wr.writerow([head_1, head_2, head_3]) @@ -246,7 +247,7 @@ class MainExperimentDataWindow(AbstractWindow): v = str((current_time-self.start_time)/60) a = v t = str(current_time-self.start_time) - with open(os.path.join(self.parent.folder, self.dataname), 'a') as file: + with open(os.path.join(self.parent.folder, self.parent.dataname), 'a') as file: wr = csv.writer(file) wr.writerow([v, a, str(current_time-self.start_time)]) self.table.insertRow(self.table.rowCount()) @@ -281,7 +282,7 @@ class MainExperimentDataWindow(AbstractWindow): f_volt.close() f_amp.close() current_time = round(time.time()*1000) - with open(os.path.join(self.parent.folder, self.dataname), 'a') as file: + with open(os.path.join(self.parent.folder, self.parent.dataname), 'a') as file: wr = csv.writer(file) wr.writerow([v, a, str(current_time-self.start_time)]) @@ -290,14 +291,22 @@ class MainExperimentChartWindow(AbstractWindow): def __init__(self, parent): super().__init__() - self.setWindowTitle('Основной эксперимент. Обработка данных') self.parent = parent + self.parent.chartname = 'Chart' + self.parent.data = Data(data_filename=os.path.join(self.parent.folder, self.parent.dataname), + saving=os.path.join(self.parent.folder, self.parent.chartname)) + self.parent.data.read_csv() + self.parent.data.x=self.parent.data.data['I_0,mA'] + self.parent.data.y=self.parent.data.data['U_34,mV'] + self.parent.data.make_grafic() + + self.setWindowTitle('Основной эксперимент. Обработка данных') self.resize(1400, 800) self.centralwidget = QWidget() self.setCentralWidget(self.centralwidget) - pixmap = QPixmap('arrow.png') + pixmap = QPixmap(os.path.join(self.parent.folder, self.parent.chartname)) self.label = QLabel(self) self.label.setPixmap(pixmap) self.label.resize(pixmap.width(), pixmap.height()) @@ -310,25 +319,23 @@ class MainExperimentChartWindow(AbstractWindow): self.hbox_layout.addWidget(self.text, 0, 1) + + + class Data: - def __init__(self, x, y, xlabel, ylabel, caption, xerr, yerr, through_0, - data_filename, color=None, centering=None, size=15, - coefficient=[0.9, 1.1]): + def __init__(self, x=[], y=[], xlabel='', ylabel='', caption='', xerr=None, + yerr=None, through_0=0, data_filename='', color=None, + centering=None, size=15, coefficient=[0.9, 1.1], saving=None): self.x = x self.y = y self.xlabel = xlabel self.ylabel = ylabel self.caption = caption - if type(yerr) == float or type(yerr) == int: - self.yerr = [yerr for _ in self.y] - else: - self.yerr = yerr - if type(xerr) == float or type(xerr) == int: - self.xerr = [xerr for _ in self.x] - else: - self.xerr = xerr + self.xerr=xerr + self.yerr=yerr + self.make_errors(xerr, yerr) self.through_0 = through_0 - if not self.color: + if not color: self.color = ['limegreen', 'indigo'] else: self.color = color @@ -336,13 +343,33 @@ class Data: self.size = size self.coefficient = coefficient self.data_filename=data_filename + self.saving=saving + def make_errors(self, xerr=None, yerr=None): + if not xerr: xerr=self.xerr + if not yerr: yerr=self.yerr + if not xerr: xerr=0 + if not yerr: yerr=0 + if not yerr or type(yerr) == float or type(yerr) == int: + self.yerr = [yerr for _ in self.y] + else: + self.yerr = yerr + if not xerr or type(xerr) == float or type(xerr) == int: + self.xerr = [xerr for _ in self.x] + else: + self.xerr = xerr + def read_csv(self): with open(self.data_filename) as file: - reader = list(csv.reader(file, delimiter=';', - quotechar=',', quoting=csv.QUOTE_MINIMAL)) + reader = list(csv.reader(file)) data = np.array(reader) - data = np.transpose(data) + dic=[] + for i in range(len(data[0])): + micro_data = [] + for j in range(len(data)): + micro_data.append(data[j][i]) + dic.append(micro_data) + data=dic dic = {} for i in range(len(data)): dic[data[i][0]] = np.array(data[i][1:]).astype(np.float) @@ -350,15 +377,15 @@ class Data: self.data=data def make_point_grafic(self): - + self.make_errors() if self.xerr[1] != 0 or self.yerr[1] != 0: plt.errorbar(self.x, self.y, yerr=self.yerr, xerr=self.xerr, linewidth=4, - linestyle='', label=self.caption, color=self.color, - ecolor=self.color, elinewidth=1, capsize=3.4, + linestyle='', label=self.caption, color=self.color[0], + ecolor=self.color[0], elinewidth=1, capsize=3.4, capthick=1.4) else: plt.scatter(self.x, self.y, linewidth=0.005, label=self.caption, - color=self.color, edgecolor='black', s=self.size) + color=self.color[0], edgecolor='black', s=self.size) if not self.centering: plt.xlabel(self.xlabel) @@ -373,7 +400,7 @@ class Data: self.ax.set_ylabel(self.xlabel, labelpad=-260, rotation=0, fontsize=14) - def make_line_grafic(self, k, b,): + def make_line_grafic(self, k, b): if min(self.x) > 0: xmin = min(self.x)*self.coefficient[0] else: @@ -385,10 +412,10 @@ class Data: xmax = max(self.x)*self.coefficient[0] x = np.arange(xmin, xmax, (xmax-xmin)/10000) plt.plot(x, k*x+b, label=self.caption, linewidth=2.4, - linestyle='-') - - def make_graffic(self, named_by_points=True): + linestyle='-', color=self.color[1]) + def make_grafic(self, named_by_points=True): + self.make_errors() if named_by_points: cap_point = self.caption line_point = None @@ -396,6 +423,7 @@ class Data: line_point = self.caption cap_point = None self.make_point_grafic() + k, b, sigma = self.approx() sigma[0] = abs(k*((sigma[0]/k)**2+(np.mean(self.yerr)/np.mean(self.y))**2 + (np.mean(self.xerr)/np.mean(self.x))**2)**0.5) @@ -405,15 +433,17 @@ class Data: else: sigma[1] = 0 - self.make_line_grafic() + self.make_line_grafic(k, b) plt.legend() + if self.saving: + plt.savefig(self.saving) return k, b, sigma def approx(self): if self.yerr[0] != 0: - sigma_y = [1/i**2 for i in self.yerr] + sigma_y = [1/i**2 for i in self.y] else: - sigma_y = np.array([1 for _ in self.yerr]) + sigma_y = np.array([1 for _ in self.y]) if self.through_0 == 0: def f(x, k): return k*x diff --git a/Automation/j/.~lock.data.csv# b/Automation/j/.~lock.data.csv# new file mode 100644 index 0000000..5a9e132 --- /dev/null +++ b/Automation/j/.~lock.data.csv# @@ -0,0 +1 @@ +,anna,anna-HP-Laptop-15-bw0xx,08.11.2022 18:47,file:///home/anna/.config/libreoffice/4; \ No newline at end of file diff --git a/Automation/j/Chart.png b/Automation/j/Chart.png new file mode 100644 index 0000000000000000000000000000000000000000..892572e4f048d8d1f638c7f466c02b9e81a2be2f GIT binary patch literal 11416 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