def __init__(self, path_prj, name_prj): super().__init__() self.tab_name = "estimhab" self.tab_position = 7 self.model_type = "Estimhab" self.eq50 = QLineEdit() self.esub = QLineEdit() self.path_prj = path_prj self.name_prj = name_prj self.path_bio_estimhab = os.path.join(self.path_bio, 'estimhab') self.total_lineedit_number = 1 self.init_iu() self.process_manager = MyProcessManager( "estimhab_plot") # SC (Suitability Curve) self.read_estimhab_dict() self.fill_input_data() self.fill_fish_name() self.check_if_ready_to_compute() self.eq1.textChanged.connect(self.check_if_ready_to_compute) self.eq2.textChanged.connect(self.check_if_ready_to_compute) self.ew1.textChanged.connect(self.check_if_ready_to_compute) self.ew2.textChanged.connect(self.check_if_ready_to_compute) self.eh1.textChanged.connect(self.check_if_ready_to_compute) self.eh2.textChanged.connect(self.check_if_ready_to_compute) self.eq50.textChanged.connect(self.check_if_ready_to_compute) self.eqmin.textChanged.connect(self.check_if_ready_to_compute) self.eqmax.textChanged.connect(self.check_if_ready_to_compute) self.esub.textChanged.connect(self.check_if_ready_to_compute) self.selected_aquatic_animal_qtablewidget.model().rowsInserted.connect( self.check_if_ready_to_compute) self.selected_aquatic_animal_qtablewidget.model().rowsRemoved.connect( self.check_if_ready_to_compute)
def __init__(self, path_prj, name_prj, send_log, title): super().__init__() self.path_prj = path_prj self.name_prj = name_prj self.send_log = send_log self.path_last_file_loaded = self.path_prj self.project_properties = load_project_properties(self.path_prj) self.setTitle(title) self.init_ui() # process_manager self.process_manager = MyProcessManager("hrr")
def __init__(self, path_prj, name_prj, send_log, title): super().__init__() self.path_prj = path_prj self.name_prj = name_prj self.send_log = send_log self.path_last_file_loaded = self.path_prj self.project_properties = load_project_properties(self.path_prj) self.setTitle(title) self.init_ui() self.msg2 = QMessageBox() self.mesh_manager_file = self.read_attribute_xml("mesh_manager_file") self.read_mesh_manager_file(self.mesh_manager_file) # process_manager self.process_manager = MyProcessManager("mesh_manager")
def __init__(self, path_prj, name_prj, send_log, title): super().__init__() self.path_prj = path_prj self.name_prj = name_prj self.send_log = send_log self.path_last_file_loaded = self.path_prj self.classhv = None self.project_properties = load_project_properties(self.path_prj) self.setTitle(title) self.init_ui() self.input_class_file_info = self.read_attribute_xml("HS_input_class") self.read_input_class(os.path.join(self.input_class_file_info["path"], self.input_class_file_info["file"])) # process_manager self.process_manager = MyProcessManager("hs")
def __init__(self, path_prj, name_prj, send_log): super().__init__() self.tab_name = "interpolation" self.tab_title = "Interpolation" self.tooltip_str = self.tr("Interpolation of habitat values") self.path_prj = path_prj self.name_prj = name_prj self.send_log = send_log self.mytablemodel = None self.path_last_file_loaded = self.path_prj self.process_manager = MyProcessManager("interpolation") self.init_ui() self.process_prog_show = ProcessProgShow(send_log=self.send_log, # progress_bar=self.nativeParentWidget().progress_bar, # progress_label=self.progress_label, run_function=self.plot_chronicle, computation_pushbutton=self.plot_chronicle_qpushbutton)
def __init__(self, path_prj, name_prj, send_log, title): super().__init__() self.path_prj = path_prj self.name_prj = name_prj self.send_log = send_log self.path_last_file_loaded = self.path_prj self.process_manager = MyProcessManager("hs_plot") self.axe_mod_choosen = 1 self.setTitle(title) self.init_ui() self.process_prog_show_input = ProcessProgShow(send_log=self.send_log, run_function=self.plot_hs_class, computation_pushbutton=self.input_class_plot_button) self.process_prog_show_area = ProcessProgShow(send_log=self.send_log, run_function=self.plot_hs_area, computation_pushbutton=self.result_plot_button_area) self.process_prog_show_volume = ProcessProgShow(send_log=self.send_log, run_function=self.plot_hs_volume, computation_pushbutton=self.result_plot_button_volume)
def __init__(self, run_function, send_log, process_type, send_refresh_filenames=None): super().__init__() widget_height = QComboBox().minimumSizeHint().height() # send_log self.send_log = send_log # progress_bar self.progress_bar = QProgressBar() self.progress_bar.setMaximumHeight(widget_height) self.progress_bar.setValue(0.0) self.progress_bar.setRange(0.0, 100.0) self.progress_bar.setTextVisible(False) # progress_label self.progress_label = QLabel() self.progress_label.setText("{0:.0f}/{1:.0f}".format(0, 0)) # run_stop_button self.run_stop_button = QPushButton(self.tr("run")) self.run_stop_button.setMaximumHeight(widget_height) change_button_color(self.run_stop_button, "#47B5E6") #47B5E6 self.run_stop_button.clicked.connect( run_function) # self.collect_data_from_gui_and_plot self.run_stop_button.setEnabled(False) # layout self.addWidget(self.progress_bar) self.addWidget(self.progress_label) self.addWidget(self.run_stop_button) # process_manager # app = QCoreApplication([]) self.process_manager = MyProcessManager(process_type) # self.process_manager.finished.connect(app.exit) # process_prog_show self.process_prog_show = ProcessProgShow( send_log=self.send_log, send_refresh_filenames=send_refresh_filenames, progressbar=self.progress_bar, progress_label=self.progress_label, computation_pushbutton=self.run_stop_button, run_function=run_function)
class ComputingGroup(QGroupBoxCollapsible): """ This class is a subclass of class QGroupBox. """ send_refresh_filenames = pyqtSignal(name='send_refresh_filenames') def __init__(self, path_prj, name_prj, send_log, title): super().__init__() self.path_prj = path_prj self.name_prj = name_prj self.send_log = send_log self.path_last_file_loaded = self.path_prj self.project_properties = load_project_properties(self.path_prj) self.setTitle(title) self.init_ui() self.msg2 = QMessageBox() self.mesh_manager_file = self.read_attribute_xml("mesh_manager_file") self.read_mesh_manager_file(self.mesh_manager_file) # process_manager self.process_manager = MyProcessManager("mesh_manager") def init_ui(self): # file_selection file_selection_label = QLabel(self.tr("Select a 2D mesh file :")) self.file_selection_listwidget = QListWidget() self.file_selection_listwidget.setSelectionMode( QAbstractItemView.ExtendedSelection) self.file_selection_listwidget.itemSelectionChanged.connect( self.names_hdf5_change) self.file_selection_listwidget.setVerticalScrollBarPolicy( Qt.ScrollBarAlwaysOff) self.file_selection_listwidget.verticalScrollBar().setEnabled(True) self.file_selection_listwidget.verticalScrollBar( ).valueChanged.connect(self.change_scroll_position) self.scrollbar = self.file_selection_listwidget.verticalScrollBar() mesh_manager_file = QLabel(self.tr("Mesh manager file (.txt)")) self.mesh_manager_filename_label = QLabel("") self.mesh_manager_file_select_pushbutton = QPushButton("...") self.mesh_manager_file_select_pushbutton.clicked.connect( self.select_mesh_manager_file_dialog) # progress_layout self.progress_layout = ProcessProgLayout( self.compute, send_log=self.send_log, process_type="mesh_manager", send_refresh_filenames=self.send_refresh_filenames) file_selection_layout = QGridLayout() file_selection_layout.addWidget(file_selection_label, 0, 0) file_selection_layout.addWidget(self.file_selection_listwidget, 1, 0) file_selection_layout.addWidget(self.scrollbar, 1, 1) file_selection_layout.setColumnStretch(0, 30) file_selection_layout.setColumnStretch(1, 1) grid_layout = QGridLayout() grid_layout.addWidget(mesh_manager_file, 0, 0, Qt.AlignLeft) grid_layout.addWidget(self.mesh_manager_filename_label, 0, 1, Qt.AlignLeft) grid_layout.addWidget(self.mesh_manager_file_select_pushbutton, 0, 2, Qt.AlignLeft) grid_layout.addLayout(self.progress_layout, 1, 0, 1, 3) general_layout = QVBoxLayout() general_layout.addLayout(file_selection_layout) general_layout.addLayout(grid_layout) self.setLayout(general_layout) def update_gui(self): selected_file_names = [ selection_el.text() for selection_el in self.file_selection_listwidget.selectedItems() ] # computing_group hyd_names = get_filename_by_type_physic( "hydraulic", os.path.join(self.path_prj, "hdf5")) hab_names = get_filename_by_type_physic( "habitat", os.path.join(self.path_prj, "hdf5")) names = hyd_names + hab_names self.file_selection_listwidget.blockSignals(True) self.file_selection_listwidget.clear() if names: for name in names: # check try: hdf5 = Hdf5Management(self.path_prj, name, new=False, edit=False) hdf5.get_hdf5_attributes(close_file=True) item_name = QListWidgetItem() item_name.setText(name) self.file_selection_listwidget.addItem(item_name) if name in selected_file_names: item_name.setSelected(True) if True: #TODO : sort files (hdf5 attributes available for HRR) .hyd, one whole profile for all units, ... pass else: pass except: self.send_log.emit( self. tr("Error: " + name + " file seems to be corrupted. Delete it with HABBY or manually." )) self.file_selection_listwidget.blockSignals(False) # preselection if one if self.file_selection_listwidget.count() == 1: self.file_selection_listwidget.selectAll() def change_scroll_position(self, index): self.file_selection_listwidget.verticalScrollBar().setValue(index) def names_hdf5_change(self): selection = self.file_selection_listwidget.selectedItems() self.progress_layout.progress_bar.setValue(0.0) self.progress_layout.progress_label.setText("{0:.0f}/{1:.0f}".format( 0.0, len(selection))) if selection: self.progress_layout.run_stop_button.setEnabled(True) else: self.progress_layout.run_stop_button.setEnabled(False) def read_mesh_manager_file(self, mesh_manager_file): if os.path.exists(mesh_manager_file): self.mesh_manager_description, warnings_list = mesh_manager_from_file( mesh_manager_file) if warnings_list: for warning in warnings_list: self.send_log.emit(warning) if self.mesh_manager_description["mesh_manager_data"] is None: self.send_log.emit( self.tr("Error: Mesh manager file : ") + os.path.basename(mesh_manager_file) + self.tr(" is not valid.")) self.progress_layout.run_stop_button.setEnabled(False) else: self.mesh_manager_filename_label.setText( os.path.basename(mesh_manager_file)) if self.file_selection_listwidget.selectedItems(): self.progress_layout.run_stop_button.setEnabled(True) else: self.progress_layout.run_stop_button.setEnabled(False) self.progress_layout.progress_bar.setValue(0.0) self.progress_layout.progress_label.setText("{0:.0f}/{1:.0f}".format( 0.0, len(self.file_selection_listwidget.selectedItems()))) def select_mesh_manager_file_dialog(self): self.mesh_manager_file = self.read_attribute_xml("mesh_manager_file") # get last path if self.mesh_manager_file != self.path_prj and self.mesh_manager_file != "": model_path = self.mesh_manager_file # path spe elif self.read_attribute_xml( "path_last_file_loaded" ) != self.path_prj and self.read_attribute_xml( "path_last_file_loaded") != "": model_path = self.read_attribute_xml( "path_last_file_loaded") # path last else: model_path = self.path_prj # path proj filename, _ = QFileDialog.getOpenFileName( self, self.tr("Select a mesh manager file"), model_path, self.tr("Text files") + " (*.txt)") if filename: self.pathfile = filename # source file path self.save_xml("mesh_manager_file") self.read_mesh_manager_file(filename) self.mesh_manager_file = self.read_attribute_xml( "mesh_manager_file") def read_attribute_xml(self, att_here): """ A function to read the text of an attribute in the xml project file. :param att_here: the attribute name (string). """ data = '' filename_path_pro = os.path.join(self.path_prj, self.name_prj + '.habby') if os.path.isfile(filename_path_pro): if att_here in {"path_last_file_loaded"}: data = load_project_properties(self.path_prj)[att_here] else: try: data = load_project_properties(self.path_prj)[att_here] except KeyError: self.save_xml("mesh_manager_file") data = load_project_properties(self.path_prj)[att_here] else: pass return data def save_xml(self, attr): """ A function to save the loaded data in the xml file. This function adds the name and the path of the newly chosen hydrological data to the xml project file. First, it open the xml project file (and send an error if the project is not saved, or if it cannot find the project file). Then, it opens the xml file and add the path and name of the file to this xml file. If the model data was already loaded, it adds the new name without erasing the old name IF the switch append_name is True. Otherwise, it erase the old name and replace it by a new name. The variable “i” has the same role than in select_file_and_show_informations_dialog. :param i: a int for the case where there is more than one file to load :param append_name: A boolean. If True, the name found will be append to the existing name in the xml file, instead of remplacing the old name by the new name. """ filename_path_pro = os.path.join(self.path_prj, self.name_prj + '.habby') # save the name and the path in the xml .prj file if not os.path.isfile(filename_path_pro): self.end_log.emit( 'Error: The project is not saved. ' 'Save the project in the General tab before saving hydrological data. \n' ) else: # change path_last_file_loaded, model_type (path) self.project_properties = load_project_properties( self.path_prj) # load_project_properties self.project_properties[ "path_last_file_loaded"] = self.pathfile # change value self.project_properties[attr] = self.pathfile # change value save_project_properties( self.path_prj, self.project_properties) # save_project_properties def compute(self): if len(self.file_selection_listwidget.selectedItems()) > 0: mesh_manager_description = self.mesh_manager_description mesh_manager_description["hdf5_name_list"] = [ selection_el.text() for selection_el in self.file_selection_listwidget.selectedItems() ] # for hdf5_file in mesh_manager_description["hdf5_name_list"]: # hdf5_1 = Hdf5Management(self.path_prj, hdf5_file, new=False, edit=False) # hdf5_1.load_hdf5(whole_profil=False) # if hdf5_1.data_2d.hvum.hdf5_and_computable_list.habs(): # self.msg2.setIcon(QMessageBox.Warning) # self.msg2.setWindowTitle(self.tr("HSI data in ") + hdf5_1.filename[:-4] + "_MM" + hdf5_1.extension + ".") # self.msg2.setText(self.tr("If computing, existing HSI data will be removed in ") + hdf5_1.filename[:-4] + "_MM" + hdf5_1.extension + ".\n"+ # self.tr("Do you really want to continue computing ?")) # self.msg2.setStandardButtons(QMessageBox.Yes | QMessageBox.No) # res = self.msg2.exec_() # # # cancel # if res == QMessageBox.No: # return # if res == QMessageBox.Yes: # break self.progress_layout.process_manager.set_mesh_manager( self.path_prj, mesh_manager_description, self.project_properties) # start thread self.progress_layout.start_process() def stop_compute(self): # stop_by_user self.process_manager.stop_by_user()
class EstimhabW(StatModUseful): """ The Estimhab class provides the graphical interface for the version of the Estimhab model written in HABBY. The Estimhab model is described elsewhere. EstimhabW() just loads the data for Estimhab given by the user. """ save_signal_estimhab = pyqtSignal() """ PyQtsignal to save the Estimhab data. """ def __init__(self, path_prj, name_prj): super().__init__() self.tab_name = "estimhab" self.tab_position = 7 self.model_type = "Estimhab" self.eq50 = QLineEdit() self.esub = QLineEdit() self.path_prj = path_prj self.name_prj = name_prj self.path_bio_estimhab = os.path.join(self.path_bio, 'estimhab') self.total_lineedit_number = 1 self.init_iu() self.process_manager = MyProcessManager( "estimhab_plot") # SC (Suitability Curve) self.read_estimhab_dict() self.fill_input_data() self.fill_fish_name() self.check_if_ready_to_compute() self.eq1.textChanged.connect(self.check_if_ready_to_compute) self.eq2.textChanged.connect(self.check_if_ready_to_compute) self.ew1.textChanged.connect(self.check_if_ready_to_compute) self.ew2.textChanged.connect(self.check_if_ready_to_compute) self.eh1.textChanged.connect(self.check_if_ready_to_compute) self.eh2.textChanged.connect(self.check_if_ready_to_compute) self.eq50.textChanged.connect(self.check_if_ready_to_compute) self.eqmin.textChanged.connect(self.check_if_ready_to_compute) self.eqmax.textChanged.connect(self.check_if_ready_to_compute) self.esub.textChanged.connect(self.check_if_ready_to_compute) self.selected_aquatic_animal_qtablewidget.model().rowsInserted.connect( self.check_if_ready_to_compute) self.selected_aquatic_animal_qtablewidget.model().rowsRemoved.connect( self.check_if_ready_to_compute) def init_iu(self): """ This function is used to initialized an instance of the EstimhabW() class. It is called by __init__(). **Technical comments and walk-through** First we looked if some data for Estimhab was saved before by an user. If yes, we will fill the GUI with the information saved before. Estimhab information is saved in hdf5 file format and the path/name of the hdf5 file is saved in the xml project file. So we open the xml project file and look if the name of an hdf5 file was saved for Estimhab. If yes, the hdf5 file is read. The format of hdf5 file is relatively simple. Each input data for Estimhab has its own dataset (qmes, hmes, wmes, q50, qrange, and substrate). Then, we have a list of string which are a code for the fish species which were analyzed. All the data contained in hdf5 file is loaded into variable. The different label are written on the graphical interface. Then, two QListWidget are modified. The first list contains all the fish species on which HABBY has info (see XML Estimhab format for more info). The second list is the fish selected by the user on which Estimhab will be run. Here, we link these lists with two functions so that the user can select/deselect fish using the mouse. The function name are add_fish() and remove_fish(). Then, we fill the first list. HABBY look up all file of xml type in the “Path_bio” folder (the one indicated in the xml project file under the attribute “Path_bio”). The name are them modified so that the only the name of species appears (and not the full path). We set the layout with all the different QLineEdit where the user can write the needed data. Estimhab model is saved using a function situated in MainWindows_1.py (frankly, I am not so sure why I did put the save function there, but anyway). So the save button just send a signal to MainWindows here, which save the data. """ available_model_label = QLabel(self.tr('Available')) selected_model_label = QLabel(self.tr('Selected')) self.lineedit_width = 50 self.spacer_width = 50 # input q1_layout = QHBoxLayout() q1_layout.addWidget(QLabel('Q1 [m<sup>3</sup>/s]')) q1_layout.addWidget(self.eq1) q1_layout.addItem(QSpacerItem(self.spacer_width, 1)) self.eq1.setFixedWidth(self.lineedit_width) q2_layout = QHBoxLayout() q2_layout.addWidget(QLabel('Q2 [m<sup>3</sup>/s]')) q2_layout.addWidget(self.eq2) q2_layout.addItem(QSpacerItem(self.spacer_width, 1)) self.eq2.setFixedWidth(self.lineedit_width) w1_layout = QHBoxLayout() w1_layout.addWidget(QLabel(self.tr("Width1 [m]"))) w1_layout.addWidget(self.ew1) w1_layout.addItem(QSpacerItem(self.spacer_width, 1)) self.ew1.setFixedWidth(self.lineedit_width) w2_layout = QHBoxLayout() w2_layout.addWidget(QLabel(self.tr("Width2 [m]"))) w2_layout.addWidget(self.ew2) w2_layout.addItem(QSpacerItem(self.spacer_width, 1)) self.ew2.setFixedWidth(self.lineedit_width) h1_layout = QHBoxLayout() h1_layout.addWidget(QLabel(self.tr("Height1 [m]"))) h1_layout.addWidget(self.eh1) self.eh1.setFixedWidth(self.lineedit_width) h2_layout = QHBoxLayout() h2_layout.addWidget(QLabel(self.tr("Height2 [m]"))) h2_layout.addWidget(self.eh2) self.eh2.setFixedWidth(self.lineedit_width) q50_layout = QHBoxLayout() q50_layout.addWidget(QLabel('Qmedian/Q50 [m<sup>3</sup>/s]')) q50_layout.addWidget(self.eq50) q50_layout.addItem(QSpacerItem(self.spacer_width, 1)) self.eq50.setFixedWidth(self.lineedit_width) sub_layout = QHBoxLayout() sub_layout.addWidget(QLabel(self.tr('Mean substrate size [m]'))) sub_layout.addWidget(self.esub) sub_layout.addItem(QSpacerItem(self.spacer_width, 1)) self.esub.setFixedWidth(self.lineedit_width) # output q1out_layout = QHBoxLayout() q1out_layout.addWidget(QLabel(self.tr("Qmin [m<sup>3</sup>/s]"))) q1out_layout.addWidget(self.eqmin) q1out_layout.addItem(QSpacerItem(self.spacer_width, 1)) self.eqmin.setFixedWidth(self.lineedit_width) q2out_layout = QHBoxLayout() q2out_layout.addWidget(QLabel(self.tr("Qmax [m<sup>3</sup>/s]"))) q2out_layout.addWidget(self.eqmax) q2out_layout.addItem(QSpacerItem(self.spacer_width, 1)) self.eqmax.setFixedWidth(self.lineedit_width) self.q2target_layout = QHBoxLayout() self.q2target_layout.addWidget( QLabel(self.tr("Qtarget [m<sup>3</sup>/s]"))) self.q2target_layout.addWidget(self.add_qtarget_button) self.q2target_layout.addWidget(self.remove_qtarget_button) self.add_qtarget_button.clicked.connect(self.add_new_qtarget) self.remove_qtarget_button.clicked.connect(self.remove_one_qtarget) # create lists with the possible fishes self.list_f.setSelectionMode(QAbstractItemView.ExtendedSelection) self.list_f.setDragDropMode(QAbstractItemView.DragDrop) self.list_f.setDefaultDropAction(Qt.MoveAction) self.list_f.setAcceptDrops(True) self.list_f.setSortingEnabled(True) self.selected_aquatic_animal_qtablewidget.setSelectionMode( QAbstractItemView.ExtendedSelection) self.selected_aquatic_animal_qtablewidget.setDragDropMode( QAbstractItemView.DragDrop) self.selected_aquatic_animal_qtablewidget.setDefaultDropAction( Qt.MoveAction) self.selected_aquatic_animal_qtablewidget.setAcceptDrops(True) self.selected_aquatic_animal_qtablewidget.setSortingEnabled(True) # insist on white background color (for linux, mac) self.setAutoFillBackground(True) p = self.palette() p.setColor(self.backgroundRole(), Qt.white) self.setPalette(p) # send model self.run_stop_button = QPushButton(self.tr('Run Estimhab'), self) self.run_stop_button.clicked.connect(self.run_estmihab) change_button_color(self.run_stop_button, "#47B5E6") self.run_stop_button.setEnabled(False) # empty frame scrolable content_widget = QFrame() # hydraulic_data_group hydraulic_data_group = QGroupBox(self.tr('Hydraulic data input')) hydraulic_data_group.setToolTip( self.tr("Double click to reset the input data group.")) hydraulic_data_layout = QGridLayout(hydraulic_data_group) hydraulic_data_layout.addLayout(q1_layout, 0, 0) hydraulic_data_layout.addLayout(w1_layout, 0, 1) hydraulic_data_layout.addLayout(h1_layout, 0, 2) hydraulic_data_layout.addLayout(q2_layout, 1, 0) hydraulic_data_layout.addLayout(w2_layout, 1, 1) hydraulic_data_layout.addLayout(h2_layout, 1, 2) hydraulic_data_layout.addLayout(q50_layout, 2, 0) hydraulic_data_layout.addLayout(sub_layout, 2, 1) hydraulic_data_group.setSizePolicy(QSizePolicy.Maximum, QSizePolicy.Maximum) self.doubleclick_input_group = DoubleClicOutputGroup() hydraulic_data_group.installEventFilter(self.doubleclick_input_group) self.doubleclick_input_group.double_clic_signal.connect( self.reset_hydraulic_data_input_group) # hydraulic_data_output_group hydraulic_data_output_group = QGroupBox( self.tr('Desired hydraulic output data')) hydraulic_data_output_group.setToolTip( self.tr("Double click to reset the outpout data group.")) hydraulic_data_layout = QGridLayout(hydraulic_data_output_group) hydraulic_data_layout.addLayout(q1out_layout, 0, 0) hydraulic_data_layout.addLayout(q2out_layout, 0, 1) hydraulic_data_layout.addLayout(self.q2target_layout, 0, 2) hydraulic_data_output_group.setSizePolicy(QSizePolicy.Maximum, QSizePolicy.Maximum) self.doubleclick_output_group = DoubleClicOutputGroup() hydraulic_data_output_group.installEventFilter( self.doubleclick_output_group) self.doubleclick_output_group.double_clic_signal.connect( self.reset_hydraulic_data_output_group) # models_group models_group = QGroupBox(self.tr('Biological models')) models_layout = QGridLayout(models_group) models_layout.addWidget(available_model_label, 0, 0) models_layout.addWidget(selected_model_label, 0, 1) models_layout.addWidget(self.list_f, 1, 0) models_layout.addWidget(self.selected_aquatic_animal_qtablewidget, 1, 1) models_layout.addWidget(self.run_stop_button, 2, 1) self.doubleclick_models_group = DoubleClicOutputGroup() models_group.installEventFilter(self.doubleclick_models_group) self.doubleclick_models_group.double_clic_signal.connect( self.reset_models_group) # gereral_layout self.layout3 = QVBoxLayout(content_widget) self.layout3.addWidget(hydraulic_data_group, Qt.AlignLeft) self.layout3.addWidget(hydraulic_data_output_group) self.layout3.addWidget(models_group) # self.setLayout(self.layout3) self.setWidgetResizable(True) self.setFrameShape(QFrame.NoFrame) self.setWidget(content_widget) def add_new_qtarget(self): # count existing number of lineedit total_widget_number = self.q2target_layout.count() self.total_lineedit_number = total_widget_number - 2 # - first : qlabel and plus and moins button + New lineedit lineedit_name = 'new_qtarget' + str(self.total_lineedit_number) setattr(self, lineedit_name, QLineEdit()) getattr(self, lineedit_name).setFixedWidth(self.lineedit_width) self.target_lineedit_list.append(getattr(self, lineedit_name)) self.q2target_layout.insertWidget(total_widget_number - 2, getattr(self, lineedit_name)) def remove_one_qtarget(self): # count existing number of lineedit total_widget_number = self.q2target_layout.count() self.total_lineedit_number = total_widget_number - 3 # - first : qlabel and plus and moins button - New lineedit if self.total_lineedit_number > 0: self.target_lineedit_list.pop(-1) self.q2target_layout.itemAt(total_widget_number - 3).widget().setParent(None) self.total_lineedit_number = self.total_lineedit_number - 1 def reset_hydraulic_data_input_group(self): # remove txt in lineedit self.eq1.setText("") self.eq2.setText("") self.ew1.setText("") self.ew2.setText("") self.eh1.setText("") self.eh2.setText("") self.eq50.setText("") self.esub.setText("") def reset_hydraulic_data_output_group(self): # remove txt in lineedit self.eqmin.setText("") self.eqmax.setText("") # remove lineedits qtarget for i in reversed(range(1, self.q2target_layout.count() - 1)): self.q2target_layout.itemAt(i).widget().setParent(None) self.total_lineedit_number = self.total_lineedit_number - 1 self.target_lineedit_list = [] def reset_models_group(self): if self.selected_aquatic_animal_qtablewidget.count() > 0: self.selected_aquatic_animal_qtablewidget.clear() self.fill_fish_name() def read_estimhab_dict(self): """ This function opens the json data created by estimhab """ # load_project_properties self.estimhab_dict = load_specific_properties(self.path_prj, [self.model_type])[0] def fill_fish_name(self): """ This function reads all latin fish name from the xml files which are contained in the biological directory related to estimhab and fill GUI fish names """ all_xmlfile = glob.glob(os.path.join(self.path_bio_estimhab, r'*.xml')) if self.estimhab_dict: selected_fish = self.estimhab_dict["fish_list"] else: selected_fish = [] for f in all_xmlfile: # open xml try: try: docxml = ET.parse(f) root = docxml.getroot() except IOError: self.send_log.emit( self.tr("Warning: ") + self.tr("The .habby project file ") + f + self.tr(" could not be open.\n")) return except ET.ParseError: self.send_log.emit( self.tr("Warning: ") + self.tr("The .habby project file ") + f + self.tr(" is not well-formed.\n")) return # find fish name fish_name = root.find(".//LatinName") # None is null for python 3 if fish_name is not None: fish_name = fish_name.text.strip() # find fish stage stage = root.find(".//estimhab/stage") # None is null for python 3 if stage is not None: stage = stage.text.strip() if stage != 'all_stage': fish_name += ' ' + stage # check if not selected if fish_name not in selected_fish: # add to the list item = QListWidgetItem(fish_name) item.setData(1, f) self.list_f.addItem(item) else: # add to the list item2 = QListWidgetItem(fish_name) item2.setData(1, f) self.selected_aquatic_animal_qtablewidget.addItem(item2) def fill_input_data(self): if self.estimhab_dict: # input data self.eq1.setText(str(self.estimhab_dict["q"][0])) self.eq2.setText(str(self.estimhab_dict["q"][1])) self.eh1.setText(str(self.estimhab_dict["h"][0])) self.eh2.setText(str(self.estimhab_dict["h"][1])) self.ew1.setText(str(self.estimhab_dict["w"][0])) self.ew2.setText(str(self.estimhab_dict["w"][1])) self.eq50.setText(str(self.estimhab_dict["q50"])) self.eqmin.setText(str(self.estimhab_dict["qrange"][0])) self.eqmax.setText(str(self.estimhab_dict["qrange"][1])) self.esub.setText(str(self.estimhab_dict["substrate"])) # qtarg if len(self.estimhab_dict["qtarg"]) > 0: while self.total_lineedit_number != len( self.estimhab_dict["qtarg"]): self.add_new_qtarget() for qtarg_num, qtarg_value in enumerate( self.estimhab_dict["qtarg"][1:]): getattr(self, 'new_qtarget' + str(qtarg_num + 2)).setText( str(qtarg_value)) def check_if_ready_to_compute(self): all_string_selection = (self.eq1.text(), self.eq2.text(), self.ew1.text(), self.ew2.text(), self.eh1.text(), self.eh2.text(), self.eq50.text(), self.eqmin.text(), self.eqmax.text(), self.esub.text()) # minimum one fish and string in input lineedits to enable run_stop_button if self.selected_aquatic_animal_qtablewidget.count( ) > 0 and "" not in all_string_selection: self.run_stop_button.setEnabled(True) else: self.run_stop_button.setEnabled(False) def change_folder(self): """ A small method to change the folder which indicates where is the biological data """ # user find new path self.path_bio_estimhab = QFileDialog.getExistingDirectory( self, self.tr("Open Directory"), os.getenv('HOME')) # update list self.list_f.clear() all_file = glob.glob(os.path.join(self.path_bio_estimhab, r'*.xml')) # make it look nicer for i in range(0, len(all_file)): all_file[i] = all_file[i].replace(self.path_bio_estimhab, "") all_file[i] = all_file[i].replace("\\", "") all_file[i] = all_file[i].replace(".xml", "") item = QListWidgetItem(all_file[i]) # add them to the menu self.list_f.addItem(item) def run_estmihab(self): """ A function to execute Estimhab by calling the estimhab function. **Technical comment** This is the function making the link between the GUI and the source code proper. The source code for Estimhab is in src/Estimhab.py. This function loads in memory the data given in the graphical interface and call sthe Estimhab model. The data could be written by the user now or it could be data which was saved in the hdf5 file before and loaded when HABBY was open (and the init function called). We check that all necessary data is present and that the data given makes sense (e.g.,the minimum discharge should not be bigger than the maximal discharge, the data should be a float, etc.). We then remove the duplicate fish species (in case the user select one specie twice) and the Estimhab model is called. The log is then written (see the paragraph on the log for more information). Next, the figures created by Estimmhab are shown. As there is only a short number of outputs for Estimhab, we create a figure in all cases (it could be changed by adding a checkbox on the GUI like in the Telemac or other hydrological class). """ # prepare data try: q = [ float(self.eq1.text().replace(",", ".")), float(self.eq2.text().replace(",", ".")) ] w = [ float(self.ew1.text().replace(",", ".")), float(self.ew2.text().replace(",", ".")) ] h = [ float(self.eh1.text().replace(",", ".")), float(self.eh2.text().replace(",", ".")) ] q50 = float(self.eq50.text().replace(",", ".")) qrange = [ float(self.eqmin.text().replace(",", ".")), float(self.eqmax.text().replace(",", ".")) ] qtarget_values_list = [] for qtarg_lineedit in self.target_lineedit_list: if qtarg_lineedit.text(): qtarget_values_list.append( float(qtarg_lineedit.text().replace(",", "."))) substrate = float(self.esub.text().replace(",", ".")) except ValueError: self.send_log.emit('Error: ' + self.tr( 'Some data are empty or not float. Cannot run Estimhab')) return # get the list of xml file fish_list = [] fish_name2 = [] for i in range(0, self.selected_aquatic_animal_qtablewidget.count()): fish_item = self.selected_aquatic_animal_qtablewidget.item(i) fish_item_str = fish_item.text() fish_list.append(os.path.basename(fish_item.data(1))) fish_name2.append(fish_item_str) # check internal logic if not fish_list: self.send_log.emit( 'Error: ' + self.tr('No fish selected. Cannot run Estimhab.')) return if qrange[0] >= qrange[1]: self.send_log.emit('Error: ' + self.tr( 'Minimum discharge bigger or equal to max discharge. Cannot run Estimhab.' )) return if qtarget_values_list: for qtarg in qtarget_values_list: if qtarg < qrange[0] or qtarg > qrange[1]: self.send_log.emit('Error: ' + self.tr( 'Target discharge is not between Qmin and Qmax. Cannot run Estimhab.' )) return if q[0] == q[1]: self.send_log.emit( 'Error: ' + self.tr('Estimhab needs two differents measured discharges.')) return if h[0] == h[1]: self.send_log.emit( 'Error: ' + self.tr('Estimhab needs two different measured height.')) return if w[0] == w[1]: self.send_log.emit( 'Error: ' + self.tr('Estimhab needs two different measured width.')) return if (q[0] > q[1] and h[0] < h[1]) or (q[0] > q[1] and w[0] < w[1]) or (q[1] > q[0] and h[1] < h[0]) \ or (q[1] > q[0] and w[1] < w[0]): self.send_log.emit( 'Error: ' + self.tr('Discharge, width, and height data are not coherent.')) return if q[0] <= 0 or q[1] <= 0 or w[0] <= 0 or w[1] <= 0 or h[0] <= 0 or h[1] <= 0 or qrange[0] <= 0 or qrange[1] <= 0 \ or substrate <= 0 or q50 <= 0: self.send_log.emit('Error: ' + self.tr( 'Negative or zero data found. Could not run Estimhab.')) return if substrate > 3: self.send_log.emit( 'Error: ' + self.tr('Substrate is too large. Could not run Estimhab.')) return self.send_log.emit(self.tr('# Computing: Estimhab...')) # check if the discharge range is realistic with the result self.qall = [q[0], q[1], qrange[0], qrange[1], q50] self.check_all_q() # run and save project_properties = load_project_properties(self.path_prj) sys.stdout = mystdout = StringIO() self.estimhab_dict = dict(q=q, w=w, h=h, q50=q50, qrange=qrange, qtarg=qtarget_values_list, substrate=substrate, path_bio=self.path_bio_estimhab, xml_list=fish_list, fish_list=fish_name2) # change_specific_properties change_specific_properties(self.path_prj, ["Estimhab"], [self.estimhab_dict]) # process state = Value("d", 0) self.p = Process(target=estimhab_mod.estimhab_process, args=(self.estimhab_dict, project_properties, self.path_prj, state), name="Estimhab") self.p.start() self.p.join() # plot plot_attr = lambda: None plot_attr.name_hdf5 = self.name_prj + '_ESTIMHAB' + '.hab' plot_attr.nb_plot = 1 self.process_manager.set_estimhab_plot_mode( self.path_prj, plot_attr, load_project_properties(self.path_prj)) self.process_manager.start() # log info str_found = mystdout.getvalue() str_found = str_found.split('\n') for i in range(0, len(str_found)): if len(str_found[i]) > 1: self.send_log.emit(str_found[i]) self.send_log.emit( self. tr("Estimhab computation done. Figure and text files created in output project folder." )) self.send_log.emit("py data = [" + str(q) + ',' + str(w) + ',' + str(h) + ',' + str(q50) + ',' + str(substrate) + ']') self.send_log.emit("py qrange =[" + str(qrange[0]) + ',' + str(qrange[1]) + ']') self.send_log.emit( "py path1= os.path.join(os.path.dirname(path_bio),'" + self.path_bio_estimhab + "')") fish_list_str = "py fish_list = [" for i in range(0, len(fish_list)): fish_list_str += "'" + fish_list[i] + "'," fish_list_str = fish_list_str[:-1] + ']' self.send_log.emit(fish_list_str) self.send_log.emit( "py [OSI, WUA] = estimhab.estimhab(data[0], data[1], data[2], data[3] ," " qrange, data[4], path1, fish_list, '.', True, {}, '.')\n")
class VisualGroup(QGroupBoxCollapsible): """ This class is a subclass of class QGroupBox. """ def __init__(self, path_prj, name_prj, send_log, title): super().__init__() self.path_prj = path_prj self.name_prj = name_prj self.send_log = send_log self.path_last_file_loaded = self.path_prj self.process_manager = MyProcessManager("hs_plot") self.axe_mod_choosen = 1 self.setTitle(title) self.init_ui() self.process_prog_show_input = ProcessProgShow(send_log=self.send_log, run_function=self.plot_hs_class, computation_pushbutton=self.input_class_plot_button) self.process_prog_show_area = ProcessProgShow(send_log=self.send_log, run_function=self.plot_hs_area, computation_pushbutton=self.result_plot_button_area) self.process_prog_show_volume = ProcessProgShow(send_log=self.send_log, run_function=self.plot_hs_volume, computation_pushbutton=self.result_plot_button_volume) def init_ui(self): # file_selection file_selection_label = QLabel(self.tr("HS files :")) self.file_selection_listwidget = QListWidget() self.file_selection_listwidget.itemSelectionChanged.connect(self.names_hdf5_change) file_selection_layout = QVBoxLayout() file_selection_layout.addWidget(file_selection_label) file_selection_layout.addWidget(self.file_selection_listwidget) # reach reach_label = QLabel(self.tr('reach(s)')) self.reach_QListWidget = QListWidget() self.reach_QListWidget.setSelectionMode(QAbstractItemView.ExtendedSelection) self.reach_QListWidget.itemSelectionChanged.connect(self.reach_hdf5_change) reach_layout = QVBoxLayout() reach_layout.addWidget(reach_label) reach_layout.addWidget(self.reach_QListWidget) # units units_label = QLabel(self.tr('unit(s)')) self.units_QListWidget = QListWidget() self.units_QListWidget.setSelectionMode(QAbstractItemView.ExtendedSelection) self.units_QListWidget.itemSelectionChanged.connect(self.unit_hdf5_change) units_layout = QVBoxLayout() units_layout.addWidget(units_label) units_layout.addWidget(self.units_QListWidget) # axe self.axe_mod_choosen = load_specific_properties(self.path_prj, ["hs_axe_mod"])[0] axe_label = QLabel(self.tr("Axe orientation :")) self.axe_mod_1_radio = QRadioButton() if self.axe_mod_choosen == 1: self.axe_mod_1_radio.setChecked(True) self.axe_mod_1_radio.setIcon(QIcon(r"file_dep/axe_mod_1.png")) self.axe_mod_1_radio.setIconSize(QSize(75, 75)) self.axe_mod_1_radio.clicked.connect(self.change_axe_mod) self.axe_mod_2_radio = QRadioButton() if self.axe_mod_choosen == 2: self.axe_mod_2_radio.setChecked(True) self.axe_mod_2_radio.setIcon(QIcon(r"file_dep/axe_mod_2.png")) self.axe_mod_2_radio.setIconSize(QSize(75, 75)) self.axe_mod_2_radio.clicked.connect(self.change_axe_mod) self.axe_mod_3_radio = QRadioButton() if self.axe_mod_choosen == 3: self.axe_mod_3_radio.setChecked(True) self.axe_mod_3_radio.setIcon(QIcon(r"file_dep/axe_mod_3.png")) self.axe_mod_3_radio.setIconSize(QSize(75, 75)) self.axe_mod_3_radio.clicked.connect(self.change_axe_mod) axe_mod_layout = QHBoxLayout() axe_mod_layout.addWidget(self.axe_mod_1_radio) axe_mod_layout.addWidget(self.axe_mod_2_radio) axe_mod_layout.addWidget(self.axe_mod_3_radio) axe_layout = QVBoxLayout() axe_layout.addWidget(axe_label) axe_layout.addLayout(axe_mod_layout) axe_layout.addStretch() selection_layout = QHBoxLayout() selection_layout.addLayout(file_selection_layout) selection_layout.addLayout(reach_layout) selection_layout.addLayout(units_layout) selection_layout.addLayout(axe_layout) # input_class input_class_label = QLabel(self.tr("Input class :")) input_class_h_label = QLabel(self.tr("h (m)")) self.input_class_h_lineedit = QLineEdit("") input_class_v_label = QLabel(self.tr("v (m)")) self.input_class_v_lineedit = QLineEdit("") self.input_class_plot_button = QPushButton(self.tr("Show input")) self.input_class_plot_button.clicked.connect(self.plot_hs_class) change_button_color(self.input_class_plot_button, "#47B5E6") self.input_class_plot_button.setEnabled(False) input_class_layout = QGridLayout() input_class_layout.addWidget(input_class_label, 0, 0, 1, 2) input_class_layout.addWidget(input_class_h_label, 1, 0) input_class_layout.addWidget(input_class_v_label, 2, 0) input_class_layout.addWidget(self.input_class_h_lineedit, 1, 1) input_class_layout.addWidget(self.input_class_v_lineedit, 2, 1) input_class_layout.addWidget(self.input_class_plot_button, 1, 2, 2, 1) # from row, from column, nb row, nb column # result result_label = QLabel(self.tr("Result :")) self.result_tableview = QTableView() self.result_tableview.setSizePolicy(QSizePolicy.MinimumExpanding, QSizePolicy.MinimumExpanding) self.result_tableview.verticalHeader().setVisible(False) self.result_tableview.horizontalHeader().setVisible(False) self.result_plot_button_area = QPushButton(self.tr("Show area")) self.result_plot_button_area.clicked.connect(self.plot_hs_area) self.result_plot_button_area.setEnabled(False) change_button_color(self.result_plot_button_area, "#47B5E6") self.result_plot_button_volume = QPushButton(self.tr("Show volume")) self.result_plot_button_volume.clicked.connect(self.plot_hs_volume) self.result_plot_button_volume.setEnabled(False) change_button_color(self.result_plot_button_volume, "#47B5E6") pushbutton_layout = QVBoxLayout() pushbutton_layout.addWidget(self.result_plot_button_area) pushbutton_layout.addWidget(self.result_plot_button_volume) result_layout = QGridLayout() result_layout.addWidget(result_label, 0, 0) result_layout.addWidget(self.result_tableview, 1, 0, 2, 1) result_layout.addLayout(pushbutton_layout, 1, 1) self.input_result_group = QGroupBox() input_result_layout = QVBoxLayout() input_result_layout.addLayout(input_class_layout) input_result_layout.addLayout(result_layout) self.input_result_group.setLayout(input_result_layout) self.input_result_group.hide() general_layout = QVBoxLayout() general_layout.addLayout(selection_layout) general_layout.addWidget(self.input_result_group) self.setLayout(general_layout) def update_gui(self): hs_names = get_filename_hs(os.path.join(self.path_prj, "hdf5")) self.file_selection_listwidget.blockSignals(True) self.file_selection_listwidget.clear() if hs_names: self.file_selection_listwidget.addItems(hs_names) self.file_selection_listwidget.blockSignals(False) def change_axe_mod(self): if self.axe_mod_1_radio.isChecked(): self.axe_mod_choosen = 1 elif self.axe_mod_2_radio.isChecked(): self.axe_mod_choosen = 2 elif self.axe_mod_3_radio.isChecked(): self.axe_mod_choosen = 3 change_specific_properties(self.path_prj, ["hs_axe_mod"], [self.axe_mod_choosen]) def names_hdf5_change(self): self.reach_QListWidget.clear() self.units_QListWidget.clear() selection = self.file_selection_listwidget.selectedItems() if selection: # read hdf5name = selection[0].text() hdf5 = Hdf5Management(self.path_prj, hdf5name, new=False, edit=False) hdf5.get_hdf5_attributes(close_file=True) # check reach self.reach_QListWidget.addItems(hdf5.data_2d.reach_list) self.input_class_h_lineedit.setText(", ".join(list(map(str, hdf5.hs_input_class[0])))) self.input_class_v_lineedit.setText(", ".join(list(map(str, hdf5.hs_input_class[1])))) self.input_class_plot_button.setEnabled(True) self.toggle_group(False) self.input_result_group.show() self.toggle_group(True) else: self.input_result_group.hide() def reach_hdf5_change(self): selection_file = self.file_selection_listwidget.selectedItems() selection_reach = self.reach_QListWidget.selectedItems() self.units_QListWidget.clear() # one file selected if len(selection_reach) == 1: hdf5name = selection_file[0].text() # create hdf5 class hdf5 = Hdf5Management(self.path_prj, hdf5name, new=False, edit=False) hdf5.get_hdf5_attributes(close_file=True) # add units for item_text in hdf5.data_2d.unit_list[self.reach_QListWidget.currentRow()]: item = QListWidgetItem(item_text) item.setTextAlignment(Qt.AlignRight) self.units_QListWidget.addItem(item) if len(selection_reach) > 1: # add units item = QListWidgetItem("all units") item.setTextAlignment(Qt.AlignRight) self.units_QListWidget.addItem(item) self.units_QListWidget.selectAll() def unit_hdf5_change(self): selection_unit = self.units_QListWidget.selectedItems() # one file selected if len(selection_unit) > 0: hdf5name = self.file_selection_listwidget.selectedItems()[0].text() # create hdf5 class hdf5 = Hdf5Management(self.path_prj, hdf5name, new=False, edit=False) hdf5.load_hydrosignature() hdf5.close_file() if len(selection_unit) == 1 and selection_unit[0].text() == "all units": # get hs data hdf5.data_2d.get_hs_summary_data([element.row() for element in self.reach_QListWidget.selectedIndexes()], list(range(hdf5.nb_unit))) else: # get hs data hdf5.data_2d.get_hs_summary_data([element.row() for element in self.reach_QListWidget.selectedIndexes()], [element.row() for element in self.units_QListWidget.selectedIndexes()]) # table mytablemodel = MyTableModel(hdf5.data_2d.hs_summary_data) self.result_tableview.setModel(mytablemodel) # set model self.result_plot_button_area.setEnabled(True) self.result_plot_button_volume.setEnabled(True) else: mytablemodel = MyTableModel(["", ""]) self.result_tableview.setModel(mytablemodel) # set model self.result_plot_button_area.setEnabled(False) self.result_plot_button_volume.setEnabled(False) def plot_hs_class(self): plot_attr = lambda: None plot_attr.nb_plot = 1 plot_attr.axe_mod_choosen = self.axe_mod_choosen plot_attr.hs_plot_type = "input_class" # process_manager self.process_manager.set_plot_hdf5_mode(self.path_prj, [self.file_selection_listwidget.selectedItems()[0].text()], plot_attr, load_project_properties(self.path_prj)) # process_prog_show self.process_prog_show_input.start_show_prog(self.process_manager) def plot_hs_area(self): plot_attr = lambda: None plot_attr.axe_mod_choosen = self.axe_mod_choosen plot_attr.hs_plot_type = "area" plot_attr.reach = [element.row() for element in self.reach_QListWidget.selectedIndexes()] plot_attr.units = [element.row() for element in self.units_QListWidget.selectedIndexes()] plot_attr.nb_plot = len(plot_attr.units) # process_manager self.process_manager.set_plot_hdf5_mode(self.path_prj, [self.file_selection_listwidget.selectedItems()[0].text()], plot_attr, load_project_properties(self.path_prj)) # process_prog_show self.process_prog_show_area.start_show_prog(self.process_manager) def plot_hs_volume(self): plot_attr = lambda: None plot_attr.axe_mod_choosen = self.axe_mod_choosen plot_attr.hs_plot_type = "volume" plot_attr.reach = [element.row() for element in self.reach_QListWidget.selectedIndexes()] plot_attr.units = [element.row() for element in self.units_QListWidget.selectedIndexes()] plot_attr.nb_plot = len(plot_attr.units) # process_manager self.process_manager.set_plot_hdf5_mode(self.path_prj, [self.file_selection_listwidget.selectedItems()[0].text()], plot_attr, load_project_properties(self.path_prj)) # process_prog_show self.process_prog_show_volume.start_show_prog(self.process_manager)
class ComputingGroup(QGroupBoxCollapsible): """ This class is a subclass of class QGroupBox. """ send_refresh_filenames = pyqtSignal(name='send_refresh_filenames') def __init__(self, path_prj, name_prj, send_log, title): super().__init__() self.path_prj = path_prj self.name_prj = name_prj self.send_log = send_log self.path_last_file_loaded = self.path_prj self.classhv = None self.project_properties = load_project_properties(self.path_prj) self.setTitle(title) self.init_ui() self.input_class_file_info = self.read_attribute_xml("HS_input_class") self.read_input_class(os.path.join(self.input_class_file_info["path"], self.input_class_file_info["file"])) # process_manager self.process_manager = MyProcessManager("hs") def init_ui(self): # file_selection file_selection_label = QLabel(self.tr("Select a 2D mesh file :")) self.file_selection_listwidget = QListWidget() self.file_selection_listwidget.setSelectionMode(QAbstractItemView.ExtendedSelection) self.file_selection_listwidget.itemSelectionChanged.connect(self.names_hdf5_change) self.file_selection_listwidget.setVerticalScrollBarPolicy(Qt.ScrollBarAlwaysOff) self.file_selection_listwidget.verticalScrollBar().setEnabled(True) self.file_selection_listwidget.verticalScrollBar().valueChanged.connect(self.change_scroll_position) self.scrollbar = self.file_selection_listwidget.verticalScrollBar() file_computed_label = QLabel(self.tr("Computed ?")) self.hs_computed_listwidget = QListWidget() self.hs_computed_listwidget.setEnabled(False) self.hs_computed_listwidget.setFlow(QListView.TopToBottom) self.hs_computed_listwidget.setVerticalScrollBarPolicy(Qt.ScrollBarAlwaysOff) self.hs_computed_listwidget.verticalScrollBar().setEnabled(True) self.hs_computed_listwidget.verticalScrollBar().valueChanged.connect(self.change_scroll_position) file_selection_layout = QGridLayout() file_selection_layout.addWidget(file_selection_label, 0, 0) file_selection_layout.addWidget(self.file_selection_listwidget, 1, 0) file_selection_layout.addWidget(file_computed_label, 0, 1) file_selection_layout.addWidget(self.hs_computed_listwidget, 1, 1) file_selection_layout.addWidget(self.scrollbar, 1, 2) file_selection_layout.setColumnStretch(0, 30) file_selection_layout.setColumnStretch(1, 1) input_class_label = QLabel(self.tr("Input class (.txt)")) self.input_class_filename = QLabel("") self.input_class_pushbutton = QPushButton("...") self.input_class_pushbutton.clicked.connect(self.select_input_class_dialog) hs_export_txt_label = QLabel(self.tr("Export results (.txt)")) self.hs_export_txt_checkbox = QCheckBox() self.hs_export_txt_checkbox.setChecked(True) hs_export_mesh_label = QLabel(self.tr("Export mesh results (.hyd or .hab)")) self.hs_export_mesh_checkbox = QCheckBox() """ progress layout """ # progress_layout self.progress_layout = ProcessProgLayout(self.compute, send_log=self.send_log, process_type="hs", send_refresh_filenames=self.send_refresh_filenames) grid_layout = QGridLayout() grid_layout.addWidget(input_class_label, 2, 0, Qt.AlignLeft) grid_layout.addWidget(self.input_class_filename, 2, 1, Qt.AlignLeft) grid_layout.addWidget(self.input_class_pushbutton, 2, 2, Qt.AlignLeft) grid_layout.addWidget(hs_export_txt_label, 3, 0, Qt.AlignLeft) grid_layout.addWidget(self.hs_export_txt_checkbox, 3, 1, Qt.AlignLeft) grid_layout.addWidget(hs_export_mesh_label, 4, 0, Qt.AlignLeft) grid_layout.addWidget(self.hs_export_mesh_checkbox, 4, 1, Qt.AlignLeft) grid_layout.addLayout(self.progress_layout, 5, 0, 1, 3) grid_layout.setColumnStretch(0, 2) grid_layout.setColumnStretch(1, 1) grid_layout.setColumnStretch(2, 1) grid_layout.setAlignment(Qt.AlignRight) general_layout = QVBoxLayout() general_layout.addLayout(file_selection_layout) general_layout.addLayout(grid_layout) self.setLayout(general_layout) def update_gui(self): selected_file_names = [selection_el.text() for selection_el in self.file_selection_listwidget.selectedItems()] # computing_group hyd_names = get_filename_by_type_physic("hydraulic", os.path.join(self.path_prj, "hdf5")) hab_names = get_filename_by_type_physic("habitat", os.path.join(self.path_prj, "hdf5")) names = hyd_names + hab_names self.file_selection_listwidget.blockSignals(True) self.file_selection_listwidget.clear() self.hs_computed_listwidget.blockSignals(True) self.hs_computed_listwidget.clear() if names: for name in names: # filename item_name = QListWidgetItem() item_name.setText(name) self.file_selection_listwidget.addItem(item_name) if name in selected_file_names: item_name.setSelected(True) # check item = QListWidgetItem() item.setText("") item.setFlags(item.flags() | Qt.ItemIsUserCheckable) try: hdf5 = Hdf5Management(self.path_prj, name, new=False, edit=False) hdf5.get_hdf5_attributes(close_file=True) if hdf5.hs_calculated: item.setCheckState(Qt.Checked) else: item.setCheckState(Qt.Unchecked) except: self.send_log.emit(self.tr("Error: " + name + " file seems to be corrupted. Delete it with HABBY or manually.")) self.hs_computed_listwidget.addItem(item) item.setTextAlignment(Qt.AlignCenter) self.file_selection_listwidget.blockSignals(False) self.hs_computed_listwidget.blockSignals(False) # preselection if one if self.file_selection_listwidget.count() == 1: self.file_selection_listwidget.selectAll() def change_scroll_position(self, index): self.file_selection_listwidget.verticalScrollBar().setValue(index) self.hs_computed_listwidget.verticalScrollBar().setValue(index) def read_input_class(self, input_class_file): if os.path.exists(input_class_file): self.classhv, warnings_list = hydrosignature_mod.hydraulic_class_from_file(input_class_file) if warnings_list: for warning in warnings_list: self.send_log.emit(warning) if self.classhv is None: self.send_log.emit(self.tr("Error: Input class file : ") + os.path.basename(input_class_file) + self.tr(" is not valid.")) self.progress_layout.run_stop_button.setEnabled(False) else: self.input_class_filename.setText(os.path.basename(input_class_file)) if self.file_selection_listwidget.selectedItems(): self.progress_layout.run_stop_button.setEnabled(True) else: self.progress_layout.run_stop_button.setEnabled(False) self.progress_layout.progress_bar.setValue(0.0) self.progress_layout.progress_label.setText( "{0:.0f}/{1:.0f}".format(0.0, len(self.file_selection_listwidget.selectedItems()))) def names_hdf5_change(self): selection = self.file_selection_listwidget.selectedItems() self.progress_layout.progress_bar.setValue(0.0) self.progress_layout.progress_label.setText( "{0:.0f}/{1:.0f}".format(0.0, len(selection))) if selection: # enable run button if self.input_class_filename.text(): self.progress_layout.run_stop_button.setEnabled(True) else: self.progress_layout.run_stop_button.setEnabled(False) else: self.progress_layout.run_stop_button.setEnabled(False) def select_input_class_dialog(self): self.input_class_file_info = self.read_attribute_xml("HS_input_class") # get last path if self.input_class_file_info["path"] != self.path_prj and self.input_class_file_info["path"] != "": model_path = self.input_class_file_info["path"] # path spe elif self.read_attribute_xml("path_last_file_loaded") != self.path_prj and self.read_attribute_xml("path_last_file_loaded") != "": model_path = self.read_attribute_xml("path_last_file_loaded") # path last else: model_path = self.path_prj # path proj filename, _ = QFileDialog.getOpenFileName(self, self.tr("Select hydraulic class file"), model_path, self.tr("Text files") + " (*.txt)") if filename: self.pathfile = os.path.dirname(filename) # source file path self.namefile = os.path.basename(filename) # source file name self.save_xml("HS_input_class") self.read_input_class(filename) self.input_class_file_info = self.read_attribute_xml("HS_input_class") def read_attribute_xml(self, att_here): """ A function to read the text of an attribute in the xml project file. :param att_here: the attribute name (string). """ data = '' filename_path_pro = os.path.join(self.path_prj, self.name_prj + '.habby') if os.path.isfile(filename_path_pro): if att_here in {"path_last_file_loaded", "HS_input_class"}: data = load_project_properties(self.path_prj)[att_here] else: data = load_project_properties(self.path_prj)[att_here]["path"] else: pass return data def save_xml(self, attr): """ A function to save the loaded data in the xml file. This function adds the name and the path of the newly chosen hydrological data to the xml project file. First, it open the xml project file (and send an error if the project is not saved, or if it cannot find the project file). Then, it opens the xml file and add the path and name of the file to this xml file. If the model data was already loaded, it adds the new name without erasing the old name IF the switch append_name is True. Otherwise, it erase the old name and replace it by a new name. The variable “i” has the same role than in select_file_and_show_informations_dialog. :param i: a int for the case where there is more than one file to load :param append_name: A boolean. If True, the name found will be append to the existing name in the xml file, instead of remplacing the old name by the new name. """ filename_path_pro = os.path.join(self.path_prj, self.name_prj + '.habby') # save the name and the path in the xml .prj file if not os.path.isfile(filename_path_pro): self.end_log.emit('Error: The project is not saved. ' 'Save the project in the General tab before saving hydrological data. \n') else: # change path_last_file_loaded, model_type (path) self.project_properties = load_project_properties(self.path_prj) # load_project_properties self.project_properties["path_last_file_loaded"] = self.pathfile # change value self.project_properties[attr]["file"] = self.namefile # change value self.project_properties[attr]["path"] = self.pathfile # change value save_project_properties(self.path_prj, self.project_properties) # save_project_properties def compute(self): if len(self.file_selection_listwidget.selectedItems()) > 0: hydrosignature_description = dict(hs_export_mesh=self.hs_export_mesh_checkbox.isChecked(), hdf5_name_list=[selection_el.text() for selection_el in self.file_selection_listwidget.selectedItems()], hs_export_txt=self.hs_export_txt_checkbox.isChecked(), classhv_input_class_file_info=self.input_class_file_info, classhv=self.classhv) self.progress_layout.process_manager.set_hs_hdf5_mode(self.path_prj, hydrosignature_description, self.project_properties) # start thread self.progress_layout.start_process() def stop_compute(self): # stop_by_user self.process_manager.stop_by_user()
class InterpolationTab(QScrollArea): def __init__(self, path_prj, name_prj, send_log): super().__init__() self.tab_name = "interpolation" self.tab_title = "Interpolation" self.tooltip_str = self.tr("Interpolation of habitat values") self.path_prj = path_prj self.name_prj = name_prj self.send_log = send_log self.mytablemodel = None self.path_last_file_loaded = self.path_prj self.process_manager = MyProcessManager("interpolation") self.init_ui() self.process_prog_show = ProcessProgShow(send_log=self.send_log, # progress_bar=self.nativeParentWidget().progress_bar, # progress_label=self.progress_label, run_function=self.plot_chronicle, computation_pushbutton=self.plot_chronicle_qpushbutton) def init_ui(self): # insist on white background color (for linux, mac) self.setAutoFillBackground(True) p = self.palette() p.setColor(self.backgroundRole(), Qt.white) self.setPalette(p) self.setWidgetResizable(True) self.setFrameShape(QFrame.NoFrame) # tools frame tools_frame = QFrame() tools_frame.setFrameShape(QFrame.NoFrame) tools_frame.setSizePolicy(QSizePolicy.Expanding, QSizePolicy.Expanding) """ Available data """ habitat_filenames_qlabel = QLabel(self.tr('Select an habitat file')) self.hab_filenames_qcombobox = QComboBox() self.hab_filenames_qcombobox.currentIndexChanged.connect(self.names_hab_change) habitat_reach_qlabel = QLabel(self.tr("Select a reach")) self.hab_reach_qcombobox = QComboBox() self.hab_reach_qcombobox.currentIndexChanged.connect(self.reach_hab_change) unit_min_title_qlabel = QLabel(self.tr("unit min :")) unit_max_title_qlabel = QLabel(self.tr("unit max :")) unit_type_title_qlabel = QLabel(self.tr("unit type :")) self.unit_min_qlabel = QLabel("") self.unit_max_qlabel = QLabel("") self.unit_type_qlabel = QLabel("") fish_available_qlabel = QLabel(self.tr('aquatic animal(s) :')) self.fish_available_qlistwidget = QListWidget() self.fish_available_qlistwidget.setSelectionMode(QAbstractItemView.ExtendedSelection) self.export_empty_text_pushbutton = QPushButton(self.tr("export empty required text file")) change_button_color(self.export_empty_text_pushbutton, "") self.export_empty_text_pushbutton.clicked.connect(self.export_empty_text_file) self.export_empty_text_pushbutton.setEnabled(False) available_firstlayout = QVBoxLayout() available_firstlayout.setAlignment(Qt.AlignTop) available_firstlayout.addWidget(habitat_filenames_qlabel) available_firstlayout.addWidget(self.hab_filenames_qcombobox) available_firstlayout.addWidget(habitat_reach_qlabel) available_firstlayout.addWidget(self.hab_reach_qcombobox) units_info_gridlayout = QGridLayout() available_firstlayout.addLayout(units_info_gridlayout) # stretch factor available_firstlayout.addWidget(fish_available_qlabel) available_firstlayout.addWidget(self.fish_available_qlistwidget) available_firstlayout.addWidget(self.export_empty_text_pushbutton) units_info_gridlayout.addWidget(unit_min_title_qlabel, 0, 0) units_info_gridlayout.addWidget(unit_max_title_qlabel, 1, 0) units_info_gridlayout.addWidget(unit_type_title_qlabel, 2, 0) units_info_gridlayout.addWidget(self.unit_min_qlabel, 0, 1) units_info_gridlayout.addWidget(self.unit_max_qlabel, 1, 1) units_info_gridlayout.addWidget(self.unit_type_qlabel, 2, 1) """ Required data """ # sequence layout fromsequence_group = QGroupBox(self.tr("from a sequence")) from_qlabel = QLabel(self.tr('min')) self.from_qlineedit = QLineEdit() self.from_qlineedit.returnPressed.connect(self.display_required_units_from_sequence) to_qlabel = QLabel(self.tr('max')) self.to_qlineedit = QLineEdit() self.to_qlineedit.returnPressed.connect(self.display_required_units_from_sequence) by_qlabel = QLabel(self.tr('by')) self.by_qlineedit = QLineEdit() self.by_qlineedit.returnPressed.connect(self.display_required_units_from_sequence) self.by_qlineedit.textEdited.connect(self.enable_seq_pushbutton) self.unit_qlabel = QLabel(self.tr('[]')) self.display_required_units_from_sequence_pushbutton = QPushButton(self.tr("run")) self.display_required_units_from_sequence_pushbutton.clicked.connect(self.display_required_units_from_sequence) change_button_color(self.display_required_units_from_sequence_pushbutton, "#47B5E6") self.display_required_units_from_sequence_pushbutton.setEnabled(False) require_secondlayout = QGridLayout() require_secondlayout.addWidget(from_qlabel, 1, 0) require_secondlayout.addWidget(self.from_qlineedit, 1, 1) require_secondlayout.addWidget(to_qlabel, 1, 2) require_secondlayout.addWidget(self.to_qlineedit, 1, 3) require_secondlayout.addWidget(by_qlabel, 1, 4) require_secondlayout.addWidget(self.by_qlineedit, 1, 5) require_secondlayout.addWidget(self.unit_qlabel, 1, 6) require_secondlayout.addWidget(self.display_required_units_from_sequence_pushbutton, 1, 7) fromsequence_group.setLayout(require_secondlayout) # txt layout fromtext_group = QGroupBox(self.tr("from .txt file")) self.fromtext_qpushbutton = QPushButton(self.tr('load and run')) change_button_color(self.fromtext_qpushbutton, "#47B5E6") self.fromtext_qpushbutton.clicked.connect(self.display_required_units_from_txtfile) fromtext_layout = QHBoxLayout() fromtext_layout.addWidget(self.fromtext_qpushbutton) fromtext_group.setLayout(fromtext_layout) """ Interpolated results """ require_units_qlabel = QLabel(self.tr('desired units and interpolated habitat values :')) self.require_unit_qtableview = QTableView() self.require_unit_qtableview.setEditTriggers(QAbstractItemView.NoEditTriggers) self.require_unit_qtableview.setSizePolicy(QSizePolicy.Expanding, QSizePolicy.Expanding) self.require_unit_qtableview.verticalHeader().setVisible(True) self.require_unit_qtableview.horizontalHeader().setVisible(True) self.require_unit_qtableview.setMinimumHeight(350) mytablemodel = MyTableModelHab("", "", "", "") self.require_unit_qtableview.setModel(mytablemodel) plot_chronicle_label = QLabel(self.tr("View interpolate chronicle :")) export_txt_chronicle_label = QLabel(self.tr("Export interpolate chronicle :")) self.plot_chronicle_qpushbutton = QPushButton(self.tr('run')) change_button_color(self.plot_chronicle_qpushbutton, "#47B5E6") self.plot_chronicle_qpushbutton.clicked.connect(self.plot_chronicle) self.plot_chronicle_qpushbutton.setEnabled(False) self.export_txt_chronicle_qpushbutton = QPushButton(self.tr('run')) change_button_color(self.export_txt_chronicle_qpushbutton, "#47B5E6") self.export_txt_chronicle_qpushbutton.clicked.connect(self.export_chronicle) self.export_txt_chronicle_qpushbutton.setEnabled(False) """ Available data """ available_data_layout = QHBoxLayout() available_data_layout.addLayout(available_firstlayout) self.available_data_group = QGroupBoxCollapsible(self.tr("Available data")) self.available_data_group.setChecked(True) self.available_data_group.setLayout(available_data_layout) """ Required data """ self.require_data_layout = QVBoxLayout() self.require_data_group = QGroupBoxCollapsible(self.tr("Desired data")) self.require_data_group.hide() self.require_data_group.setChecked(False) self.require_data_group.setLayout(self.require_data_layout) require_first_layout = QHBoxLayout() require_first_layout.addWidget(fromsequence_group) require_first_layout.addWidget(fromtext_group) self.require_data_layout.addLayout(require_first_layout) """ Interpolated results """ self.interpolated_results_group = QGroupBoxCollapsible(self.tr("Interpolated results")) self.interpolated_results_group.hide() self.interpolated_results_group.setChecked(False) require_unit_layout = QVBoxLayout() require_unit_layout.addWidget(require_units_qlabel) require_unit_layout.addWidget(self.require_unit_qtableview) plot_export_layout = QGridLayout() plot_export_layout.addWidget(plot_chronicle_label, 0, 0) plot_export_layout.addWidget(export_txt_chronicle_label, 0, 1) plot_export_layout.addWidget(self.plot_chronicle_qpushbutton, 1, 0) plot_export_layout.addWidget(self.export_txt_chronicle_qpushbutton, 1, 1) require_unit_layout.addLayout(plot_export_layout) unit_hv_layout = QHBoxLayout() unit_hv_layout.addLayout(require_unit_layout) self.interpolated_results_group.setLayout(unit_hv_layout) # vertical layout global_layout = QVBoxLayout() global_layout.setAlignment(Qt.AlignTop) tools_frame.setLayout(global_layout) global_layout.addWidget(self.available_data_group) global_layout.addWidget(self.require_data_group) global_layout.addWidget(self.interpolated_results_group) # global_layout.addStretch() self.setWidget(tools_frame) self.refresh_gui() def refresh_gui(self): # get list of file name by type names = get_filename_by_type_physic("habitat", os.path.join(self.path_prj, "hdf5")) current_index = self.hab_filenames_qcombobox.currentIndex() # self.hab_filenames_qcombobox.blockSignals(True) self.hab_filenames_qcombobox.clear() if names: if current_index == -1: current_index = 1 # append_empty_element_to_list names = [""] + names # change list widget self.hab_filenames_qcombobox.addItems(names) self.hab_filenames_qcombobox.setCurrentIndex(current_index) # self.hab_filenames_qcombobox.blockSignals(False) def disable_and_clean_group_widgets(self, disable): """ Disable and clean widgets. :param checker: :return: """ self.require_data_group.show() self.require_data_group.setChecked(True) # available self.unit_min_qlabel.setText("") self.unit_max_qlabel.setText("") self.unit_type_qlabel.setText("") self.fish_available_qlistwidget.clear() self.export_empty_text_pushbutton.setDisabled(disable) # desired self.from_qlineedit.setText("") self.from_qlineedit.setDisabled(disable) self.to_qlineedit.setText("") self.to_qlineedit.setDisabled(disable) self.by_qlineedit.setText("") self.by_qlineedit.setDisabled(disable) self.fromtext_qpushbutton.setDisabled(disable) self.require_unit_qtableview.model().clear() if disable: self.interpolated_results_group.hide() # disable pushbutton self.plot_chronicle_qpushbutton.setDisabled(disable) self.export_txt_chronicle_qpushbutton.setDisabled(disable) def names_hab_change(self): """ Ajust item list according to hdf5 filename selected by user """ hdf5name = self.hab_filenames_qcombobox.currentText() # no file if not hdf5name: # clean self.hab_reach_qcombobox.clear() self.require_data_group.hide() # file if hdf5name: # clean self.hab_reach_qcombobox.clear() # create hdf5 class to get hdf5 inforamtions hdf5 = Hdf5Management(self.path_prj, hdf5name, new=False, edit=False) if hdf5.file_object: hdf5.get_hdf5_attributes(close_file=True) if len(hdf5.data_2d.reach_list) == 1: reach_names = hdf5.data_2d.reach_list else: reach_names = [""] + hdf5.data_2d.reach_list unit_type = hdf5.data_2d.unit_type if "Date" not in unit_type: self.hab_reach_qcombobox.addItems(reach_names) else: if self.sender().hasFocus(): self.send_log.emit(self.tr("Warning: This file contain date unit. " "To be interpolated, file must contain discharge or timestep unit.")) def reach_hab_change(self): hdf5name = self.hab_filenames_qcombobox.currentText() reach_name = self.hab_reach_qcombobox.currentText() self.unit_qlabel.setText("[]") # no file if not reach_name: # clean self.disable_and_clean_group_widgets(True) # file if reach_name: # clean self.disable_and_clean_group_widgets(False) # clean hdf5 = Hdf5Management(self.path_prj, hdf5name, new=False, edit=False) hdf5.get_hdf5_attributes(close_file=True) unit_type = hdf5.data_2d.unit_type unit_type = unit_type.replace("m3/s", "m<sup>3</sup>/s") unit_type_value = unit_type[unit_type.index("["):unit_type.index("]")+1] reach_index = hdf5.data_2d.reach_list.index(reach_name) units_name = hdf5.data_2d.unit_list[reach_index] # hab if hdf5.data_2d.hvum.hdf5_and_computable_list.habs().meshs().names_gui(): for mesh in hdf5.data_2d.hvum.hdf5_and_computable_list.habs().meshs(): mesh_item = QListWidgetItem(mesh.name_gui, self.fish_available_qlistwidget) mesh_item.setData(Qt.UserRole, mesh) self.fish_available_qlistwidget.addItem(mesh_item) self.fish_available_qlistwidget.selectAll() # set min and max unit for from to by unit_number_list = list(map(float, units_name)) min_unit = min(unit_number_list) max_unit = max(unit_number_list) self.unit_min_qlabel.setText(str(min_unit)) self.unit_max_qlabel.setText(str(max_unit)) self.unit_type_qlabel.setText(unit_type) # sequence if len(unit_number_list) > 1: self.from_qlineedit.setText(str(min_unit)) self.to_qlineedit.setText(str(max_unit)) self.unit_qlabel.setText(unit_type_value) elif len(unit_number_list) == 1: pass # self.send_log.emit("Warning: " + self.tr("Interpolation need at least two time/discharge unit. " # "Their is only one is this file.")) def enable_seq_pushbutton(self): if self.by_qlineedit.text(): self.display_required_units_from_sequence_pushbutton.setEnabled(True) else: self.display_required_units_from_sequence_pushbutton.setEnabled(False) def display_required_units_from_sequence(self): from_sequ = self.from_qlineedit.text().replace(",", ".") to_sequ = self.to_qlineedit.text().replace(",", ".") by_sequ = self.by_qlineedit.text().replace(",", ".") # is string if from_sequ == "" or to_sequ == "" or by_sequ == "": self.send_log.emit('Error: ' + self.tr('The sequence values must be specified (from, to and by).')) return # is float string if not isstranumber(from_sequ) or not isstranumber(to_sequ) or not isstranumber(by_sequ): self.send_log.emit('Error: ' + self.tr('The sequence values must be of numerical type.')) return # is float min < max if not float(from_sequ) < float(to_sequ): self.send_log.emit('Error: ' + self.tr('Max sequence value must be strictly greater than min sequence value.')) return # is by > 0 if not float(by_sequ) > 0: self.send_log.emit('Error: ' + self.tr('By sequence value must be strictly greater than 0.')) return # is fish selected selection = self.fish_available_qlistwidget.selectedItems() if not selection: self.send_log.emit('Error: ' + self.tr('No fish selected.')) return # ok else: from_sequ = float(from_sequ) # from to_sequ = float(to_sequ) # to by_sequ = float(by_sequ) # by # dict range chonicle_from_seq = dict(units=list(frange(from_sequ, to_sequ, by_sequ))) # types text_unit = self.unit_type_qlabel.text() types_from_seq = dict(units=text_unit) # #[text_unit.find('[') + 1:text_unit.find(']')] # display self.create_model_array_and_display(chonicle_from_seq, types_from_seq, source="seq") def display_required_units_from_txtfile(self): # is fish ? selection = self.fish_available_qlistwidget.selectedItems() if not selection: self.send_log.emit('Error: ' + self.tr('No fish selected.')) return # find the filename based on user choice filename_path = QFileDialog.getOpenFileName(self, self.tr("Select file"), self.path_last_file_loaded, "File (*.txt)")[0] self.path_last_file_loaded = os.path.dirname(filename_path) # exeption: you should be able to clik on "cancel" if filename_path: chronicle_from_file, types_from_file = read_chronicle_from_text_file(filename_path) if not chronicle_from_file: self.send_log.emit(types_from_file) if chronicle_from_file: # display self.create_model_array_and_display(chronicle_from_file, types_from_file, source=filename_path) def create_model_array_and_display(self, chronicle, types, source): hvum = HydraulicVariableUnitManagement() # get fish selected for selection in self.fish_available_qlistwidget.selectedItems(): hvum.user_target_list.append(selection.data(Qt.UserRole)) # get filename hdf5name = self.hab_filenames_qcombobox.currentText() # load hdf5 data hdf5 = Hdf5Management(self.path_prj, hdf5name, new=False, edit=False) hdf5.get_hdf5_attributes(close_file=True) # get reach_name reach_index = hdf5.data_2d.reach_list.index(self.hab_reach_qcombobox.currentText()) # check matching units for interpolation valid, text = check_matching_units(hdf5.data_2d.unit_type, types) if not valid: self.send_log.emit("Warning: " + self.tr("Interpolation not done.") + text) # disable pushbutton self.plot_chronicle_qpushbutton.setEnabled(False) self.export_txt_chronicle_qpushbutton.setEnabled(False) if valid: data_to_table, horiz_headers, vertical_headers = compute_interpolation(hdf5.data_2d, hvum.user_target_list, reach_index, chronicle, types, rounddata=True) for horiz_header_num, horiz_header in enumerate(horiz_headers): horiz_headers[horiz_header_num] = horiz_header.replace("m<sup>3</sup>/s", "m3/s") self.mytablemodel = MyTableModelHab(data_to_table, horiz_headers, vertical_headers, source=source) self.require_unit_qtableview.model().clear() self.require_unit_qtableview.setModel(self.mytablemodel) # set model # ajust width header = self.require_unit_qtableview.horizontalHeader() for i in range(len(horiz_headers)): header.setSectionResizeMode(i, QHeaderView.ResizeToContents) self.require_unit_qtableview.verticalHeader().setDefaultSectionSize( self.require_unit_qtableview.verticalHeader().minimumSectionSize()) self.plot_chronicle_qpushbutton.setEnabled(True) self.export_txt_chronicle_qpushbutton.setEnabled(True) self.send_log.emit(self.tr("Interpolation done. Interpolated values can now be view in graphic and export in text file.")) # disable pushbutton self.plot_chronicle_qpushbutton.setEnabled(True) self.export_txt_chronicle_qpushbutton.setEnabled(True) self.interpolated_results_group.show() self.interpolated_results_group.setChecked(True) def export_empty_text_file(self): hdf5name = self.hab_filenames_qcombobox.currentText() if hdf5name: # create hdf5 class hdf5 = Hdf5Management(self.path_prj, hdf5name, new=False, edit=False) # get hdf5 inforamtions hdf5.get_hdf5_attributes(close_file=True) unit_type = hdf5.data_2d.unit_type units_name = hdf5.data_2d.unit_list[self.hab_reach_qcombobox.currentIndex()] unit_number = list(map(float, units_name)) min_unit = min(unit_number) max_unit = max(unit_number) # export exported = export_empty_text_from_hdf5(unit_type, min_unit, max_unit, hdf5name, self.path_prj) if exported: self.send_log.emit(self.tr("Empty text has been exported in 'output/text' project folder. Open and fill it " "with the desired values and then import it in HABBY.")) if not exported: self.send_log.emit('Error: ' + self.tr('The file has not been exported as it may be opened by another program.')) def plot_chronicle(self): hvum = HydraulicVariableUnitManagement() # get fish selected for selection in self.fish_available_qlistwidget.selectedItems(): hvum.user_target_list.append(selection.data(Qt.UserRole)) # get filename hdf5name = self.hab_filenames_qcombobox.currentText() if not hdf5name: self.send_log.emit('Error: ' + self.tr('No .hab selected.')) return if self.mytablemodel: # max if len(hvum.user_target_list) > 32: self.send_log.emit('Warning: ' + self.tr( 'You cannot display more than 32 habitat values per graph. Current selected : ') + str( len(hvum.user_target_list)) + ". " + self.tr("Only the first 32 will be displayed.") + " " + self.tr( 'You have to re-compute interpolation with 32 selected habitat values at maximum. There is no limit for txt exports.')) hvum.user_target_list = hvum.user_target_list[:32] # seq or txt source = self.mytablemodel.source # reread from seq (tablemodel) if source == "seq": units = dict(units=list(map(float, self.mytablemodel.rownames))) unit_type = dict(units=self.unit_type_qlabel.text()) # reread from text file (re-read file) else: units, unit_type = read_chronicle_from_text_file(source) # load figure option project_properties = load_project_properties(self.path_prj) interp_attr = lambda: None interp_attr.reach = self.hab_reach_qcombobox.currentText() interp_attr.units = units interp_attr.unit_type = unit_type interp_attr.hvum = hvum interp_attr.mode = "plot" # process_manager self.process_manager.set_interpolation_hdf5_mode(self.path_prj, self.hab_filenames_qcombobox.currentText(), interp_attr, project_properties) # process_prog_show self.process_prog_show.start_show_prog(self.process_manager) def export_chronicle(self): hvum = HydraulicVariableUnitManagement() # get fish selected for selection in self.fish_available_qlistwidget.selectedItems(): hvum.user_target_list.append(selection.data(Qt.UserRole)) # get filename hdf5name = self.hab_filenames_qcombobox.currentText() if not hdf5name: self.send_log.emit('Error: ' + self.tr('No .hab selected.')) return if self.mytablemodel: # fish names and units names from tableview fish_names_osi_wua = self.mytablemodel.colnames fish_names = [] for fish in fish_names_osi_wua: if "osi_" in fish: fish_names.append(fish.replace("osi_", "")) if "wua_" in fish: fish_names.append(fish.replace("wua_", "")) # seq or txt source = self.mytablemodel.source # reread from seq (tablemodel) if source == "seq": units = dict(units=list(map(float, self.mytablemodel.rownames))) # types text_unit = self.unit_type_qlabel.text() unit_type = dict(units=text_unit[text_unit.find('[') + 1:text_unit.find(']')]) # reread from text file (re-read file) else: units, unit_type = read_chronicle_from_text_file(source) # load figure option project_properties = load_project_properties(self.path_prj) interp_attr = lambda: None interp_attr.reach = self.hab_reach_qcombobox.currentText() interp_attr.units = units interp_attr.unit_type = unit_type interp_attr.hvum = hvum interp_attr.mode = "export" # process_manager self.process_manager.set_interpolation_hdf5_mode(self.path_prj, hdf5name, interp_attr, project_properties) # process_prog_show self.process_prog_show.start_show_prog(self.process_manager)
class ComputingGroup(QGroupBoxCollapsible): """ This class is a subclass of class QGroupBox. """ send_refresh_filenames = pyqtSignal(name='send_refresh_filenames') def __init__(self, path_prj, name_prj, send_log, title): super().__init__() self.path_prj = path_prj self.name_prj = name_prj self.send_log = send_log self.path_last_file_loaded = self.path_prj self.project_properties = load_project_properties(self.path_prj) self.setTitle(title) self.init_ui() # process_manager self.process_manager = MyProcessManager("hrr") def init_ui(self): # file_selection file_selection_label = QLabel(self.tr("Select a 2D mesh file :")) self.file_selection_listwidget = QListWidget() self.file_selection_listwidget.setSelectionMode( QAbstractItemView.ExtendedSelection) self.file_selection_listwidget.itemSelectionChanged.connect( self.names_hdf5_change) self.file_selection_listwidget.setVerticalScrollBarPolicy( Qt.ScrollBarAlwaysOff) self.file_selection_listwidget.verticalScrollBar().setEnabled(True) self.file_selection_listwidget.verticalScrollBar( ).valueChanged.connect(self.change_scroll_position) self.scrollbar = self.file_selection_listwidget.verticalScrollBar() file_selection_layout = QGridLayout() file_selection_layout.addWidget(file_selection_label, 0, 0) file_selection_layout.addWidget(self.file_selection_listwidget, 1, 0) file_selection_layout.addWidget(self.scrollbar, 1, 2) file_selection_layout.setColumnStretch(0, 30) file_selection_layout.setColumnStretch(1, 1) """ progress layout """ # progress_layout self.progress_layout = ProcessProgLayout( self.compute, send_log=self.send_log, process_type="hrr", send_refresh_filenames=self.send_refresh_filenames) grid_layout = QGridLayout() grid_layout.addLayout(self.progress_layout, 5, 0, 1, 3) general_layout = QVBoxLayout() general_layout.addLayout(file_selection_layout) general_layout.addLayout(grid_layout) self.setLayout(general_layout) def update_gui(self): selected_file_names = [ selection_el.text() for selection_el in self.file_selection_listwidget.selectedItems() ] # computing_group hyd_names = get_filename_by_type_physic( "hydraulic", os.path.join(self.path_prj, "hdf5")) names = hyd_names self.file_selection_listwidget.blockSignals(True) self.file_selection_listwidget.clear() if names: for name in names: # check try: hdf5 = Hdf5Management(self.path_prj, name, new=False, edit=False) hdf5.get_hdf5_attributes(close_file=True) item_name = QListWidgetItem() item_name.setText(name) self.file_selection_listwidget.addItem(item_name) if True: #TODO : sort files (hdf5 attributes available for HRR) .hyd, one whole profile for all units, ... pass else: pass except: self.send_log.emit( self. tr("Error: " + name + " file seems to be corrupted. Delete it with HABBY or manually." )) self.file_selection_listwidget.blockSignals(False) # preselection if one if self.file_selection_listwidget.count() == 1: self.file_selection_listwidget.selectAll() def change_scroll_position(self, index): self.file_selection_listwidget.verticalScrollBar().setValue(index) def names_hdf5_change(self): selection = self.file_selection_listwidget.selectedItems() self.progress_layout.progress_bar.setValue(0.0) self.progress_layout.progress_label.setText("{0:.0f}/{1:.0f}".format( 0.0, len(selection))) if selection: self.progress_layout.run_stop_button.setEnabled(True) else: self.progress_layout.run_stop_button.setEnabled(False) def compute(self): if len(self.file_selection_listwidget.selectedItems()) > 0: hrr_description = dict( deltatlist=[], hdf5_name_list=[ selection_el.text() for selection_el in self.file_selection_listwidget.selectedItems() ]) self.progress_layout.process_manager.set_hrr_hdf5_mode( self.path_prj, hrr_description, self.project_properties) # start thread self.progress_layout.start_process() def stop_compute(self): # stop_by_user self.process_manager.stop_by_user()