class PlayerInfoField(QWidget): #Widget for inputting player info. names = ['Alex', 'Clifford', 'Tyrone', 'Ava', 'Ralph', 'Emily', 'Falcon', 'Giselle', 'Jaeger', 'Sally', 'Quentin', 'Lara'] def __init__(self, parent, index): super(PlayerInfoField, self).__init__(parent) self.index = index self.layout = QHBoxLayout() self.auto_button = Button(self, 'Auto') self.auto_button.setFixedWidth(60) self.auto_button.clicked.connect(self.generate_name) self.layout.addWidget(self.auto_button) self.name_field = QLineEdit() self.name_field.setPalette(QPalette(Qt.white)) self.name_field.setPlaceholderText('Name') self.name_field.setClearButtonEnabled(True) self.name_field.setFixedWidth(250) self.layout.addWidget(self.name_field) self.AItoggle = QCheckBox() self.AItoggle.setText('Computer') self.AItoggle.setFixedWidth(100) self.layout.addWidget(self.AItoggle) self.AItoggle.stateChanged.connect(self.AIToggled) self.AIdifficulty = QComboBox() self.AIdifficulty.setPalette(QPalette(Qt.white)) self.AIdifficulty.setFixedWidth(100) self.AIdifficulty.addItems(['Braindead', 'Easy', 'Normal', 'Hard', 'HAL-9000']) self.AIdifficulty.setCurrentIndex(2) self.AIdifficulty.setDisabled(True) self.layout.addWidget(self.AIdifficulty) self.spacer = QSpacerItem(40, 20, QSizePolicy.Expanding, QSizePolicy.Minimum) self.layout.addItem(self.spacer) self.layout.setContentsMargins(0, 0, 0, 0) self.setLayout(self.layout) def generate_name(self): self.name_field.setText(PlayerInfoField.names[self.index]) def AIToggled(self): if self.AItoggle.checkState() == Qt.Checked: self.AIdifficulty.setEnabled(True) else: self.AIdifficulty.setDisabled(True)
def update_aliases_on_gui(self): '''Updates aliases on the dialog using the info in the book's aliases dict''' aliases_widget = QWidget() aliases_layout = QGridLayout(aliases_widget) aliases_layout.setAlignment(Qt.AlignTop) # add aliases for current book for index, (character, aliases) in enumerate(sorted(self.book.aliases.items())): label = QLabel(character + ':') label.setFixedWidth(150) aliases_layout.addWidget(label, index, 0) line_edit = QLineEdit(', '.join([self.TITLE_CASE(alias) for alias in aliases])) line_edit.setFixedWidth(350) line_edit.textEdited.connect(functools.partial(self.edit_aliases, character)) aliases_layout.addWidget(line_edit, index, 1) self._scroll_area.setWidget(aliases_widget)
def update_aliases_on_gui(self): self.aliases_widget = QWidget() self.aliases_layout = QGridLayout(self.aliases_widget) self.aliases_layout.setAlignment(Qt.AlignTop) # add aliases for current book for index, aliases in enumerate(sorted(self.book.aliases.items())): label = QLabel(aliases[0] + ':') label.setFixedWidth(125) self.aliases_layout.addWidget(label, index, 0) line_edit = QLineEdit(', '.join(aliases[1])) line_edit.setFixedWidth(300) line_edit.textEdited.connect(functools.partial(self.edit_aliases, aliases[0])) self.aliases_layout.addWidget(line_edit, index, 1) self.scroll_area.setWidget(self.aliases_widget)
def update_aliases_on_gui(self): '''Updates aliases on the dialog using the info in the book's aliases dict''' aliases_widget = QWidget() aliases_layout = QGridLayout(aliases_widget) aliases_layout.setAlignment(Qt.AlignTop) # add aliases for current book for index, (character, aliases) in enumerate(sorted(self.book.aliases.items())): label = QLabel(character + ':') label.setFixedWidth(150) aliases_layout.addWidget(label, index, 0) line_edit = QLineEdit(', '.join( [self.TITLE_CASE(alias) for alias in aliases])) line_edit.setFixedWidth(350) line_edit.textEdited.connect( functools.partial(self.edit_aliases, character)) aliases_layout.addWidget(line_edit, index, 1) self._scroll_area.setWidget(aliases_widget)
class ConfigWidget(QWidget): """ GUI for configuration of default user input values. """ def __init__(self): """ Initialize the GUI elements for the config dialog. """ QWidget.__init__(self) self.layout = QVBoxLayout() self.layout.setSpacing(20) self.setLayout(self.layout) # Create an editable box for user to input Comic Vine API Key. self.api_layout = QHBoxLayout() self.api_msg = QLineEdit(self) self.api_msg.setFixedWidth(350) self.api_msg.setText(prefs["comic_vine_api_key"]) self.api_label = QLabel("Comic Vine API Key") self.api_label.setBuddy(self.api_msg) self.api_layout.addWidget(self.api_label) self.api_layout.addWidget(self.api_msg) # Create an editable box for user to input Tags to add to all books. self.tags_layout = QHBoxLayout() self.tags_msg = QLineEdit(self) self.tags_msg.setText(prefs["tags_to_add"]) self.tags_label = QLabel("Tags To Add") self.tags_label.setBuddy(self.tags_msg) self.tags_layout.addWidget(self.tags_label) self.tags_layout.addWidget(self.tags_msg) # Add the fields to the main layout. self.layout.addLayout(self.api_layout) self.layout.addLayout(self.tags_layout) def save_settings(self): """ Save user input to the default configuration. """ prefs["comic_vine_api_key"] = self.api_msg.text() prefs["tags_to_add"] = self.tags_msg.text()
def _create_widget(self, value): if isinstance(value, str): widget = QLineEdit() widget.setText(value) widget.setPlaceholderText('String Val') elif isinstance(value, list): return [self._create_widget(v) for v in value] else: if isinstance(value, int): widget = QSpinBox() else: widget = QDoubleSpinBox() decimal = str(value)[::-1].find('.') widget.setDecimals(decimal) widget.setSingleStep(pow(10, -decimal)) widget.setMinimum(-9999999) widget.setMaximum(9999999) widget.setValue(value) widget.setFixedWidth(100) widget.setAlignment(Qt.AlignRight) return widget
class ComicalibreDialog(QDialog): """ The main dialog for users to enter options before starting. """ def __init__(self, gui, icon, do_user_config): """ Initialize the gui dialog. """ QDialog.__init__(self, gui) self.gui = gui self.icon = icon self.do_user_config = do_user_config self.db = gui.current_db self.create_gui() def start_process(self, process_type): """ Starts the processing worker and progress bar. """ prefs["comic_vine_api_key"] = self.api_msg.text() prefs["tags_to_add"] = self.tags_msg.text() self.worker = ComicalibreWork(self.gui) self.result_text.setText("Processing...") self.title_start.setEnabled(False) self.series_start.setEnabled(False) self.ids_start.setEnabled(False) keep_tags = self.keep_tags_cb.isChecked() errors = self.worker.process(self.progress_bar, process_type, keep_tags) self.title_start.setEnabled(True) self.series_start.setEnabled(True) self.ids_start.setEnabled(True) results = "Finished!" + os.linesep for error in errors: results = results + error + os.linesep self.result_text.setText(results) def title_process(self): self.start_process(0) def series_process(self): self.start_process(1) def ids_process(self): self.start_process(2) def create_gui(self): """ Layout arrangement for the dialog and its input widgets. """ self.layout = QVBoxLayout() self.layout.setSpacing(20) self.setLayout(self.layout) # Create an editable box for user to input Comic Vine API Key. self.api_layout = QHBoxLayout() self.api_msg = QLineEdit(self) self.api_msg.setFixedWidth(350) self.api_msg.setText(prefs["comic_vine_api_key"]) self.api_label = QLabel("Comic Vine API Key") self.api_label.setBuddy(self.api_msg) self.api_layout.addWidget(self.api_label) self.api_layout.addWidget(self.api_msg) # Create an editable box for user to input Tags to add to all books. self.tags_layout = QHBoxLayout() self.tags_msg = QLineEdit(self) self.tags_msg.setText(prefs["tags_to_add"]) self.tags_label = QLabel("Tags To Add") self.tags_label.setBuddy(self.tags_msg) self.tags_layout.addWidget(self.tags_label) self.tags_layout.addWidget(self.tags_msg) # Add the fields to the main layout. self.layout.addLayout(self.api_layout) self.layout.addLayout(self.tags_layout) # Option to keep current tags. self.keep_tags_cb = QCheckBox("Keep existing tags while adding new.", self) self.layout.addWidget(self.keep_tags_cb) # Separate the buttons from the input. self.btn_sep = QFrame() self.btn_sep.setFrameShape(QFrame.HLine) self.btn_sep.setFrameShadow(QFrame.Sunken) self.layout.addWidget(self.btn_sep) # Create a start button to kick off the processing with title. self.title_start = QPushButton("Using Title - Hover For Details", self) self.title_start.setToolTip( "This expects the title of a book to have a " "specific formatted string containing volume " "ID and issue#. e.g." + os.linesep + "Desired " "Title --- v1234 n0124" + os.linesep + "Where " "--- is required and the number after v " "matches Comic Vine's volume ID. The number " "after n is the issue number.") self.title_start.clicked.connect(self.title_process) self.layout.addWidget(self.title_start) # Create a start button to kick off the processing with series. self.series_start = QPushButton("Using Series - Hover For Details", self) self.series_start.setToolTip( "This expects the series name to match the " "Comic Vine volume ID and the series number " "equals issue number.") self.series_start.clicked.connect(self.series_process) self.layout.addWidget(self.series_start) # Create a start button to kick off the processing with CV IDs. self.ids_start = QPushButton("Using IDs - Hover For Details", self) self.ids_start.setToolTip( "This expects two custom columns with lookup " "comicvineissueid and comicvinevolumeid. " "These must match Comic Vine's IDs for the " "issue and the volume.") self.ids_start.clicked.connect(self.ids_process) self.layout.addWidget(self.ids_start) # Separate the progress and results. self.result_sep = QFrame() self.result_sep.setFrameShape(QFrame.HLine) self.result_sep.setFrameShadow(QFrame.Sunken) self.layout.addWidget(self.result_sep) # Create progress bar. self.progress_bar = QProgressBar() self.progress_bar.setRange(0, 100) self.progress_bar.setMinimumWidth(485) self.layout.addWidget(self.progress_bar) # Create results text area. self.result_box = QGroupBox() self.result_box.setTitle("Results") self.result_text = QLabel("Run Comicalibre to see results.") self.result_scroll = QScrollArea() self.result_scroll.setWidget(self.result_text) self.result_scroll.setWidgetResizable(True) self.result_layout = QVBoxLayout() self.result_layout.addWidget(self.result_scroll) self.result_box.setLayout(self.result_layout) self.layout.addWidget(self.result_box) self.setWindowTitle("Comicalibre") self.setWindowIcon(self.icon) self.resize(self.sizeHint())
class ApplicationWindow(QMainWindow): def __init__(self): super().__init__() self.currentPath = sys.path[0] # 程序运行的路径 self.initUI() self.xTrain = None def initUI(self): self.setWindowIcon(QIcon(r'G:\myRepostory\graduateProject\logo\xjtu.jpg')) #菜单 #Qaction openFileAct = QAction('&打开',self,triggered = self.openFile) openFileAct.setShortcut('Ctrl+O') exitAct = QAction('&退出',self,triggered=self.fileQuit) exitAct.setShortcut('Ctrl+Q') menubar = self.menuBar() #开始菜单 fileMenu = menubar.addMenu('&开始') fileMenu.addAction(openFileAct) fileMenu.addAction(exitAct) #方法 #帮助 helpMenu = menubar.addMenu('&帮助') aboutAction = QAction('&关于',self,triggered = self.about) helpMenu.addAction(aboutAction) #状态栏 self.statusBar().showMessage('准备就绪',2000) #主界面布局 self.main_widget = QWidget(self) # mainFunctionLabel = QLabel('命令') importButton = QPushButton("导入数据") importButton.clicked.connect(self.loadData) startButton = QPushButton('开始') startButton.clicked.connect(self.startSelection) stopButton = QPushButton('停止') stopButton.clicked.connect(self.stopSelection) plotButton = QPushButton('绘图') plotButton.clicked.connect(self.plotPic) exitButton = QPushButton('退出') exitButton.clicked.connect(self.fileQuit) self.drawPic = DynamicDrawMachines(self.main_widget,width=5,height=4,dpi=100) self.hboxButtonBox = QGroupBox('命令') self.hboxButton = QHBoxLayout() self.hboxButton.addWidget(importButton) self.hboxButton.addWidget(startButton) self.hboxButton.addWidget(stopButton) self.hboxButton.addWidget(plotButton) self.hboxButton.addWidget(exitButton) self.hboxButtonBox.setLayout(self.hboxButton) self.gboxAlgo = QGridLayout() experNumLabel = QLabel('训练集比例') self.trainPTxt = QLineEdit() self.trainPTxt.setText('0.8') self.trainPTxt.setFixedWidth(100) algorithmsLable = QLabel('算法') self.availableAlgos = ['PLS','RReliefF','UVE-PLS','SA-PLS','GA-PLS','ACO-PLS','LASSO','Elastic Net','FP-Tree-PLS'] self.algorithmBlock = QComboBox() self.algorithmBlock.insertItems(1,self.availableAlgos) self.algorithmBlock.currentIndexChanged.connect(self.changeAlgorithm) self.changeParameter = QPushButton('修改算法参数') self.changeParameter.clicked.connect(self.changeAlgoParameter) self.gboxAlgoBox = QGroupBox('算法') self.gboxAlgo.addWidget(algorithmsLable, 0, 0) self.gboxAlgo.addWidget(self.algorithmBlock, 0, 1) self.gboxAlgo.addWidget(self.changeParameter,0,2) self.gboxAlgo.addWidget(experNumLabel,0,3) self.gboxAlgo.addWidget(self.trainPTxt,0,4) self.gboxAlgoBox.setLayout(self.gboxAlgo) analysisLabel = QLabel('分析结果') rmsecvLabel = QLabel('RMSECV') rmsetLabel = QLabel('RMSET') rmsepLabel = QLabel('RMSEP') r2cvLabel = QLabel('R2CV') r2pLabel = QLabel('R2P') CRlabel = QLabel('CR') self.numrmsecvLabel = QLabel('0') self.numrmsetLabel = QLabel('0') self.numrmsepLabel = QLabel('0') self.numr2cvLabel = QLabel('1') self.numr2pLabel = QLabel('1') self.numCRlabel = QLabel('1') self.gboxAnalysisBox = QGroupBox('分析结果') self.gboxAnalysis = QGridLayout() # self.gboxAnalysis.addWidget(analysisLabel,0,0) self.gboxAnalysis.addWidget(rmsecvLabel,1,0) self.gboxAnalysis.addWidget(rmsetLabel,1,1) self.gboxAnalysis.addWidget(rmsepLabel,1,2) self.gboxAnalysis.addWidget(r2cvLabel,1,3) self.gboxAnalysis.addWidget(r2pLabel,1,4) self.gboxAnalysis.addWidget(CRlabel,1,5) self.gboxAnalysis.addWidget(self.numrmsecvLabel, 2, 0) self.gboxAnalysis.addWidget(self.numrmsetLabel, 2, 1) self.gboxAnalysis.addWidget(self.numrmsepLabel, 2, 2) self.gboxAnalysis.addWidget(self.numr2cvLabel, 2, 3) self.gboxAnalysis.addWidget(self.numr2pLabel, 2, 4) self.gboxAnalysis.addWidget(self.numCRlabel, 2, 5) self.gboxAnalysisBox.setLayout(self.gboxAnalysis) self.vboxButton = QVBoxLayout(self.main_widget) # self.vboxButton.addWidget(mainFunctionLabel) # self.vboxButton.addLayout(self.hboxButton) self.vboxButton.addWidget(self.hboxButtonBox) # self.vboxButton.addLayout(self.gboxAlgo) self.vboxButton.addWidget(self.gboxAlgoBox) self.vboxButton.addWidget(self.drawPic) # self.vboxButton.addLayout(self.gboxAnalysis) self.vboxButton.addWidget(self.gboxAnalysisBox) self.setLayout(self.vboxButton) self.main_widget.setFocus() self.setCentralWidget(self.main_widget) # 设置分辨率 self.setGeometry(300,300,600,700) self.show() #更改参数窗口 # self.changeParaWindow = changeParaWindow() # self.changeParaWindow.setWindowTitle("修改参数") def about(self): QMessageBox.about(self, "关于", """ sol yang 2018 """ ) def noDataWarning(self): QMessageBox.about(self,"没有数据", """ 请先读取数据 """) def openFile(self): fname = QFileDialog.getOpenFileName(self, '打开文件', self.currentPath,"CSV Files (*.csv);;Excel File (*.xlsx);;所有文件 (*)") if fname[0]: f = open(fname[0], 'r') with f: data = f.read() def fileQuit(self): self.close() def closeEvent(self, ce): self.fileQuit() def loadData(self): self.statusBar().showMessage('正在加载数据', 2000) ''' read data ''' self.CO, self.CO2, self.CH4, self.specData = readData() d = pd.read_excel('./data/NONO2SO2.xlsx') lines = d.shape[0] self.NO = d['NO'].as_matrix().reshape(lines, 1) self.NO2 = d['NO2'].as_matrix().reshape(lines, 1) self.SO2 = d['SO2'].as_matrix().reshape(lines, 1) self.specData2 = d.iloc[:, 4:].as_matrix() self.statusBar().showMessage('加载数据完成', 2000) ''' split the data set If int, random_state is the seed used by the random number generator; If RandomState instance, random_state is the random number generator; If None, the random number generator is the RandomState instance used by np.random. ''' self.xTrainOrigin, self.xTestOrigin, self.yTrainOrigin, self.yTestOrigin = \ train_test_split(self.specData2, self.SO2, test_size=0.2, random_state=42) ''' 数据预处理 ''' # mean removal self.scalerX = preprocessing.StandardScaler().fit(self.xTrainOrigin) self.xTrain = self.scalerX.transform(self.xTrainOrigin) self.xTest = self.scalerX.transform(self.xTestOrigin) self.scalerY = preprocessing.StandardScaler().fit(self.yTrainOrigin) self.yTrain = self.scalerY.transform(self.yTrainOrigin) self.yTest = self.scalerY.transform(self.yTestOrigin) ''' 计算模型评价参数 ''' def modelMerit(self, SelectedIndex): xTrainSelected = self.xTrain[:, SelectedIndex] xTestSelected = self.xTest[:, SelectedIndex] kf = model_selection.KFold(n_splits=5, random_state=10) trans, features = xTrainSelected.shape lvMax = int(min(trans, features) / 3) lvBest = 0 rmsecvBest = np.inf for lvTemp in range(1, lvMax + 1): squareArray = np.array([[]]) for train, test in kf.split(xTrainSelected): xTrainTemp = xTrainSelected[train, :] yTrainTemp = self.yTrain[train] xTestTemp = xTrainSelected[test, :] yTestTemp = self.yTrain[test] yPredictTemp, coefTemp = PLS(xTestTemp, yTestTemp, xTrainTemp, yTrainTemp, lvTemp) yPredictTempTrue = self.scalerY.inverse_transform(yPredictTemp) yTestTempTrue = self.scalerY.inverse_transform(yTestTemp) residual = yPredictTempTrue - yTestTempTrue square = np.dot(residual.T, residual) squareArray = np.append(squareArray, square) # squareArray.append(square) RMSECV = np.sqrt(np.sum(squareArray) / xTrainSelected.shape[0]) if RMSECV < rmsecvBest: rmsecvBest = RMSECV lvBest = lvTemp plsModel = cross_decomposition.PLSRegression(n_components=lvBest) plsModel.fit(xTrainSelected, self.yTrain) yPredict = plsModel.predict(xTestSelected) yTrainPredict = plsModel.predict(xTrainSelected) yTrainPredictTrue = self.scalerY.inverse_transform(yTrainPredict) yPredictTrue = self.scalerY.inverse_transform(yPredict) self.yPredcit = yPredict MEST = sm.mean_squared_error(self.yTrainOrigin, yTrainPredictTrue) RMSET = np.sqrt(MEST) R2T = sm.r2_score(self.yTrainOrigin, yTrainPredictTrue) MSEP = sm.mean_squared_error(self.yTestOrigin, yPredictTrue) RMSEP = np.sqrt(MSEP) R2P = sm.r2_score(self.yTestOrigin, yPredictTrue) # 计算交叉验证误差 yPredictCV = np.array([[]]) yTrueCV = np.array([[]]) for train, test in kf.split(xTrainSelected): xTrainTemp = xTrainSelected[train, :] yTrainTemp = self.yTrain[train] xTestTemp = xTrainSelected[test, :] yTestTemp = self.yTrain[test] yPredictTemp, coefTemp = PLS(xTestTemp, yTestTemp, xTrainTemp, yTrainTemp, lvBest) yPredictTempTrue = self.scalerY.inverse_transform(yPredictTemp) yTestTempTrue = self.scalerY.inverse_transform(yTestTemp) yPredictCV = np.append(yPredictCV, yPredictTempTrue) yTrueCV = np.append(yTrueCV, yTestTempTrue) residual = yPredictTempTrue - yTestTempTrue square = np.dot(residual.T, residual) squareArray = np.append(squareArray, square) # squareArray.append(square) RMSECV = np.sqrt(np.sum(squareArray) / xTrainSelected.shape[0]) R2CV = sm.r2_score(yPredictCV, yTrueCV) CR = 1 - len(SelectedIndex) / self.xTrain.shape[1] return rmsecvBest, RMSET, RMSEP, R2T, R2P, R2CV, CR def startSelection(self): self.selectedAlgorithm = self.algorithmBlock.currentText() if(self.xTrain is None): self.noDataWarning() return xTrain = self.xTrain xTest = self.xTest yTrain = self.yTrain yTest = self.yTest ''' 'PLS','RReliefF','UVE-PLS','SA-PLS','GA-PLS', 'ACO-PLS','LASSO','Elastic Net','FP-Tree-PLS' ''' self.statusBar().showMessage('%s算法开始' % self.selectedAlgorithm, 1000) if self.selectedAlgorithm=='RReliefF': w = RReliefF(self.xTrain, self.yTrain) th = np.percentile(w, 80) # 计算分位数 selectedIndex = np.where(w >= th)[0] elif self.selectedAlgorithm=='PLS': selectedIndex = list(range(self.xTrain.shape[1])) modelMerit = self.modelMerit(selectedIndex) self.displayMerit(modelMerit) self.statusBar().showMessage('%s算法结束' % self.selectedAlgorithm) def displayMerit(self,modelMerit): self.numrmsecvLabel.setText('%.2f' %modelMerit[0]) self.numrmsetLabel.setText('%.2f' %modelMerit[1]) self.numrmsepLabel.setText('%.2f' %modelMerit[2]) self.numr2cvLabel.setText('%.2f' %modelMerit[-2]) self.numr2pLabel.setText('%.2f' %modelMerit[4]) self.numCRlabel.setText('%.2f' %modelMerit[-1]) def stopSelection(self): pass def plotPic(self): if (self.xTrain is None): self.noDataWarning() return yTure = self.scalerY.inverse_transform(self.yTest) yPredict = self.scalerY.inverse_transform(self.yPredcit) self.drawPic.scatter2D(yTure,yPredict) def changeAlgorithm(self): self.selectedAlgorithm = self.algorithmBlock.currentText() self.statusBar().showMessage('选择%s算法' %self.selectedAlgorithm, 1000) def changeAlgoParameter(self): ''' 'PLS','RReliefF','UVE-PLS','SA-PLS','GA-PLS', 'ACO-PLS','LASSO','Elastic Net','FP-Tree-PLS' ''' self.selectedAlgorithm = self.algorithmBlock.currentText() if self.selectedAlgorithm == 'FP-Tree-PLS': self.changeParaWindow = changeFPParaWindow() elif self.selectedAlgorithm == 'SA-PLS': self.changeParaWindow = changeSAParaWindow() else: self.changeParaWindow = classicWindow() self.changeParaWindow.show()
class FunctionPlot(QWidget): '''Plotting of Z(t) = f(X(t),Y(t), where X(t) and Y(t) are the coordinates of the target, and Z(t) is a Python expression given by the user. For example : Z(t) = np.atan2(Y(), X(t), to compute the angle of the polar coordinates of the target. ''' def __init__(self, mainWindow): # call the constructor of the base class: super().__init__(mainWindow) self.mw = mainWindow # remember the reference on thje main window # Attributes (persistent data in the object) self.__figure = None # the plotting figure self.__axe1 = None # plot Z1 Axes self.__axe2 = None # plot Z2 Axes (twinx) self.__canvas = None # used by matplotlib to plot data self.__toolbar = None # the tool bar below the plot self.__time = None # abcissa values for plot self.__xlim = None # plot xmin and xmax self.__z1lim = None # plot ymin and ymax self.__z2lim = None # plot ymin and ymax self.__XYLabel1 = ["",""] # X and Y plot labels self.__XYLabel2 = ["",""] # X and Y plot labels self.__Z1 = None # data to plot: Z1(t) = f(X(t),Y(t),t) self.__Z1 = None # data to plot: Z2(t) = f(X(t),Y(t),t) self.__labelZ1Edit = QLabel("Z1 : Python expr. to plot", self) self.__lineZ1Edit = QLineEdit("Y-Y.mean()",self) self.__labelZ1label = QLabel("Z1 axis label:", self) self.__lineZ1label = QLineEdit("Z1 [unit]",self) self.__labelZ2Edit = QLabel("Z2 : Python expr. to plot", self) self.__lineZ2Edit = QLineEdit("cos(2*pi*12*T)",self) self.__labelZ2label = QLabel("Z2 axis label:", self) self.__lineZ2label = QLineEdit("Z2 [unit]",self) self.__btnPlot1 = QPushButton("Plot",self) self.__btnPlot2 = QPushButton("Plot",self) self.__btnClear1 = QPushButton("Clear",self) self.__btnClear2 = QPushButton("Clear",self) self.__btnClear = QPushButton("Clear All",self) self.__btnCSV = QPushButton(QIcon("icones/csv.png"), "Export CSV", self) self.__initUI() # GUI initialization def __initUI(self): self.__figure, self.__axe1 = plt.subplots() self.__axe2 = self.__axe1.twinx() self.__figure.subplots_adjust(left=0.1,right=0.9,bottom=0.14,top=0.92) self.__canvas = FigureCanvas(self.__figure) self.__toolbar = NavigationToolbar(self.__canvas, self) self.__btnPlot1.clicked.connect(self.PlotZ1) self.__btnPlot2.clicked.connect(self.PlotZ2) self.__btnClear1.clicked.connect(self.ClearAxe1) self.__btnClear2.clicked.connect(self.ClearAxe2) self.__btnClear.clicked.connect(self.ClearAxes) self.__btnCSV.clicked.connect(self.ExportCSV) self.__btnCSV.setEnabled(False) mess = '''Type in a Python expression like: Y-Y.mean() In this expression you can use use: - the position vector X or Y, - the vecolity vector VX or VX, - the time vector T''' self.__lineZ1Edit.setToolTip(mess) self.__lineZ2Edit.setToolTip(mess) self.__lineZ1Edit.setFixedWidth(200) self.__lineZ2Edit.setFixedWidth(200) vbox = QVBoxLayout() self.setLayout(vbox) # Ligne 1 : tracé de l'image self.setLayout(vbox) hbox = QHBoxLayout() hbox.addWidget(self.__labelZ1Edit) hbox.addWidget(self.__lineZ1Edit) hbox.addWidget(self.__labelZ1label) hbox.addWidget(self.__lineZ1label) hbox.addStretch() hbox.addWidget(self.__btnClear1) hbox.addWidget(self.__btnPlot1) vbox.addLayout(hbox) hbox = QHBoxLayout() hbox.addWidget(self.__labelZ2Edit) hbox.addWidget(self.__lineZ2Edit) hbox.addWidget(self.__labelZ2label) hbox.addWidget(self.__lineZ2label) hbox.addStretch() hbox.addWidget(self.__btnClear2) hbox.addWidget(self.__btnPlot2) vbox.addLayout(hbox) vbox.addWidget(self.__canvas) hbox = QHBoxLayout() hbox.addWidget(self.__toolbar) hbox.addStretch() hbox.addWidget(self.__btnClear) hbox.addWidget(self.__btnCSV) vbox.addLayout(hbox) def __AutoSizePlotXZLim(self, num_axe, color): if self.mw.target_pos is None: return if num_axe == 1: X, Z = self.__time, self.__Z1 axe = self.__axe1 xmil, zlim = self.__xlim, self.__z1lim XYLabel = self.__XYLabel1 elif num_axe == 2: X, Z = self.__time, self.__Z2 axe = self.__axe2 xmil, zlim = self.__xlim, self.__z2lim XYLabel = self.__XYLabel2 deltaZ = np.nanmax(Z) - np.nanmin(Z) xlim = np.array([np.nanmin(X), np.nanmax(X)]) zlim = np.array([np.nanmin(Z)-0.1*deltaZ, np.nanmax(Z)+0.1*deltaZ]) axe.set_xlim(*xlim) axe.set_ylim(*zlim) axe.set_xlabel(XYLabel[0]) axe.set_ylabel(XYLabel[1], color=color) axe.set_aspect("auto") self.__canvas.draw() def ClearAxe1(self): self.__axe1.clear() self.__canvas.draw() self.__Z1 = None def ClearAxe2(self): self.__axe2.clear() self.__canvas.draw() self.__Z2 = None def ClearAxes(self): self.__axe1.clear() self.__axe2.clear() self.__canvas.draw() self.__btnCSV.setEnabled(False) def __buildTimeVector(self, target_pos): # Récupération de la valeur de FP (Frame per seconde) pour calcul # du pas de temps et des abscisses : X = target_pos[0] if self.mw.imageTab.video_FPS is not None: deltaT = 1./self.mw.imageTab.video_FPS self.__time = np.arange(len(X))*deltaT self.__XYLabel1[0] = "temps [s]" self.__XYLabel2[0] = "temps [s]" else: self.__time = np.arange(len(X))+1 self.__XYLabel1[0] = "image #" self.__XYLabel2[0] = "image #" def PlotZ1(self): target_pos = self.mw.target_pos if target_pos is None: return self.__buildTimeVector(target_pos) X, Y, T = target_pos[0], target_pos[1], self.__time VX, VY = self.mw.target_veloc expr = self.__lineZ1Edit.text() try: self.__Z1 = eval(expr) except: print("cannot plot this expression <{}>".format(expr)) return self.__XYLabel1[1] = self.__lineZ1label.text() self.__AutoSizePlotXZLim(1, 'b') # tracé de courbe X(t) self.__axe1.plot(self.__time, self.__Z1, color = 'b', marker = 'o', markersize = 2, linewidth = .4, label="Z1(t)="+expr) self.__axe1.grid(True) self.__axe1.legend(fontsize=9, framealpha=0.7, bbox_to_anchor=(-0.1, 1.1), loc='upper left') self.__axe1.tick_params(axis='y', labelcolor='b') self.__canvas.draw() self.__btnCSV.setEnabled(True) def PlotZ2(self): target_pos = self.mw.target_pos if target_pos is None: return self.__buildTimeVector(target_pos) X, Y, T = target_pos[0], target_pos[1], self.__time VX, VY = self.mw.target_veloc expr = self.__lineZ2Edit.text() try: self.__Z2 = eval(expr) except: print("cannot plot this expression <{}>".format(expr)) return self.__XYLabel2[1] = self.__lineZ2label.text() self.__AutoSizePlotXZLim(2, 'm') # tracé de courbe X(t) self.__axe2.plot(self.__time, self.__Z2, color = 'm', marker = 'o', markersize = 2, linewidth = .4, label="Z2(t)="+expr) #self.__axe2.grid(True) self.__axe2.legend(fontsize=8, framealpha=0.7, bbox_to_anchor=(1.1, 1.1), loc='upper right') self.__axe2.tick_params(axis='y', labelcolor='m') self.__canvas.draw() self.__btnCSV.setEnabled(True) def ExportCSV(self): '''Export Data in a CSV file.''' if self.__Z1 is None : self.mw.statusBar().showMessage("No data to export") return # Lance un sélecteur de fichier pour choisir le fichier à écrire.''' fname = QFileDialog.getSaveFileName(self, 'Choose a name for the CSV file to write', self.mw.cur_dir, 'CSV file (*.csv *.txt)') if fname[0] == "": return nbData = len(self.__time) if self.mw.imageTab.video_FPS is not None: deltaT = 1./self.mw.imageTab.video_FPS time = np.arange(nbData)*deltaT tlabel, tformat = "T [seconde]", "%10.6e" else: time = range(1, nbImages+1) tlabel, tformat = "image #", "%10d" # building headers: zlabel = self.__lineZlabel.text() zformat = "%10.6e" header = "{};{}".format(tlabel, zlabel) fmt = (tformat, zformat) data = [] data.append(time) data.append(self.__Z1.tolist()) data = np.array(data) fileName = fname[0] if not fileName.endswith(".csv"): fileName += ".csv" np.savetxt(fileName, data.transpose(), delimiter=";", header=header, fmt=fmt)