class GuiProgram(Ui_sweepergui): cols = 0 sweep_id = 'mereni' full_data = [] negative_current = False log_sweep = True stop = True decade_combo_values = ['5', '10', '25', '50'] save_directory = False save_filename = False def __init__(self, dialog): Ui_sweepergui.__init__(self) self.setupUi(dialog) # Connect "add" button with a custom function (addInputTextToListbox) self.exportButton.clicked.connect(self.export_data) self.startBtn.clicked.connect(self.startFunc) self.logRadioButton.clicked.connect(self.switch_linear) self.linRadioButton.clicked.connect(self.switch_linear) self.dynamicDelayRadio.clicked.connect(self.switch_dynamic_delay) self.constantDelayRadio.clicked.connect(self.switch_dynamic_delay) # Populate comboBox self.decadeComboBox.clear() self.decadeComboBox.addItems(self.decade_combo_values) self.decadeComboBox.setCurrentIndex(1) self.exportButton.setEnabled(False) # Try to load last parameters from Pickle self.load_parameters() self.save_directory = os.path.dirname(os.path.abspath(__file__)) # Připojení k instrumentu #self.inst = Instrument('GPIB0::17::INSTR', visa_location='C:\WINDOWS\SysWOW64\\visa32.dll') self.inst = Instrument('GPIB0::17::INSTR', virtual=True) def make_pretty(self): self.littleProgBar.setValue(84) self.littleProgBar.setMaximum(100) self.bigProgBar.setMaximum(5) self.bigProgBar.setValue(3) self.startBtn.setText('Stop') self.ax.clear() # Clear contents of current axis # Plot cosmetics self.ax.set_xlabel('Current $I$ (nA)') self.ax.set_ylabel('Voltage $U$ (V)') self.ax.set_title( 'Sweep ID: 2018-04-21_11:22:37 $n$-ZnO/$p$-GaN sample #692') data = [] dd = np.loadtxt('demo_data/01.txt') for i in range(int(len(dd.T) / 2)): data.append((dd[:, 2 * i] * 1e6, dd[:, 2 * i + 1])) color_1 = '#0066FF' color_3 = '#6600CC' color_2 = '#FF0000' self.ax.plot(data[2][0], data[2][1], color=color_2) self.ax.plot(data[3][0], data[3][1], '--', color=color_2) self.ax.plot(data[4][0], data[4][1], color=color_3) self.ax.plot(data[5][0], data[5][1], '--', color=color_3) self.ax.plot(data[0][0], data[0][1], color=color_1) self.ax.plot(data[1][0], data[1][1], '--', color=color_1) #plt.tight_layout() # --- PLOTTING ----------------------------------------------------------- # ------------------------------------------------------------------------ # ------------------------------------------------------------------------ # ------------------------------------------------------------------------ def plot_data(self, data): ''' Plots the provided data onto the figure in the GUI. ''' original_xlim = self.ax.get_xlim() original_ylim = self.ax.get_ylim() self.ax.clear() # Clear contents of current axis # Plot cosmetics self.ax.set_xlabel('I [A]') self.ax.set_ylabel('U [V]') self.ax.set_title('Sweep ID: ' + self.sweep_id) for i in range(len(data)): x, y = data[i] if i == len(data) - 1: color = '#0066FF' elif i == len(data) - 2: color = '#6600CC' else: color = '#FF0000' if self.chkLoop.checkState(): half = int(len(x) / 2) end = len(x) self.ax.plot(x[0:half], y[0:half], color=color) self.ax.plot(x[half:end], y[half:end], '--', color=color) else: self.ax.plot(x, y, color=color) if self.log_sweep: self.ax.set_xscale('log') else: self.ax.set_xscale('linear') if i != 0 and self.chkLockRange.checkState(): self.ax.set_xlim(original_xlim) self.ax.set_ylim(original_ylim) self.canvas.get_default_filename = self.get_default_filename self.canvas.draw() # Propagate changes to GUI def clear_plot(self): self.ax.clear() # Clear contents of current axis self.canvas.draw() # Propagate changes to GUI def put_figure_into_gui(self, fig, ax): ''' Creates a figure and places it inside the GUI container. ''' # Figure self.fig = fig self.ax = ax # Canvas self.canvas = FigureCanvas(self.fig) self.mplvl.addWidget(self.canvas) self.canvas.draw() # Toolbar self.toolbar = NavigationToolbar(self.canvas, self.mplwindow, coordinates=True) self.mplvl.addWidget(self.toolbar) def remove_figure_from_gui(self, ): ''' Deletes the figure from the GUI. ''' # Canvas self.mplvl.removeWidget(self.canvas) self.canvas.close() self.canvas.deleteLater() # this prevents memory leaks # Toolbar self.mplvl.removeWidget(self.toolbar) self.toolbar.close() self.toolbar.deleteLater() # this prevent memory leaks def get_default_filename(self): """ Return a string, which includes extension, suitable for use as a default filename. """ default_basename = self.save_filename or "sweep_{}".format( self.sweep_id) or 'image' default_filetype = self.canvas.get_default_filetype() default_filename = default_basename + '.' + default_filetype save_dir = os.path.expanduser( matplotlib.rcParams.get('savefig.directory', '')) # ensure non-existing filename in save dir i = 1 while os.path.isfile(os.path.join(save_dir, default_filename)): # attach numerical count to basename default_filename = '{0}_({1}).{2}'.format(default_basename, i, default_filetype) i += 1 return default_filename # --- GUI collecting and starting MEASUREMENTS --------------------------- # ------------------------------------------------------------------------ # ------------------------------------------------------------------------ # ------------------------------------------------------------------------ def validateInput(self, sw_min, sw_max, decade, delay, log_sweep, step): # Unit testing :P try: a = float(sw_min) a = float(sw_max) if not log_sweep: a = float(step) except: return False, "Některé parametry se nedají převést na čísla." # Code if log_sweep: if (float(sw_min) > 0 and float(sw_max) > 0 and float(sw_min) != float(sw_max)): return True, "OK" else: return False, "Kraje intervalu jsou stejné nebo je alespoň jeden záp**ný." else: # lin sweep if (float(sw_min) != float(sw_max) and abs(float(sw_max) - float(sw_min)) > float(step)): # step fits into (start, stop) interval and start != stop test_array = np.arange(float(sw_max), float(sw_min), float(step)) if self.chkLoop.checkState() and len(test_array) * 2 > 1000: return False, "Počet bodů ve sweepu je {} > 1000. \nBuffer by přetekl, zvolte jemnější krok, menší rozsah nebo vypněte obousměrnost měření.".format( 2 * len(test_array)) elif len(test_array) > 1000: return False, "Počet bodů ve sweepu je {} > 1000. \nBuffer by přetekl, zvolte jemnější krok nebo menší rozsah.".format( len(test_array)) else: return True, "OK" else: return False, "Kraje intervalu se rovnají, nebo je krok větší než rozsah." def stopFunc(self): print('ABORT! Attempted to STOP sweep!') self.inst.operate(False) self.stop = True def startFunc(self): ''' Posbírá z GUI parametry a odpovídajícím způsobem přeloží.''' # vypnout ruční brzdu self.stop = False # aktuální čas pro ID self.sweep_id = '{0:%Y-%m-%d_%H-%M-%S}'.format(datetime.datetime.now()) self.save_filename = False sense_local = self.senseLocalRadioButton.isChecked() sense_remote = self.senseRemoteRadioButton.isChecked() self.sense_local = sense_local sw_min = str(self.startEdit.text()) sw_max = str(self.endEdit.text()) step = str(self.stepEdit.text()) # Pokud je zapojený zesilovač if not self.sense_local: sw_min = str(float(sw_min) * 1e3) sw_max = str(float(sw_max) * 1e3) step = str(float(step) * 1e3) # TODO: this should be made more logical... self.custom_capacity_used = self.dynamicDelayRadio.isChecked() if self.custom_capacity_used: self.custom_capacity = int(self.capacitySpinBox.value()) delay = str(self.delaySpinBox.value()) decade = str(self.decadeComboBox.currentIndex()) n = self.pocetMereniBox.value() self.bigProgBar.setValue(0) self.bigProgBar.setMaximum(n) self.littleProgBar.setValue(0) log_sweep = self.logRadioButton.isChecked() lin_sweep = self.linRadioButton.isChecked() self.log_sweep = log_sweep col_source = self.sourceCheckBox.checkState() col_delay = self.delayCheckBox.checkState() col_measure = self.measureCheckBox.checkState() col_time = self.timeCheckBox.checkState() self.cols = 0 if col_source: self.cols += 1 if col_delay: self.cols += 2 if col_measure: self.cols += 4 if col_time: self.cols += 8 input_valid, err = self.validateInput(sw_min, sw_max, decade, delay, log_sweep, step) if self.chkAutorange.checkState(): sweep_range = '0' else: sweep_range = str( misc.get_range_number(float(sw_min), float(sw_max))) print("!! Using sweep range: {}".format(sweep_range)) if sweep_range == '0': print( 'POZOR: Manualni nastaveni range selhalo, prilis vysoke proudy?' ) if input_valid: self.save_parameters() self.measure(sw_min, sw_max, decade, delay, log_sweep, step, n, sweep_range) else: self.show_notification(err) # --- ACTUAL MEASUREMENTS ------------------------------------------------ # ------------------------------------------------------------------------ # ------------------------------------------------------------------------ # ------------------------------------------------------------------------ def measure(self, sw_min, sw_max, decade, delay, log_sweep, step, n, sweep_range): ''' Spustí měření s již validovanými parametry. ''' # Disable UI self.enable_ui(False) # Smaže aktuální graf self.clear_plot() # Declare Export not done on this sweep self.exportButton.setText('Export') # Local or Remote sense? if self.sense_local: print("Zapinam Sense - LOCAL.") self.inst.write("O0X") else: print("Zapinam Sense - REMOTE.") self.inst.write("O1X") # Úvodní stabilizace stabilize_time = self.stableSpinBox.value() print("Uvodni stabilizace v DC modu - {} s.".format(stabilize_time)) self.stabilize(sw_min, stabilize_time) # Nastavení sweepu self.inst.set_source_and_function('I', 'Sweep') # Nastavení formátu dat self.inst.write("G" + str(self.cols) + ",2,2X") if self.log_sweep: self.inst.write("Q2," + sw_min + "," + sw_max + "," + decade + "," + sweep_range + "," + delay + "X") if self.chkLoop.checkState(): self.inst.write("Q8," + sw_max + "," + sw_min + "," + decade + "," + sweep_range + "," + delay + "X") else: self.inst.write("Q1," + sw_min + "," + sw_max + "," + step + "," + sweep_range + "," + delay + "X") if self.chkLoop.checkState(): self.inst.write("Q7," + sw_max + "," + sw_min + "," + step + "," + sweep_range + "," + delay + "X") # Manual modification of delays for each value if self.custom_capacity_used: if self.chkLoop.checkState(): delay_arr = delays.delays_round(float(sw_min), float(sw_max), int(decade), self.custom_capacity) else: delay_arr = delays.delays_up(float(sw_min), float(sw_max), int(decade), self.custom_capacity) self.inst.set_custom_delays(delay_arr) data = [] self.full_data = [] self.np_data = [] n_hotovych_mereni = 0 for mereni in range(n): if self.stop: break output = self.run_sweep() if output: if not self.sense_local: output = misc.shift_data(output, cols=self.cols, shift=-3) sweep_results = misc.nice_format(output, cols=self.cols) unpacked_results = misc.unpack(sweep_results, cols=self.cols) data.append(unpacked_results) self.full_data.append(sweep_results) self.np_data = misc.pack_data(self.np_data, unpacked_results) print('Ukladam docasna data...') self.dump_data() n_hotovych_mereni += 1 self.bigProgBar.setValue(n_hotovych_mereni) self.plot_data(data) if n_hotovych_mereni != n: sleep_time = self.sleepSpinBox.value() print("Pauza mezi sweepy - {} s.".format(sleep_time)) self.artSleep(sleep_time) else: print("Output byl prazdny. Prerusene mereni?") self.inst.operate(False) self.enable_ui(True) def run_sweep(self): ''' Provede jeden sweep, který už musí být definovaný ve stroji. Na konci 3 vteřiny spí, aby se mělo napětí čas ustálit před dalším měřením. Vrací string se všemi hodnotami sweepu. ''' print('\nSpoustim sweep...') self.inst.write("U8X") out = self.inst.read() print('U8X -> ' + out) out = out.replace('\r', '').replace('\n', '') print("Out: {}".format(out)) sweep_defined_size = int(out[-4:]) print('Pocet bodu ve sweepu: ' + str(sweep_defined_size)) self.littleProgBar.setValue(0) self.inst.trigger() # Immediate trigger sweep_done = False while not sweep_done: if self.stop: break self.artSleep(0.2) self.inst.write("U11X") status = self.inst.read() if (status == 'SMS' + str(sweep_defined_size).zfill(4) + '\r\n'): sweep_done = True else: status_edit = status.replace('\r', '').replace('\n', '') try: progress = int(status_edit[-4:]) self.littleProgBar.setValue( int(progress / sweep_defined_size * 100)) except: print('Invalid progress!') print('Jeden sweep hotov.') self.littleProgBar.setValue(100) if self.stop: return "" else: return self.inst.read() def stabilize(self, bias, stabilize_time): # Počáteční stabilizace self.inst.set_source_and_function('I', 'DC') self.inst.write("B" + bias + ",0,20X") self.inst.operate(True) self.inst.trigger() self.artSleep(stabilize_time) # --- EXPORT and DATA operations ----------------------------------------- # ------------------------------------------------------------------------ # ------------------------------------------------------------------------ # ------------------------------------------------------------------------ def dump_data(self): save_file_name = 'C:\Repa\k237\data_temp.txt' try: np.savetxt(save_file_name, self.np_data, fmt='%.4e', header=self.get_measurement_parameters() + "\nPOZOR, prubezne ukladana data mohou byt nekompletni", delimiter='\t') except: print("Nouzovy dump se nepovedl.") def export_data(self): """ Exportuje data pomocí ukládacího dialogu Qt. V případě chybného zadání souboru nic neudělá a postěžuje si do konzole. """ proposed_name = self.save_filename or 'sweep_' + self.sweep_id # Qt Dialog na výběr souboru k uložení save_file_name, _ = QtWidgets.QFileDialog.getSaveFileName( None, 'Exportovat výsledky měření', #'C:\Repa\k237\data\sweep_' + proposed_name + '.txt', os.path.join(self.save_directory, proposed_name + '.txt'), 'Text Files (*.txt);;All Files (*)') # Vlastní uložení souboru try: np.savetxt(save_file_name, self.np_data, fmt='%.4e', header=self.get_measurement_parameters(), delimiter='\t') # Update GUI self.exportButton.setText('Export ✔') self.save_directory = os.path.dirname(save_file_name) self.save_filename = os.path.splitext( os.path.basename(save_file_name))[0] except: print("Export neuspesny. Data pravdepodobne nejsou ulozena!") # Update GUI self.exportButton.setText('Export ✗') def get_measurement_parameters(self): out = '' out += "Sweep ID: {}\n".format(self.sweep_id) if self.log_sweep: out += "Log sweep:\n" out += "Rozsah (min, max) [A]: {}, {}\n".format( self.startEdit.text(), self.endEdit.text()) out += "Bodu na dekadu [-]: {}\n".format( self.decade_combo_values[self.decadeComboBox.currentIndex()]) else: out += "Linear sweep\n" out += "Rozsah (min, max, points) [A]: {}, {}, {}\n".format( self.startEdit.text(), self.endEdit.text(), self.stepEdit.text()) out += "Delay [ms]: {}\n".format(self.delaySpinBox.value()) out += "Pocet charakteristik [-]: {}\n".format( self.pocetMereniBox.value()) if self.sense_local: out += "Sense: local\n" else: out += "Sense: remote\n" out += "Sloupce (Source, Measure, Delay, Time): {} {} {} {}\n".format( int(self.sourceCheckBox.checkState() / 2), int(self.measureCheckBox.checkState() / 2), int(self.delayCheckBox.checkState() / 2), int(self.timeCheckBox.checkState() / 2)) out += "Uvodni DC stabilizace [s]: {}\n".format( self.stableSpinBox.value()) out += "Stabilizace [s]: {}\n".format(self.sleepSpinBox.value()) out += "\nI[A] (x)\tU[V .e-3] (y1, y2, ...) " return out # --- GUI parameters and ENABLE/DISABLE ---------------------------------- # ------------------------------------------------------------------------ # ------------------------------------------------------------------------ # ------------------------------------------------------------------------ def save_parameters(self): parameters_dict = { 'sw_min': str(self.startEdit.text()), 'sw_max': str(self.endEdit.text()), 'step': str(self.stepEdit.text()), 'delay': int(self.delaySpinBox.value()), 'decade': int(self.decadeComboBox.currentIndex()), 'n': int(self.pocetMereniBox.value()), 'log_sweep': self.logRadioButton.isChecked(), 'lin_sweep': self.linRadioButton.isChecked(), 'sense_local': self.senseLocalRadioButton.isChecked(), 'sense_remote': self.senseRemoteRadioButton.isChecked(), 'col_source': self.sourceCheckBox.checkState(), 'col_delay': self.delayCheckBox.checkState(), 'col_measure': self.measureCheckBox.checkState(), 'col_time': self.timeCheckBox.checkState(), 'stabilize_time': self.stableSpinBox.value(), 'sleep_time': self.sleepSpinBox.value(), 'chk_loop': self.chkLoop.checkState(), 'chk_lock_range': self.chkLockRange.checkState(), 'chk_autorange': self.chkAutorange.checkState(), } # For pickle, the file needs to be opened in binary mode, hence the "wb" with open("last_parameters.pickle", "wb") as params_file: pickle.dump(parameters_dict, params_file) def load_parameters(self): try: # For pickle, the file needs to be opened in binary mode, hence the "wb" with open("last_parameters.pickle", "rb") as params_file: parameters_dict = pickle.load(params_file) self.startEdit.setText(parameters_dict['sw_min']) self.endEdit.setText(parameters_dict['sw_max']) self.stepEdit.setText(parameters_dict['step']) self.delaySpinBox.setValue(parameters_dict['delay']) self.decadeComboBox.setCurrentIndex(parameters_dict['decade']) self.pocetMereniBox.setValue(parameters_dict['n']) self.logRadioButton.setChecked(parameters_dict['log_sweep']) self.linRadioButton.setChecked(parameters_dict['lin_sweep']) self.senseLocalRadioButton.setChecked( parameters_dict['sense_local']) self.senseRemoteRadioButton.setChecked( parameters_dict['sense_remote']) self.sourceCheckBox.setChecked(parameters_dict['col_source']) self.delayCheckBox.setChecked(parameters_dict['col_delay']) self.measureCheckBox.setChecked(parameters_dict['col_measure']) self.timeCheckBox.setChecked(parameters_dict['col_time']) self.stableSpinBox.setValue(parameters_dict['stabilize_time']) self.sleepSpinBox.setValue(parameters_dict['sleep_time']) self.chkLoop.setChecked(parameters_dict['chk_loop']) self.chkLockRange.setChecked(parameters_dict['chk_lock_range']) self.chkAutorange.setChecked(parameters_dict['chk_autorange']) self.switch_linear() self.switch_dynamic_delay() print("Nacteni poslednich parametru uspesne! :)") except: print("Nacteni poslednich parametru selhalo. :(") def switch_linear(self): log_sweep = self.logRadioButton.isChecked() lin_sweep = self.linRadioButton.isChecked() if log_sweep: self.stepEdit.setEnabled(False) self.decadeComboBox.setEnabled(True) else: self.decadeComboBox.setEnabled(False) self.stepEdit.setEnabled(True) def switch_dynamic_delay(self): const_delay = self.constantDelayRadio.isChecked() dynamic_delay = self.dynamicDelayRadio.isChecked() if const_delay: self.capacitySpinBox.setEnabled(False) self.delaySpinBox.setEnabled(True) else: self.delaySpinBox.setEnabled(False) self.capacitySpinBox.setEnabled(True) def enable_ui(self, status): ui_elements = [ self.startEdit, self.endEdit, self.stepEdit, self.delaySpinBox, self.decadeComboBox, self.pocetMereniBox, self.logRadioButton, self.linRadioButton, self.senseLocalRadioButton, self.senseRemoteRadioButton, self.sourceCheckBox, self.delayCheckBox, self.measureCheckBox, self.timeCheckBox, self.stableSpinBox, self.sleepSpinBox, self.chkLoop, self.chkAutorange, self.exportButton, ] for element in ui_elements: element.setEnabled(status) if status: self.switch_linear() self.switch_dynamic_delay() if status: self.startBtn.clicked.disconnect() self.startBtn.clicked.connect(self.startFunc) self.startBtn.setText("Start") self.exportButton.setFocus() else: self.startBtn.clicked.disconnect() self.startBtn.clicked.connect(self.stopFunc) self.startBtn.setText("Abort") self.startBtn.setFocus() self.exportButton.setText('Export') def artSleep(self, sleepTime): """ Čeká čas sleepTime v sekundách, zatím ale každých 50 milisekund řeší akce, o které se někdo pokoušel v GUI. """ stop_time = QtCore.QTime() stop_time.restart() while stop_time.elapsed() < sleepTime * 1000: QtWidgets.QApplication.processEvents(QtCore.QEventLoop.AllEvents, 50) def show_notification(self, err): msg = QtWidgets.QMessageBox() msg.setIcon(QtWidgets.QMessageBox.Warning) msg.setText("Chybné parametry sweepu.") msg.setInformativeText(err) msg.setWindowTitle("Sweeper - varování") msg.exec_()
class GuiProgram(Ui_sweepergui): cols = 0 sweep_id = 0 full_data = [] negative_current = False log_sweep = True stop = True decade_combo_values = ['5', '10', '25', '50'] def __init__(self, dialog): Ui_sweepergui.__init__(self) self.setupUi(dialog) # Connect "add" button with a custom function (addInputTextToListbox) self.exportButton.clicked.connect(self.export_data) self.startBtn.clicked.connect(self.startFunc) self.logRadioButton.clicked.connect(self.switch_linear) self.linRadioButton.clicked.connect(self.switch_linear) # Populate comboBox self.decadeComboBox.clear() self.decadeComboBox.addItems(self.decade_combo_values) self.decadeComboBox.setCurrentIndex(1) # Try to load last parameters from Pickle self.load_parameters() # Připojení k instrumentu #self.inst = Instrument('GPIB0::17::INSTR', visa_location='C:\WINDOWS\SysWOW64\\visa32.dll') self.inst = Instrument('GPIB0::17::INSTR', virtual=False) def artSleep(self, sleepTime): """ Čeká čas sleepTime v sekundách, zatím ale každých 50 milisekund řeší akce, o které se někdo pokoušel v GUI. """ stop_time = QtCore.QTime() stop_time.restart() while stop_time.elapsed() < sleepTime * 1000: QtWidgets.QApplication.processEvents(QtCore.QEventLoop.AllEvents, 50) def plot_figure(self): fig1 = Figure() ax1f1 = fig1.add_subplot(111) ax1f1.plot(np.random.rand(5)) self.rmmpl() self.addmpl(fig1) def plot_data(self, data): fig1 = Figure() ax1f1 = fig1.add_subplot(111) ax1f1.set_xlabel('I [A]') ax1f1.set_ylabel('U [V]') ax1f1.set_title('Sweep ID: ' + self.sweep_id) for d in data: x, y = d ax1f1.plot(x, y, color='red') if self.log_sweep: ax1f1.set_xscale('log') else: ax1f1.set_xscale('linear') self.rmmpl() self.addmpl(fig1) def addmpl(self, fig): self.canvas = FigureCanvas(fig) self.mplvl.addWidget(self.canvas) self.canvas.draw() self.toolbar = NavigationToolbar(self.canvas, self.mplwindow, coordinates=True) self.mplvl.addWidget(self.toolbar) def rmmpl(self, ): self.mplvl.removeWidget(self.canvas) self.canvas.close() self.canvas.deleteLater() self.mplvl.removeWidget(self.toolbar) self.toolbar.close() self.toolbar.deleteLater() def save_parameters(self): parameters_dict = { 'sw_min': str(self.startEdit.text()), 'sw_max': str(self.endEdit.text()), 'step': str(self.stepEdit.text()), 'delay': int(self.delaySpinBox.value()), 'decade': int(self.decadeComboBox.currentIndex()), 'n': int(self.pocetMereniBox.value()), 'log_sweep': self.logRadioButton.isChecked(), 'lin_sweep': self.linRadioButton.isChecked(), 'sense_local': self.senseLocalRadioButton.isChecked(), 'sense_remote': self.senseRemoteRadioButton.isChecked(), 'col_source': self.sourceCheckBox.checkState(), 'col_delay': self.delayCheckBox.checkState(), 'col_measure': self.measureCheckBox.checkState(), 'col_time': self.timeCheckBox.checkState(), 'stabilize_time': self.stableSpinBox.value(), 'sleep_time': self.sleepSpinBox.value() } # For pickle, the file needs to be opened in binary mode, hence the "wb" with open("last_parameters.pickle", "wb") as params_file: pickle.dump(parameters_dict, params_file) def load_parameters(self): try: # For pickle, the file needs to be opened in binary mode, hence the "wb" with open("last_parameters.pickle", "rb") as params_file: parameters_dict = pickle.load(params_file) self.startEdit.setText(parameters_dict['sw_min']) self.endEdit.setText(parameters_dict['sw_max']) self.stepEdit.setText(parameters_dict['step']) self.delaySpinBox.setValue(parameters_dict['delay']) self.decadeComboBox.setCurrentIndex(parameters_dict['decade']) self.pocetMereniBox.setValue(parameters_dict['n']) self.logRadioButton.setChecked(parameters_dict['log_sweep']) self.linRadioButton.setChecked(parameters_dict['lin_sweep']) self.senseLocalRadioButton.setChecked( parameters_dict['sense_local']) self.senseRemoteRadioButton.setChecked( parameters_dict['sense_remote']) self.sourceCheckBox.setChecked(parameters_dict['col_source']) self.delayCheckBox.setChecked(parameters_dict['col_delay']) self.measureCheckBox.setChecked(parameters_dict['col_measure']) self.timeCheckBox.setChecked(parameters_dict['col_time']) self.stableSpinBox.setValue(parameters_dict['stabilize_time']) self.sleepSpinBox.setValue(parameters_dict['sleep_time']) self.switch_linear() print("Nacteni poslednich parametru uspesne! :)") except: print("Nacteni poslednich parametru selhalo. :(") def validateInput(self, sw_min, sw_max, decade, delay, log_sweep, step): # Unit testing :P try: a = float(sw_min) a = float(sw_max) if not log_sweep: a = float(step) except: return False # Code if log_sweep: if (float(sw_min) > 0 and float(sw_max) > 0 and float(sw_min) != float(sw_max)): return True else: return False else: # lin sweep if (float(sw_min) != float(sw_max) and abs(float(sw_max) - float(sw_min)) > float(step)): return True else: return False def stopFunc(self): print('ABORT! Attempted to STOP sweep!') self.inst.operate(False) self.stop = True def startFunc(self): ''' Posbírá z GUI parametry a odpovídajícím způsobem přeloží.''' # vypnout ruční brzdu self.stop = False # aktuální čas pro ID self.sweep_id = '{0:%Y-%m-%d_%H-%M-%S}'.format(datetime.datetime.now()) sw_min = str(self.startEdit.text()) sw_max = str(self.endEdit.text()) step = str(self.stepEdit.text()) delay = str(self.delaySpinBox.value()) decade = str(self.decadeComboBox.currentIndex()) n = self.pocetMereniBox.value() self.bigProgBar.setValue(0) self.bigProgBar.setMaximum(n) self.littleProgBar.setValue(0) log_sweep = self.logRadioButton.isChecked() lin_sweep = self.linRadioButton.isChecked() self.log_sweep = log_sweep sense_local = self.senseLocalRadioButton.isChecked() sense_remote = self.senseRemoteRadioButton.isChecked() self.sense_local = sense_local col_source = self.sourceCheckBox.checkState() col_delay = self.delayCheckBox.checkState() col_measure = self.measureCheckBox.checkState() col_time = self.timeCheckBox.checkState() self.cols = 0 if col_source: self.cols += 1 if col_delay: self.cols += 2 if col_measure: self.cols += 4 if col_time: self.cols += 8 if self.validateInput(sw_min, sw_max, decade, delay, log_sweep, step): self.save_parameters() self.measure(sw_min, sw_max, decade, delay, log_sweep, step, n) else: print('Input failed validation.') self.show_notification('failed_validation') def show_notification(self, code): if code == 'failed_validation': msg = QtWidgets.QMessageBox() msg.setIcon(QtWidgets.QMessageBox.Warning) msg.setText("Chybné parametry sweepu.") msg.setInformativeText("") msg.setWindowTitle("Sweeper - varování") msg.setDetailedText("TODO") msg.exec_() def measure(self, sw_min, sw_max, decade, delay, log_sweep, step, n): ''' Spustí měření s již validovanými parametry. ''' # Disable UI self.enable_ui(False) # Declare Export not done on this sweep self.exportButton.setText('Export') # Local or Remote sense? if self.sense_local: print("Zapinam Sense - LOCAL.") self.inst.write("O0X") else: print("Zapinam Sense - REMOTE.") self.inst.write("O1X") # Úvodní stabilizace stabilize_time = self.stableSpinBox.value() print("Uvodni stabilizace v DC modu - {} s.".format(stabilize_time)) self.stabilize(sw_min, stabilize_time) # Nastavení sweepu self.inst.set_source_and_function('I', 'Sweep') # Nastavení formátu dat self.inst.write("G" + str(self.cols) + ",2,2X") if self.log_sweep: self.inst.write("Q2," + sw_min + "," + sw_max + "," + decade + ",0," + delay + "X") else: self.inst.write("Q1," + sw_min + "," + sw_max + "," + step + ",0," + delay + "X") data = [] self.full_data = [] n_hotovych_mereni = 0 for mereni in range(n): if self.stop: break output = self.run_sweep() if output: sweep_results = misc.nice_format(output, cols=self.cols) data.append(misc.unpack(sweep_results, cols=self.cols)) self.full_data.append(sweep_results) print('Ukladam docasna data...') self.dump_data() n_hotovych_mereni += 1 self.bigProgBar.setValue(n_hotovych_mereni) self.plot_data(data) if n_hotovych_mereni != n: sleep_time = self.sleepSpinBox.value() print("Pauza mezi sweepy - {} s.".format(sleep_time)) self.artSleep(sleep_time) else: print("Output was empty. Interrupted measurement?") self.inst.operate(False) self.enable_ui(True) #self.plot_data(data) def run_sweep(self): ''' Provede jeden sweep, který už musí být definovaný ve stroji. Na konci 3 vteřiny spí, aby se mělo napětí čas ustálit před dalším měřením. Vrací string se všemi hodnotami sweepu. ''' print('\nSpoustim sweep...') self.inst.write("U8X") out = self.inst.read() print('U8X -> ' + out) out = out.replace('\r', '').replace('\n', '') print("Out: {}".format(out)) sweep_defined_size = int(out[-4:]) print('Pocet bodu ve sweepu: ' + str(sweep_defined_size)) self.littleProgBar.setValue(0) self.inst.trigger() # Immediate trigger sweep_done = False while not sweep_done: if self.stop: break self.artSleep(0.2) self.inst.write("U11X") status = self.inst.read() if (status == 'SMS' + str(sweep_defined_size).zfill(4) + '\r\n'): sweep_done = True else: status_edit = status.replace('\r', '').replace('\n', '') try: progress = int(status_edit[-4:]) self.littleProgBar.setValue( int(progress / sweep_defined_size * 100)) except: print('Invalid progress!') print('Jeden sweep hotov.') self.littleProgBar.setValue(100) if self.stop: return "" else: return self.inst.read() def stabilize(self, bias, stabilize_time): # Počáteční stabilizace self.inst.set_source_and_function('I', 'DC') self.inst.write("B" + bias + ",0,20X") self.inst.operate(True) self.inst.trigger() self.artSleep(stabilize_time) def switch_linear(self): log_sweep = self.logRadioButton.isChecked() lin_sweep = self.linRadioButton.isChecked() if log_sweep: self.stepEdit.setEnabled(False) self.decadeComboBox.setEnabled(True) else: self.decadeComboBox.setEnabled(False) self.stepEdit.setEnabled(True) def enable_ui(self, status): ui_elements = [ self.startEdit, self.endEdit, self.stepEdit, self.delaySpinBox, self.decadeComboBox, self.pocetMereniBox, self.logRadioButton, self.linRadioButton, self.senseLocalRadioButton, self.senseRemoteRadioButton, self.sourceCheckBox, self.delayCheckBox, self.measureCheckBox, self.timeCheckBox, self.stableSpinBox, self.sleepSpinBox, ] for element in ui_elements: element.setEnabled(status) if status: self.switch_linear() if status: self.startBtn.clicked.disconnect() self.startBtn.clicked.connect(self.startFunc) self.startBtn.setText("Start") else: self.startBtn.clicked.disconnect() self.startBtn.clicked.connect(self.stopFunc) self.startBtn.setText("Abort") self.exportButton.setText('Export') def get_export_data(self): output = "" output += '# ======== Sweep ID: ' + self.sweep_id + ' ========' + '\n' output += '# ======== ' + str(len( self.full_data)) + ' sweeps' + ' ========' + '\n' output += self.get_measurement_parameters() for data in self.full_data: output += '# ======== SWEEP START ========\n' output += data.replace(',', ' ') output += '# ======== SWEEP END ========\n\n' return output def dump_data(self): save_file_name = 'C:\Repa\k237\sweeper\data_temp.txt' try: with open(save_file_name, "w", encoding="utf-8") as text_file: text = self.get_export_data() text_file.write(text) except: print("Nouzovy dump se nepovedl.") def export_data(self): """ Exportuje data pomocí ukládacího dialogu Qt. V případě chybného zadání souboru nic neudělá a postěžuje si do konzole. """ proposed_name = self.sweep_id # Qt Dialog na výběr souboru k uložení save_file_name, _ = QtWidgets.QFileDialog.getSaveFileName( None, 'Exportovat výsledky měření', 'C:\Repa\k237\data\sweep_' + proposed_name + '.txt', 'Text Files (*.txt);;All Files (*)') # Vlastní uložení souboru try: with open(save_file_name, "w", encoding="utf-8") as text_file: text = self.get_export_data() text_file.write(text) # Update GUI self.exportButton.setText('Export ✔') except: print("Export neuspesny. Data pravdepodobne nejsou ulozena!") # Update GUI self.exportButton.setText('Export ✗') def get_measurement_parameters(self): out = '' out += "# Sweep ID: {}\n".format(self.sweep_id) if self.log_sweep: out += "# Log sweep:\n" out += "# Rozsah (min, max) [A]: {}, {}\n".format( self.startEdit.text(), self.endEdit.text()) out += "# Bodů na dekádu [-]: {}\n".format( self.decade_combo_values[self.decadeComboBox.currentIndex()]) else: out += "# Linear sweep\n" out += "# Rozsah (min, max, points) [A]: {}, {}, {}\n".format( self.startEdit.text(), self.endEdit.text(), self.stepEdit.text()) out += "# Delay [ms]: {}\n".format(self.delaySpinBox.value()) out += "# Počet charakteristik [-]: {}\n".format( self.pocetMereniBox.value()) if self.sense_local: out += "# Sense: local\n" else: out += "# Sense: remote\n" out += "# Sloupce (Source, Measure, Delay, Time): {} {} {} {}\n".format( int(self.sourceCheckBox.checkState() / 2), int(self.measureCheckBox.checkState() / 2), int(self.delayCheckBox.checkState() / 2), int(self.timeCheckBox.checkState() / 2)) out += "# Uvodní DC stabilizace [s]: {}\n".format( self.stableSpinBox.value()) out += "# Stabilizace [s]: {}\n".format(self.sleepSpinBox.value()) return out
class Main(QMainWindow, Ui_MainWindow): def __init__(self, ): super(Main, self).__init__() self.setupUi(self) self.showMaximized() self.ave = np.array([]) # empty array for average bore self.auto_flag = False # autoscale flag self.spinBoxval = 0 # defualt 4D data_cube dimension self.spinBox.hide() # hide option unless 4D self.colourmap = 'viridis' # default colourmap self.interpMethod = 'nearest' # default interp method self.cmapmin = None # default colourbar range, i.e let matplotlib decide self.cmapmax = None self.hres = 1 # default res, i.e jut voxel numbers on axis self.vres = 1 self.Normx = None # normalisation method. default set to None self.Normy = None self.Normz = None self.XView.setChecked(True) self.fig = Figure() self.ax1 = self.fig.add_subplot(111) self.X = datacube() self.AveBoreView = 'X' # change view of cube self.XView.toggled.connect(lambda: self.btnstate(self.XView)) self.YView.toggled.connect(lambda: self.btnstate(self.YView)) self.ZView.toggled.connect(lambda: self.btnstate(self.ZView)) self.Bore.toggled.connect(lambda: self.btnstate(self.Bore)) self.AverageBore.toggled.connect( lambda: self.btnstate(self.AverageBore)) # update data when slider moved self.Scroll_Horz.valueChanged[int].connect(self.sliderval) self.Scroll_Vert.valueChanged[int].connect(self.sliderval) self.file_open(args) self.Open.triggered.connect(self.file_open) self.Save_Avg_Bore.triggered.connect(self.saveBore) self.Reset.triggered.connect(self.reset_plot) self.AutoScale.triggered.connect(self.Auto_Scale_plot) # self.Bore_View.triggered.connect(self.ViewBore) self.action_Save_Gif.triggered.connect(self.saveGif) self.action_Colour_Map.triggered.connect(self.changeColourMap) self.action_Interpolation_Method.triggered.connect(self.changeInterpolationMethod) self.action_Colour_Bar_Clip.triggered.connect(self.changeclipColourBarRange) self.action_Save_Image.triggered.connect(self.saveImage) self.action_Normalisation_Method.triggered.connect(self.changeNormMethod) self.action_Bore_Location.triggered.connect(self.setBoreLocation) self.spinBox.valueChanged.connect(self.changeSpinbox) def setBoreLocation(self, ): xloc, ok = QtWidgets.QInputDialog.getInt( self, 'Input location', 'Enter X location:') yloc, ok = QtWidgets.QInputDialog.getInt( self, 'Input location', 'Enter Y location:') self.Scroll_Horz.setValue(xloc) self.Scroll_Vert.setValue(yloc) if self.Bore.isChecked(): if self.BoreView == 'X': self.im.set_ydata(self.X.data[:, xloc, yloc][::]) elif self.BoreView == 'Y': self.im.set_ydata(self.X.data[xloc, :, yloc][::]) elif self.BoreView == 'Z': self.im.set_ydata(self.X.data[yloc, xloc, :][::]) # try and redraw try: self.im.axes.figure.canvas.draw() if self.auto_flag: self.im.autoscale() except AttributeError: pass def changeNormMethod(self, ): # func to change Normalisation method of matshow method = self.getNormDialog() if(method == 'Log'): self.Normx = colors.LogNorm(vmin=0.1, vmax=self.X.data[self.ind, :, :].max()) self.Normy = colors.LogNorm(vmin=0.1, vmax=self.X.data[:, self.ind, :].max()) self.Normz = colors.LogNorm(vmin=0.1, vmax=self.X.data[:, :, self.ind].max()) elif(method == 'Symmetric Log'): self.Normx = colors.SymLogNorm(linthresh=1., vmin=self.X.data[self.ind, :, :].min(), vmax=self.X.data[self.ind, :, :].max()) self.Normy = colors.SymLogNorm(linthresh=1., vmin=self.X.data[:, self.ind, :].min(), vmax=self.X.data[:, self.ind, :].max()) self.Normz = colors.SymLogNorm(linthresh=1., vmin=self.X.data[:, :, self.ind].max(), vmax=self.X.data[:, :, self.ind].max()) elif(method == 'Linear'): self.Normx = None self.Normy = None self.Normz = None self.reset_plot(False) self.init_plot() def saveImage(self, ): # saves data and image of current view name = self.showGifDialog() if self.XView.isChecked(): np.savetxt(name + '.dat', self.X.data[self.Scroll_Vert.value(), :, :], delimiter=' ') elif self.YView.isChecked(): np.savetxt(name + '.dat', self.X.data[:, self.Scroll_Vert.value(), :], delimiter=' ') elif self.ZView.isChecked(): np.savetxt(name + '.dat', self.X.data[:, :, self.Scroll_Vert.value()], delimiter=' ') self.hres, self.vres = self.showextentDialog() # scale x, y ticks to actual scale based upon user definition # thanks https://stackoverflow.com/a/17816809/6106938 # change so that it uses extent=[xmin, xmax, ymin, ymax] # set default as None # then change here. extent added to matshow(*args, extent=[...]) ticks = ticker.FuncFormatter(lambda x, pos: '{0:g}'.format(x * self.hres)) self.ax1.xaxis.set_major_formatter(ticks) ticks = ticker.FuncFormatter(lambda y, pos: '{0:g}'.format(y * self.vres)) self.ax1.yaxis.set_major_formatter(ticks) self.fig.savefig(name + '.png') def changeColourMap(self, ): # change cmap self.colourmap = self.showColourmapsDialog() self.reset_plot(False) self.init_plot() def changeclipColourBarRange(self, ): # change vmin, vmax for cbar self.cmapmin, self.cmapmax = self.showclipColourBarDialog() self.reset_plot(False) self.init_plot() def changeInterpolationMethod(self, ): # change interpolation method for image self.interpMethod = str(self.showInterpolationDialog()) self.reset_plot(False) self.init_plot() def saveGif(self): rang = self.showGifframesDialog() # get range of frames step = self.showGifstepDialog() # get number of images name = self.showGifDialog() # name of file tight = self.showGifExtent() # tight or not # loop over range and make images tmpplace = self.Scroll_Vert.value() if rang * step > tmpplace: rang = tmpplace for i in range(rang): self.Scroll_Horz.setValue(self.ind) self.Scroll_Vert.setValue(tmpplace - (i * step)) self.sliderval() if tight: extent = self.ax1.get_window_extent().transformed(fig.dpi_scale_trans.inverted()) self.fig.savefig(str(i).zfill(3) + 'pic.png', bbox_inches=extent) else: self.fig.savefig(str(i).zfill(3) + 'pic.png') # use ffmpeg to create gif if tight: os.system("mogrify -trim *pic.png") os.system("ffmpeg -framerate 10 -pattern_type glob -i '*pic.png' -c:v libx264 -r 24 -pix_fmt yuv420p -vf 'pad=ceil(iw/2)*2:ceil(ih/2)*2' " + name + ".mp4") os.system('rm *pic.png') print('done') def changeSpinbox(self): # for 4d data cubes self.spinBoxval = int(self.spinBox.value()) fd = open(self.name, 'rb') self.readslice(fd, self.ndim, np.float64, self.cubeorder) self.reset_plot() self.init_plot() def Auto_Scale_plot(self): # autoscale cbar on plot and reset clipping if any self.cmapmin = None self.cmapmax = None if not self.auto_flag: self.auto_flag = True else: self.auto_flag = False def sliderval(self): # move slider and update data if self.XView.isChecked(): # fd = open(self.name, 'rb') self.X.readslice(self.Scroll_Horz.value()) self.im.set_data(self.X.data[self.Scroll_Vert.value(), :, :]) # self.Scroll_Horz.setValue(0) # pin unsed slider elif self.YView.isChecked(): self.X.readslice(self.Scroll_Horz.value()) self.im.set_data(self.X.data[:, self.Scroll_Vert.value(), :]) # self.Scroll_Horz.setValue(0) # pin unsed slider elif self.ZView.isChecked(): self.X.readslice(self.Scroll_Horz.value()) self.im.set_data(self.X.data[:, :, self.Scroll_Vert.value()]) # self.Scroll_Horz.setValue(0) # pin unsed slider elif self.Bore.isChecked(): if self.BoreView == 'X': self.im.set_ydata(self.X.data[:, self.Scroll_Horz.value(), self.Scroll_Vert.value()][::]) if self.auto_flag: self.ax1.relim() self.ax1.autoscale_view(True, True, True) elif self.BoreView == 'Y': self.im.set_ydata(self.X.data[self.Scroll_Horz.value(), :, self.Scroll_Vert.value()][::]) if self.auto_flag: self.ax1.relim() self.ax1.autoscale_view(True, True, True) elif self.BoreView == 'Z': self.im.set_ydata(self.X.data[self.Scroll_Vert.value(), self.Scroll_Horz.value(), :][::]) if self.auto_flag: self.ax1.relim() self.ax1.autoscale_view(True, True, True) elif self.AverageBore.isChecked(): self.Scroll_Horz.setValue(self.ind) self.Scroll_Vert.setValue(self.ind) # try and redraw try: self.im.axes.figure.canvas.draw() if self.auto_flag: self.im.autoscale() except AttributeError: pass def addmpl(self): # add plot to anvas self.rmmpl() self.canvas = FigureCanvas(self.fig) self.mplvl.addWidget(self.canvas) self.canvas.draw() self.toolbar = NavigationToolbar(self.canvas, self.mplwindow) self.mplvl.addWidget(self.toolbar) def rmmpl(self): # delete plot from canvas try: self.canvas.close() self.canvas.deleteLater() self.toolbar.close() self.toolbar.deleteLater() gc.collect() except: pass def saveBore(self,): # save bore as a list of points name = QtWidgets.QFileDialog.getSaveFileName(self, 'Save File') f = open(name, 'w') if len(self.ave) > 1: for i in range(len(self.ave)): f.write(str(self.ave[i]) + '\n') f.close() else: if self.BoreView == "X": tmp = self.X[:, self.Scroll_Horz.value(), self.Scroll_Vert.value()] elif self.BoreView == "Y": tmp = self.X[self.Scroll_Horz.value(), :, self.Scroll_Vert.value()] elif self.BoreView == "Z": tmp = self.X[self.Scroll_Horz.value(), self.Scroll_Vert.value(), :] for i in range(len(tmp)): f.write(str(tmp[i]) + '\n') def file_open(self, args): self.reset_plot() while True: try: # get file name if args.file is None: self.X.name = QtWidgets.QFileDialog.getOpenFileName(self, 'Open File')[0] else: self.X.name = args.file # get precision of data cube self.X.dtype, self.X.cubeorder, item = self.getPrec(args) # get dimensions of data cube. can be guessed bool4d = False if self.X.cubeorder == 4: bool4d = True self.X.ndim = self.getSize(args, item, bool4d) try: fd = open(self.X.name, 'rb') except FileNotFoundError: self.ErrorDialog("File not Found!") self.X.name = QtWidgets.QFileDialog.getOpenFileName(self, 'Open File')[0] self.X.readslice(0) self.init_plot() break except ValueError: size = os.path.getsize(self.X.name) if "Real*8" in item: size /= 8 elif "Real*4" in item: size /= 4 mssg = "Value of Ndim or precision is incorrect for this data cube.\n On disk size is: {:010d}.\n".format(int(size)) val2 = self.X.is_perfect_n(size, 2.) val3 = self.X.is_perfect_n(size, 3.) if (val2 and val3) != 0: mssg += " Try x=y={:04d}, z=1\n or x=y=z={:04d}.".format(int(val2), int(val3)) elif val2 != 0: mssg += "Try x=y={:04d}, z=1.".format(int(val2)) elif val3 != 0: mssg += "Try x=y=z={:04d}.".format(int(val3)) self.ErrorDialog(mssg) args.ndim = None args.fpprec = None except UnboundLocalError: pass break def getSize(self, args, item, bool4d): if args.ndim is None and item: size = os.path.getsize(self.X.name) if "Real*8" in item: size /= 8 elif "Real*4" in item: size /= 4 if self.X.is_perfect_n(size, 3.) != 0: size = self.X.is_perfect_n(size, 3.) ndim = (size, size, size) else: ndim = self.showNdimDialog(bool4d) else: ndim = (args.ndim, args.ndim, args.ndim) return ndim def getPrec(self, args): # get precision of data cube item = None if args.fpprec is None: item = str(self.showDtDialog()) if "Real*8" in item: dt = np.float64 elif "Real*4" in item: dt = np.float32 if "4 dim" in item: dim = 4 elif "3 dim" in item: dim = 3 else: if args.fpprec == 1: dt = np.float32 dim = 4 elif args.fpprec == 2: dt = np.float64 dim = 4 elif args.fpprec == 3: dt = np.float32 dim = 3 elif args.fpprec == 4: dt = np.float64 dim = 3 return dt, dim, item def btnstate(self, b): if b.text() == "X View": if b.isChecked() is True: self.reset_plot(False) self.Scroll_Vert.setMaximum(self.rows - 1) self.im = self.ax1.matshow(self.X.data[self.ind, :, :], vmin=self.cmapmin, vmax=self.cmapmax, cmap=str(self.colourmap), interpolation=self.interpMethod, norm=self.Normx) self.fig.colorbar(self.im) self.fig.set_tight_layout(True) self.ax1.set_aspect('auto') self.addmpl() if b.text() == "Y View": if b.isChecked() is True: self.reset_plot(False) self.Scroll_Vert.setMaximum(self.cols - 1) self.im = self.ax1.matshow(self.X.data[:, self.ind, :], vmin=self.cmapmin, vmax=self.cmapmax, cmap=str(self.colourmap), interpolation=self.interpMethod, norm=self.Normy) self.fig.colorbar(self.im) self.fig.set_tight_layout(True) self.ax1.set_aspect('auto') self.addmpl() if b.text() == "Z View": if b.isChecked() is True: self.reset_plot(False) self.Scroll_Vert.setMaximum(self.slices - 1) self.im = self.ax1.matshow(self.X.data[:, :, self.ind], vmin=self.cmapmin, vmax=self.cmapmax, cmap=str(self.colourmap), interpolation=self.interpMethod, norm=self.Normz) try: self.fig.colorbar(self.im) except ZeroDivisionError: self.ErrorDialog("Divison by zero, try another range") self.Normz = None self.Normy = None self.Normz = None self.cmapmin = None self.cmapmax = None self.btnstate(b) self.fig.set_tight_layout(True) self.ax1.set_aspect('auto') self.addmpl() if b.text() == "Draw Bore": if b.isChecked() is True: self.ViewBore() self.reset_plot(False) if self.BoreView == 'X': self.im, = self.ax1.plot(self.X.data[:, self.ind, self.ind]) elif self.BoreView == 'Y': self.im, = self.ax1.plot(self.X.data[self.ind, :, self.ind]) elif self.BoreView == 'Z': self.im, = self.ax1.plot(self.X.data[self.ind, self.ind, :]) self.fig.set_tight_layout(True) self.addmpl() if b.text() == "Avg. Bore": if b.isChecked() is True: self.AveBoreChecked() def ViewBore(self): self.BoreView = self.showBoreViewDialog() if self.BoreView == 'X': self.view = (1, 2) elif self.BoreView == 'Y': self.view = (0, 2) elif self.BoreView == 'Z': self.view = (0, 1) def AveBoreChecked(self): self.ViewBore() self.reset_plot(False) if len(self.ave) == 0: self.ave = np.array([]) self.ave = np.sum(self.X.data, self.view) self.ave /= (len(self.X.data[self.view[0]]) * len(self.X.data[self.view[1]])) self.im = self.ax1.plot(self.ave[::]) self.fig.set_tight_layout(True) self.addmpl() def reset_plot(self, *args): self.ave = np.array([]) self.fig.clf() self.ax1.clear() gc.collect() # fixes most of memory leak self.fig = Figure() self.ax1 = self.fig.add_subplot(111) self.rmmpl() def init_plot(self, ): self.rmmpl() if self.X.cubeorder == 4: self.rows, self.cols, self.slices, self.depth = self.X.ndim else: self.rows, self.cols, self.slices = self.X.ndim self.depth = 0 self.ind = 0 # int(rows / 2) if self.XView.isChecked(): view = self.XView self.Scroll_Vert.setMaximum(self.rows) self.Scroll_Horz.setMaximum(self.depth) elif self.YView.isChecked(): view = self.YView self.Scroll_Vert.setMaximum(self.cols) self.Scroll_Horz.setMaximum(self.depth) elif self.ZView.isChecked(): view = self.ZView self.Scroll_Vert.setMaximum(self.slices) self.Scroll_Horz.setMaximum(self.cols) elif self.AverageBore.isChecked(): view = self.AverageBore self.Scroll_Vert.setMaximum(self.rows) elif self.Bore_View.isChecked(): view = self.ViewBore self.Scroll_Vert.setMaximum(self.cols) self.Scroll_Horz.setMaximum(self.rows) self.btnstate(view) self.Scroll_Horz.setValue(self.ind) self.Scroll_Vert.setValue(self.ind) def showGifframesDialog(self, ): text, ok = QtWidgets.QInputDialog.getInt( self, '# of frames', 'Enter # of frames:') if ok: return(text) def showGifstepDialog(self, ): text, ok = QtWidgets.QInputDialog.getInt( self, 'Step size', 'Enter value of step:') if ok: return(text) def showGifExtent(self, ): items = ("Colour Bar", "No Colour Bar") text, ok = QtWidgets.QInputDialog.getItem( self, "Colour Bar on GIF?", " ", items, 0, False) if ok and text: if items == "Colour Bar": text = False else: text = True return text def showNdimDialog(self, bool4d): text1, ok1 = QtWidgets.QInputDialog.getInt( self, 'Input Ndim', 'Enter X Ndim:') if ok1: text2, ok2 = QtWidgets.QInputDialog.getInt( self, 'Input Ndim', 'Enter Y Ndim:') if ok2: text3, ok3 = QtWidgets.QInputDialog.getInt( self, 'Input Ndim', 'Enter Z Ndim:') if ok3 and bool4d: text4, ok4 = QtWidgets.QInputDialog.getInt( self, 'Input Ndim', 'Enter T Ndim:') return (text1, text2, text3, text4) else: return (text1, text2, text3) def showDtDialog(self, ): items = ("4 dim Real*4", "4 dim Real*8", "3 dim Real*4", "3 dim Real*8") item, ok = QtWidgets.QInputDialog.getItem(self, "Select Fortran Precision", "Precisions", items, 0, False) if ok and item: return item def showBoreViewDialog(self, ): items = ("X", "Y", "Z") item, ok = QtWidgets.QInputDialog.getItem(self, "Select Average Bore Direction", "Views", items, 0, False) if ok and item: return item def showGifDialog(self, ): text, ok = QtWidgets.QInputDialog.getText( self, 'Filename Dialog', 'Enter filename:') if ok: return str(text) def showextentDialog(self, ): hres, ok = QtWidgets.QInputDialog.getDouble( self, 'Data Extent', 'Enter horizontal resolution:', 0, -100, 100, 9,) if ok: vres, ok = QtWidgets.QInputDialog.getDouble( self, 'Data Extent', 'Enter vertical resolution:', 0, -100, 100, 9,) if ok: return (hres, vres) def getNormDialog(self, ): items = ("Log", "Linear", "Symmetric Log") item, ok = QtWidgets.QInputDialog.getItem(self, "Select cbar normalisation method", "Method:", items, 0, False) if ok and item: return item def showColourmapsDialog(self, ): items = ('viridis', 'inferno', 'plasma', 'magma', 'Blues', 'BuGn', 'BuPu', 'GnBu', 'Greens', 'Greys', 'Oranges', 'OrRd', 'PuBu', 'PuBuGn', 'PuRd', 'Purples', 'RdPu', 'Reds', 'YlGn', 'YlGnBu', 'YlOrBr', 'YlOrRd', 'afmhot', 'autumn', 'bone', 'cool', 'copper', 'gist_heat', 'gray', 'hot', 'pink', 'spring', 'summer', 'winter', 'BrBG', 'bwr', 'coolwarm', 'PiYG', 'PRGn', 'PuOr', 'RdBu', 'RdGy', 'RdYlBu', 'RdYlGn', 'Spectral', 'seismic', 'Accent', 'Dark2', 'Paired', 'Pastel1', 'Pastel2', 'Set1', 'Set2', 'Set3', 'Vega10', 'Vega20', 'Vega20b', 'Vega20c', 'gist_earth', 'terrain', 'ocean', 'gist_stern', 'brg', 'CMRmap', 'cubehelix', 'gnuplot', 'gnuplot2', 'gist_ncar', 'nipy_spectral', 'jet', 'rainbow', 'gist_rainbow', 'hsv', 'flag', 'prism') item, ok = QtWidgets.QInputDialog.getItem(self, "Select Colour Map", "Cmaps", items, 0, False) if ok and item: return item def showInterpolationDialog(self, ): items = ('none', 'nearest', 'bilinear', 'bicubic', 'spline16', 'spline36', 'hanning', 'hamming', 'hermite', 'kaiser', 'quadric', 'catrom', 'gaussian', 'bessel', 'mitchell', 'sinc', 'lanczos') item, ok = QtWidgets.QInputDialog.getItem(self, "Select Interpolation Method", "Methods", items, 0, False) if ok and item: return item def showclipColourBarDialog(self, ): text1, ok1 = QtWidgets.QInputDialog.getDouble( self, 'Input cbar min', 'Enter min:', 0., np.finfo("d").min, np.finfo("d").max, 10) if ok1: text2, ok2 = QtWidgets.QInputDialog.getDouble( self, 'Input cbar max', 'Enter max:', 0., np.finfo("d").min, np.finfo("d").max, 10) if ok2: return (float(text1), float(text2)) def ErrorDialog(self, ErrMsg): QtWidgets.QMessageBox.warning(self, "Error", ErrMsg)