def edit_cell(self, parent, row, column): """ Returns the editor widget to use for editing a specified cell's value. """ self.cell_row = cell_row = self.data_row_for(row) grid_adapter = self.grid_adapter # Get the editor factory to use. If none, exit (read-only cell): editor_factory = grid_adapter.get_editor(cell_row, column) if editor_factory is None: return None # Create the requested type of editor from the editor factory: # Note: We save the editor reference so that the editor doesn't get # garbage collected too soon. self.cell_column = column object, name = grid_adapter.get_alias(cell_row, column) handler = None if grid_adapter.get_change_mode(cell_row, column) != "live": handler = DeferredEditHandler(target_object=object, defer_modified=True).set(target_name=name) object = handler.defer_object editor = editor_factory.simple_editor(self.ui, object, name, "").set(item=self.item, object_name="") # Tell the editor to actually build the editing widget: editor.prepare(control_adapter(parent)) # Make sure that the editor is a control (and not a layout): self._editor = editor control = editor.control if not isinstance(control, QWidget): layout = control control = QWidget(parent) control.setLayout(layout) layout.setContentsMargins(5, 0, 5, 0) control._editor = editor control._handler = handler header = self.control.horizontalHeader() column_width = header.sectionSize(column) if self.factory.resize_cell_editor: control.setGeometry(0, 0, column_width, self.height) else: # Adjust the row height of the grid row to fit the editor control: height = control.height() if height > self.height: control._row = row self.control.verticalHeader().resizeSection(row, height) # Resize the grid column width to fit the editor if necessary: width = control.width() if width > column_width: control._column = column control._width = column_width header.resizeSection(column, width) # Return the editing widget as the result: return control
class OutputAnalyserDialog(QDialog): def __init__(self, iface, parent, params): QDialog.__init__(self, parent) self.iface = iface self.parent = parent self.params = params self.output_reader = None self.tool = None self.element_ids_nodes = None self.element_ids_links = None self.nodes_lay = None self.links_lay = None self.setWindowTitle(Parameters.plug_in_name) # Selection changed listeners self.params.junctions_vlay.selectionChanged.connect( self.feature_sel_changed) self.params.reservoirs_vlay.selectionChanged.connect( self.feature_sel_changed) self.params.tanks_vlay.selectionChanged.connect( self.feature_sel_changed) self.params.pipes_vlay.selectionChanged.connect( self.feature_sel_changed) self.params.pumps_vlay.selectionChanged.connect( self.feature_sel_changed) self.params.valves_vlay.selectionChanged.connect( self.feature_sel_changed) # self.setMinimumWidth(min_width) # self.setMinimumHeight(min_height) fra_main_lay = QVBoxLayout(self) self.fra_out_file = QFrame(self) fra_out_file_lay = QHBoxLayout(self.fra_out_file) self.lbl_out_file = QLabel('Simulation output file:') self.txt_out_file = QLineEdit('') self.txt_out_file.setReadOnly(True) self.btn_out_file = QToolButton() self.btn_out_file.setText('...') self.btn_out_file.clicked.connect(self.btn_out_file_clicked) fra_out_file_lay.addWidget(self.lbl_out_file) fra_out_file_lay.addWidget(self.txt_out_file) fra_out_file_lay.addWidget(self.btn_out_file) self.tab_widget = QTabWidget(self) # Graphs tab --------------------------------------------------------------------------------------------------- self.tab_graphs = QWidget() tab_graphs_lay = QHBoxLayout(self.tab_graphs) # Left frame self.fra_graphs_left = QFrame() self.fra_graphs_left.setMaximumWidth(100) fra_graphs_left_lay = QVBoxLayout(self.fra_graphs_left) self.btn_sel_element = QPushButton('Pick') self.btn_sel_element.clicked.connect(self.btn_sel_element_clicked) fra_graphs_left_lay.addWidget(self.btn_sel_element) # Nodes self.grb_nodes = QGroupBox(u'Nodes') lay_grb_nodes = QVBoxLayout(self.grb_nodes) self.chk_node_demand = QCheckBox('Demand') lay_grb_nodes.addWidget(self.chk_node_demand) self.chk_node_head = QCheckBox('Head') lay_grb_nodes.addWidget(self.chk_node_head) self.chk_node_pressure = QCheckBox('Pressure') lay_grb_nodes.addWidget(self.chk_node_pressure) self.chk_node_quality = QCheckBox('Quality') lay_grb_nodes.addWidget(self.chk_node_quality) fra_graphs_left_lay.addWidget(self.grb_nodes) # Links self.grb_links = QGroupBox(u'Links') lay_grb_links = QVBoxLayout(self.grb_links) self.chk_link_flow = QCheckBox('Flow') lay_grb_links.addWidget(self.chk_link_flow) self.chk_link_velocity = QCheckBox('Velocity') lay_grb_links.addWidget(self.chk_link_velocity) self.chk_link_headloss = QCheckBox('Headloss') lay_grb_links.addWidget(self.chk_link_headloss) self.chk_link_quality = QCheckBox('Quality') lay_grb_links.addWidget(self.chk_link_quality) fra_graphs_left_lay.addWidget(self.grb_links) self.btn_draw_graph = QPushButton('Draw') self.btn_draw_graph.clicked.connect(self.draw_graphs) fra_graphs_left_lay.addWidget(self.btn_draw_graph) self.spacer = QSpacerItem(20, 40, QSizePolicy.Minimum, QSizePolicy.Expanding) fra_graphs_left_lay.addItem(self.spacer) tab_graphs_lay.addWidget(self.fra_graphs_left) # Right frame self.fra_graphs_right = QFrame() fra_graphs_right_lay = QVBoxLayout(self.fra_graphs_right) fra_graphs_right_lay.setContentsMargins(0, 0, 0, 0) self.static_canvas = StaticMplCanvas(self.fra_graphs_right, width=5, height=4, dpi=100) fra_graphs_right_lay.addWidget(self.static_canvas) tab_graphs_lay.addWidget(self.fra_graphs_right) # lay.addWidget(self.button) self.tab_widget.addTab(self.tab_graphs, 'Graphs') # Maps tab ----------------------------------------------------------------------------------------------------- self.tab_maps = QWidget() tab_maps_lay = QHBoxLayout(self.tab_maps) # Left frame self.fra_maps_left = QFrame() self.fra_maps_left.setMaximumWidth(200) fra_maps_left_lay = QVBoxLayout(self.fra_maps_left) self.grb_maps = QGroupBox(u'Variable') grb_maps_lay = QVBoxLayout(self.grb_maps) self.rad_maps_node_demand = QRadioButton(u'Node demand') grb_maps_lay.addWidget(self.rad_maps_node_demand) self.rad_maps_node_head = QRadioButton(u'Node head') grb_maps_lay.addWidget(self.rad_maps_node_head) self.rad_maps_node_pressure = QRadioButton(u'Node pressure') grb_maps_lay.addWidget(self.rad_maps_node_pressure) self.rad_maps_node_quality = QRadioButton(u'Node quality') grb_maps_lay.addWidget(self.rad_maps_node_quality) self.rad_maps_link_flow = QRadioButton(u'Link flow') grb_maps_lay.addWidget(self.rad_maps_link_flow) self.rad_maps_link_velocity = QRadioButton(u'Link velocity') grb_maps_lay.addWidget(self.rad_maps_link_velocity) self.rad_maps_link_headloss = QRadioButton(u'Link headloss') grb_maps_lay.addWidget(self.rad_maps_link_headloss) self.rad_maps_link_quality = QRadioButton(u'Link quality') grb_maps_lay.addWidget(self.rad_maps_link_quality) fra_maps_left_lay.addWidget(self.grb_maps) fra_maps_left_lay.addItem(self.spacer) tab_maps_lay.addWidget(self.fra_maps_left) # Right maps frame self.fra_maps_right = QFrame() fra_maps_right_lay = QVBoxLayout(self.fra_maps_right) self.fra_maps_right_time = QFrame() fra_maps_right_time_lay = QFormLayout(self.fra_maps_right_time) self.lbl_map_times = QLabel(u'Period [h]:') self.cbo_map_times = QComboBox() fra_maps_right_time_lay.addRow(self.lbl_map_times, self.cbo_map_times) fra_maps_right_lay.addWidget(self.fra_maps_right_time) self.btn_draw_map = QPushButton(u'Draw map') self.btn_draw_map.clicked.connect(self.draw_maps) fra_maps_right_lay.addWidget(self.btn_draw_map) fra_maps_right_lay.addItem(self.spacer) tab_maps_lay.addWidget(self.fra_maps_right) self.tab_widget.addTab(self.tab_maps, 'Maps') # # Add to main fra_main_lay.addWidget(self.fra_out_file) fra_main_lay.addWidget(self.tab_widget) self.setup() self.initialize() # self.read_outputs() # Set size self.setMinimumWidth(self.tab_graphs.width()) self.setMinimumHeight(self.tab_graphs.height()) def setup(self): pass def btn_out_file_clicked(self): config_file = ConfigFile(Parameters.config_file_path) out_file = QFileDialog.getOpenFileName(self, 'Select out file', config_file.get_last_out_file(), 'Out files (*.out)') if out_file is None or out_file == '': return config_file.set_last_out_file(out_file) self.txt_out_file.setText(out_file) self.read_outputs() if self.output_reader is None: return # Fill times combo self.cbo_map_times.clear() for period_s in self.output_reader.period_results.iterkeys(): text = self.seconds_to_string( period_s, self.output_reader.sim_duration_secs, self.output_reader.report_time_step_secs) self.cbo_map_times.addItem(text, period_s) def initialize(self): # Graphs self.grb_nodes.setEnabled(False) self.grb_links.setEnabled(False) # Maps self.rad_maps_node_demand.setChecked(True) def feature_sel_changed(self): is_nodes = False sel_junctions = self.params.junctions_vlay.selectedFeatureCount() sel_reservoirs = self.params.reservoirs_vlay.selectedFeatureCount() sel_tanks = self.params.tanks_vlay.selectedFeatureCount() if sel_junctions > 0 or sel_reservoirs > 0 or sel_tanks > 0: is_nodes = True self.grb_nodes.setEnabled(is_nodes) is_links = False sel_pipes = self.params.pipes_vlay.selectedFeatureCount() sel_pumps = self.params.pumps_vlay.selectedFeatureCount() sel_valves = self.params.valves_vlay.selectedFeatureCount() if sel_pipes > 0 or sel_pumps > 0 or sel_valves > 0: is_links = True self.grb_links.setEnabled(is_links) def read_outputs(self): try: QApplication.setOverrideCursor(Qt.WaitCursor) self.output_reader = BinaryOutputReader() self.output_reader.read(self.txt_out_file.text()) QApplication.restoreOverrideCursor() # Check if output compatible with loaded project compatible = True out_nodes_nr = self.output_reader.nodes_nr out_tanks_reservs_nr = self.output_reader.tanks_reservs_nr out_juncts_nr = out_nodes_nr - out_tanks_reservs_nr out_links_nr = self.output_reader.links_nr out_pumps_nr = self.output_reader.pumps_nr out_valves_nr = self.output_reader.valves_nr out_pipes_nr = out_links_nr - out_pumps_nr - out_valves_nr if out_juncts_nr != self.params.junctions_vlay.featureCount(): compatible = False if out_tanks_reservs_nr != ( self.params.reservoirs_vlay.featureCount() + self.params.tanks_vlay.featureCount()): compatible = False if out_pipes_nr != self.params.pipes_vlay.featureCount(): compatible = False if out_valves_nr != self.params.valves_vlay.featureCount(): compatible = False if out_pumps_nr != self.params.pumps_vlay.featureCount(): compatible = False if not compatible: message = 'The out file appears to incompatible with the actual project layers.' QMessageBox.warning(self, Parameters.plug_in_name, message, QMessageBox.Ok) self.output_reader = None self.txt_out_file.setText('') else: # Message after reading completed message = 'Out file loaded: ' + str( out_nodes_nr) + ' nodes, ' + str( out_links_nr) + ' links found.' # Clear refs to output layer self.params.out_lay_node_demand = None self.params.out_lay_node_head = None self.params.out_lay_node_pressure = None self.params.out_lay_node_quality = None self.params.out_lay_link_flow = None self.params.out_lay_link_velocity = None self.params.out_lay_link_headloss = None self.params.out_lay_link_quality = None QMessageBox.information(self, Parameters.plug_in_name, message, QMessageBox.Ok) finally: # self.iface.messageBar().pushWarning( # Parameters.plug_in_name, # 'Error while reading output file.') # TODO: softcode # self.output_reader = None # self.txt_out_file.setText('') QApplication.restoreOverrideCursor() def btn_sel_element_clicked(self): if self.output_reader is None: self.iface.messageBar().pushMessage( Parameters.plug_in_name, 'Please select the simulation out file.', QgsMessageBar.WARNING, 5) # TODO: softcode return self.tool = SelectTool(self, self.params) self.iface.mapCanvas().setMapTool(self.tool) cursor = QCursor() cursor.setShape(Qt.ArrowCursor) self.iface.mapCanvas().setCursor(cursor) def draw_graphs(self): # Get selected features self.element_ids_nodes = [] for junction_feat in self.params.junctions_vlay.selectedFeatures(): self.element_ids_nodes.append( junction_feat.attribute(Junction.field_name_eid)) for reservoir_feat in self.params.reservoirs_vlay.selectedFeatures(): self.element_ids_nodes.append( reservoir_feat.attribute(Reservoir.field_name_eid)) for tank_feat in self.params.tanks_vlay.selectedFeatures(): self.element_ids_nodes.append( tank_feat.attribute(Tank.field_name_eid)) self.element_ids_links = [] for pipe_feat in self.params.pipes_vlay.selectedFeatures(): self.element_ids_links.append( pipe_feat.attribute(Pipe.field_name_eid)) for pump_feat in self.params.pumps_vlay.selectedFeatures(): self.element_ids_links.append( pump_feat.attribute(Pump.field_name_eid)) for valve_feat in self.params.valves_vlay.selectedFeatures(): self.element_ids_links.append( valve_feat.attribute(Valve.field_name_eid)) # Build values dictionaries xs = self.output_reader.report_times ys_d_d = {} params_count = 0 # Nodes if self.grb_nodes.isEnabled(): if self.chk_node_demand.isChecked(): params_count += 1 ys_d = {} for element_id in self.element_ids_nodes: ys_d[element_id] = [ self.output_reader.node_demands_d[element_id], self.params.options.flow_units ] ys_d_d[OutputParamCodes.NODE_DEMAND] = ys_d if self.chk_node_head.isChecked(): params_count += 1 ys_d = {} for element_id in self.element_ids_nodes: ys_d[element_id] = [ self.output_reader.node_heads_d[element_id], Options.units_diameter_tanks[self.params.options.units] ] ys_d_d[OutputParamCodes.NODE_HEAD] = ys_d if self.chk_node_pressure.isChecked(): params_count += 1 ys_d = {} for element_id in self.element_ids_nodes: ys_d[element_id] = [ self.output_reader.node_pressures_d[element_id], Options.units_pressure[self.params.options.units] ] ys_d_d[OutputParamCodes.NODE_PRESSURE] = ys_d if self.chk_node_quality.isChecked(): params_count += 1 ys_d = {} for element_id in self.element_ids_nodes: ys_d[element_id] = [ self.output_reader.node_qualities_d[element_id], Quality.quality_units_text[ self.params.options.quality.mass_units] ] ys_d_d[OutputParamCodes.NODE_QUALITY] = ys_d # Links if self.grb_links.isEnabled(): if self.chk_link_flow.isChecked(): params_count += 1 ys_d = {} for element_id in self.element_ids_links: ys_d[element_id] = [ self.output_reader.link_flows_d[element_id], self.params.options.flow_units ] ys_d_d[OutputParamCodes.LINK_FLOW] = ys_d if self.chk_link_velocity.isChecked(): params_count += 1 ys_d = {} for element_id in self.element_ids_links: ys_d[element_id] = [ self.output_reader.link_velocities_d[element_id], Options.units_velocity[self.params.options.units] ] ys_d_d[OutputParamCodes.LINK_VELOCITY] = ys_d if self.chk_link_headloss.isChecked(): params_count += 1 ys_d = {} for element_id in self.element_ids_links: ys_d[element_id] = [ self.output_reader.link_headlosses_d[element_id], Options.units_diameter_tanks[self.params.options.units] ] ys_d_d[OutputParamCodes.LINK_HEADLOSS] = ys_d if self.chk_link_quality.isChecked(): params_count += 1 ys_d = {} for element_id in self.element_ids_links: ys_d[element_id] = [ self.output_reader.link_qualities_d[element_id], Quality.quality_units_text[ self.params.options.quality.mass_units] ] ys_d_d[OutputParamCodes.LINK_QUALITY] = ys_d if ys_d_d: self.static_canvas.draw_output_line(xs, ys_d_d, params_count) def draw_maps(self): """ Draws layers with all the attributes :return: """ report_time = self.cbo_map_times.itemText( self.cbo_map_times.currentIndex()) if self.rad_maps_node_demand.isChecked( ): # ------------------------------------------------------------------- lay_name = u'Node demand' lay_id = self.draw_map(LayerType.NODE, self.params.out_lay_node_demand_id, lay_name, self.output_reader.node_demands_d, report_time) self.params.out_lay_node_demand_id = lay_id elif self.rad_maps_node_head.isChecked(): lay_name = u'Node head' lay_id = self.draw_map(LayerType.NODE, self.params.out_lay_node_head_id, lay_name, self.output_reader.node_heads_d, report_time) self.params.out_lay_node_head_id = lay_id elif self.rad_maps_node_pressure.isChecked(): lay_name = u'Node pressure' lay_id = self.draw_map(LayerType.NODE, self.params.out_lay_node_pressure_id, lay_name, self.output_reader.node_pressures_d, report_time) self.params.out_lay_node_pressure_id = lay_id elif self.rad_maps_node_quality.isChecked(): lay_name = u'Node quality' lay_id = self.draw_map(LayerType.NODE, self.params.out_lay_node_quality_id, lay_name, self.output_reader.node_qualities_d, report_time) self.params.out_lay_node_quality_id = lay_id elif self.rad_maps_link_flow.isChecked( ): # ------------------------------------------------------------------- lay_name = u'Link flow' lay_id = self.draw_map(LayerType.LINK, self.params.out_lay_link_flow_id, lay_name, self.output_reader.link_flows_d, report_time) self.params.out_lay_link_flow_id = lay_id elif self.rad_maps_link_velocity.isChecked(): lay_name = u'Link velocity' lay_id = self.draw_map(LayerType.LINK, self.params.out_lay_link_velocity_id, lay_name, self.output_reader.link_velocities_d, report_time) self.params.out_lay_link_velocity_id = lay_id elif self.rad_maps_link_headloss.isChecked(): lay_name = u'Link headloss' lay_id = self.draw_map(LayerType.LINK, self.params.out_lay_link_headloss_id, lay_name, self.output_reader.link_headlosses_d, report_time) self.params.out_lay_link_headloss_id = lay_id elif self.rad_maps_link_quality.isChecked(): lay_name = u'Link quality' lay_id = self.draw_map(LayerType.LINK, self.params.out_lay_link_quality_id, lay_name, self.output_reader.link_qualities_d, report_time) self.params.out_lay_link_quality_id = lay_id def draw_map(self, lay_type, lay_id, lay_name, dataset, report_time): try: QApplication.setOverrideCursor(Qt.WaitCursor) lay_name += ' ' + report_time lay = LayerUtils.get_lay_from_id(lay_id) if lay is None: if lay_type == LayerType.NODE: lay = self.create_out_node_layer(lay_name, dataset) ns = NodeSymbology() lay.setRendererV2( ns.make_graduated_sym_renderer(lay, report_time)) elif lay_type == LayerType.LINK: lay = self.create_out_link_layer(lay_name, dataset) ls = LinkSymbology() lay.setRendererV2( ls.make_flow_sym_renderer(lay, report_time)) lay_id = lay.id() QgsMapLayerRegistry.instance().addMapLayer(lay) self.params.out_layers.append(lay) else: lay.setLayerName(lay_name) lay.triggerRepaint() QApplication.restoreOverrideCursor() finally: QApplication.restoreOverrideCursor() return lay_id def btn_cancel_clicked(self): self.setVisible(False) def btn_ok_clicked(self): pass def create_out_node_layer(self, lay_name, values_d): return self.create_out_layer(lay_name, values_d, LayerType.NODE) def create_out_link_layer(self, lay_name, values_d): return self.create_out_layer(lay_name, values_d, LayerType.LINK) def create_out_layer(self, lay_name, values_d, lay_type): field_name_vars = [] periods = self.output_reader.period_results.keys() for period_s in periods: text = self.seconds_to_string( period_s, self.output_reader.sim_duration_secs, self.output_reader.report_time_step_secs) field_name_vars.append(text) if lay_type == LayerType.NODE: new_lay = MemoryDS.create_nodes_lay(self.params, field_name_vars, lay_name, self.params.crs) elif lay_type == LayerType.LINK: new_lay = MemoryDS.create_links_lay(self.params, field_name_vars, lay_name, self.params.crs) with edit(new_lay): # Update attributes for feat in new_lay.getFeatures(): fid = feat.id() eid = feat.attribute(Node.field_name_eid) values = values_d[eid] for p in range(len(periods)): new_lay.changeAttributeValue(fid, p + 1, values[p]) return new_lay def seconds_to_string(self, period_s, duration_s, interval_s): day = int(math.floor(period_s / 86400)) hour = period_s / 3600 - day * 24 minute = period_s / 60 - day * 24 * 60 - hour * 60 second = period_s - day * 86400 - hour * 3600 - minute * 60 text = '' if duration_s >= 86400: # We need days text += str(day) + 'd' if duration_s >= 3600: # We need hours text += '{:02}'.format(hour) + 'H' text += '{:02}'.format(minute) + 'm' if second > 0: text += '{:02}'.format(second) + 's' return text
class RingWindow(QMainWindow): image: RingImageQLabel statusbar: QtGui.QStatusBar def __init__(self): super(RingWindow, self).__init__() path = os.path.join(sys.path[0], __package__) uic.loadUi(os.path.join(path, 'gui_ring.ui'), self) self.move(50, 0) self.ctrl = QWidget() uic.loadUi(os.path.join(path, 'gui_ring_controls.ui'), self.ctrl) self.ctrl.show() self.ctrl.zSpin.valueChanged.connect(self.onZValueChange) self.ctrl.openButton.pressed.connect(self.onOpenButton) self.ctrl.addButton.pressed.connect(self.onAddButton) self.ctrl.plotButton.pressed.connect(self.onPlotButton) self.ctrl.measureButton.pressed.connect(self.onMeasureButton) self.ctrl.dnaSpin.valueChanged.connect(self.onDnaValChange) self.ctrl.actSpin.valueChanged.connect(self.onActValChange) self.ctrl.dnaChk.toggled.connect(self.onImgToggle) self.ctrl.actChk.toggled.connect(self.onImgToggle) self.ctrl.renderChk.stateChanged.connect(self.onRenderChk) self.image.clicked.connect(self.onImgUpdate) self.image.lineUpdated.connect(self.onImgUpdate) self.image.linePicked.connect(self.onLinePickedFromImage) self.image.dnaChannel = self.ctrl.dnaSpin.value() self.image.actChannel = self.ctrl.actSpin.value() self.grph = GraphWidget() self.grph.show() self.grph.linePicked.connect(self.onLinePickedFromGraph) self.ctrl.setWindowFlags(self.ctrl.windowFlags() & ~QtCore.Qt.WindowStaysOnTopHint) self.grph.setWindowFlags(self.grph.windowFlags() & ~QtCore.Qt.WindowStaysOnTopHint) self.image.dnaChannel = self.ctrl.dnaSpin.value() self.image.actChannel = self.ctrl.actSpin.value() self.measure_n = 0 self.selectedLine = None self.df = pd.DataFrame() self.file = "/Users/Fabio/data/lab/airyscan/nil.czi" self.resizeEvent(None) self.moveEvent(None) def resizeEvent(self, event): # this is a hack to resize everithing when the user resizes the main window self.grph.setFixedWidth(self.width()) self.image.setFixedWidth(self.width()) self.image.setFixedHeight(self.height()) self.image.resizeEvent(None) self.moveEvent(None) def moveEvent(self, QMoveEvent): px = self.geometry().x() py = self.geometry().y() pw = self.geometry().width() ph = self.geometry().height() dw = self.ctrl.width() dh = self.ctrl.height() self.ctrl.setGeometry(px + pw, py, dw, dh) dw = self.grph.width() dh = self.grph.height() self.grph.setGeometry(px, py + ph + 20, dw, dh) # super(RingWindow, self).mouseMoveEvent(event) def closeEvent(self, event): if not self.df.empty: self.df.loc[:, "condition"] = self.ctrl.experimentLineEdit.text() self.df.loc[:, "l"] = self.df.loc[:, "l"].apply(lambda v: np.array2string(v, separator=',')) self.df.to_csv(os.path.join(os.path.dirname(self.image.file), "ringlines.csv")) self.grph.close() self.ctrl.close() def focusInEvent(self, QFocusEvent): logger.debug('focusInEvent') self.ctrl.activateWindow() self.grph.activateWindow() def showEvent(self, event): self.setFocus() def _graphTendency(self): df = pd.DataFrame(self.image.measurements).drop(['x', 'y', 'c', 'ls0', 'ls1', 'd', 'sum'], axis=1) df.loc[:, "xx"] = df.loc[:, "l"].apply( lambda v: np.arange(start=0, stop=len(v) * self.image.dl, step=self.image.dl)) df = m.vector_column_to_long_fmt(df, val_col="l", ix_col="xx") sns.lineplot(x="xx", y="l", data=df, ax=self.grph.ax, color='k', ci="sd", zorder=20) self.grph.ax.set_ylabel('') self.grph.ax.set_xlabel('') self.grph.canvas.draw() def _graph(self, alpha=1.0): self.grph.clear() if self.image.measurements is not None: for me in self.image.measurements: x = np.arange(start=0, stop=len(me['l']) * self.image.dl, step=self.image.dl) lw = 0.1 if self.image.selectedLine is not None and me != self.image.selectedLine else 0.5 self.grph.ax.plot(x, me['l'], linewidth=lw, linestyle='-', color=me['c'], alpha=alpha, zorder=10, picker=5, label=me['n']) self.grph.format_ax() self.statusbar.showMessage("ptp: %s" % ["%d " % me['d'] for me in self.image.measurements]) self.grph.canvas.draw() @QtCore.pyqtSlot() def onImgToggle(self): logger.debug('onImgToggle') if self.ctrl.dnaChk.isChecked(): self.image.activeCh = "dna" if self.ctrl.actChk.isChecked(): self.image.activeCh = "act" @QtCore.pyqtSlot() def onRenderChk(self): logger.debug('onRenderChk') self.image.render = self.ctrl.renderChk.isChecked() @QtCore.pyqtSlot() def onOpenButton(self): logger.debug('onOpenButton') qfd = QtGui.QFileDialog() path = os.path.dirname(self.file) if self.image.file is not None: self.statusbar.showMessage("current file: %s" % os.path.basename(self.image.file)) flt = "zeiss(*.czi)" f = QtGui.QFileDialog.getOpenFileName(qfd, "Open File", path, flt) if len(f) > 0: self.image.file = f self.image.zstack = self.ctrl.zSpin.value() self.image.dnaChannel = self.ctrl.dnaSpin.value() self.ctrl.nchLbl.setText("%d channels" % self.image.nChannels) self.ctrl.nzsLbl.setText("%d z-stacks" % self.image.nZstack) self.ctrl.nfrLbl.setText("%d %s" % (self.image.nFrames, "frames" if self.image.nFrames > 1 else "frame")) @QtCore.pyqtSlot() def onImgUpdate(self): logger.debug('onImgUpdate') self.ctrl.renderChk.setChecked(True) self._graph() @QtCore.pyqtSlot() def onMeasureButton(self): logger.debug('onMeasureButton') self.image.paint_measures() self._graph(alpha=0.2) self._graphTendency() @QtCore.pyqtSlot() def onZValueChange(self): logger.debug('onZValueChange') self.image.zstack = self.ctrl.zSpin.value() % self.image.nZstack self.ctrl.zSpin.setValue(self.image.zstack) self._graph() @QtCore.pyqtSlot() def onDnaValChange(self): logger.debug('onDnaValChange') val = self.ctrl.dnaSpin.value() % self.image.nChannels self.ctrl.dnaSpin.setValue(val) self.image.dnaChannel = val if self.ctrl.dnaChk.isChecked(): self.image.activeCh = "dna" self.ctrl.dnaChk.setChecked(True) @QtCore.pyqtSlot() def onActValChange(self): logger.debug('onActValChange') val = self.ctrl.actSpin.value() % self.image.nChannels self.ctrl.actSpin.setValue(val) self.image.actChannel = val if self.ctrl.actChk.isChecked(): self.image.activeCh = "act" self.ctrl.actChk.setChecked(True) @QtCore.pyqtSlot() def onAddButton(self): logger.debug('onAddButton') if self.image.measurements is not None: new = pd.DataFrame(self.image.measurements) if self.selectedLine is not None: new = new.loc[new["n"] == self.selectedLine] new.loc[:, "m"] = self.measure_n new.loc[:, "z"] = self.image.zstack new.loc[:, "file"] = os.path.basename(self.image.file) # new.loc[:, "x"] = new.loc[:, "l"].apply(lambda v: np.arange(start=0, stop=len(v), step=self.image.dl)) self.df = self.df.append(new, ignore_index=True, sort=False) self.measure_n += 1 print(self.df) @QtCore.pyqtSlot() def onPlotButton(self): logger.debug('onPlotButton') if self.image.measurements is None: return import matplotlib.pyplot as plt import seaborn as sns from matplotlib.gridspec import GridSpec plt.style.use('bmh') pal = sns.color_palette("Blues", n_colors=len(self.image.measurements)) fig = plt.figure(figsize=(2, 2 * 4), dpi=300) gs = GridSpec(nrows=2, ncols=1, height_ratios=[4, 0.5]) ax1 = plt.subplot(gs[0, 0]) ax2 = plt.subplot(gs[1, 0]) self.image.drawMeasurements(ax1, pal) lw = 1 for me, c in zip(self.image.measurements, pal): x = np.arange(start=0, stop=len(me['l']) * self.image.dl, step=self.image.dl) ax2.plot(x, me['l'], linewidth=lw, linestyle='-', color=c, alpha=1, zorder=10) ax1.xaxis.set_major_locator(ticker.MultipleLocator(20)) ax1.xaxis.set_minor_locator(ticker.MultipleLocator(10)) ax1.yaxis.set_major_locator(ticker.MultipleLocator(20)) ax1.yaxis.set_minor_locator(ticker.MultipleLocator(10)) ax2.xaxis.set_major_locator(ticker.MultipleLocator(1)) ax2.xaxis.set_minor_locator(ticker.MultipleLocator(0.5)) ax2.yaxis.set_major_locator(ticker.MultipleLocator(1e4)) ax2.yaxis.set_minor_locator(ticker.MultipleLocator(5e3)) ax2.yaxis.set_major_formatter(EngFormatter(unit='')) fig.savefig(os.path.basename(self.image.file) + ".pdf") @QtCore.pyqtSlot() def onLinePickedFromGraph(self): logger.debug('onLinePickedFromGraph') self.selectedLine = self.grph.selectedLine if self.grph.selectedLine is not None else None if self.selectedLine is not None: self.image.selectedLine = self.selectedLine self.statusbar.showMessage("line %d selected" % self.selectedLine) @QtCore.pyqtSlot() def onLinePickedFromImage(self): logger.debug('onLinePickedFromImage') self.selectedLine = self.image.selectedLine['n'] if self.image.selectedLine is not None else None if self.selectedLine is not None: self.statusbar.showMessage("line %d selected" % self.selectedLine)
slider = QWidget(wmain) palette = slider.palette() palette.setColor(QPalette.Window, QColor('green')) slider.setPalette(palette) slider.setFixedSize(640, 480) Layout.addWidget(slider) button = QPushButton('hey', wmain) palette = slider.palette() palette.setColor(QPalette.Window, QColor('red')) slider.setPalette(palette) slider.setFixedSize(600, 400) Layout.addWidget(button) #scroll = QScrollArea() #scroll.setWidget(wmain) #scroll.resize(200, 300) #scroll.show() wmain.show() #wmain.scroll(100, 100) print wmain.x(), wmain.y(), wmain.width(), wmain.height() preview = WidgetPreview(wmain) preview.resize(100, 100) preview.show() app.exec_()
class PreviewWindow(QMainWindow): """ QMainWindow subclass used to show frames & tracking. """ def __init__(self, controller): QMainWindow.__init__(self) # set controller self.controller = controller # set title self.setWindowTitle("Preview") # get parameter window position & size param_window_x = self.controller.param_window.x() param_window_y = self.controller.param_window.y() param_window_width = self.controller.param_window.width() # set position & size to be next to the parameter window self.setGeometry(param_window_x + param_window_width, param_window_y, 10, 10) # create main widget self.main_widget = QWidget(self) self.main_widget.setMinimumSize(QSize(500, 500)) # create main layout self.main_layout = QGridLayout(self.main_widget) self.main_layout.setContentsMargins(0, 0, 0, 0) self.main_layout.setSpacing(0) # create label that shows frames self.image_widget = QWidget(self) self.image_layout = QVBoxLayout(self.image_widget) self.image_layout.setContentsMargins(0, 0, 0, 0) self.image_label = PreviewQLabel(self) self.image_label.setSizePolicy(QSizePolicy.MinimumExpanding, QSizePolicy.MinimumExpanding) self.image_label.setAlignment(Qt.AlignTop | Qt.AlignLeft) self.image_label.hide() self.image_layout.addWidget(self.image_label) self.main_layout.addWidget(self.image_widget, 0, 0) # self.image_label.setStyleSheet("border: 1px solid rgba(122, 127, 130, 0.5)") self.bottom_widget = QWidget(self) self.bottom_layout = QVBoxLayout(self.bottom_widget) self.bottom_layout.setContentsMargins(8, 0, 8, 8) self.bottom_widget.setMaximumHeight(40) self.main_layout.addWidget(self.bottom_widget, 1, 0) # create label that shows crop instructions self.instructions_label = QLabel("") self.instructions_label.setStyleSheet("font-size: 11px;") self.instructions_label.setAlignment(Qt.AlignCenter) self.bottom_layout.addWidget(self.instructions_label) # create image slider self.image_slider = QSlider(Qt.Horizontal) self.image_slider.setFocusPolicy(Qt.StrongFocus) self.image_slider.setTickPosition(QSlider.NoTicks) self.image_slider.setTickInterval(1) self.image_slider.setSingleStep(1) self.image_slider.setValue(0) self.image_slider.valueChanged.connect(self.controller.show_frame) self.image_slider.hide() self.bottom_layout.addWidget(self.image_slider) self.zoom = 1 self.offset = [0, 0] self.center_y = 0 self.center_x = 0 # initialize variables self.image = None # image to show self.tracking_data = None # list of tracking data self.selecting_crop = False # whether user is selecting a crop self.changing_heading_angle = False # whether the user is changing the heading angle self.body_crop = None self.final_image = None # set main widget self.setCentralWidget(self.main_widget) # set window buttons if pyqt_version == 5: self.setWindowFlags(Qt.CustomizeWindowHint | Qt.WindowMinimizeButtonHint | Qt.WindowMaximizeButtonHint | Qt.WindowFullscreenButtonHint) else: self.setWindowFlags(Qt.CustomizeWindowHint | Qt.WindowMinimizeButtonHint | Qt.WindowMaximizeButtonHint) self.show() def wheelEvent(self, event): old_zoom = self.zoom self.zoom = max(1, self.zoom + event.pixelDelta().y() / 100) self.zoom = int(self.zoom * 100) / 100.0 self.update_image_label(self.final_image, zooming=True) def start_selecting_crop(self): # start selecting crop self.selecting_crop = True # add instruction text self.instructions_label.setText("Click & drag to select crop area.") def plot_image(self, image, params, crop_params, tracking_results, new_load=False, new_frame=False, show_slider=True, crop_around_body=False): if image is None: self.update_image_label(None) self.image_slider.hide() self.image_label.hide() else: if new_load: self.image_label.show() self.remove_tail_start() if show_slider: if not self.image_slider.isVisible(): self.image_slider.setValue(0) self.image_slider.setMaximum(self.controller.n_frames - 1) self.image_slider.show() else: self.image_slider.hide() max_inititial_size = 500 if image.shape[0] > max_inititial_size: min_height = max_inititial_size min_width = max_inititial_size * image.shape[ 1] / image.shape[0] elif image.shape[1] > max_inititial_size: min_width = max_inititial_size min_height = max_inititial_size * image.shape[ 0] / image.shape[1] else: min_height = image.shape[0] min_width = image.shape[1] self.main_widget.setMinimumSize( QSize(min_width, min_height + self.bottom_widget.height())) # convert to RGB if len(image.shape) == 2: image = cv2.cvtColor(image, cv2.COLOR_GRAY2RGB) # update image self.image = image.copy() try: body_crop = params['body_crop'] except: body_crop = None try: tail_start_coords = params['tail_start_coords'] # add tail start point to image cv2.circle(image, (int( round(tail_start_coords[1] - crop_params['offset'][1])), int( round(tail_start_coords[0] - crop_params['offset'][0]))), 1, (180, 180, 50), -1) except (KeyError, TypeError) as error: tail_start_coords = None if tracking_results is not None: body_position = tracking_results['body_position'] heading_angle = tracking_results['heading_angle'] # add tracking to image image = tracking.add_tracking_to_frame(image, tracking_results, cropped=True) if body_crop is not None and body_position is not None: if not crop_around_body: # copy image overlay = image.copy() # draw tail crop overlay cv2.rectangle(overlay, (int(body_position[1] - body_crop[1]), int(body_position[0] - body_crop[0])), (int(body_position[1] + body_crop[1]), int(body_position[0] + body_crop[0])), (242, 242, 65), -1) # overlay with the original image cv2.addWeighted(overlay, 0.2, image, 0.8, 0, image) self.body_crop = None else: self.body_crop = body_crop if crop_around_body: _, image = tracking.crop_frame_around_body( image, body_position, params['body_crop']) self.final_image = image # update image label self.update_image_label( self.final_image, zoom=(not (crop_around_body and body_position is not None)), new_load=new_load) def draw_crop_selection(self, start_crop_coords, end_crop_coords): if self.selecting_crop and self.image is not None: # convert image to rgb if len(self.image.shape) < 3: image = np.repeat(self.image[:, :, np.newaxis], 3, axis=2) else: image = self.image.copy() # copy image overlay = image.copy() # draw crop selection overlay cv2.rectangle(overlay, (start_crop_coords[1], start_crop_coords[0]), (end_crop_coords[1], end_crop_coords[0]), (255, 51, 0), -1) # overlay with the original image cv2.addWeighted(overlay, 0.5, image, 0.5, 0, image) # update image label self.update_image_label(image) def change_offset(self, prev_coords, new_coords): self.offset[0] -= new_coords[0] - prev_coords[0] self.offset[1] -= new_coords[1] - prev_coords[1] self.update_image_label(self.final_image) def draw_tail_start(self, rel_tail_start_coords): if self.controller.params['type'] == "headfixed": # send new tail start coordinates to controller self.controller.update_tail_start_coords(rel_tail_start_coords) # clear instructions text self.instructions_label.setText("") if self.image is not None: image = self.image.copy() cv2.circle(image, (int(round(rel_tail_start_coords[1])), int(round(rel_tail_start_coords[0]))), 1, (180, 180, 50), -1) # update image label self.update_image_label(image) def remove_tail_start(self): self.update_image_label(self.image) def add_angle_overlay(self, angle): image = self.image.copy() image_height = self.image.shape[0] image_width = self.image.shape[1] center_y = image_height / 2 center_x = image_width / 2 cv2.arrowedLine( image, (int(center_x - 0.3 * image_height * np.sin((angle + 90) * np.pi / 180)), int(center_y - 0.3 * image_width * np.cos((angle + 90) * np.pi / 180))), (int(center_x + 0.3 * image_height * np.sin((angle + 90) * np.pi / 180)), int(center_y + 0.3 * image_width * np.cos((angle + 90) * np.pi / 180))), (50, 255, 50), 2) self.update_image_label(image) def remove_angle_overlay(self): self.update_image_label(self.image) def update_image_label(self, image, zoom=True, new_load=False, zooming=False): if image is not None and self.zoom != 1 and zoom: if zooming: self.offset[0] = min( max( 0, self.offset[0] + int( (self.image_label.image.shape[0]) / 2.0) - int(round((image.shape[0] / self.zoom) / 2.0))), image.shape[0] - int(round(image.shape[0] / self.zoom))) self.offset[1] = min( max( 0, self.offset[1] + int( (self.image_label.image.shape[1]) / 2.0) - int(round((image.shape[1] / self.zoom) / 2.0))), image.shape[1] - int(round(image.shape[1] / self.zoom))) else: self.offset[0] = min( max(0, self.offset[0]), image.shape[0] - int(round(image.shape[0] / self.zoom))) self.offset[1] = min( max(0, self.offset[1]), image.shape[1] - int(round(image.shape[1] / self.zoom))) if self.center_y is None: self.center_y = int(round(image.shape[0] / 2.0)) if self.center_x is None: self.center_x = int(round(image.shape[1] / 2.0)) image = image[ self.offset[0]:int(round(image.shape[0] / self.zoom)) + self.offset[0], self.offset[1]:int(round(image.shape[1] / self.zoom)) + self.offset[1], :].copy() if image is not None: if zoom: self.setWindowTitle("Preview - Zoom: {:.1f}x".format( self.zoom)) else: self.setWindowTitle("Preview - Zoom: 1x") else: self.setWindowTitle("Preview") self.image_label.update_pixmap(image, new_load=new_load) def crop_selection(self, start_crop_coord, end_crop_coord): if self.selecting_crop: # stop selecting the crop self.selecting_crop = False # clear instruction text self.instructions_label.setText("") # update crop parameters from the selection self.controller.update_crop_from_selection(start_crop_coord, end_crop_coord) def closeEvent(self, ce): if not self.controller.closing: ce.ignore() else: ce.accept()