def __init__(self, enable_toolbar=True): QWidget.__init__(self) self.watermark_alpha = 0.05 self.data = [] self.input_files = [] self.hide_title = False self.force_data_max = False self.force_data_min = False self.fix_scales = False self.setWindowIcon(icon_get("plot")) self.ax = [] self.last_plot = [] self.main_vbox = QVBoxLayout() self.fig = Figure(figsize=(2.5, 2), dpi=100) self.canvas = FigureCanvas(self.fig) self.zero_frame_enable = False self.zero_frame_list = [] self.cb = None if enable_toolbar == True: self.plot_ribbon = plot_ribbon() self.plot_ribbon.setSizePolicy(QSizePolicy.Minimum, QSizePolicy.Minimum) self.plot_ribbon.tb_export_as_jpg.clicked.connect( self.callback_save_image) self.plot_ribbon.tb_export_as_csv.clicked.connect( self.callback_save_csv) self.plot_ribbon.tb_export_as_txt.clicked.connect( self.callback_save_txt) self.plot_ribbon.tb_export_as_gnuplot.clicked.connect( self.callback_save_gnuplot) self.plot_ribbon.tb_copy.clicked.connect(self.callback_do_clip) #self.plot_ribbon.tb_export_as_jpg.triggered.connect(self.save_image) self.tb_refresh = QAction(icon_get("view-refresh"), _("Refresh graph"), self) self.tb_refresh.triggered.connect(self.callback_refresh) self.plot_ribbon.plot_toolbar.addAction(self.tb_refresh) nav_bar = NavigationToolbar(self.canvas, self) actions = nav_bar.findChildren(QAction) for a in actions: if a.text() == 'Save': nav_bar.removeAction(a) break nav_bar.setToolButtonStyle(Qt.ToolButtonTextUnderIcon) nav_bar.setIconSize(QSize(42, 42)) self.plot_ribbon.plot_toolbar.addWidget(nav_bar) self.fig.canvas.mpl_connect('motion_notify_event', self.mouse_move) self.plot_ribbon.tb_color_black.triggered.connect( self.callback_black) self.plot_ribbon.tb_color_rainbow.triggered.connect( self.callback_rainbow) self.plot_ribbon.tb_scale_autoscale.triggered.connect( self.callback_autoscale_y) self.plot_ribbon.tb_scale_log_y.triggered.connect( self.callback_toggle_log_scale_y) self.plot_ribbon.tb_scale_log_x.triggered.connect( self.callback_toggle_log_scale_x) #new way to do math for o in self.plot_ribbon.math_opps: o[0].triggered.connect(lambda: self.callback_math_opp(o[1])) #old way to do math self.plot_ribbon.math_norm_to_peak_of_all_data.triggered.connect( self.callback_norm_to_peak_of_all_data) self.plot_ribbon.math_heat_map.triggered.connect( self.callback_set_heat_map) self.plot_ribbon.math_heat_map_edit.triggered.connect( self.callback_heat_map_edit) self.plot_ribbon.math_subtract_first_point.triggered.connect( self.callback_toggle_subtract_first_point) self.plot_ribbon.math_add_min_point.triggered.connect( self.callback_toggle_add_min) self.plot_ribbon.math_invert_y_axis.triggered.connect( self.callback_toggle_invert_y) self.main_vbox.addWidget(self.plot_ribbon) self.canvas.figure.patch.set_facecolor("white") self.canvas.setMinimumSize(800, 350) self.canvas.setSizePolicy(QSizePolicy.Expanding, QSizePolicy.Expanding) self.main_vbox.addWidget(self.canvas) self.setLayout(self.main_vbox)
class QtFrame(QWidget): def __init__(self, routes_line_color=(0.6, 0.2, 0.8), routes_marker_color=(0, 0, 1.0), predictions_line_color=(1.0, 0.4, 0), predictions_marker_color=(0, 0, 1.0), marker_size=0.75, line_thickness=0.5, mark_every=5, anomaly_threshold=0.5): """ Constructor of QtFrame Parameters: routes_line_color: the color for route lines routes_marker_color: the color for route markers predictions_line_color: the color for prediction lines predictions_marker_color: the color for prediction markers marker_size: the size of markers line_thickness: the width of lines mark_every: the number to show only every n-th marker """ # Create a PyQt5-Application self.app = QApplication(sys.argv) QWidget.__init__(self) self.line_thickness = line_thickness self.marker_size = marker_size self.mark_every = mark_every self.anomaly_threshold = anomaly_threshold # Create the plot and a matplotlib NavigationToolbar self.plot_layout = QVBoxLayout(self) self.vis = Visualization( routes_line_color=routes_line_color, routes_marker_color=routes_marker_color, predictions_line_color=predictions_line_color, predictions_marker_color=predictions_marker_color, marker_size=marker_size, line_thickness=line_thickness, mark_every=mark_every, anomaly_threshold=anomaly_threshold) self.navi_toolbar = NavigationToolbar(self.vis, self) # Remove not used buttons inside the navigation toolbar actions = self.navi_toolbar.findChildren(QAction) for a in actions: if a.text() == "Customize" or a.text() == "Subplots": self.navi_toolbar.removeAction(a) # Create custom buttons and checkbox to interact with the plot self.settings_row = QHBoxLayout() self.settings_row_2 = QHBoxLayout() self.settings_row_2.setContentsMargins(0, 0, 0, 10) self.button_zoom = QPushButton("Zoom to calculated scope") self.button_routes_line_color = QPushButton("Set routes line color") self.button_routes_marker_color = QPushButton( "Set routes marker color") self.button_prediction_line_color = QPushButton( "Set prediction line color") self.button_prediction_marker_color = QPushButton( "Set prediction marker color") self.button_line_width = QPushButton("Set line width") self.button_marker_size = QPushButton("Set marker size") self.button_mark_every = QPushButton("Set every n-th marker") self.checkbox_anomalies = QCheckBox("Show Anomalies") self.label_anomaly_threshold = QLabel("Anomaly threshold: %.4f" % round(self.anomaly_threshold, 5)) self.label_anomaly_threshold.setFixedWidth(200) self.slider_anomaly_threshold = QSlider(Qt.Horizontal) self.slider_anomaly_threshold.setFixedWidth(200) self.slider_anomaly_threshold.setTickPosition(QSlider.NoTicks) self.slider_anomaly_threshold.setRange(0, 10000) self.slider_anomaly_threshold.setValue(self.anomaly_threshold * 10000) # Add layouts and widgets self.plot_layout.addWidget(self.vis) self.plot_layout.addWidget(self.navi_toolbar) self.plot_layout.addLayout(self.settings_row) self.plot_layout.addLayout(self.settings_row_2) self.settings_row.addWidget(self.button_zoom) self.settings_row.addWidget(self.button_routes_line_color) self.settings_row.addWidget(self.button_routes_marker_color) self.settings_row.addWidget(self.button_prediction_line_color) self.settings_row.addWidget(self.button_prediction_marker_color) self.settings_row.addWidget(self.button_line_width) self.settings_row.addWidget(self.button_marker_size) self.settings_row.addWidget(self.button_mark_every) self.settings_row.addStretch(1) self.settings_row_2.addWidget(self.checkbox_anomalies) self.settings_row_2.addWidget(self.label_anomaly_threshold) self.settings_row_2.addWidget(self.slider_anomaly_threshold) self.settings_row_2.addStretch(1) # Connect custom buttons and checkbox to functions self.zoom_to_calc_scope = False self.button_zoom.clicked.connect(self.__button_zoom_clicked) self.button_routes_line_color.clicked.connect( self.__button_routes_line_color_clicked) self.button_routes_marker_color.clicked.connect( self.__button_routes_marker_color_clicked) self.button_prediction_line_color.clicked.connect( self.__button_prediction_line_color_clicked) self.button_prediction_marker_color.clicked.connect( self.__button_prediction_marker_color_clicked) self.button_line_width.clicked.connect( self.__button_line_width_clicked) self.button_marker_size.clicked.connect( self.__button_marker_size_clicked) self.button_mark_every.clicked.connect( self.__button_mark_every_clicked) self.anomalies_visible = False self.checkbox_anomalies.stateChanged.connect( self.__checkbox_anomalies_changed) self.slider_anomaly_threshold.valueChanged.connect( self.__slider_anomaly_threshold_value_changed) def set_scope(self, scope): """ Sets the scope for visualization Parameters: scope: the scope object to use for visualization """ self.vis.set_scope(scope) def draw_map(self): """ Draws a map in the background """ self.vis.draw_map() def draw_routes(self): """ Draws the routes of the ships """ self.vis.draw_routes() def draw_predictions(self): """ Draws the predictions of the ships """ self.vis.draw_predictions() def show_dialog(self): """ Starts the PyQt5-Application maximized """ self.showMaximized() sys.exit(self.app.exec_()) def __button_zoom_clicked(self): """ Zooms to calculated or to user scope """ self.zoom_to_calc_scope = not self.zoom_to_calc_scope self.vis.change_zoom(self.zoom_to_calc_scope) if self.zoom_to_calc_scope: self.button_zoom.setText("Zoom to user scope") else: self.button_zoom.setText("Zoom to calculated scope") def __button_routes_line_color_clicked(self): """ Changes the color of route lines and route patches """ color = QColorDialog.getColor() if color.isValid(): self.vis.change_route_line_color(color.name()) def __button_routes_marker_color_clicked(self): """ Changes the color of route markers """ color = QColorDialog.getColor() if color.isValid(): self.vis.change_route_marker_color(color.name()) def __button_prediction_line_color_clicked(self): """ Changes the color of prediction lines and prediction patches """ color = QColorDialog.getColor() if color.isValid(): self.vis.change_prediction_line_color(color.name()) def __button_prediction_marker_color_clicked(self): """ Changes the color of prediction markers """ color = QColorDialog.getColor() if color.isValid(): self.vis.change_prediction_marker_color(color.name()) def __button_line_width_clicked(self): """ Changes the line width and patch size """ val, okPressed = QInputDialog.getDouble(self, "Set line width", "Value:", self.line_thickness, 0, 100, 4) if okPressed: self.vis.change_line_width(val) self.line_thickness = val def __button_marker_size_clicked(self): """ Changes the marker size """ val, okPressed = QInputDialog.getDouble(self, "Set marker size", "Value:", self.marker_size, 0, 100, 4) if okPressed: self.vis.change_marker_size(val) self.marker_size = val def __button_mark_every_clicked(self): """ Shows only n-th marker """ val, okPressed = QInputDialog.getInt(self, "Set every n-th marker", "Value:", self.mark_every, 1, 1000) if okPressed: self.vis.change_mark_every(val) self.mark_every = val def __checkbox_anomalies_changed(self): """ Shows anomaly annotations """ self.vis.show_anomalies(self.checkbox_anomalies.isChecked()) def __slider_anomaly_threshold_value_changed(self): """ Changes the anomaly threshold and redraw the anomaly annotations, if necessary """ val = self.slider_anomaly_threshold.value() / 10000 self.label_anomaly_threshold.setText("Anomaly threshold: %.4f" % round(val, 5)) self.vis.change_anomaly_thresh(val) self.vis.show_anomalies(self.checkbox_anomalies.isChecked()) self.anomaly_threshold = val
class MplWindow(UI_MainWindow, MainWindow): def __init__(self): super(MplWindow, self).__init__() self.verbose = 1 self.setupUi(self) self.showMaximized() self.fig = Figure() self.graph_sequence = [] self.graph_sequence_comments = [] self._V6fromPHC = [] # self._log = '' # self.setRequiresRecomputing() self.setActiveGraph(GraphCouplerCurve(window=self)) self.init_widgets() self.init_mpl() # self.init_data() self.init_plot() #self.init_pick() self.dockLog.resize(self.dockLog.minimumWidth() * 2, 300) self.dockLog.updateGeometry() def setActiveGraph(self, G): self.graph = G self.updateParameter() if self.graph.isComputed(): self.setComputed() else: self.setRequiresRecomputing() def init_widgets(self): """Initialize the widgets, mainly connecting the relevant signals""" self.plainTextEdit.setReadOnly(True) # self.plainTextEdit.setCenterOnScroll(True) # self.plainTextEdit.setMaximumBlockCount(40) self.doubleSpinBoxLengths = { '12': self.doubleSpinBoxL12, '13': self.doubleSpinBoxL13, '14': self.doubleSpinBoxL14, '15': self.doubleSpinBoxL15, '16': self.doubleSpinBoxL16, '27': self.doubleSpinBoxL27, '37': self.doubleSpinBoxL37, '47': self.doubleSpinBoxL47, '57': self.doubleSpinBoxL57, '67': self.doubleSpinBoxL67, '23': self.doubleSpinBoxL23, '34': self.doubleSpinBoxL34, '45': self.doubleSpinBoxL45, '56': self.doubleSpinBoxL56, } self.update_graph2tabLengths() self.update_graph2phi() for e in self.doubleSpinBoxLengths: self.doubleSpinBoxLengths[e].valueChanged.connect( self.update_tabLengths2graph) self.update_graph2R26() self.doubleSpinBoxR26.valueChanged.connect(self.update_R26toGraph) self.doubleSpinBoxY2.valueChanged.connect(self.update_yV2toGraph) self.doubleSpinBoxPhi.valueChanged.connect(self.update_phi2graph) self.doubleSpinBoxTheta.valueChanged.connect(self.update_theta2graph) self.pushButtonPlot.clicked.connect(self.computeCouplerCurves) self.pushButtonPlot.setShortcut(QKeySequence("Ctrl+P")) self.checkBoxBranches = { 'orange': self.checkBoxOrange, 'red': self.checkBoxRed, 'green': self.checkBoxGreen, 'blue': self.checkBoxBlue } for c in self.checkBoxBranches: self.checkBoxBranches[c].stateChanged.connect(self.plotScene) self.checkBoxMirror.stateChanged.connect(self.plotScene) # self.spinBoxSamples.valueChanged.connect(self.updateSamples) self.comboBoxGraphFor.currentTextChanged.connect( self.updateDisplayedGraph) self.spinBoxParameter.valueChanged.connect(self.updateDisplayedGraph) self.spinBoxParameter.setWrapping(True) self.spinBoxParameterStep.valueChanged.connect( self.update_parameterStep) self.doc_tb = self.addToolBar("File") self.loadLengthsButton = QAction(QIcon.fromTheme("document-open"), "Load lengths", self) self.doc_tb.addAction(self.loadLengthsButton) self.loadLengthsButton.triggered.connect(self.loadLengths) action = self.menuFile.addAction('Load lengths') action.triggered.connect(self.loadLengths) self.saveLengthsButton = QAction(QIcon.fromTheme("document-save"), "Save lengths", self) self.doc_tb.addAction(self.saveLengthsButton) self.saveLengthsButton.triggered.connect(self.saveLengths) action = self.menuFile.addAction('Save lengths') action.triggered.connect(self.saveLengths) self.inOut_tb = self.addToolBar("Input/Output") self.insertLengthsButton = QAction(QIcon.fromTheme("insert-text"), "Insert lengths", self) self.inOut_tb.addAction(self.insertLengthsButton) self.insertLengthsButton.triggered.connect(self.insertLengths) action = self.menuInputOutput.addAction('Insert lengths') action.triggered.connect(self.insertLengths) self.insertLengthsByEmbeddingsButton = QAction( "Insert lengths by embedding", self) self.inOut_tb.addAction(self.insertLengthsByEmbeddingsButton) self.insertLengthsByEmbeddingsButton.triggered.connect( self.insertLengthsByEmbeddings) action = self.menuInputOutput.addAction('Insert lengths by embedding') action.triggered.connect(self.insertLengthsByEmbeddings) self.exportLengthsButton = QAction("Export lengths", self) self.inOut_tb.addAction(self.exportLengthsButton) self.exportLengthsButton.triggered.connect(self.exportLengths) action = self.menuInputOutput.addAction('Export lengths') action.triggered.connect(self.exportLengths) self.actionFullscreen.toggled.connect(self.fullScreen) self.updateParameter() self.buttonLoadSequence.clicked.connect(self.loadSequence) self.spinBoxImgInSeq.setMinimum(1) self.spinBoxImgInSeq.setMaximum(1) self.spinBoxImgInSeq.valueChanged.connect(self.plotGraphFromSequence) self.spinBoxSeqLength.setReadOnly(True) self.spinBoxSeqLength.setButtonSymbols(QAbstractSpinBox.NoButtons) self.noteToImgInSeq.setReadOnly(True) self.boxInfoImgInSeq.setVisible(False) self.buttonRunPHC.clicked.connect(self.runPHC) self.spinBoxNumberReal.setReadOnly(True) self.spinBoxNumberReal.setButtonSymbols(QAbstractSpinBox.NoButtons) self.buttonRotateVertices.clicked.connect(self.rotateVertices) # self.exportButton.clicked.connect(self.exportLengths) self.doubleSpinBox_x.valueChanged.connect(self.plotScene) self.doubleSpinBox_y.valueChanged.connect(self.plotScene) self.doubleSpinBox_z.valueChanged.connect(self.plotScene) dockWidgets = self.findChildren(QDockWidget) for dockWidget in dockWidgets: action = self.menuView.addAction(dockWidget.windowTitle()) action.setCheckable(True) action.setChecked(True) action.triggered.connect(dockWidget.setVisible) dockWidget.visibilityChanged.connect(action.setChecked) # dockWidget.setSizePolicy(QSizePolicy.Minimum, QSizePolicy.Fixed) # dockWidget.updateGeometry() # self.dockLog.setSizePolicy(QSizePolicy.Minimum, QSizePolicy.Expanding) # self.dockLog.updateGeometry() self.buttonSamplingPhiTheta.clicked.connect(self.runSamplingPhiTheta) self._possibleParametrizedVertices = { '[2, 1, 6, 3, 7]': [2, 1, 6, 3, 7], '[2, 3, 1, 7, 6]': [2, 3, 1, 7, 6], '[2, 6, 1, 7, 3]': [2, 6, 1, 7, 3], '[2, 7, 6, 3, 1]': [2, 7, 6, 3, 1], '[3, 1, 2, 4, 7]': [3, 1, 2, 4, 7], '[3, 2, 1, 7, 4]': [3, 2, 1, 7, 4], '[3, 4, 1, 7, 2]': [3, 4, 1, 7, 2], '[3, 7, 2, 4, 1]': [3, 7, 2, 4, 1], '[4, 1, 3, 5, 7]': [4, 1, 3, 5, 7], '[4, 3, 1, 7, 5]': [4, 3, 1, 7, 5], '[4, 5, 1, 7, 3]': [4, 5, 1, 7, 3], '[4, 7, 3, 5, 1]': [4, 7, 3, 5, 1], '[5, 1, 4, 6, 7]': [5, 1, 4, 6, 7], '[5, 4, 1, 7, 6]': [5, 4, 1, 7, 6], '[5, 6, 1, 7, 4]': [5, 6, 1, 7, 4], '[5, 7, 4, 6, 1]': [5, 7, 4, 6, 1], '[6, 1, 5, 2, 7]': [6, 1, 5, 2, 7], '[6, 2, 1, 7, 5]': [6, 2, 1, 7, 5], '[6, 5, 1, 7, 2]': [6, 5, 1, 7, 2], '[6, 7, 5, 2, 1]': [6, 7, 5, 2, 1] } self.comboBoxParamVert.setInsertPolicy(6) for comb in self._possibleParametrizedVertices: self.comboBoxParamVert.addItem(comb) self.buttonFindMore.clicked.connect(self.findMoreEmbeddings) self.tabifyDockWidget(self.dockBranches, self.dockSceneShift) self.tabifyDockWidget(self.dockSceneShift, self.dockSequenceNavigation) def fullScreen(self, bool): if bool: self.showFullScreen() else: self.showMaximized() def loadLengths(self): options = QFileDialog.Options() # options |= QFileDialog.DontUseNativeDialog fileName, _ = QFileDialog.getOpenFileName( self, "Load lengths", "./examples", "Python Objects (*.p);;All Files (*)", options=options) if fileName: try: self.printLog('Lengths loaded from: ' + fileName) lengths, R26 = pickle.load(open(fileName, 'rb')) lengths['26'] = R26 self.graph.setLengthsAndUpdateFixedTriangle(lengths) # self.graph.setR26(R26) blocked = self.doubleSpinBoxR26.blockSignals(True) self.update_graph2R26() self.update_graph2tabLengths() self.update_graph2phi() self.doubleSpinBoxR26.blockSignals(blocked) self.computeCouplerCurves() except Exception as e: self.showError('Some problem with loading: \n' + str(e)) def saveLengths(self): options = QFileDialog.Options() # options |= QFileDialog.DontUseNativeDialog fileName, _ = QFileDialog.getSaveFileName( self, "Save lengths", "./examples", "Python Objects (*.p);;All Files (*)", options=options) if fileName: self.printLog('Lengths saved to: ' + fileName) pickle.dump( [self.graph._lengths, self.graph.getR26()], open(fileName, 'wb')) def insertLengths(self): text, ok = QInputDialog.getMultiLineText( self, 'Insert lengths', 'Insert lengths as dictionary or list of squares of lengths:') if ok: try: evaluated_expr = ast.literal_eval(str(text)) if not type(evaluated_expr) is dict: g = evaluated_expr lengths = { '12': np.sqrt(g[0]), '13': np.sqrt(g[1]), '14': np.sqrt(g[2]), '15': np.sqrt(g[3]), '16': np.sqrt(g[4]), '27': np.sqrt(g[5]), '37': np.sqrt(g[6]), '47': np.sqrt(g[7]), '57': np.sqrt(g[8]), '67': np.sqrt(g[9]), '23': np.sqrt(g[10]), '34': np.sqrt(g[11]), '45': np.sqrt(g[12]), '56': np.sqrt(g[13]), '26': np.sqrt(g[14]) } else: lengths = evaluated_expr if type(lengths) == dict: self.printLog('Inserted lengths: ') self.graph.setLengthsAndUpdateFixedTriangle(lengths) self.update_graph2R26() self.update_graph2tabLengths() self.update_graph2phi() self.computeCouplerCurves() else: self.showError( 'Input must be list containing dictionary of lengths and float R26 or list of squares of lengths' ) except Exception as e: self.showError('Problem with input: \n' + str(e)) def insertLengthsByEmbeddings(self): text, ok = QInputDialog.getMultiLineText( self, 'Insert embedding', 'Insert list of coordinates of v1,..., v7:') if ok: try: evaluated_expr = ast.literal_eval(str(text)) v1, v2, v3, v4, v5, v6, v7 = evaluated_expr lengths = { '12': self.graph.dist(v1, v2), '13': self.graph.dist(v1, v3), '14': self.graph.dist(v1, v4), '15': self.graph.dist(v1, v5), '16': self.graph.dist(v1, v6), '27': self.graph.dist(v2, v7), '37': self.graph.dist(v3, v7), '47': self.graph.dist(v4, v7), '57': self.graph.dist(v5, v7), '67': self.graph.dist(v6, v7), '23': self.graph.dist(v2, v3), '34': self.graph.dist(v3, v4), '45': self.graph.dist(v4, v5), '56': self.graph.dist(v5, v6), '26': self.graph.dist(v2, v6) } self.printLog('Inserted lengths: ') self.graph.setLengthsAndUpdateFixedTriangle(lengths) self.update_graph2R26() self.update_graph2tabLengths() self.update_graph2phi() self.computeCouplerCurves() except Exception as e: self.showError('Problem with input: \n' + str(e)) def showError(self, s): msg = QErrorMessage(self) msg.showMessage(s) self.printLog(s) def init_plot(self): """Initialize the plot of the axes""" self.fig.subplots_adjust(left=0.0, top=1, right=1, bottom=0.0) self._branches_plot = self.fig.add_subplot(111, projection='3d') self._branches_plot.axis(aspect='equal') self._branches_plot.auto_scale_xyz([-1, 1], [-1, 1], [-1, 1]) self._firstPlot = True def init_mpl(self): """Initialize the mpl canvas and connect the relevant parts""" self.canvas = FigureCanvas(self.fig) self.canvas.draw() self.figLayout.addWidget(self.canvas) NavigationToolbar.toolitems = [ t for t in NavigationToolbar.toolitems if t[0] in ("Save", ) ] #,"Pan","Zoom","Subplots")] self.img_tb = NavigationToolbar(self.canvas, self, coordinates=False) actions = self.img_tb.findChildren(QAction) for a in actions: if a.text() == 'Customize': self.img_tb.removeAction(a) break self.addToolBar(self.img_tb) self.buttonAxelVisualisation = QAction('Axel visualisation', self) self.img_tb.addAction(self.buttonAxelVisualisation) self.buttonAxelVisualisation.triggered.connect(self.axelVisualisation) action = self.menuInputOutput.addAction('Axel visualisation') action.triggered.connect(self.axelVisualisation) def updateParameter(self): N = self.graph.getSamples() self.spinBoxParameter.setMaximum(N) blocked = self.spinBoxParameter.blockSignals(True) self.spinBoxParameter.setValue(N / 2) self.spinBoxParameter.blockSignals(blocked) self.spinBoxParameterStep.setValue(N / 20) def update_parameterStep(self): self.spinBoxParameter.setSingleStep(self.spinBoxParameterStep.value()) def updateDisplayedGraph(self): if self.isComputed(): self.plotScene() else: self.showError('Recomputation of coupler curve needed!') def update_graph2tabLengths(self): self.printLog('Tab Lengths updated from graph', verbose=1) for e in self.doubleSpinBoxLengths: blocked = self.doubleSpinBoxLengths[e].blockSignals(True) self.doubleSpinBoxLengths[e].setValue(self.graph.getEdgeLength(e)) self.doubleSpinBoxLengths[e].blockSignals(blocked) self.printLog(e + ': ' + str(self.doubleSpinBoxLengths[e].value()), verbose=2) def update_tabLengths2graph(self): self.printLog('Graph updated from tab Lengths', verbose=1) lengths = { '12': self.doubleSpinBoxL12.value(), '13': self.doubleSpinBoxL13.value(), '14': self.doubleSpinBoxL14.value(), '15': self.doubleSpinBoxL15.value(), '16': self.doubleSpinBoxL16.value(), '27': self.doubleSpinBoxL27.value(), '37': self.doubleSpinBoxL37.value(), '47': self.doubleSpinBoxL47.value(), '57': self.doubleSpinBoxL57.value(), '67': self.doubleSpinBoxL67.value(), '23': self.doubleSpinBoxL23.value(), '34': self.doubleSpinBoxL34.value(), '45': self.doubleSpinBoxL45.value(), '56': self.doubleSpinBoxL56.value(), '26': self.doubleSpinBoxR26.value() } try: self.graph.setLengthsAndUpdateFixedTriangle(lengths) except TriangleInequalityError as e: self.showError( 'Please, change the lengths, triangle inequality is violated!!!\n' + str(e)) self.update_graph2yV2() self.update_graph2phi() self.setRequiresRecomputing() def update_phi2graph(self): self.graph.setPhiDegree(self.doubleSpinBoxPhi.value()) blocked = self.doubleSpinBoxY2.blockSignals(True) self.doubleSpinBoxY2.setValue(self.graph.getyV2()) self.doubleSpinBoxY2.blockSignals(blocked) self.update_yV2toGraph() def update_theta2graph(self): self.graph.setThetaDegree(self.doubleSpinBoxTheta.value()) blocked = self.doubleSpinBoxR26.blockSignals(True) self.doubleSpinBoxR26.setValue(self.graph.getR26()) self.doubleSpinBoxR26.blockSignals(blocked) self.update_R26toGraph() def update_R26toGraph(self): self.printLog('Graph updated from R26') self.graph.setR26(self.doubleSpinBoxR26.value()) self.labelRecomputePHC.setText( '<html><head/><body><p><span style=" color:#ff0000;">Recomputation needed</span></p></body></html>' ) self.update_graph2theta() if self.isComputed(): self.graph.computeIntersections() self.plotScene() else: self.showError('Recomputation of coupler curve needed!') def update_yV2toGraph(self): self.printLog('v2 changed') self.labelRecomputePHC.setText( '<html><head/><body><p><span style=" color:#ff0000;">Recomputation needed</span></p></body></html>' ) self.graph.setyV2(self.doubleSpinBoxY2.value()) self.update_graph2tabLengths() self.update_graph2phi() if self.isComputed(): self.graph.computeIntersections() self.plotScene() else: self.showError('Recomputation of coupler curve needed!') def update_graph2R26(self): blocked = self.doubleSpinBoxR26.blockSignals(True) self.doubleSpinBoxR26.setValue(self.graph.getR26()) self.doubleSpinBoxR26.blockSignals(blocked) self.update_graph2yV2() self.update_graph2theta() def update_graph2yV2(self): blocked = self.doubleSpinBoxY2.blockSignals(True) self.doubleSpinBoxY2.setValue(self.graph.getyV2()) self.doubleSpinBoxY2.blockSignals(blocked) self.update_graph2phi() def update_graph2phi(self): self.update_graph2theta() blocked = self.doubleSpinBoxPhi.blockSignals(True) self.doubleSpinBoxPhi.setValue(self.graph.getPhiDegree()) self.doubleSpinBoxPhi.blockSignals(blocked) def update_graph2theta(self): blocked = self.doubleSpinBoxTheta.blockSignals(True) self.doubleSpinBoxTheta.setValue(self.graph.getThetaDegree()) self.doubleSpinBoxTheta.blockSignals(blocked) def setRequiresRecomputing(self): self.graph.setRequiresRecomputing(propagate=False) self.labelComputed.setText( '<html><head/><body><p><span style=" color:#ff0000;">Recomputation needed</span></p></body></html>' ) self._V6fromPHC = [] self.labelRecomputePHC.setText( '<html><head/><body><p><span style=" color:#ff0000;">Recomputation needed</span></p></body></html>' ) def setComputed(self): self.graph.setComputed(propagate=False) self.labelComputed.setText('Ready') c_x, c_y, c_z = self.graph.getCenterOfGravity() self.doubleSpinBox_x.setValue(-c_x) self.doubleSpinBox_y.setValue(-c_y) self.doubleSpinBox_z.setValue(-c_z) def isComputed(self): return self.graph.isComputed() def computeCouplerCurves(self): N = self.spinBoxSamples.value() self.printLog('Computing coupler curve') self.pushButtonPlot.setEnabled(False) self.graph.computeCouplerCurve(N) self.updateParameter() self.updateDisplayedGraph() self.pushButtonPlot.setEnabled(True) def plotScene(self): c_x, c_y, c_z = self.doubleSpinBox_x.value( ), self.doubleSpinBox_y.value(), self.doubleSpinBox_z.value() def draw(points, style='black', line_width=2): self._branches_plot.plot([x + c_x for x, y, z in points], [y + c_y for x, y, z in points], [z + c_z for x, y, z in points], style, linewidth=line_width) if self.isComputed(): if not self._firstPlot: xlim = self._branches_plot.get_xlim() ylim = self._branches_plot.get_ylim() zlim = self._branches_plot.get_zlim() minbound = min([xlim[0], ylim[0], zlim[0]]) maxbound = max([xlim[1], ylim[1], zlim[1]]) else: minbound = self.graph.minbound maxbound = self.graph.maxbound self._firstPlot = False self._branches_plot.cla() if self.comboBoxGraphFor.currentText() == 'orange': pos = self.graph.getPositionsOfVertices( self.spinBoxParameter.value() - 1, 0, 0, 0) elif self.comboBoxGraphFor.currentText() == 'red': pos = self.graph.getPositionsOfVertices( self.spinBoxParameter.value() - 1, 0, 1, 0) elif self.comboBoxGraphFor.currentText() == 'green': pos = self.graph.getPositionsOfVertices( self.spinBoxParameter.value() - 1, 0, 0, 1) elif self.comboBoxGraphFor.currentText() == 'blue': pos = self.graph.getPositionsOfVertices( self.spinBoxParameter.value() - 1, 0, 1, 1) else: pos = None allOrange = True for c in self.checkBoxBranches: if self.checkBoxBranches[c].checkState(): for part in self.graph.getBranch(c): if allOrange: draw(part, 'darkorange', line_width=2) else: draw(part, c, line_width=2) if self.checkBoxMirror.checkState(): for c in self.checkBoxBranches: if self.checkBoxBranches[c].checkState(): for part in self.graph.getMirrorBranch(c): if allOrange: draw(part, 'darkorange', line_width=2) else: draw(part, 'dark' + c, line_width=2) draw(self.graph.intersections_mirror, 'ro') draw(self.graph.intersections, 'ro') if pos: v1, v2, v3, v4, v5, v6, v7 = pos draw([v2, v3, v7, v2, v1, v3, v4, v5, v1, v4, v7, v6, v5, v7]) draw([v1, v6]) # draw([v1, v2, v3], 'ko') draw(pos, 'ko') draw([v6, v6], 'y^') for i, v in enumerate(pos): self._branches_plot.text(v[0] + 0.1 + c_x, v[1] + c_y, v[2] + c_z, 'v' + str(i + 1), size=20) self._branches_plot.set_xlim3d(minbound, maxbound) self._branches_plot.set_ylim3d(minbound, maxbound) self._branches_plot.set_zlim3d(minbound, maxbound) self._branches_plot.get_proj() else: self.showError('Recomputation of coupler curve needed!') if self._V6fromPHC: draw(self._V6fromPHC, 'go') # self._branches_plot.auto_scale_xyz([minbound, maxbound], [minbound, maxbound], [minbound, maxbound]) # x, y, z = self.graph.getSphere(100) # self._branches_plot.plot_surface(x, y, z, alpha=0.2, color='grey', shade=True, linewidth=0) self._branches_plot.set_axis_off() self.canvas.draw() def printLog(self, s, verbose=0, newLine=True): # self._log += s +'\n' # self.plainTextEdit.setPlainText(self._log) if verbose <= self.verbose: if newLine: print s self.plainTextEdit.appendPlainText(str(s)) else: print s, self.plainTextEdit.insertPlainText(str(s)) self.plainTextEdit.moveCursor(QTextCursor.End) self.plainTextEdit.ensureCursorVisible() QApplication.processEvents() def setGraphSequence(self, seq, seq_comments): self.graph_sequence = seq self.graph_sequence_comments = seq_comments self.spinBoxSeqLength.setValue(len(seq)) self.spinBoxImgInSeq.setMinimum(1) self.spinBoxImgInSeq.setMaximum(len(self.graph_sequence)) self.noteToImgInSeq.setPlainText( self.graph_sequence_comments[self.spinBoxImgInSeq.value() - 1]) self.boxInfoImgInSeq.setVisible(True) self.pushButtonPlot.setEnabled(False) N = self.spinBoxSamples.value() for graph in self.graph_sequence: graph.computeCouplerCurve(N) self.plotGraphFromSequence() self.pushButtonPlot.setEnabled(True) def loadSequence(self): options = QFileDialog.Options() fileName, _ = QFileDialog.getOpenFileName( self, "Load sequence", "./sequences", "Python Objects (*.p);;All Files (*)", options=options) if fileName: try: self.printLog('Sequence loaded from: ' + fileName) seq = pickle.load(open(fileName, 'rb')) graph_sequence = [] graph_sequence_comments = [] if type(seq[0]) == list: for g in seq: lengths = { '12': np.sqrt(g[0]), '13': np.sqrt(g[1]), '14': np.sqrt(g[2]), '15': np.sqrt(g[3]), '16': np.sqrt(g[4]), '27': np.sqrt(g[7]), '37': np.sqrt(g[9]), '47': np.sqrt(g[11]), '57': np.sqrt(g[13]), '67': np.sqrt(g[14]), '23': np.sqrt(g[5]), '34': np.sqrt(g[8]), '45': np.sqrt(g[10]), '56': np.sqrt(g[12]), '26': np.sqrt(g[6]) } graph_sequence.append( GraphCouplerCurve(lengths=lengths, window=self)) try: graph_sequence_comments.append(str(g[15])) except: graph_sequence_comments.append(str(' ')) else: self.printLog(seq) for len_seq in seq[1]: for lengths in len_seq[1]: graph_sequence.append( GraphCouplerCurve(lengths=lengths, window=self)) graph_sequence_comments.append(str(' ')) self.setGraphSequence(graph_sequence, graph_sequence_comments) except Exception as e: self.showError('Some problem with loading: \n' + str(e)) def plotGraphFromSequence(self): if self.graph_sequence: self.setActiveGraph( self.graph_sequence[self.spinBoxImgInSeq.value() - 1]) self._V6fromPHC = [] self.noteToImgInSeq.setPlainText( self.graph_sequence_comments[self.spinBoxImgInSeq.value() - 1]) self.update_graph2tabLengths() self.update_graph2R26() self.updateParameter() self.updateDisplayedGraph() self.labelRecomputePHC.setText( '<html><head/><body><p><span style=" color:#ff0000;">Recomputation needed</span></p></body></html>' ) def runPHC(self): self.buttonRunPHC.setEnabled(False) self._V6fromPHC = self.graph.getSolutionsForV6(usePrev=False) num_sol = len(self._V6fromPHC) self.printLog('Number of real solutions by PHC:') self.printLog(str(num_sol)) self.spinBoxNumberReal.setValue(num_sol) self.plotScene() self.labelRecomputePHC.setText('Green points OK') self.buttonRunPHC.setEnabled(True) return num_sol def rotateVertices(self): self.buttonRotateVertices.setEnabled(False) self.printLog('Rotating labeling of vertices:') rotated_lengths = { '12': self.graph.getEdgeLength('13'), '13': self.graph.getEdgeLength('14'), '14': self.graph.getEdgeLength('15'), '15': self.graph.getEdgeLength('16'), '16': self.graph.getEdgeLength('12'), '27': self.graph.getEdgeLength('37'), '37': self.graph.getEdgeLength('47'), '47': self.graph.getEdgeLength('57'), '57': self.graph.getEdgeLength('67'), '67': self.graph.getEdgeLength('27'), '23': self.graph.getEdgeLength('34'), '34': self.graph.getEdgeLength('45'), '45': self.graph.getEdgeLength('56'), '56': self.graph.getEdgeLength('26'), '26': self.graph.getEdgeLength('23') } self.graph.setLengthsAndUpdateFixedTriangle(rotated_lengths) blocked = self.doubleSpinBoxR26.blockSignals(True) self.update_graph2R26() self.update_graph2tabLengths() self.doubleSpinBoxR26.blockSignals(blocked) self.computeCouplerCurves() self.buttonRotateVertices.setEnabled(True) def showDialog(self, texts): dialog = QDialog(self) dialog.textBrowser = QPlainTextEdit(dialog) dialog.verticalLayout = QVBoxLayout(dialog) dialog.verticalLayout.addWidget(dialog.textBrowser) dialog.setMinimumSize(600, 300) for s in texts: dialog.textBrowser.appendPlainText(str(s)) dialog.show() def exportLengths(self): len_vect = [] for e in ['12', '13', '14', '15', '16', '23']: len_vect.append(self.graph.getEdgeLength(e)) len_vect.append(self.graph.getR26()) for e in ['27', '34', '37', '45', '47', '56', '57', '67']: len_vect.append(self.graph.getEdgeLength(e)) squared = True if squared: tmp = copy.copy(len_vect) len_vect = [] for r in tmp: len_vect.append(r**2) dialog = QDialog(self) dialog.textBrowser = QPlainTextEdit(dialog) dialog.textBrowser.appendPlainText(str(len_vect)) len_dict = copy.deepcopy(self.graph._lengths) len_dict[(2, 6)] = self.graph.getR26() dialog.textBrowser.appendPlainText(str(len_dict)) dialog.verticalLayout = QVBoxLayout(dialog) dialog.verticalLayout.addWidget(dialog.textBrowser) dialog.setMinimumSize(600, 300) dialog.exec_() def axelVisualisation(self): # #colors blue = [0, 0, 255] cyan = [0, 255, 255] green = [0, 255, 0] magenta = [255, 0, 255] dark_yellow = [100, 100, 0] yellow = [255, 255, 0] dark_green = [0, 190, 0] red = [255, 0, 0] black = [0, 0, 0] colors = { 'orange': yellow, 'red': red, 'green': green, 'blue': blue, 'darkorange': dark_yellow, 'darkred': cyan, 'darkgreen': dark_green, 'darkblue': magenta } if self.isComputed(): v = VisualizationAxel("/home/jan/Programs/miniconda3/bin/axel-s") if self.comboBoxGraphFor.currentText() == 'orange': pos = self.graph.getPositionsOfVertices( self.spinBoxParameter.value() - 1, 0, 0, 0) elif self.comboBoxGraphFor.currentText() == 'red': pos = self.graph.getPositionsOfVertices( self.spinBoxParameter.value() - 1, 0, 1, 0) elif self.comboBoxGraphFor.currentText() == 'green': pos = self.graph.getPositionsOfVertices( self.spinBoxParameter.value() - 1, 0, 0, 1) elif self.comboBoxGraphFor.currentText() == 'blue': pos = self.graph.getPositionsOfVertices( self.spinBoxParameter.value() - 1, 0, 1, 1) else: pos = None if pos: v1, v2, v3, v4, v5, v6, v7 = pos v.add_polyline( [v2, v3, v7, v2, v1, v3, v4, v5, v1, v4, v7, v6, v5, v7], color=black) v.add_polyline([v1, v6], color=black) v.add_points([v1, v2, v3], color=black, size=1.5) v.add_points(self.graph.intersections, color=red, size=1.0) for c in self.checkBoxBranches: if self.checkBoxBranches[c].checkState(): for part in self.graph.getBranch(c): v.add_polyline(part, color=colors[c]) if self.checkBoxMirror.checkState(): v.add_points(self.graph.intersections_mirror, color=red, size=1.0) for c in self.checkBoxBranches: if self.checkBoxBranches[c].checkState(): for part in self.graph.getMirrorBranch(c): v.add_polyline(part, color=colors['dark' + c]) if self._V6fromPHC: v.add_points(self._V6fromPHC, color=dark_green, size=1.0) v.show() else: self.showError('Recomputation of coupler curve needed!') def runSamplingPhiTheta(self): self.computeCouplerCurves() n = 0 first = True while n < 48 and (not self.interrupt.checkState() or first): first = False self.printLog('Sampling phi and theta') alg = AlgRealEmbeddings( 'Max7vertices', num_phi=self.spinBoxSamplesPhi.value(), num_theta=self.spinBoxSamplesTheta.value(), choice_from_clusters='closestToAverageLength', window=self) alg.runSamplingPhiTheta( self.graph.getLengths(), self._possibleParametrizedVertices[ self.comboBoxParamVert.currentText()]) self.printLog('Sampling finished, see sequence') if not self.interrupt.checkState(): self.printLog('Rotating:') self.rotateVertices() def findMoreEmbeddings(self): self.computeCouplerCurves() self.printLog('Searching more embeddings:') alg = AlgRealEmbeddings('Max7vertices', window=self, num_phi=self.spinBoxSamplesPhi.value(), num_theta=self.spinBoxSamplesTheta.value(), name=self.lineEditName.text()) alg.findMoreEmbeddings(self.graph.getLengths()) if not self.interrupt.checkState(): self.printLog('Rotating:') self.rotateVertices() def showClusters(self, clusters, centers): pass newDialog = QDialog(self) newDialog.figure = Figure() newDialog.canvas = FigureCanvas(newDialog.figure) layout = QVBoxLayout() layout.addWidget(newDialog.canvas) newDialog.setLayout(layout) ax = newDialog.figure.add_subplot(111) for cluster in clusters: ax.plot([x for x, y in cluster], [y for x, y in cluster], 'o') ax.plot([x for x, y in centers], [y for x, y in centers], 'ro') newDialog.canvas.draw() newDialog.show()