class EXample(QWidget): def __init__(self): super().__init__() self.initUI() def initUI(self): self.lbl = QLabel("Ubuntu", self) # 设置Label默认值 combo = QComboBox(self) combo.addItem("Ubuntu") combo.addItem("Mandriva") combo.addItem("Fedora") combo.addItem("Arch") combo.addItem("Gentoo") combo.move(50, 50) self.lbl.move(50, 150) combo.activated[str].connect(self.onActivated) self.setGeometry(300, 300, 600, 400) self.setWindowTitle("QComboBox") self.show() def onActivated(self, text): self.lbl.setText(text) self.lbl.adjustSize()
class Example(QWidget): def initUI(self): self.lbl = QLabel("Ubuntu", self) self.lbl.move(50, 150) combo = QComboBox(self) combo.addItem("Ubuntu") combo.addItem("Mac OS") combo.addItem("Windows") combo.addItem("Red Hat") combo.addItem("Fedora") combo.move(50, 50) combo.setGeometry(50, 50, 100, 100) combo.activated[str].connect(self.onActivated) self.setGeometry(300, 300, 200, 200) self.setWindowTitle('QComboBox') self.show() def onActivated(self, text): self.lbl.setText(text) self.lbl.adjustSize() # This is needed to update the label as the textedit got updated def __init__(self): super(Example, self).__init__() self.initUI()
class ComboBox(QWidget): def __init__(self): super().__init__() self.initUI() def initUI(self): self.lbl = QLabel('中国', self) self.lbl.move(50, 150) combo = QComboBox(self) combo.addItem('中国') combo.addItem('美国') combo.addItem('法国') combo.addItem('德国') combo.addItem('俄罗斯') combo.addItem('澳大利亚') combo.move(50, 50) combo.activated[str].connect(self.onActivated) combo1 = QComboBox(self) combo1.addItem('Item1') combo1.addItem('Item2') combo1.addItem('Item3') combo1.move(200, 50) self.setGeometry(300, 300, 300, 200) self.setWindowTitle('QComboBox控件') self.show() def onActivated(self, text): self.lbl.setText(text) self.lbl.adjustSize()
def initRadioButtons(self): width = self.width() height = self.height() self.deterministicRadio = QRadioButton('Deterministic Queue', self) self.deterministicRadio.setFont(QFont('Sanserif', 18)) self.deterministicRadio.setStyleSheet('QRadioButton{color:maroon}') self.deterministicRadio.adjustSize() self.deterministicRadio.move(100, 100) self.deterministicRadio.clicked.connect(self.deterministicRadioClicked) self.stochasticRadio = QRadioButton('Stochastic Queue', self) self.stochasticRadio.setFont(QFont('Sanserif', 18)) self.stochasticRadio.setStyleSheet('QRadioButton{color:darkslategray}') self.stochasticRadio.adjustSize() self.stochasticRadio.move((width / 2) + 50, 100) self.stochasticRadio.clicked.connect(self.stochasticRadioClicked) self.deterministicRadio = QRadioButton('WhatEver Queue', self) self.deterministicRadio.setFont(QFont('Sanserif', 18)) self.deterministicRadio.setStyleSheet('QRadioButton{color:steelblue}') self.deterministicRadio.adjustSize() self.deterministicRadio.move(300, 200) icon1 = QIcon('line.png') label1 = QLabel('Sample', self) pixmap1 = icon1.pixmap(100, 100, QIcon.Active, QIcon.On) label1.setPixmap(pixmap1) label1.move((width / 2) - 50, 300) label1.adjustSize()
class Viewer(QMainWindow): def __init__(self): QMainWindow.__init__(self) self.scaleFactor = 1.0 self.imageLabel = QLabel() self.imageLabel.setSizePolicy(QSizePolicy.Ignored, QSizePolicy.Ignored) self.imageLabel.setScaledContents(True) self.imageLabel.show() self.markers = Markers(self.imageLabel, IMG_FILE[:-3] + "json") km = KeysManager(self.markers) self.scrollArea = MyScrollArea(self.zoom, self.click, km.keyEventKB) self.scrollArea.setWidget(self.imageLabel) self.scrollArea.setVisible(False) def load_image(self): self.imageLabel.setPixmap(load_img()) self.scrollArea.setVisible(True) self.imageLabel.adjustSize() def zoom(self, scr_x, scr_y, factor): # # figure out pixel coordinate where mouse pointer is # hsb = self.scrollArea.horizontalScrollBar() cur_pixel_x = (hsb.value() + scr_x) / self.scaleFactor vsb = self.scrollArea.verticalScrollBar() cur_pixel_y = (vsb.value() + scr_y) / self.scaleFactor # # rescale the image # self.scaleFactor *= factor self.imageLabel.resize(self.scaleFactor * self.imageLabel.pixmap().size()) self.markers.zoom(self.scaleFactor) # # adjust scroll so the we zoom in/out at where we are pointing # left_pixel_x = cur_pixel_x - (scr_x / self.scaleFactor) hsb.setValue(left_pixel_x * self.scaleFactor) top_pixel_y = cur_pixel_y - (scr_y / self.scaleFactor) vsb.setValue(top_pixel_y * self.scaleFactor) def click(self, x, y): x /= self.scaleFactor y /= self.scaleFactor self.markers.add(x, y, self.scaleFactor) def save_markers(self): self.markers.save()
def createBackArrow(self): icon1 = QIcon('arrow_back.png') label1 = QLabel('Sample', self) pixmap1 = icon1.pixmap(20, 20, QIcon.Active, QIcon.On) label1.setPixmap(pixmap1) label1.move(25, 25) label1.adjustSize() label1.mousePressEvent = self.arrowbackClicked
def quit_message(self) -> QDialog: """Displays a window while SCOUTS is exiting""" message = QDialog(self) message.setWindowTitle('Exiting SCOUTS') message.resize(300, 50) label = QLabel('SCOUTS is exiting, please wait...', message) label.setStyleSheet(self.style['label']) label.adjustSize() label.setAlignment(Qt.AlignCenter) label.move(int((message.width() - label.width()) / 2), int((message.height() - label.height()) / 2)) return message
def loading_message(self) -> QDialog: """Returns the message box to be displayed while the user waits for the input data to load.""" message = QDialog(self) message.setWindowTitle('Loading') message.resize(300, 50) label = QLabel('loading DataFrame into memory...', message) label.setStyleSheet(self.style['label']) label.adjustSize() label.setAlignment(Qt.AlignCenter) label.move(int((message.width() - label.width()) / 2), int((message.height() - label.height()) / 2)) return message
class LineEdit(QWidget): def __init__(self): super().__init__() self.initUI() def initUI(self): self.label=QLabel(self) lineEdit=QLineEdit(self) lineEdit.move(80,100) self.label.move(80,40) lineEdit.textChanged[str].connect(self.onChanged) self.setGeometry(300,300,280,170) self.setWindowTitle('QlineEdit控件') self.show() def onChanged(self,text): self.label.setText(text) self.label.adjustSize()
class TemplateInfo(QWidget): def __init__(self): super().__init__() self.setFixedHeight(Theme.browser.info.height) layout = QVBoxLayout() layout.setAlignment(Qt.AlignTop) layout.setSpacing(0) layout.setContentsMargins(0, 0, 0, 0) self.setLayout(layout) self.setAttribute(Qt.WA_StyledBackground) self.setStyleSheet(Theme.browser.info.style) self._initName() self._initDescription() def _initName(self): self.name = QLabel() self.name.setWordWrap(True) self.name.setStyleSheet(Theme.browser.info.headerStyle) self.name.setFont(Theme.browser.info.headerFont) self.layout().addWidget(self.name) def _initDescription(self): self.description = QTextEdit() self.description.setReadOnly(True) self.description.setVerticalScrollBar(ScrollBar()) self.description.setStyleSheet(Theme.browser.info.textAreaStyle) self.description.setFont(Theme.browser.info.textAreaFont) self.description.setTextColor(Theme.browser.info.textAreaFontColor) self.description.setContextMenuPolicy(Qt.NoContextMenu) self.layout().addWidget(self.description) def setTemplate(self, template): if template is None: self.name.setText("") self.description.setText("") else: self.name.setText(template.backend_name) self.description.setText(template.description) self.name.adjustSize() self.description.adjustSize()
def ui_components(self): # fonts font = QFont("Roboto", 15) # 'enter country name' label enter_country_label = QLabel("Enter country name: ", self) enter_country_label.setFont(font) enter_country_label.move(10, 10) enter_country_label.adjustSize() # 'country name' line edit country_name = QLineEdit(self) country_name.setFixedSize(200, 25) country_name.setFont(font) country_name.setPlaceholderText("Ex: Tunisia") country_name.move(10, 40) country_name_submit = QPushButton("Search", self) country_name_submit.setFixedSize(130, 25) country_name_submit.move(220, 40) # Displays worldwide data as default cases_label = QLabel( f"Current cases: {data.CoronaCases('').total_cases}", self) cases_label.setFont(font) cases_label.adjustSize() cases_label.move(10, 85) deaths_label = QLabel( f"Current deaths: {data.CoronaCases('').total_deaths}", self) deaths_label.setFont(font) deaths_label.adjustSize() deaths_label.move(10, 112.8) recovered_label = QLabel( f"Current recovered: {data.CoronaCases('').total_recovered}", self) recovered_label.setFont(font) recovered_label.adjustSize() recovered_label.move(10, 140) # Updates the labels with country specific data. def label_updater(): cases_label.setText( f"Current cases: {data.CoronaCases('country/'+country_name.text().lower()).total_cases}" ) deaths_label.setText( f"Current deaths: {data.CoronaCases('country/'+ country_name.text().lower()).total_deaths}" ) recovered_label.setText( f"Current recovered: {data.CoronaCases('country/'+ country_name.text().lower()).total_recovered}" ) country_name_submit.clicked.connect(label_updater)
class Example(QWidget): def initUI(self): qle = QLineEdit(self) qle.move(60, 100) qle.textChanged[str].connect(self.onChanged) self.lbl = QLabel(self) self.lbl.move(60, 40) self.setGeometry(300, 300, 280, 170) self.setWindowTitle('QLineEdit') self.show() def onChanged(self, text): self.lbl.setText(text) self.lbl.adjustSize() # This is needed to update the label as the textedit got updated def __init__(self): super(Example, self).__init__() self.initUI()
def ui_components(self): font = QFont("Roboto", 16) title_label = QLabel("Current exchange rates are:", self) title_label.setFont(font) title_label.move(10, 2) title_label.setStyleSheet("color: blue") title_label.adjustSize() rate_usd_tnd = Exchanges().usd_tnd() rate_usd_eur = Exchanges().usd_eur() rate_tnd_eur = Exchanges().tnd_eur() usd_tnd_label = QLabel(f"1 USD is {rate_usd_tnd} TND.", self) usd_tnd_label.setFont(font) usd_tnd_label.move(10, 40) usd_tnd_label.adjustSize() usd_eur_label = QLabel(f"1 USD is {rate_usd_eur} EUR.", self) usd_eur_label.setFont(font) usd_eur_label.move(10, 67) usd_eur_label.adjustSize() tnd_eur_label = QLabel(f"1 TND is {rate_tnd_eur} EUR.", self) tnd_eur_label.setFont(font) tnd_eur_label.move(10, 93) tnd_eur_label.adjustSize()
class SCOUTS(QMainWindow): """Main Window Widget for SCOUTS.""" style = { 'title': 'QLabel {font-size: 18pt; font-weight: 600}', 'header': 'QLabel {font-size: 12pt; font-weight: 520}', 'label': 'QLabel {font-size: 10pt}', 'button': 'QPushButton {font-size: 10pt}', 'md button': 'QPushButton {font-size: 12pt}', 'run button': 'QPushButton {font-size: 18pt; font-weight: 600}', 'line edit': 'QLineEdit {font-size: 10pt}', 'checkbox': 'QCheckBox {font-size: 10pt}', 'radio button': 'QRadioButton {font-size: 10pt}' } def __init__(self) -> None: """SCOUTS Constructor. Defines all aspects of the GUI.""" # ### # ### Main Window setup # ### # Inherits from QMainWindow super().__init__() self.rootdir = get_project_root() self.threadpool = QThreadPool() # Sets values for QMainWindow self.setWindowTitle("SCOUTS") self.setWindowIcon( QIcon( os.path.abspath(os.path.join(self.rootdir, 'src', 'scouts.ico')))) # Creates StackedWidget as QMainWindow's central widget self.stacked_pages = QStackedWidget(self) self.setCentralWidget(self.stacked_pages) # Creates Widgets for individual "pages" and adds them to the StackedWidget self.main_page = QWidget() self.samples_page = QWidget() self.gating_page = QWidget() self.pages = (self.main_page, self.samples_page, self.gating_page) for page in self.pages: self.stacked_pages.addWidget(page) # ## Sets widget at program startup self.stacked_pages.setCurrentWidget(self.main_page) # ### # ### MAIN PAGE # ### # Main page layout self.main_layout = QVBoxLayout(self.main_page) # Title section # Title self.title = QLabel(self.main_page) self.title.setText('SCOUTS - Single Cell Outlier Selector') self.title.setStyleSheet(self.style['title']) self.title.adjustSize() self.main_layout.addWidget(self.title) # ## Input section # Input header self.input_header = QLabel(self.main_page) self.input_header.setText('Input settings') self.input_header.setStyleSheet(self.style['header']) self.main_layout.addChildWidget(self.input_header) self.input_header.adjustSize() self.main_layout.addWidget(self.input_header) # Input frame self.input_frame = QFrame(self.main_page) self.input_frame.setFrameShape(QFrame.StyledPanel) self.input_frame.setLayout(QFormLayout()) self.main_layout.addWidget(self.input_frame) # Input button self.input_button = QPushButton(self.main_page) self.input_button.setStyleSheet(self.style['button']) self.set_icon(self.input_button, 'x-office-spreadsheet') self.input_button.setObjectName('input') self.input_button.setText(' Select input file (.xlsx or .csv)') self.input_button.clicked.connect(self.get_path) # Input path box self.input_path = QLineEdit(self.main_page) self.input_path.setObjectName('input_path') self.input_path.setStyleSheet(self.style['line edit']) # Go to sample naming page self.samples_button = QPushButton(self.main_page) self.samples_button.setStyleSheet(self.style['button']) self.set_icon(self.samples_button, 'preferences-other') self.samples_button.setText(' Name samples...') self.samples_button.clicked.connect(self.goto_samples_page) # Go to gating page self.gates_button = QPushButton(self.main_page) self.gates_button.setStyleSheet(self.style['button']) self.set_icon(self.gates_button, 'preferences-other') self.gates_button.setText(' Gating && outlier options...') self.gates_button.clicked.connect(self.goto_gates_page) # Add widgets above to input frame Layout self.input_frame.layout().addRow(self.input_button, self.input_path) self.input_frame.layout().addRow(self.samples_button) self.input_frame.layout().addRow(self.gates_button) # ## Analysis section # Analysis header self.analysis_header = QLabel(self.main_page) self.analysis_header.setText('Analysis settings') self.analysis_header.setStyleSheet(self.style['header']) self.analysis_header.adjustSize() self.main_layout.addWidget(self.analysis_header) # Analysis frame self.analysis_frame = QFrame(self.main_page) self.analysis_frame.setFrameShape(QFrame.StyledPanel) self.analysis_frame.setLayout(QVBoxLayout()) self.main_layout.addWidget(self.analysis_frame) # Cutoff text self.cutoff_text = QLabel(self.main_page) self.cutoff_text.setText('Type of outlier to select:') self.cutoff_text.setToolTip( 'Choose whether to select outliers using the cutoff value from a reference\n' 'sample (OutR) or by using the cutoff value calculated for each sample\n' 'individually (OutS)') self.cutoff_text.setStyleSheet(self.style['label']) # Cutoff button group self.cutoff_group = QButtonGroup(self) # Cutoff by sample self.cutoff_sample = QRadioButton(self.main_page) self.cutoff_sample.setText('OutS') self.cutoff_sample.setObjectName('sample') self.cutoff_sample.setStyleSheet(self.style['radio button']) self.cutoff_sample.setChecked(True) self.cutoff_group.addButton(self.cutoff_sample) # Cutoff by reference self.cutoff_reference = QRadioButton(self.main_page) self.cutoff_reference.setText('OutR') self.cutoff_reference.setObjectName('ref') self.cutoff_reference.setStyleSheet(self.style['radio button']) self.cutoff_group.addButton(self.cutoff_reference) # Both cutoffs self.cutoff_both = QRadioButton(self.main_page) self.cutoff_both.setText('both') self.cutoff_both.setObjectName('sample ref') self.cutoff_both.setStyleSheet(self.style['radio button']) self.cutoff_group.addButton(self.cutoff_both) # Markers text self.markers_text = QLabel(self.main_page) self.markers_text.setStyleSheet(self.style['label']) self.markers_text.setText('Show results for:') self.markers_text.setToolTip( 'Individual markers: for each marker, select outliers\n' 'Any marker: select cells that are outliers for AT LEAST one marker' ) # Markers button group self.markers_group = QButtonGroup(self) # Single marker self.single_marker = QRadioButton(self.main_page) self.single_marker.setText('individual markers') self.single_marker.setObjectName('single') self.single_marker.setStyleSheet(self.style['radio button']) self.single_marker.setChecked(True) self.markers_group.addButton(self.single_marker) # Any marker self.any_marker = QRadioButton(self.main_page) self.any_marker.setText('any marker') self.any_marker.setObjectName('any') self.any_marker.setStyleSheet(self.style['radio button']) self.markers_group.addButton(self.any_marker) # Both methods self.both_methods = QRadioButton(self.main_page) self.both_methods.setText('both') self.both_methods.setObjectName('single any') self.both_methods.setStyleSheet(self.style['radio button']) self.markers_group.addButton(self.both_methods) # Tukey text self.tukey_text = QLabel(self.main_page) self.tukey_text.setStyleSheet(self.style['label']) # Tukey button group self.tukey_text.setText('Tukey factor:') self.tukey_group = QButtonGroup(self) # Low Tukey value self.tukey_low = QRadioButton(self.main_page) self.tukey_low.setText('1.5') self.tukey_low.setStyleSheet(self.style['radio button']) self.tukey_low.setChecked(True) self.tukey_group.addButton(self.tukey_low) # High Tukey value self.tukey_high = QRadioButton(self.main_page) self.tukey_high.setText('3.0') self.tukey_high.setStyleSheet(self.style['radio button']) self.tukey_group.addButton(self.tukey_high) # Add widgets above to analysis frame layout self.analysis_frame.layout().addWidget(self.cutoff_text) self.cutoff_buttons = QHBoxLayout() for button in self.cutoff_group.buttons(): self.cutoff_buttons.addWidget(button) self.analysis_frame.layout().addLayout(self.cutoff_buttons) self.analysis_frame.layout().addWidget(self.markers_text) self.markers_buttons = QHBoxLayout() for button in self.markers_group.buttons(): self.markers_buttons.addWidget(button) self.analysis_frame.layout().addLayout(self.markers_buttons) self.analysis_frame.layout().addWidget(self.tukey_text) self.tukey_buttons = QHBoxLayout() for button in self.tukey_group.buttons(): self.tukey_buttons.addWidget(button) self.tukey_buttons.addWidget(QLabel()) # aligns row with 2 buttons self.analysis_frame.layout().addLayout(self.tukey_buttons) # ## Output section # Output header self.output_header = QLabel(self.main_page) self.output_header.setText('Output settings') self.output_header.setStyleSheet(self.style['header']) self.output_header.adjustSize() self.main_layout.addWidget(self.output_header) # Output frame self.output_frame = QFrame(self.main_page) self.output_frame.setFrameShape(QFrame.StyledPanel) self.output_frame.setLayout(QFormLayout()) self.main_layout.addWidget(self.output_frame) # Output button self.output_button = QPushButton(self.main_page) self.output_button.setStyleSheet(self.style['button']) self.set_icon(self.output_button, 'folder') self.output_button.setObjectName('output') self.output_button.setText(' Select output folder') self.output_button.clicked.connect(self.get_path) # Output path box self.output_path = QLineEdit(self.main_page) self.output_path.setStyleSheet(self.style['line edit']) # Generate CSV checkbox self.output_csv = QCheckBox(self.main_page) self.output_csv.setText('Export multiple text files (.csv)') self.output_csv.setStyleSheet(self.style['checkbox']) self.output_csv.setChecked(True) # Generate XLSX checkbox self.output_excel = QCheckBox(self.main_page) self.output_excel.setText('Export multiple Excel spreadsheets (.xlsx)') self.output_excel.setStyleSheet(self.style['checkbox']) self.output_excel.clicked.connect(self.enable_single_excel) # Generate single, large XLSX checkbox self.single_excel = QCheckBox(self.main_page) self.single_excel.setText( 'Also save one multi-sheet Excel spreadsheet') self.single_excel.setToolTip( 'After generating all Excel spreadsheets, SCOUTS combines them into ' 'a single\nExcel spreadsheet where each sheet corresponds to an output' 'file from SCOUTS') self.single_excel.setStyleSheet(self.style['checkbox']) self.single_excel.setEnabled(False) self.single_excel.clicked.connect(self.memory_warning) # Add widgets above to output frame layout self.output_frame.layout().addRow(self.output_button, self.output_path) self.output_frame.layout().addRow(self.output_csv) self.output_frame.layout().addRow(self.output_excel) self.output_frame.layout().addRow(self.single_excel) # ## Run & help-quit section # Run button (stand-alone) self.run_button = QPushButton(self.main_page) self.set_icon(self.run_button, 'system-run') self.run_button.setText(' Run!') self.run_button.setStyleSheet(self.style['run button']) self.main_layout.addWidget(self.run_button) self.run_button.clicked.connect(self.run) # Help-quit frame (invisible) self.helpquit_frame = QFrame(self.main_page) self.helpquit_frame.setLayout(QHBoxLayout()) self.helpquit_frame.layout().setMargin(0) self.main_layout.addWidget(self.helpquit_frame) # Help button self.help_button = QPushButton(self.main_page) self.set_icon(self.help_button, 'help-about') self.help_button.setText(' Help') self.help_button.setStyleSheet(self.style['md button']) self.help_button.clicked.connect(self.get_help) # Quit button self.quit_button = QPushButton(self.main_page) self.set_icon(self.quit_button, 'process-stop') self.quit_button.setText(' Quit') self.quit_button.setStyleSheet(self.style['md button']) self.quit_button.clicked.connect(self.close) # Add widgets above to help-quit layout self.helpquit_frame.layout().addWidget(self.help_button) self.helpquit_frame.layout().addWidget(self.quit_button) # ### # ### SAMPLES PAGE # ### # Samples page layout self.samples_layout = QVBoxLayout(self.samples_page) # ## Title section # Title self.samples_title = QLabel(self.samples_page) self.samples_title.setText('Name your samples') self.samples_title.setStyleSheet(self.style['title']) self.samples_title.adjustSize() self.samples_layout.addWidget(self.samples_title) # Subtitle self.samples_subtitle = QLabel(self.samples_page) string = ( 'Please name the samples to be analysed by SCOUTS.\n\nSCOUTS searches the first ' 'column of your data\nand locates the exact string as part of the sample name.' ) self.samples_subtitle.setText(string) self.samples_subtitle.setStyleSheet(self.style['label']) self.samples_subtitle.adjustSize() self.samples_layout.addWidget(self.samples_subtitle) # ## Sample addition section # Sample addition frame self.samples_frame = QFrame(self.samples_page) self.samples_frame.setFrameShape(QFrame.StyledPanel) self.samples_frame.setLayout(QGridLayout()) self.samples_layout.addWidget(self.samples_frame) # Sample name box self.sample_name = QLineEdit(self.samples_page) self.sample_name.setStyleSheet(self.style['line edit']) self.sample_name.setPlaceholderText('Sample name ...') # Reference check self.is_reference = QCheckBox(self.samples_page) self.is_reference.setText('Reference?') self.is_reference.setStyleSheet(self.style['checkbox']) # Add sample to table self.add_sample_button = QPushButton(self.samples_page) QShortcut(QKeySequence("Return"), self.add_sample_button, self.write_to_sample_table) self.set_icon(self.add_sample_button, 'list-add') self.add_sample_button.setText(' Add sample (Enter)') self.add_sample_button.setStyleSheet(self.style['button']) self.add_sample_button.clicked.connect(self.write_to_sample_table) # Remove sample from table self.remove_sample_button = QPushButton(self.samples_page) QShortcut(QKeySequence("Delete"), self.remove_sample_button, self.remove_from_sample_table) self.set_icon(self.remove_sample_button, 'list-remove') self.remove_sample_button.setText(' Remove sample (Del)') self.remove_sample_button.setStyleSheet(self.style['button']) self.remove_sample_button.clicked.connect( self.remove_from_sample_table) # Add widgets above to sample addition layout self.samples_frame.layout().addWidget(self.sample_name, 0, 0) self.samples_frame.layout().addWidget(self.is_reference, 1, 0) self.samples_frame.layout().addWidget(self.add_sample_button, 0, 1) self.samples_frame.layout().addWidget(self.remove_sample_button, 1, 1) # ## Sample table self.sample_table = QTableWidget(self.samples_page) self.sample_table.setColumnCount(2) self.sample_table.setHorizontalHeaderItem(0, QTableWidgetItem('Sample')) self.sample_table.setHorizontalHeaderItem( 1, QTableWidgetItem('Reference?')) self.sample_table.horizontalHeader().setSectionResizeMode( 0, QHeaderView.Stretch) self.sample_table.horizontalHeader().setSectionResizeMode( 1, QHeaderView.ResizeToContents) self.samples_layout.addWidget(self.sample_table) # ## Save & clear buttons # Save & clear frame (invisible) self.saveclear_frame = QFrame(self.samples_page) self.saveclear_frame.setLayout(QHBoxLayout()) self.saveclear_frame.layout().setMargin(0) self.samples_layout.addWidget(self.saveclear_frame) # Clear samples button self.clear_samples = QPushButton(self.samples_page) self.set_icon(self.clear_samples, 'edit-delete') self.clear_samples.setText(' Clear table') self.clear_samples.setStyleSheet(self.style['md button']) self.clear_samples.clicked.connect(self.prompt_clear_data) # Save samples button self.save_samples = QPushButton(self.samples_page) self.set_icon(self.save_samples, 'document-save') self.save_samples.setText(' Save samples') self.save_samples.setStyleSheet(self.style['md button']) self.save_samples.clicked.connect(self.goto_main_page) # Add widgets above to save & clear layout self.saveclear_frame.layout().addWidget(self.clear_samples) self.saveclear_frame.layout().addWidget(self.save_samples) # ### # ### GATING PAGE # ### # Gating page layout self.gating_layout = QVBoxLayout(self.gating_page) # ## Title section # Title self.gates_title = QLabel(self.gating_page) self.gates_title.setText('Gating & outlier options') self.gates_title.setStyleSheet(self.style['title']) self.gates_title.adjustSize() self.gating_layout.addWidget(self.gates_title) # ## Gating options section # Gating header self.gate_header = QLabel(self.gating_page) self.gate_header.setText('Gating') self.gate_header.setStyleSheet(self.style['header']) self.gate_header.adjustSize() self.gating_layout.addWidget(self.gate_header) # Gating frame self.gate_frame = QFrame(self.gating_page) self.gate_frame.setFrameShape(QFrame.StyledPanel) self.gate_frame.setLayout(QFormLayout()) self.gating_layout.addWidget(self.gate_frame) # Gating button group self.gating_group = QButtonGroup(self) # Do not gate samples self.no_gates = QRadioButton(self.gating_page) self.no_gates.setObjectName('no_gate') self.no_gates.setText("Don't gate samples") self.no_gates.setStyleSheet(self.style['radio button']) self.no_gates.setChecked(True) self.gating_group.addButton(self.no_gates) self.no_gates.clicked.connect(self.activate_gate) # CyToF gating self.cytof_gates = QRadioButton(self.gating_page) self.cytof_gates.setObjectName('cytof') self.cytof_gates.setText('Mass Cytometry gating') self.cytof_gates.setStyleSheet(self.style['radio button']) self.cytof_gates.setToolTip( 'Exclude cells for which the average expression of all\n' 'markers is below the selected value') self.gating_group.addButton(self.cytof_gates) self.cytof_gates.clicked.connect(self.activate_gate) # CyToF gating spinbox self.cytof_gates_value = QDoubleSpinBox(self.gating_page) self.cytof_gates_value.setMinimum(0) self.cytof_gates_value.setMaximum(1) self.cytof_gates_value.setValue(0.1) self.cytof_gates_value.setSingleStep(0.05) self.cytof_gates_value.setEnabled(False) # scRNA-Seq gating self.rnaseq_gates = QRadioButton(self.gating_page) self.rnaseq_gates.setText('scRNA-Seq gating') self.rnaseq_gates.setStyleSheet(self.style['radio button']) self.rnaseq_gates.setToolTip( 'When calculating cutoff, ignore reads below the selected value') self.rnaseq_gates.setObjectName('rnaseq') self.gating_group.addButton(self.rnaseq_gates) self.rnaseq_gates.clicked.connect(self.activate_gate) # scRNA-Seq gating spinbox self.rnaseq_gates_value = QDoubleSpinBox(self.gating_page) self.rnaseq_gates_value.setMinimum(0) self.rnaseq_gates_value.setMaximum(10) self.rnaseq_gates_value.setValue(0) self.rnaseq_gates_value.setSingleStep(1) self.rnaseq_gates_value.setEnabled(False) # export gated population checkbox self.export_gated = QCheckBox(self.gating_page) self.export_gated.setText('Export gated cells as an output file') self.export_gated.setStyleSheet(self.style['checkbox']) self.export_gated.setEnabled(False) # Add widgets above to Gate frame layout self.gate_frame.layout().addRow(self.no_gates, QLabel()) self.gate_frame.layout().addRow(self.cytof_gates, self.cytof_gates_value) self.gate_frame.layout().addRow(self.rnaseq_gates, self.rnaseq_gates_value) self.gate_frame.layout().addRow(self.export_gated, QLabel()) # ## Outlier options section # Outlier header self.outlier_header = QLabel(self.gating_page) self.outlier_header.setText('Outliers') self.outlier_header.setStyleSheet(self.style['header']) self.outlier_header.adjustSize() self.gating_layout.addWidget(self.outlier_header) # Outlier frame self.outlier_frame = QFrame(self.gating_page) self.outlier_frame.setFrameShape(QFrame.StyledPanel) self.outlier_frame.setLayout(QVBoxLayout()) self.gating_layout.addWidget(self.outlier_frame) # Top outliers information self.top_outliers = QLabel(self.gating_page) self.top_outliers.setStyleSheet(self.style['label']) self.top_outliers.setText( 'By default, SCOUTS selects the top outliers from the population') self.top_outliers.setStyleSheet(self.style['label']) # Bottom outliers data self.bottom_outliers = QCheckBox(self.gating_page) self.bottom_outliers.setText('Include results for low outliers') self.bottom_outliers.setStyleSheet(self.style['checkbox']) # Non-outliers data self.not_outliers = QCheckBox(self.gating_page) self.not_outliers.setText('Include results for non-outliers') self.not_outliers.setStyleSheet(self.style['checkbox']) # Add widgets above to Gate frame layout self.outlier_frame.layout().addWidget(self.top_outliers) self.outlier_frame.layout().addWidget(self.bottom_outliers) self.outlier_frame.layout().addWidget(self.not_outliers) # ## Save/back button self.save_gates = QPushButton(self.gating_page) self.set_icon(self.save_gates, 'go-next') self.save_gates.setText(' Back to main menu') self.save_gates.setStyleSheet(self.style['md button']) self.gating_layout.addWidget(self.save_gates) self.save_gates.clicked.connect(self.goto_main_page) # ## Add empty label to take vertical space self.empty_label = QLabel(self.gating_page) self.empty_label.setSizePolicy(QSizePolicy.Expanding, QSizePolicy.Expanding) self.gating_layout.addWidget(self.empty_label) # ### # ### ICON SETTING # ### def set_icon(self, widget: QWidget, icon: str) -> None: """Associates an icon to a widget.""" i = QIcon() i.addPixmap( QPixmap( os.path.abspath( os.path.join(self.rootdir, 'src', 'default_icons', f'{icon}.svg')))) widget.setIcon(QIcon.fromTheme(icon, i)) # ### # ### STACKED WIDGET PAGE SWITCHING # ### def goto_main_page(self) -> None: """Switches stacked widget pages to the main page.""" self.stacked_pages.setCurrentWidget(self.main_page) def goto_samples_page(self) -> None: """Switches stacked widget pages to the samples table page.""" self.stacked_pages.setCurrentWidget(self.samples_page) def goto_gates_page(self) -> None: """Switches stacked widget pages to the gating & other options page.""" self.stacked_pages.setCurrentWidget(self.gating_page) # ### # ### MAIN PAGE GUI LOGIC # ### def get_path(self) -> None: """Opens a dialog box and sets the chosen file/folder path, depending on the caller widget.""" options = QFileDialog.Options() options |= QFileDialog.DontUseNativeDialog sender_name = self.sender().objectName() if sender_name == 'input': query, _ = QFileDialog.getOpenFileName(self, "Select file", "", "All Files (*)", options=options) elif sender_name == 'output': query = QFileDialog.getExistingDirectory(self, "Select Directory", options=options) else: return if query: getattr(self, f'{sender_name}_path').setText(query) def enable_single_excel(self) -> None: """Enables checkbox for generating a single Excel output.""" if self.output_excel.isChecked(): self.single_excel.setEnabled(True) else: self.single_excel.setEnabled(False) self.single_excel.setChecked(False) # ### # ### SAMPLE NAME/SAMPLE TABLE GUI LOGIC # ### def write_to_sample_table(self) -> None: """Writes data to sample table.""" table = self.sample_table ref = 'no' sample = self.sample_name.text() if sample: for cell in range(table.rowCount()): item = table.item(cell, 0) if item.text() == sample: self.same_sample() return if self.is_reference.isChecked(): for cell in range(table.rowCount()): item = table.item(cell, 1) if item.text() == 'yes': self.more_than_one_reference() return ref = 'yes' sample = QTableWidgetItem(sample) is_reference = QTableWidgetItem(ref) is_reference.setFlags(Qt.ItemIsEnabled) row_position = table.rowCount() table.insertRow(row_position) table.setItem(row_position, 0, sample) table.setItem(row_position, 1, is_reference) self.is_reference.setChecked(False) self.sample_name.setText('') def remove_from_sample_table(self) -> None: """Removes data from sample table.""" table = self.sample_table rows = set(index.row() for index in table.selectedIndexes()) for index in sorted(rows, reverse=True): self.sample_table.removeRow(index) def prompt_clear_data(self) -> None: """Prompts option to clear all data in the sample table.""" if self.confirm_clear_data(): table = self.sample_table while table.rowCount(): self.sample_table.removeRow(0) # ### # ### GATING GUI LOGIC # ### def activate_gate(self) -> None: """Activates/deactivates buttons related to gating.""" if self.sender().objectName() == 'no_gate': self.cytof_gates_value.setEnabled(False) self.rnaseq_gates_value.setEnabled(False) self.export_gated.setEnabled(False) self.export_gated.setChecked(False) elif self.sender().objectName() == 'cytof': self.cytof_gates_value.setEnabled(True) self.rnaseq_gates_value.setEnabled(False) self.export_gated.setEnabled(True) elif self.sender().objectName() == 'rnaseq': self.cytof_gates_value.setEnabled(False) self.rnaseq_gates_value.setEnabled(True) self.export_gated.setEnabled(True) # ### # ### CONNECT SCOUTS TO ANALYTICAL MODULES # ### def run(self) -> None: """Runs SCOUTS as a Worker, based on user input in the GUI.""" try: data = self.parse_input() except Exception as error: trace = traceback.format_exc() self.propagate_error((error, trace)) else: data['widget'] = self worker = Worker(func=start_scouts, **data) worker.signals.started.connect(self.analysis_has_started) worker.signals.finished.connect(self.analysis_has_finished) worker.signals.success.connect(self.success_message) worker.signals.error.connect(self.propagate_error) self.threadpool.start(worker) def parse_input(self) -> Dict: """Returns user input on the GUI as a dictionary.""" # Input and output input_dict = { 'input_file': str(self.input_path.text()), 'output_folder': str(self.output_path.text()) } if not input_dict['input_file'] or not input_dict['output_folder']: raise NoIOPathError # Set cutoff by reference or by sample rule input_dict['cutoff_rule'] = self.cutoff_group.checkedButton( ).objectName() # 'sample', 'ref', 'sample ref' # Outliers for each individual marker or any marker in row input_dict['marker_rule'] = self.markers_group.checkedButton( ).objectName() # 'single', 'any', 'single any' # Tukey factor used for calculating cutoff input_dict['tukey_factor'] = float( self.tukey_group.checkedButton().text()) # '1.5', '3.0' # Output settings input_dict['export_csv'] = True if self.output_csv.isChecked( ) else False input_dict['export_excel'] = True if self.output_excel.isChecked( ) else False input_dict['single_excel'] = True if self.single_excel.isChecked( ) else False # Retrieve samples from sample table input_dict['sample_list'] = [] for tuples in self.yield_samples_from_table(): input_dict['sample_list'].append(tuples) if not input_dict['sample_list']: raise NoSampleError # Set gate cutoff (if any) input_dict['gating'] = self.gating_group.checkedButton().objectName( ) # 'no_gate', 'cytof', 'rnaseq' input_dict['gate_cutoff_value'] = None if input_dict['gating'] != 'no_gate': input_dict['gate_cutoff_value'] = getattr( self, f'{input_dict["gating"]}_gates_value').value() input_dict['export_gated'] = True if self.export_gated.isChecked( ) else False # Generate results for non-outliers input_dict['non_outliers'] = False if self.not_outliers.isChecked(): input_dict['non_outliers'] = True # Generate results for bottom outliers input_dict['bottom_outliers'] = False if self.bottom_outliers.isChecked(): input_dict['bottom_outliers'] = True # return dictionary with all gathered inputs return input_dict def yield_samples_from_table( self) -> Generator[Tuple[str, str], None, None]: """Yields sample names from the sample table.""" table = self.sample_table for cell in range(table.rowCount()): sample_name = table.item(cell, 0).text() sample_type = table.item(cell, 1).text() yield sample_name, sample_type # ### # ### MESSAGE BOXES # ### def analysis_has_started(self) -> None: """Disables run button while SCOUTS analysis is underway.""" self.run_button.setText(' Working...') self.run_button.setEnabled(False) def analysis_has_finished(self) -> None: """Enables run button after SCOUTS analysis has finished.""" self.run_button.setEnabled(True) self.run_button.setText(' Run!') def success_message(self) -> None: """Info message box used when SCOUTS finished without errors.""" title = "Analysis finished!" mes = "Your analysis has finished. No errors were reported." if self.stacked_pages.isEnabled() is True: QMessageBox.information(self, title, mes) def memory_warning(self) -> None: """Warning message box used when user wants to generate a single excel file.""" if self.sender().isChecked(): title = 'Memory warning!' mes = ( "Depending on your dataset, this option can consume a LOT of memory and take" " a long time to process. Please make sure that your computer can handle it!" ) QMessageBox.information(self, title, mes) def same_sample(self) -> None: """Error message box used when the user tries to input the same sample twice in the sample table.""" title = 'Error: sample name already in table' mes = ( "Sorry, you can't do this because this sample name is already in the table. " "Please select a different name.") QMessageBox.critical(self, title, mes) def more_than_one_reference(self) -> None: """Error message box used when the user tries to input two reference samples in the sample table.""" title = "Error: more than one reference selected" mes = ( "Sorry, you can't do this because there is already a reference column in the table. " "Please remove it before adding a reference.") QMessageBox.critical(self, title, mes) def confirm_clear_data(self) -> bool: """Question message box used to confirm user action of clearing sample table.""" title = 'Confirm Action' mes = "Table will be cleared. Are you sure?" reply = QMessageBox.question(self, title, mes, QMessageBox.Yes | QMessageBox.No, QMessageBox.No) if reply == QMessageBox.Yes: return True return False # ### # ### EXCEPTIONS & ERRORS # ### def propagate_error(self, error: Tuple[Exception, str]) -> None: """Calls the appropriate error message box based on type of Exception raised.""" if isinstance(error[0], NoIOPathError): self.no_io_path_error_message() elif isinstance(error[0], NoReferenceError): self.no_reference_error_message() elif isinstance(error[0], NoSampleError): self.no_sample_error_message() elif isinstance(error[0], PandasInputError): self.pandas_input_error_message() elif isinstance(error[0], SampleNamingError): self.sample_naming_error_message() else: self.generic_error_message(error) def no_io_path_error_message(self) -> None: """Message displayed when the user did not include an input file path, or an output folder path.""" title = 'Error: no file/folder' message = ("Sorry, no input file and/or output folder was provided. " "Please add the path to the necessary file/folder.") QMessageBox.critical(self, title, message) def no_reference_error_message(self) -> None: """Message displayed when the user wants to analyse cutoff based on a reference, but did not specify what sample corresponds to the reference.""" title = "Error: No reference selected" message = ( "Sorry, no reference sample was found on the sample list, but analysis was set to " "reference. Please add a reference sample, or change the rule for cutoff calculation." ) QMessageBox.critical(self, title, message) def no_sample_error_message(self) -> None: """Message displayed when the user did not add any samples to the sample table.""" title = "Error: No samples selected" message = ( "Sorry, the analysis cannot be performed because no sample names were input. " "Please add your sample names.") QMessageBox.critical(self, title, message) def pandas_input_error_message(self) -> None: """Message displayed when the input file cannot be read (likely because it is not a Excel or csv file).""" title = 'Error: unexpected input file' message = ( "Sorry, the input file could not be read. Please make sure that " "the data is save in a valid format (supported formats are: " ".csv, .xlsx).") QMessageBox.critical(self, title, message) def sample_naming_error_message(self) -> None: """Message displayed when none of the sample names passed by the user are found in the input DataFrame.""" title = 'Error: sample names not in input file' message = ( "Sorry, your sample names were not found in the input file. Please " "make sure that the names were typed correctly (case-sensitive).") QMessageBox.critical(self, title, message) def generic_error_message(self, error: Tuple[Exception, str]) -> None: """Error message box used to display any error message (including traceback) for any uncaught errors.""" title = 'An error occurred!' name, trace = error QMessageBox.critical(self, title, f"{str(name)}\n\nfull traceback:\n{trace}") def not_implemented_error_message(self) -> None: """Error message box used when the user accesses a functionality that hasn't been implemented yet.""" title = "Not yet implemented" mes = "Sorry, this functionality has not been implemented yet." QMessageBox.critical(self, title, mes) # ### # ### HELP & QUIT # ### @staticmethod def get_help() -> None: """Opens SCOUTS documentation on the browser. Called when the user clicks the "help" button""" webbrowser.open('https://scouts.readthedocs.io/en/master/') def closeEvent(self, event: QEvent) -> None: """Defines the message box for when the user wants to quit SCOUTS.""" title = 'Quit SCOUTS' mes = "Are you sure you want to quit?" reply = QMessageBox.question(self, title, mes, QMessageBox.Yes | QMessageBox.No, QMessageBox.No) if reply == QMessageBox.Yes: self.stacked_pages.setEnabled(False) message = self.quit_message() waiter = Waiter(waiter_func=self.threadpool.activeThreadCount) waiter.signals.started.connect(message.show) waiter.signals.finished.connect(message.destroy) waiter.signals.finished.connect(sys.exit) self.threadpool.start(waiter) event.ignore() def quit_message(self) -> QDialog: """Displays a window while SCOUTS is exiting""" message = QDialog(self) message.setWindowTitle('Exiting SCOUTS') message.resize(300, 50) label = QLabel('SCOUTS is exiting, please wait...', message) label.setStyleSheet(self.style['label']) label.adjustSize() label.setAlignment(Qt.AlignCenter) label.move(int((message.width() - label.width()) / 2), int((message.height() - label.height()) / 2)) return message
class Window(QWidget): def __init__(self): super().__init__() self.setWindowTitle('Queues\'Project') self.setGeometry(150,150,800,500) self.setFixedSize(800,500) self.setIcon() self.center() self.createLayout() self.backGroundcolorChanger() def backGroundcolorChanger(self): icon1=QIcon('colors.png') label1=QLabel('ColorPalette',self) pixmap1=icon1.pixmap(30,30,QIcon.Active,QIcon.On) label1.setPixmap(pixmap1) label1.setToolTip('go to Previous Screen') label1.mousePressEvent=self.getBackgroundColor self.namesLabel=QLabel('Designed by:\n\tAbd-ElRahman Abd-ElFattah Habib.\n\tMohammed Ahmed Mekkawy.\n\tElSayed Abd-ElMohaymen ElSayed.\n',self) self.namesLabel.width=300 width=self.width() height=self.height() label1.move(width-40,height-40) self.namesLabel.move(10,height-60) self.namesLabel.adjustSize() def getBackgroundColor(self,event): color = QColorDialog.getColor() self.setStyleSheet('background-color:%s'%color.name()) self.namesLabel.setStyleSheet('color:white') def createLayout(self): icon1=QIcon('line.png') label1=QLabel('Sample',self) pixmap1=icon1.pixmap(200,200,QIcon.Active,QIcon.On) label1.setPixmap(pixmap1) self.submitButton=QPushButton('Continue',self) self.submitButton.setFont(QFont('Sanserif',18)) self.submitButton.setStyleSheet('background-color: blueviolet;color:white;border: 1px solid; border-radius:15px') self.submitButton.clicked.connect(self.handleSubmitClick) vbox=QVBoxLayout() vbox.setAlignment(Qt.AlignCenter) vbox.setContentsMargins(10,30,10,30) vbox.addWidget(label1) vbox.setSpacing(50) vbox.addWidget(self.submitButton) self.setLayout(vbox) def handleSubmitClick(self): self.main = main.MainWindow() self.main.show() self.destroy() def center(self): qRect=self.frameGeometry() centerpoint = QDesktopWidget().availableGeometry().center() qRect.moveCenter(centerpoint) self.move(qRect.topLeft()) def setIcon(self): appIcon= QIcon('line.png') self.setWindowIcon(appIcon) def closeEvent(self,event): userInfo = QMessageBox.question(self,'Closing ?','Do u want to quit ?',QMessageBox.Yes|QMessageBox.No) if userInfo == QMessageBox.Yes: event.accept() elif userInfo == QMessageBox.No: event.ignore()
class RootsApp(QMainWindow): standard_deviation_threshold = 0.1 # when I receive a measurement from the sensor I check if its standard deviation; if it's too low it means the sensor is not working temporary_database_filename = "temporary.db" # the current session is stored in a temporary database. When the user saves, it is copied at the desired location def __init__(self): super().__init__(); self.setWindowTitle("Roots") self.setFixedWidth(1200) self.resize(1200, 1200) self.threadpool = QThreadPool(); self.object_list = list() self.is_training_on = False self.interaction_under_training = None self.n_measurements_collected = 0 self.n_measurements_to_collect = 3 self.sensor_not_responding = True self.sensor_not_responding_timeout = 2000 # milliseconds self.database_connection = self.create_temporary_database() self.active_object = None self.number_of_objects_added = 0 self.sensor_start_freq = 250000 self.sensor_end_freq = 3000000 # creates the plot self.plotWidget = pyqtgraph.PlotWidget(title = "Sensor Response") self.plotWidget.setFixedHeight(300) self.plotWidget.getAxis("bottom").setLabel("Excitation frequency", "Hz") self.plotWidget.getAxis("left").setLabel("Volts", "V") self.dataPlot = self.plotWidget.plot() # timer used to see if the sensor is responding self.timer = QTimer() self.timer.setInterval(self.sensor_not_responding_timeout) self.timer.timeout.connect(self.timer_timeout) self.timer_timeout() # defines the actions in the file menu with button actions iconExit = QIcon("icons/icon_exit.png") btnActionExit = QAction(iconExit, "Exit", self) btnActionExit.setStatusTip("Click to terminate the program") btnActionExit.triggered.connect(self.exit) iconSave = QIcon("icons/icon_save.ico") buttonActionSave = QAction(iconSave, "Save current set of objects", self) # buttonActionSave.setStatusTip("Click to perform action 2") buttonActionSave.triggered.connect(self.save) iconOpen = QIcon("icons/icon_load.png") buttonActionOpen = QAction(iconOpen, "Load set of objects", self) buttonActionOpen.triggered.connect(self.open) # toolbar toolBar = QToolBar("Toolbar") toolBar.addAction(buttonActionSave) toolBar.addAction(buttonActionOpen) toolBar.setIconSize(QSize(64, 64)) toolBar.setStyleSheet(styles.toolbar) self.addToolBar(toolBar) # menu menuBar = self.menuBar() menuBar.setStyleSheet(styles.menuBar) menuFile = menuBar.addMenu("File") menuOptions = menuBar.addMenu("Options") menuView = menuBar.addMenu("View") menuConnect = menuBar.addMenu("Connect") menuFile.addAction(buttonActionSave) menuFile.addAction(buttonActionOpen) menuFile.addAction(btnActionExit) # status bar self.setStatusBar(QStatusBar(self)) # creates the "My Objects" label labelMyObjects = QLabel("My Objects") labelMyObjects.setFixedHeight(100) labelMyObjects.setAlignment(Qt.AlignCenter) labelMyObjects.setStyleSheet(styles.labelMyObjects) # button "add object" icon_plus = QIcon("icons/icon_add.png") self.btn_create_object = QPushButton("Add Object") self.btn_create_object.setCheckable(False) self.btn_create_object.setIcon(icon_plus) self.btn_create_object.setFixedHeight(80) self.btn_create_object.setStyleSheet(styles.addObjectButton) self.btn_create_object.clicked.connect(self.create_object) # defines the layout of the "My Objects" section self.verticalLayout = QVBoxLayout() self.verticalLayout.setContentsMargins(0,0,0,0) self.verticalLayout.addWidget(labelMyObjects) self.verticalLayout.addWidget(self.btn_create_object) self.spacer = QSpacerItem(0,2000, QSizePolicy.Expanding, QSizePolicy.Expanding) self.verticalLayout.setSpacing(0) self.verticalLayout.addSpacerItem(self.spacer) #adds spacer # defines the ComboBox which holds the names of the objects self.comboBox = QComboBox() self.comboBox.addItem("- no object selected") self.comboBox.currentIndexChanged.connect(self.comboBox_index_changed) self.comboBox.setFixedSize(300, 40) self.comboBox.setStyleSheet(styles.comboBox) self.update_comboBox() # defines the label "Selected Object" (above the comboBox) self.labelComboBox = QLabel() self.labelComboBox.setText("Selected Object:") self.labelComboBox.setStyleSheet(styles.labelComboBox) self.labelComboBox.adjustSize() # vertical layout for the combobox and its label self.VLayoutComboBox = QVBoxLayout() self.VLayoutComboBox.addWidget(self.labelComboBox) self.VLayoutComboBox.addWidget(self.comboBox) # label with the output text (the big one on the right) self.labelClassification = QLabel() self.labelClassification.setText("No interaction detected") self.labelClassification.setFixedHeight(80) self.labelClassification.setStyleSheet(styles.labelClassification) self.labelClassification.adjustSize() HLayoutComboBox = QHBoxLayout() HLayoutComboBox.addLayout(self.VLayoutComboBox) HLayoutComboBox.addSpacerItem(QSpacerItem(1000,0, QSizePolicy.Expanding, QSizePolicy.Expanding)); #adds spacer HLayoutComboBox.addWidget(self.labelClassification) # creates a frame that contains the combobox and the labels frame = QFrame() frame.setStyleSheet(styles.frame) frame.setLayout(HLayoutComboBox) # sets the window layout with the elements created before self.windowLayout = QVBoxLayout() self.windowLayout.addWidget(self.plotWidget) self.windowLayout.addWidget(frame) self.windowLayout.addLayout(self.verticalLayout) # puts everything into a frame and displays it on the window self.mainWindowFrame = QFrame() self.mainWindowFrame.setLayout(self.windowLayout) self.mainWindowFrame.setStyleSheet(styles.mainWindowFrame) self.setCentralWidget(self.mainWindowFrame) self.create_object() # creates one object at the beginning # ----------------------------------------------------------------------------------------------------------- # Shows a welcome message def show_welcome_msg(self): welcome_msg = QMessageBox() welcome_msg.setText("Welcome to the Roots application!") welcome_msg.setIcon(QMessageBox.Information) welcome_msg.setInformativeText(strings.welcome_text) welcome_msg.setWindowTitle("Welcome") welcome_msg.exec_() # ----------------------------------------------------------------------------------------------------------- # When the user changes the object in the combobox, updates the active object def comboBox_index_changed(self, index): object_name = self.comboBox.currentText() for object in self.object_list: if object.name == object_name: self.set_active_object(object) print("DEBUG: selected object changed. Object name: {0}".format(object.name)) return # ----------------------------------------------------------------------------------------------------------- # This function allows to save the current objects on a file def save(self): current_path = os.getcwd() directory_path = current_path + "/Saved_Workspaces" if not os.path.exists(directory_path): os.mkdir(directory_path) file_path = None [file_path, file_extension] = QFileDialog.getSaveFileName(self,"Roots", directory_path, "Roots database (*.db)") if file_path is None: return temp_database_path = current_path + "/" + RootsApp.temporary_database_filename shutil.copyfile(temp_database_path, file_path) # copies the temporary database to save the current workspace return # ----------------------------------------------------------------------------------------------------------- # this function creates a clean database where all the data of this session will be temporarily stored def create_temporary_database(self): current_path = os.getcwd() file_path = current_path + "/" + RootsApp.temporary_database_filename if os.path.exists(file_path): # if the database is already there it deletes it to reset it os.remove(file_path) print("DEBUG: removing database. (in 'RootsApp.create_temporary_database()'") database_connection = database.create_connection(RootsApp.temporary_database_filename) # creates the temporary database database.create_tables(database_connection) # initializes the database database.reset_db(database_connection) # resets the database (not needed but it doesn't cost anything to put it) return database_connection # ----------------------------------------------------------------------------------------------------------- # This function allows to load previously created objects from a file def open(self): current_path = os.getcwd() saved_files_directory = current_path + "/Saved_Workspaces" [file_path, file_extension] = QFileDialog.getOpenFileName(self,"Roots", saved_files_directory, "Roots database (*.db)"); if file_path == '': return for object in self.object_list.copy(): # deletes all the objects print("DEBUG: deleting object {0} (in 'open()')".format(object.name)) self.delete_object(object) temp_database_path = current_path + "/" + RootsApp.temporary_database_filename self.database_connection.close() os.remove(temp_database_path) shutil.copyfile(file_path, temp_database_path) # replaces the temporary database with the file to open self.database_connection = database.create_connection(temp_database_path) object_tuples = database.get_all_objects(self.database_connection) for object_tuple in object_tuples: object_ID, object_name = object_tuple location_IDs = database.get_locations_id_for_object(self.database_connection, object_ID) formatted_location_IDs = [] for location_ID in location_IDs: formatted_location_IDs.append(location_ID[0]) print("DEBUG: loading object {0} with location IDs {1}. (in 'RootsApp.open()')".format(object_name, formatted_location_IDs)) self.add_object(object_name, object_ID, formatted_location_IDs) self.train_classifiers() return # ----------------------------------------------------------------------------------------------------------- # This function updates the ComboBox whenever objects are created, destroyed or the active object has changed def update_comboBox(self): print("DEBUG: repainting ComboBox. (in 'RootsApp.update_comboBox()'") self.comboBox.clear() self.comboBox.addItem("none") for object in self.object_list: self.comboBox.addItem(object.name) self.comboBox.adjustSize() # ----------------------------------------------------------------------------------------------------------- # This is a timer which is restarted every time a measurement is received. If it elapses it means that the sesnor is not connected def timer_timeout(self): print("DEBUG: timer timeout. (in 'RootsApp.timer_timeout()'") self.sensor_not_responding = True self.statusBar().showMessage(strings.sensor_disconnected) self.statusBar().setStyleSheet(styles.statusBarError) self.plotWidget.setTitle("Sensor not connected") # ----------------------------------------------------------------------------------------------------------- # This function creates a new object in the database and then calls the "add_object" function, which adds the newly created object to the application def create_object(self): new_object_name = "Object {0}".format(self.number_of_objects_added + 1) [new_object_ID, location_IDs] = database.create_object(self.database_connection, new_object_name) self.add_object(new_object_name, new_object_ID, location_IDs) # ----------------------------------------------------------------------------------------------------------- # This function deletes an object from the database, and from the application object list. It alsos destroys the object def delete_object(self, object): print("DEBUG: deleting object {0}. (in 'RootsApp.delete_object()')".format(object.ID)) database.delete_object(self.database_connection, object.ID) self.object_list.remove(object) self.verticalLayout.removeItem(object.layout) self.update_comboBox() object.delete() # ----------------------------------------------------------------------------------------------------------- # This function adds an object to the current application. Note that if you want to create an object ex-novo you should call "create_object". This function is useful when loading existing objects from a file def add_object(self, name, object_ID, location_IDs): self.number_of_objects_added += 1 new_object = Object(name, object_ID, location_IDs, self) self.object_list.append(new_object) for ID in location_IDs: # initializes the measurements with 0 if the measurement is empty #print("DEBUG: initializing location ID {0}".format(ID)) measurements = database.get_measurements_for_location(self.database_connection, ID) print("DEBUG: location {0} of object {1} is trained: {2}. (in 'RootsApp.add_object()')".format(ID, new_object.name, database.is_location_trained(self.database_connection, ID))) if len(measurements) == 0: database.save_points(self.database_connection, [0], ID) database.set_location_trained(self.database_connection, ID, "FALSE") elif database.is_location_trained(self.database_connection, ID) == "TRUE": new_object.get_interaction_by_ID(ID).setCalibrated(True) # inserts the newly created object before the "Add Object" button index = self.verticalLayout.indexOf(self.btn_create_object) self.verticalLayout.insertLayout(index, new_object.layout) self.update_comboBox() print("DEBUG: object {0} added. (in 'RootsApp.add_object()')".format(new_object.name)) return # ----------------------------------------------------------------------------------------------------------- # This function takes as input the measurement data and formats it to plot it on the graph def update_graph(self, data): frequency_step = (self.sensor_end_freq - self.sensor_start_freq) / len(data) x_axis = numpy.arange(self.sensor_start_freq, self.sensor_end_freq, frequency_step) formatted_data = numpy.transpose(numpy.asarray([x_axis, data])) self.dataPlot.setData(formatted_data) # ----------------------------------------------------------------------------------------------------------- # This function starts the UDP server that receives the measurements def run_UDP_server(self, UDP_IP, UDP_PORT): self.UDPServer = UDPServer(UDP_IP, UDP_PORT) self.UDPServer.signals.measurementReceived.connect(self.process_measurement) self.threadpool.start(self.UDPServer) # ----------------------------------------------------------------------------------------------------------- # This function changes some global variables to tell the application to save the incoming measurements into the database. The measurements belong to the interaction passed as argument def start_collecting_measurements(self, interaction): if self.sensor_not_responding: print("DEBUG: warning! Can't start calibration, the sensor is not responding! (in 'RootsApp.start_collecting_measurements()')") error_msg = QMessageBox() error_msg.setText("Can't start calibration!") error_msg.setIcon(QMessageBox.Critical) error_msg.setInformativeText('The sensor is not responding, make sure it is connected') error_msg.setWindowTitle("Error") error_msg.exec_() else: print("starting to collect measurements into the database at location ID {0} (in 'RootsApp.start_collecting_measurements()')".format(interaction.ID)); self.is_training_on = True self.interaction_under_training = interaction database.delete_measurements_from_location(self.database_connection, interaction.ID) # resets the location measurements self.progress_dialog = QProgressDialog("Calibrating", "Abort", 0, self.n_measurements_to_collect, self) self.progress_dialog.setWindowModality(Qt.WindowModal) self.progress_dialog.setWindowTitle("Calibration") self.progress_dialog.setFixedSize(400, 200) self.progress_dialog.setValue(0) self.progress_dialog.exec_() # ----------------------------------------------------------------------------------------------------------- # This function is called by the UDP thread every time that a measurement is received. It does the following: # 1. Plots the incoming measurement # 2. IF training mode IS on: # Predicts the interaction (tries to guess where the user is touching) # ELSE: # Saves the measurement and retrains the classifier with the new data def process_measurement(self, received_data): self.sensor_not_responding = False self.plotWidget.setTitle("Sensor response") self.timer.start() # starts the timer that checks if we are receiving data from the sensor measurement = received_data.split(' ') # get rid of separator measurement = [float(i) for i in measurement] # convert strings to float self.update_graph(measurement) self.predict_interaction(measurement) # checks the standard deviation of the received data to see if the sensor is working well if (numpy.std(measurement) < self.standard_deviation_threshold): self.statusBar().showMessage(strings.sensor_not_working) self.statusBar().setStyleSheet(styles.statusBarError) else: self.statusBar().setStyleSheet(styles.statusBar) if self.is_training_on: print("saving measurement {0} into database at location_ID {1}. (in 'RootsApp.process_measurement()')".format(self.n_measurements_collected + 1, self.interaction_under_training.ID)) database.save_points(self.database_connection, measurement, self.interaction_under_training.ID) self.n_measurements_collected += 1 self.progress_dialog.setValue(self.n_measurements_collected) if (self.n_measurements_collected >= self.n_measurements_to_collect): self.is_training_on = False self.n_measurements_collected = 0 print("DEBUG: {0} measurements were saved at location_ID {1}. (in 'RootsApp.process_measurement()')".format(self.n_measurements_to_collect, self.interaction_under_training.ID)) self.train_classifiers() self.interaction_under_training.setCalibrated(True) # this makes the button "Calibrate" change coulour # ----------------------------------------------------------------------------------------------------------- # This function retrains the classifiers using all the measurements present in the database and assigns to each object its classifier def train_classifiers(self): #[objects_ID, classifiers] classifiers = classifier.get_classifiers(self.database_connection) print("DEBUG: the following classifiers were created: {0}. (in 'RootsApp.train_classifiers')".format(classifiers)) for object in self.object_list: for index, tuple in enumerate(classifiers): object_ID, classif = tuple; # extracts the object ID and the classifier from the tuple if object_ID == object.ID: object.classifier = classif del classifiers[index] # ----------------------------------------------------------------------------------------------------------- # This function changes the current active object (the software tries to guess where the user is touching using the calibration data from the active object) def set_active_object(self, active_object): self.active_object = active_object for obj in self.object_list: if obj == active_object: active_object.set_highlighted(True) else: obj.set_highlighted(False) index = self.comboBox.findText(self.active_object.name) # updates the index of the ComboBox self.comboBox.setCurrentIndex(index) # ----------------------------------------------------------------------------------------------------------- # This function changes the name of an object. It updates the database AND the application data structure. def rename_object(self, object, new_name): print("DEBUG: changing name of object '{0}' (in 'RootsApp.rename_object')".format(object.name)) object.set_name(new_name) database.rename_object(self.database_connection, object.ID, new_name) self.update_comboBox() # ----------------------------------------------------------------------------------------------------------- # This function uses the classifier of the active object to guess where the user is touching, based on the incoming measurement def predict_interaction(self, measurement): if (len(self.object_list) <= 0): self.labelClassification.setText("No objects available") self.statusBar().showMessage(strings.no_objects) return if self.active_object is None: self.labelClassification.setText("No object selected") self.statusBar().showMessage(strings.no_object_selected) return if self.active_object.classifier is None: self.labelClassification.setText("The object is not calibrated") self.statusBar().showMessage(strings.object_not_calibrated) return else: predicted_interaction_id = self.active_object.classifier(measurement) interaction = self.active_object.get_interaction_by_ID(predicted_interaction_id) self.labelClassification.setText(interaction.name) self.statusBar().showMessage("") #print("DEBUG: predicted interaction ID: ", interaction.ID) # ----------------------------------------------------------------------------------------------------------- # This is a system event that gets called whenever the user tries to close the application. It calls the "exit()" # function (just below) to open a dialog to make sure the user really wants to quit. def closeEvent(self, event): if not self.exit(): event.ignore() # ----------------------------------------------------------------------------------------------------------- # This function gets called when the user cliks on the "Exit" button in the "File" menu or when it tries to close the window (indirectly) # Here we open a dialog to make sure the user really wants to quit. def exit(self): dialogWindow = DialogExit() answer = dialogWindow.exec_() if (answer == True): self.UDPServer.stop() self.close() return answer
class SochasticScreen(QMainWindow): def __init__(self): super().__init__() self.setWindowTitle('Sochastic Queue') self.setGeometry(150, 150, 1000, 600) self.setFixedSize(1000, 600) self.center() self.setIcon() self.initUi() self.createBackArrow() self.initUi() def showDeterministicGraph(self): self.dete_graph = deterministic_graph.DeterministicGraphScreen() self.dete_graph.show() def handleSubmit(self): st1 = self.lambdaQEditText.toPlainText( ) + " " + self.meoQEditText.toPlainText( ) + " " + self.capacityQEditText.toPlainText( ) + " " + self.alreadyPresentpeopleQEditText.toPlainText() lam2 = 0 meo2 = 0 n = 0 if re.match(r"[0-9]+/[0-9]+\b", self.lambdaQEditText.toPlainText()): print("gggg") ar2 = re.split("/", self.lambdaQEditText.toPlainText()) lam2 = int(ar2[0]) / float(ar2[1]) if int(ar2[1]) != 0: n += 1 st1 = self.meoQEditText.toPlainText( ) + " " + self.capacityQEditText.toPlainText( ) + " " + self.alreadyPresentpeopleQEditText.toPlainText() if re.match(r"[0-9]+/[0-9]+\b", self.meoQEditText.toPlainText()): print("yyyy") ar2 = re.split("/", self.meoQEditText.toPlainText()) meo2 = int(ar2[0]) / float(ar2[1]) if int(ar2[0]) != 0 or int(ar2[1]) != 0: n += 1 if n != 1: st1 = self.capacityQEditText.toPlainText( ) + " " + self.alreadyPresentpeopleQEditText.toPlainText() else: st1 = self.lambdaQEditText.toPlainText( ) + " " + self.capacityQEditText.toPlainText( ) + " " + self.alreadyPresentpeopleQEditText.toPlainText() ar1 = re.search(r"[^\d\s.//]", st1) ar = re.findall(r"([0-9]+\.[0-9]+)|(\.[0-9]+)|([0-9]+)", st1) if (len(ar) + n == 4 and ar1 == None): if lam2 == 0: lam2 = float(self.lambdaQEditText.toPlainText()) if meo2 == 0: meo2 = float(self.meoQEditText.toPlainText()) soch = QueueOperations.sochasitc( lam2, meo2, int(self.alreadyPresentpeopleQEditText.toPlainText()), int(self.capacityQEditText.toPlainText())) st = "L: " + str("{:.2f}".format(soch.L())) + ", Lq: " + str( "{:.2f}".format(soch.Lq())) + ", W: " + str("{:.2f}".format( soch.W())) + ", Wq:" + str("{:.2f}".format(soch.Wq())) self.resultLabel.setText(st) self.resultLabel.setVisible(True) else: self.resultLabel.setGeometry((self.width() / 2) - 60, 500, 200, 100) self.resultLabel.setText("Invalid Input") self.resultLabel.setVisible(True) def initUi(self): self.lambdaLabel = QLabel('λ : ', self) self.lambdaLabel.setFont(QFont('Sanserif', 16)) self.lambdaLabel.move(100, 100) self.lambdaLabel.adjustSize() self.lambdaQEditText = QTextEdit(self) self.lambdaQEditText.setGeometry(140, 90, 200, 50) self.lambdaQEditText.setStyleSheet( "border: 1px solid; border-radius:15px; background-color: palette(base); " ) self.lambdaQEditText.setFont(QFont('Sanserif', 13)) self.lambdaQEditText.setAlignment(Qt.AlignCenter) self.lambdaQEditText.setPlaceholderText('arrival rate..') self.lambdaQEditText.setTextColor(QColor(255, 0, 0)) self.meoLabel = QLabel('μ : ', self) self.meoLabel.setFont(QFont('Sanserif', 16)) self.meoLabel.move(600, 100) self.meoLabel.adjustSize() self.meoQEditText = QTextEdit(self) self.meoQEditText.setGeometry(640, 90, 200, 50) self.meoQEditText.setStyleSheet( "border: 1px solid; border-radius:15px; background-color: palette(base); " ) self.meoQEditText.setFont(QFont('Sanserif', 13)) self.meoQEditText.setAlignment(Qt.AlignCenter) self.meoQEditText.setPlaceholderText('service rate..') self.meoQEditText.setTextColor(QColor(0, 0, 255)) #self.nServersLabel=QLabel('n : ',self) #self.nServersLabel.setFont(QFont('Sanserif',16)) #self.nServersLabel.move(350,200) #self.nServersLabel.adjustSize() # self.nServersQEditText=QTextEdit(self) # self.nServersQEditText.setGeometry(380,190,200,50) # self.nServersQEditText.setStyleSheet("border: 1px solid; border-radius:15px; background-color: palette(base); ") # self.nServersQEditText.setFont(QFont('Sanserif',13)) # self.nServersQEditText.setAlignment(Qt.AlignCenter) # self.nServersQEditText.setPlaceholderText('enter the servers number..') # self.nServersQEditText.setTextColor(QColor(0, 255, 0)) self.capacityLabel = QLabel('k : ', self) self.capacityLabel.setFont(QFont('Sanserif', 16)) self.capacityLabel.move(600, 300) self.capacityLabel.adjustSize() self.capacityQEditText = QTextEdit(self) self.capacityQEditText.setGeometry(640, 290, 200, 50) self.capacityQEditText.setStyleSheet( "border: 1px solid; border-radius:15px; background-color: palette(base); " ) self.capacityQEditText.setFont(QFont('Sanserif', 13)) self.capacityQEditText.setAlignment(Qt.AlignCenter) self.capacityQEditText.setPlaceholderText('Capacity..') self.capacityQEditText.setTextColor(QColor(0, 0, 255)) self.alreadyPresentpeopleLabel = QLabel('c : ', self) self.alreadyPresentpeopleLabel.setFont(QFont('Sanserif', 16)) self.alreadyPresentpeopleLabel.move(100, 300) self.alreadyPresentpeopleLabel.adjustSize() self.alreadyPresentpeopleQEditText = QTextEdit(self) self.alreadyPresentpeopleQEditText.setGeometry(140, 290, 200, 50) self.alreadyPresentpeopleQEditText.setStyleSheet( "border: 1px solid; border-radius:15px; background-color: palette(base); " ) self.alreadyPresentpeopleQEditText.setFont(QFont('Sanserif', 13)) self.alreadyPresentpeopleQEditText.setAlignment(Qt.AlignCenter) self.alreadyPresentpeopleQEditText.setPlaceholderText('servers..') self.alreadyPresentpeopleQEditText.setTextColor(QColor(0, 255, 0)) self.submitButton = QPushButton('Submit', self) self.submitButton.setFont(QFont('Sanserif', 14)) self.submitButton.setStyleSheet( 'color:white;background-color:firebrick;border: 0px solid; border-radius:15px' ) self.submitButton.move((self.width() / 2) - 50, 460) self.submitButton.clicked.connect(self.handleSubmit) #out Label................ self.resultLabel = QLabel( '.......................................................................', self) self.resultLabel.setFont(QFont('Sanserif', 14)) self.resultLabel.setStyleSheet('color:magenta') self.resultLabel.adjustSize() self.resultLabel.setVisible(False) self.resultLabel.setGeometry((self.width() / 2) - 180, 470, 400, 90) def createBackArrow(self): icon1 = QIcon('arrow_back.png') label1 = QLabel('Sample', self) pixmap1 = icon1.pixmap(20, 20, QIcon.Active, QIcon.On) label1.setPixmap(pixmap1) label1.move(25, 25) label1.adjustSize() label1.mousePressEvent = self.arrowbackClicked def arrowbackClicked(self, event): print('arrow back clicked') self.main = main.MainWindow() self.main.show() self.destroy() def center(self): qRect = self.frameGeometry() centerpoint = QDesktopWidget().availableGeometry().center() qRect.moveCenter(centerpoint) self.move(qRect.topLeft()) def setIcon(self): appIcon = QIcon('line.png') self.setWindowIcon(appIcon) def closeEvent(self, event): userInfo = QMessageBox.question(self, 'Closing ?', 'Do u want to quit ?', QMessageBox.Yes | QMessageBox.No) if userInfo == QMessageBox.Yes: event.accept() self.close() #sys.exit(QApplication(sys.argv).exec_()) elif userInfo == QMessageBox.No: event.ignore()
class Canvas (QWidget): def __init__(self): QWidget.__init__(self) self.file = "mug.webp" self.__img = cv2.imread(self.file) self.__mask = np.zeros(1) self.original = cv2.imread(self.file) self.__thirdChannelMask = np.dstack((self.__mask, self.__mask, self.__mask)) self.__nseg = 1 self.__sig = 1 self.__comp = 1 self.nSlider = QSlider(orientation=Qt.Horizontal) self.sigSlider = QSlider(orientation=Qt.Horizontal) self.thicSlider = QSlider(orientation=Qt.Horizontal) self.resize_spinbox = QSpinBox(self) self.resize_spinbox.setRange(1, 100) self.resize_spinbox.setValue(100) self.resize_spinbox.setSuffix(" %") self.double_spin_width = QDoubleSpinBox(self) self.double_spin_width.setSuffix(" px") self.double_spin_width.setValue(0) self.double_spin_width.setRange(1, 2000) self.double_spin_height = QDoubleSpinBox(self) self.double_spin_height.setSuffix(" px") self.double_spin_height.setValue(0) self.double_spin_height.setRange(1, 2000) self.zeroModeCheck = QCheckBox("Usar SLIC0") self.__highlightcolor = QColor(255, 255, 255) self.__transparency = 0.5 self.__AllColors = [self.__highlightcolor.toTuple()[:3]] nLabel = QLabel("Numero de segmentos:") sigLabel = QLabel("Sigma:") thicLabel = QLabel("Compactação:") resizeLabel = QLabel("Fator de resize da image:") makssizeLabel = QLabel("Dimensão da mascara de saída:") self.__label = QLabel() nLabel.setToolTip("O número aproximado de labels da imagem segmentada") sigLabel.setToolTip("A largura da Gaussiana") thicLabel.setToolTip("Equilibra a proximidade das cores e a proximidade do espaço, maiores valores tornam os Superpixels mais quadrados") self.nSlider.setMinimum(1) self.nSlider.setMaximum(100) self.sigSlider.setMinimum(1) self.sigSlider.setMaximum(100) self.thicSlider.setMinimum(1) self.thicSlider.setMaximum(100) glayout1 = QGridLayout() glayout1.addWidget(nLabel, 0, 0) glayout1.addWidget(self.nSlider, 0, 1) glayout1.addWidget(sigLabel, 1, 0) glayout1.addWidget(self.sigSlider, 1, 1) glayout1.addWidget(thicLabel, 2, 0) glayout1.addWidget(self.thicSlider, 2, 1) glayout2 = QGridLayout() glayout2.addWidget(resizeLabel, 0, 0) glayout2.addWidget(self.resize_spinbox, 0, 1) glayout2.addWidget(self.zeroModeCheck, 0, 2) glayout2.addWidget(makssizeLabel, 1, 0) glayout2.addWidget(self.double_spin_width, 1, 1) glayout2.addWidget(self.double_spin_height, 1, 2) glayout2.setColumnStretch(3, 1) self.__label.setAlignment(Qt.AlignLeft | Qt.AlignTop) mainlayout = QVBoxLayout() mainlayout.addLayout(glayout1) mainlayout.addLayout(glayout2) mainlayout.addStretch(1) mainlayout.addWidget(self.__label) mainlayout.addStretch(1) mainlayout.setAlignment(Qt.AlignCenter) self.setLayout(mainlayout) self.nSlider.sliderReleased.connect(self.onNsegChange) self.sigSlider.sliderReleased.connect(self.onSigChange) self.thicSlider.sliderReleased.connect(self.onCompChange) self.__label.mousePressEvent = self.Highlight self.resize_spinbox.valueChanged.connect(self.Resize) self.open_image(self.__img) def getBackground(self): mask = self.__thirdChannelMask.copy() mask_r = mask[:, :, 2] mask_g = mask[:, :, 1] mask_b = mask[:, :, 0] offImage = list() for color in self.__AllColors: b_off = mask_b != color[2] g_off = mask_g != color[1] r_off = mask_r != color[0] aux = np.logical_and(b_off, g_off) offImage.append(np.logical_and(aux, r_off)) final = offImage[0] for cut in offImage: final = np.logical_or(final, cut) return final def changeImage(self): self.__mask = slic(self.__img, n_segments=self.__nseg, compactness=self.__comp, sigma=self.__sig, convert2lab=True, slic_zero=self.zeroModeCheck.isChecked()) mask = self.__mask.copy() mask = np.dstack((mask, mask, mask)) mask = img_as_ubyte(mask) self.__thirdChannelMask = mask img = cv2.addWeighted(self.__img, 1, mask, 0.5, 0) marc_img = mark_boundaries(img, self.__mask) self.open_image(marc_img) def load_image(self): self.__img = cv2.imread(self.file) self.original = self.__img self.double_spin_width.setValue(self.__img.shape[1]) self.double_spin_height.setValue(self.__img.shape[0]) val = self.resize_spinbox.value() newDim = int(self.__img.shape[1]*val/100), int(self.__img.shape[0]*val/100) self.__img = cv2.resize(self.__img, newDim) self.open_image(self.__img) def open_image(self, img): if img.shape[2] == 4: qformat = QImage.Format_RGBA8888 else: qformat = QImage.Format_RGB888 copy = img_as_ubyte(img) qimg = QImage(copy.data, copy.shape[1], copy.shape[0], copy.strides[0], qformat).rgbSwapped() pixmap = QPixmap.fromImage(qimg) self.__label.setPixmap(pixmap) self.__label.adjustSize() @Slot() def onNsegChange(self): self.__nseg = self.nSlider.value() self.changeImage() @Slot() def onSigChange(self): self.__sig = self.sigSlider.value() self.changeImage() @Slot() def onCompChange(self): self.__comp = self.thicSlider.value() self.changeImage() @Slot() def onFileOpen(self): self.thicSlider.setValue(1) self.nSlider.setValue(1) self.sigSlider.setValue(1) diag = QFileDialog() file = diag.getOpenFileName()[0] if file != "": self.file = file self.load_image() @Slot() def onSaveFile(self): diag = QFileDialog() file = diag.getSaveFileName()[0] if self.file != "": self.__label.pixmap().save(file) @Slot() def onSaveMask(self): diag = QFileDialog() file = diag.getSaveFileName()[0] final_img = cv2.resize(self.__mask, (self.double_spin_width.value(), self.double_spin_height.value())) if file != "": cv2.imwrite(file, final_img) @Slot() def Highlight(self, e): if e.x() < 0 or e.x() > self.__img.shape[1] or e.y() < 0 or e.y() > self.__img.shape[0]: return self.__mask = flood_fill(self.__mask, (e.y(), e.x()), 255) self.__thirdChannelMask[:, :, 2] = flood_fill(self.__thirdChannelMask[:, :, 2], (e.y(), e.x()), self.__highlightcolor.red()) self.__thirdChannelMask[:, :, 1] = flood_fill(self.__thirdChannelMask[:, :, 1], (e.y(), e.x()), self.__highlightcolor.green()) self.__thirdChannelMask[:, :, 0] = flood_fill(self.__thirdChannelMask[:, :, 0], (e.y(), e.x()), self.__highlightcolor.blue()) img = cv2.addWeighted(self.__img, 1, self.__thirdChannelMask, self.__transparency, 0) marc_img = mark_boundaries(img, self.__mask) self.open_image(marc_img) @Slot() def exportBinary(self): diag = QFileDialog() file = diag.getSaveFileName()[0] mask = self.__thirdChannelMask.copy() final = self.getBackground() b = mask[:, :, 0] g = mask[:, :, 1] r = mask[:, :, 2] b[final] = 0 g[final] = 0 r[final] = 0 final_img = cv2.resize(mask, (int(self.double_spin_width.value()), int(self.double_spin_height.value()))) if file != "": cv2.imwrite(file, final_img) @Slot() def onRemoveBackgroud(self): box = QMessageBox() box.setText("Selecione a cor do background") box.setIcon(QMessageBox.Information) box.exec() diag = QColorDialog() backColor = diag.getColor() final = self.getBackground() b = self.__img[:, :, 0] g = self.__img[:, :, 1] r = self.__img[:, :, 2] b[final] = backColor.blue() g[final] = backColor.green() r[final] = backColor.red() self.open_image(self.__img) @Slot() def Resize(self): val = self.resize_spinbox.value() newDim = int(self.original.shape[1] * val / 100), int(self.original.shape[0] * val / 100) self.__img = cv2.resize(self.original, newDim) self.open_image(self.__img) @Slot() def setHighlightColor(self, color): self.__highlightcolor = color @Slot() def getAllColors(self, colors): self.__AllColors = colors @Slot() def setTran(self, value): self.__transparency = 1- value/100 @Slot() def onUndo(self): self.thicSlider.setValue(1) self.nSlider.setValue(1) self.sigSlider.setValue(1) self.onNsegChange() self.onSigChange() self.onCompChange() self.__img = self.original self.open_image(self.__img)
class Artigence(QMainWindow): def __init__(self): super(Artigence, self).__init__() # Basic Settings self.setGeometry(300, 200, 682, 422) self.setMinimumSize(QSize(682, 422)) self.setMaximumSize(QSize(682, 422)) self.setWindowIcon(QIcon("arti.PNG")) self.setWindowTitle("Artigence Home") # Color Scheme self.palette = QPalette() self.palette.setColor(self.palette.Window, QColor('#000000')) self.palette.setColor(self.palette.WindowText, QColor('#FFFFFF')) self.setPalette(self.palette) self.light_palette = QPalette() self.light_palette.setColor(self.light_palette.Window, QColor('#FFFFFF')) self.light_palette.setColor(self.light_palette.WindowText, QColor('#000000')) # Setting MenuBar self.menubar = QMenuBar(self) self.menubar.setGeometry(0, 0, 682, 21) self.date_menu = QMenu(self.menubar) self.date_menu.setTitle(str(datetime.now().strftime('%d-%m-%Y'))) self.theme_menu = QMenu(self.menubar) self.theme_menu.setTitle('Theme') self.dark_theme = QAction('Dark Theme') self.dark_theme.setShortcut(QKeySequence('Ctrl+Shift+D')) self.theme_menu.addAction(self.dark_theme) self.dark_theme.triggered.connect(lambda: self.dark()) self.light_theme = QAction('Light Theme') self.light_theme.setShortcut(QKeySequence('Ctrl+Shift+L')) self.theme_menu.addAction(self.light_theme) self.light_theme.triggered.connect(lambda: self.light()) self.app_menu = QMenu(self.menubar) self.app_menu.setTitle('Apps') self.calculator_menu = QAction('Calculator') self.calculator_menu.setShortcut(QKeySequence('Alt+C')) self.app_menu.addAction(self.calculator_menu) self.calculator_menu.triggered.connect(lambda: self.calculator_func()) self.game_menu = QAction('GameHub') self.game_menu.setShortcut(QKeySequence('Alt+G')) self.app_menu.addAction(self.game_menu) self.game_menu.triggered.connect(lambda: self.games_func()) self.music_menu = QAction('Muse (Music)') self.music_menu.setShortcut(QKeySequence('Alt+M')) self.app_menu.addAction(self.music_menu) self.music_menu.triggered.connect(lambda: self.music_func()) self.news_menu = QAction('News') self.news_menu.setShortcut(QKeySequence('Alt+E')) self.app_menu.addAction(self.news_menu) self.news_menu.triggered.connect(lambda: self.news_func()) self.notepad_menu = QAction('Notepad') self.notepad_menu.setShortcut(QKeySequence('Alt+N')) self.app_menu.addAction(self.notepad_menu) self.notepad_menu.triggered.connect(lambda: self.notepad_func()) self.pronunciator = QAction('Pronunciator') self.pronunciator.setShortcut(QKeySequence('Alt+P')) self.app_menu.addAction(self.pronunciator) self.pronunciator.triggered.connect(lambda: self.pronunciator_func()) self.translate_menu = QAction('Translate') self.translate_menu.setShortcut(QKeySequence('Alt+T')) self.app_menu.addAction(self.translate_menu) self.translate_menu.triggered.connect(lambda: self.translate_func()) self.weather_menu = QAction('Weather') self.weather_menu.setShortcut(QKeySequence('Alt+W')) self.app_menu.addAction(self.weather_menu) self.weather_menu.triggered.connect(lambda: self.weather_func()) self.setMenuBar(self.menubar) self.menubar.addAction(self.date_menu.menuAction()) self.menubar.addAction(self.theme_menu.menuAction()) self.menubar.addAction(self.app_menu.menuAction()) # Creating Widgets self.query = QLineEdit(self) self.query.setGeometry(QRect(20, 30, 451, 41)) self.query.setMinimumSize(QSize(451, 41)) self.query.setMaximumSize(QSize(451, 41)) self.query.setPlaceholderText("Enter your Query Here:") self.query.setFont(QFont('Roboto', 16)) self.query.setClearButtonEnabled(True) self.update = QPushButton(self) self.update.setGeometry(QRect(491, 30, 171, 41)) self.update.setMinimumSize(QSize(1, 1)) self.update.setMaximumSize(QSize(171, 51)) self.update.setText("What's New in the Updates?") self.update.setCursor(QCursor(Qt.PointingHandCursor)) self.suggestions = QLabel(self) self.suggestions.setGeometry(QRect(20, 220, 111, 31)) self.suggestions.setMinimumSize(QSize(111, 31)) self.suggestions.setMaximumSize(QSize(111, 31)) self.suggestions.setText("Suggestions:") self.suggestions.setFont(QFont('Roboto', 14)) self.chrome = QPushButton(self) self.chrome.setGeometry(QRect(20, 260, 91, 31)) self.chrome.setCursor(QCursor(Qt.PointingHandCursor)) self.chrome.setText('Open Chrome') self.games = QPushButton(self) self.games.setGeometry(QRect(420, 260, 91, 31)) self.games.setCursor(QCursor(Qt.PointingHandCursor)) self.games.setText('Games') self.cmd = QPushButton(self) self.cmd.setGeometry(QRect(160, 260, 91, 31)) self.cmd.setCursor(QCursor(Qt.PointingHandCursor)) self.cmd.setText('Open Cmd') self.joke = QPushButton(self) self.joke.setGeometry(QRect(160, 310, 91, 31)) self.joke.setCursor(QCursor(Qt.PointingHandCursor)) self.joke.setText('Joke Please!!') self.music = QPushButton(self) self.music.setGeometry(QRect(290, 260, 91, 31)) self.music.setCursor(QCursor(Qt.PointingHandCursor)) self.music.setText('Music') self.youtube = QPushButton(self) self.youtube.setGeometry(QRect(290, 310, 91, 31)) self.youtube.setCursor(QCursor(Qt.PointingHandCursor)) self.youtube.setText('Youtube') self.time = QPushButton(self) self.time.setGeometry(QRect(20, 310, 91, 31)) self.time.setCursor(QCursor(Qt.PointingHandCursor)) self.time.setText('Tell Time') self.weather = QPushButton(self) self.weather.setGeometry(QRect(420, 310, 91, 31)) self.weather.setCursor(QCursor(Qt.PointingHandCursor)) self.weather.setText('Weather') self.calculator = QPushButton(self) self.calculator.setGeometry(QRect(550, 260, 101, 31)) self.calculator.setCursor(QCursor(Qt.PointingHandCursor)) self.calculator.setText('Calculator') self.wikipedia = QPushButton(self) self.wikipedia.setGeometry(QRect(550, 310, 101, 31)) self.wikipedia.setCursor(QCursor(Qt.PointingHandCursor)) self.wikipedia.setText('India Wikipedia') self.news = QPushButton(self) self.news.setGeometry(QRect(20, 360, 91, 31)) self.news.setCursor(QCursor(Qt.PointingHandCursor)) self.news.setText('Latest News') self.meaning = QPushButton(self) self.meaning.setGeometry(QRect(420, 360, 231, 31)) self.meaning.setCursor(QCursor(Qt.PointingHandCursor)) self.meaning.setText('Meaning of Obsolete (or any word)') self.harry_potter = QPushButton(self) self.harry_potter.setGeometry(QRect(290, 360, 91, 31)) self.harry_potter.setCursor(QCursor(Qt.PointingHandCursor)) self.harry_potter.setText('Harry Potter') self.translate = QPushButton(self) self.translate.setGeometry(QRect(160, 360, 91, 31)) self.translate.setCursor(QCursor(Qt.PointingHandCursor)) self.translate.setText('Open Translate') self.line = QFrame(self) self.line.setGeometry(QRect(20, 200, 661, 16)) self.line.setFrameShape(QFrame.HLine) self.line.setFrameShadow(QFrame.Sunken) self.label = QLabel(self) self.label.setGeometry(QRect(20, 100, 631, 91)) self.label.setFont(QFont('Roboto', 12)) self.label.setTextFormat(Qt.AutoText) self.label.setWordWrap(True) self.wish() # Making the Widgets Functional self.query.returnPressed.connect(lambda: self.on_enter()) self.query.returnPressed.connect(lambda: self.clear_text()) self.update.clicked.connect(lambda: self.update_func()) self.music.clicked.connect(lambda: self.music_func()) self.games.clicked.connect(lambda: self.games_func()) self.calculator.clicked.connect(lambda: self.calculator_func()) self.weather.clicked.connect(lambda: self.weather_func()) self.news.clicked.connect(lambda: self.news_func()) self.translate.clicked.connect(lambda: self.translate_func()) self.time.clicked.connect(lambda: self.time_func()) self.joke.clicked.connect(lambda: self.joke_func()) self.youtube.clicked.connect(lambda: self.youtube_func()) self.wikipedia.clicked.connect(lambda: self.wikipedia_func()) self.chrome.clicked.connect(lambda: self.chrome_func()) self.cmd.clicked.connect(lambda: self.cmd_func()) self.meaning.clicked.connect(lambda: self.meaning_func()) self.harry_potter.clicked.connect(lambda: self.potter_func()) def pronunciator_func(self): self.speak('Opening Pronunciator') from pronunciator import Pronunciator self.pronunciator_win = Pronunciator() self.pronunciator_win.show() def pong_func(self): import pong def notepad_func(self): self.speak('Opening Notepad') from notepad import Notepad self.notepad_win = Notepad() self.notepad_win.show() def update_func(self): os.startfile('Each Version Updates.txt') def translate_func(self): self.speak( 'Opening Translate\nPlease Wait as opening Translate may take up to 4-5 seconds' ) from translate import Translate self.translate_win = Translate() self.translate_win.show() def games_func(self): self.speak('Opening GameHub') from games import GameHub self.game_win = GameHub() self.game_win.show() def weather_func(self): self.speak('Opening Weather.') from weather import Weather self.weather_win = Weather() self.weather_win.show() def music_func(self): self.speak('Opening Muse') from music import Music self.music_win = Music() self.music_win.show() def calculator_func(self): self.speak('Opening Calculator.') from calculator import Calculator self.calculator_win = Calculator() self.calculator_win.show() def news_func(self): self.speak('Opening News.') from news import News self.news_win = News() self.news_win.show() self.speak( 'Welcome to News.\nThese are the latest international headlines according to BBC News Network.' ) def chrome_func(self): try: chrome_path = 'C:\\Program Files (x86)\\Google\\Chrome\\Application\\chrome.exe' os.startfile(chrome_path) self.speak('Opening Chrome.') except Exception: self.speak( 'No Google Chrome installation found on the host device.') def cmd_func(self): cmd_path = 'C:\\Windows\\system32\\cmd.exe' os.startfile(cmd_path) self.speak('Opening Command Prompt.') def time_func(self): question = 'time' app_id = 'LLQ4QY-A7K3LEL4T8' client = wolframalpha.Client(app_id) res = client.query(question) answer = next(res.results).text self.speak(answer) def joke_func(self): self.speak(pyjokes.get_joke()) def youtube_func(self): webbrowser.open('https://www.youtube.com') self.speak('Opening Youtube.') def wikipedia_func(self): try: self.speak('Searching Wikipedia. Please Wait...') query = 'India'.replace('wikipedia', '') result = wikipedia.summary(query, sentences=1) self.speak('According to Wikipedia...') self.speak(result) except Exception as e: self.speak(e) def meaning_func(self): question = 'obsolete' app_id = 'LLQ4QY-A7K3LEL4T8' client = wolframalpha.Client(app_id) res = client.query(question) answer = next(res.results).text self.speak(answer) def potter_func(self): new = 2 google_url = "http://google.com/?#q=" webbrowser.open(google_url + 'Harry Potter', new=new) def clear_text(self): self.query.clear() def on_enter(self): user_query = self.query.text().lower() if 'wikipedia' in user_query: try: self.speak('Searching Wikipedia. Please Wait...') user_query = user_query.replace('wikipedia', '') result = wikipedia.summary(user_query, sentences=1) self.speak('According to Wikipedia...') self.speak(result) except Exception as e: self.speak('Please try again later.') self.speak(e) elif 'youtube' in user_query: webbrowser.open('https://www.youtube.com') self.speak('Opening Youtube.') elif 'google' in user_query: webbrowser.open('https://www.google.com/') self.speak('Opening Google.') elif 'chrome' in user_query: # You'll have to download google chrome first on your desktop/pc. try: chrome_path = 'C:\\Program Files (x86)\\Google\\Chrome\\Application\\chrome.exe' os.startfile(chrome_path) self.speak('Opening Chrome') except Exception: self.speak( 'No Google Chrome installation found on the host device.') elif 'cmd' in user_query: cmd_path = 'C:\\Windows\\system32\\cmd.exe' os.startfile(cmd_path) self.speak('Opening Command Prompt.') elif 'control panel' in user_query: cp_path = 'C:\\Windows\\system32\\control.exe' os.startfile(cp_path) self.speak('Opening Control Panel.') elif 'bye' in user_query or 'goodbye' in user_query or 'good night' in user_query or 'see you later' in user_query: self.speak(random.choice(self.bye)) sys.exit() elif 'hello' in user_query or 'hi' in user_query: self.speak(random.choice(self.hello)) elif 'joke' in user_query: self.speak(pyjokes.get_joke()) elif 'who are you' in user_query: self.speak('I am Artigence, your artificial intelligence.') elif 'map' in user_query or 'maps' in user_query: self.speak('Opening Google Maps.') webbrowser.open("https://www.google.com/maps") elif 'open calculator' in user_query or 'calculator' in user_query: self.calculator_func() elif 'news' in user_query: self.news_func() self.speak( 'Welcome to News.\nThese are the latest international headlines according to BBC News Network.' ) elif 'weather' in user_query: self.weather_func() elif 'games' in user_query: self.games_func() elif 'pronunciator' in user_query or 'pronounce' in user_query: self.pronunciator_func() elif 'translate' in user_query: self.translate_func() elif 'music' in user_query: self.music_func() elif 'notepad' in user_query: self.notepad_func() else: try: question = user_query app_id = 'LLQ4QY-A7K3LEL4T8' client = wolframalpha.Client(app_id) res = client.query(question) answer = next(res.results).text self.label.setText(answer) self.label.adjustSize() except: new = 2 google_url = "http://google.com/?#q=" query = user_query webbrowser.open(google_url + query, new=new) # The A.I. will speak through this function def speak(self, audio): self.engine = pyttsx3.init('sapi5') voices = self.engine.getProperty('voices') self.engine.setProperty('voice', voices[1].id) self.engine.setProperty('rate', 165) self.label.setText(audio) self.engine.say(audio) self.engine.runAndWait() self.label.clear() def wish(self): hour = int(datetime.now().hour) if 0 <= hour < 12: self.speak('Good Morning.') elif 12 <= hour < 18: self.speak('Good Afternoon.') else: self.speak('Good Evening.') self.speak('I am Artigence.') self.speak('How may I help you today') hello = ['Kon\'nichiwa', 'Ciao', 'Hola', 'Bonjour', 'Hello', 'Hi', 'Hiya'] bye = [ 'Adios', 'Goodbye', 'Bye-Bye', 'See you next time.', 'Artigence Out.', 'It was nice talking to you sir. Have a nice day.' ] def dark(self): self.setPalette(self.palette) def light(self): self.setPalette(self.light_palette)
class MapWidget(QQuickWidget): def __init__(self, data, model): super(MapWidget, self).__init__(resizeMode=QQuickWidget.SizeRootObjectToView) self.data = data self.model = model self.attribute_button = QPushButton(self) self.attribute_button.setStyleSheet("color: black") self.menu = QMenu("Pick an attribute", self) # Create Menu Options self.humidity_attribute = QAction("humidity") self.pressure_attribute = QAction("pressure") self.temperature_attribute = QAction("temperature") self.wind_speed_attribute = QAction("wind_speed") # due to frequent access of dates based on index, we store this data separately self.uniqueDates = self.data["datetime"].apply( lambda x: x.split(' ')[0]).unique().tolist() self.aggregation = 1 self.rootContext().setContextProperty("markermodel", model) self.rootContext().setContextProperty("MapWidget", self) qml_path = os.path.join(os.path.dirname(__file__), "map.qml") self.setSource(QUrl.fromLocalFile(qml_path)) positions = self.get_positions(self.data) names = self.get_names(self.data) # get first date of dataset in yy-mm-dd self.currentDate = self.uniqueDates[0] # Set Labels self.date_label = QLabel( "selected date: " + str(self.currentDate).replace("-", "."), self) self.date_label.setStyleSheet("color: black") # Set Previous and Next Buttons self.previous_button = QPushButton("Previous", self) self.next_button = QPushButton("Next", self) self.previous_button.clicked.connect( partial(self.on_button_clicked, "previous")) self.next_button.clicked.connect( partial(self.on_button_clicked, "next")) values = self.get_values(self.data, "humidity") colors = self.get_colors(self.data, "humidity") for i in range(0, len(names)): geo_coordinates = QGeoCoordinate(positions[i][0], positions[i][1]) name = names[i] value = values[i] color = colors[i] model.append_marker({ "position": geo_coordinates, "color": color, "name": name, "value": value, "date": self.currentDate }) self.create_interface() return def add_attribute_to_menu(self, attribute_action, attribute): attribute_action.triggered.connect(lambda: self.clicked(attribute)) self.menu.addAction(attribute_action) def create_date_picker(self, index): tmp_time = self.uniqueDates[index] time_QFormat = tmp_time.split("-") # date is parsed and converted to int to comply with required format of QDate date_picker = QDateTimeEdit( QDate(int(time_QFormat[0]), int(time_QFormat[1]), int(time_QFormat[2])), self) date_picker.setDisplayFormat("yyyy.MM.dd") date_picker.setCalendarPopup(True) date_picker.setCalendarWidget(QCalendarWidget()) date_picker.resize(date_picker.width() + 20, date_picker.height()) return date_picker def set_date_pickers(self, slider): # Set Date Picker for Start of self.slider date_picker_start = self.create_date_picker(0) date_picker_start.setToolTip( "Select the BEGINNING of the time period from which the data is displayed" ) date_picker_start.move( slider.property("x") - date_picker_start.width() - 30, slider.property("y")) # Set Date Picker for End of self.slider date_picker_end = self.create_date_picker(-1) date_picker_end.setToolTip( "Select the END of the time period from which the data is displayed" ) date_picker_end.move( slider.property("x") + slider.property("width") + 30, slider.property("y")) # Set Date Pickers Boundaries Based on First and Last Date in Given Data date_picker_start.setMinimumDate(date_picker_start.date()) date_picker_end.setMinimumDate(date_picker_start.date()) date_picker_start.setMaximumDate(date_picker_end.date()) date_picker_end.setMaximumDate(date_picker_end.date()) return date_picker_start, date_picker_end def create_interface(self): self.attribute_button.move(50, 0) # Create a Menu Option for Each Attribute self.add_attribute_to_menu(self.humidity_attribute, "humidity") self.add_attribute_to_menu(self.pressure_attribute, "pressure") self.add_attribute_to_menu(self.temperature_attribute, "temperature") self.add_attribute_to_menu(self.wind_speed_attribute, "wind_speed") self.attribute_button.setMenu(self.menu) self.attribute_button.resize(self.menu.width() + 50, self.attribute_button.height()) # Get self.slider from QML File self.slider = self.rootObject().findChild(QObject, "slider") # Set Date Pickers self.date_picker_start, self.date_picker_end = self.set_date_pickers( self.slider) self.date_picker_start.dateChanged.connect(lambda: self.change_date( self.slider, self.self.date_picker_start, self.date_picker_end)) self.date_picker_end.dateChanged.connect(lambda: self.change_date( self.slider, self.self.date_picker_start, self.date_picker_end)) # Label Holding the Current Date Selected by User self.date_label.move( self.slider.property("x") + (self.slider.width() / 2) - 100, self.slider.property("y") + 30) self.date_label.adjustSize() # Set Buttons Position self.previous_button.setStyleSheet("color: black") self.previous_button.move(self.slider.property("x"), self.slider.property("y") + 50) self.previous_button.adjustSize() self.next_button.setStyleSheet("color: black") self.next_button.move( self.slider.property("x") + self.slider.width() - 70, self.slider.property("y") + 50) self.next_button.adjustSize() jump_label = QLabel("self.slider jump (in days): ", self) jump_label.setStyleSheet("color: black") jump_label.move(self.date_label.x(), self.date_label.y() + 40) jump_label.adjustSize() self.jump_value = QLineEdit(self) self.jump_value.move(jump_label.x() + jump_label.width(), jump_label.y() - 5) self.jump_value.resize(35, self.jump_value.height()) self.jump_value.editingFinished.connect( lambda: self.slider.setProperty("stepSize", self.jump_value.text() )) agg_label = QLabel(self) agg_label.setStyleSheet("color: black") agg_label.move(self.date_label.x(), self.jump_value.y() + 40) agg_label.setText("mean (in days): ") agg_label.adjustSize() agg_value = QLineEdit(self) agg_value.move(self.jump_value.x(), agg_label.y() - 5) agg_value.resize(35, agg_value.height()) agg_value.editingFinished.connect( lambda: self.set_agg(agg_value.text())) # Initialize Visualization self.humidity_attribute.trigger() self.change_date(self.slider, self.date_picker_start, self.date_picker_end) def on_button_clicked(self, action): jump_value = int(self.jump_value.text()) slider_value = int(self.slider.property("value")) current_date = pandas.to_datetime(self.currentDate) start_date = self.date_picker_start.date().toPython() end_date = self.date_picker_end.date().toPython() if action == "next": if current_date + datetime.timedelta(days=jump_value) <= end_date: self.slider.setProperty("value", slider_value + jump_value) self.update_date(int(self.slider.property("value"))) elif action == "previous": if current_date - datetime.timedelta( days=jump_value) >= start_date: self.slider.setProperty("value", slider_value - jump_value) self.update_date(int(self.slider.property("value"))) @Slot(int) def update_date(self, value): self.currentDate = self.uniqueDates[value - 1] self.date_label.setText("selected date: " + str(self.currentDate).replace("-", ".")) self.clicked(self.attribute_button.text()) # TODO: visualise time series data, not just int created by aggregation # TODO: create setting of visualised time period for user # calculates the difference (in days) between start date and end date and rescales the self.slider def set_agg(self, value): self.aggregation = int(value) self.clicked(self.attribute_button.text()) def change_date(self, slider, date_picker_start, date_picker_end): dif = self.uniqueDates\ .index(date_picker_end.date().toString("yyyy-MM-dd")) - self.uniqueDates.index(date_picker_start.date().toString("yyyy-MM-dd")) slider.setProperty("to", dif + 1) # when button is clicked, changes values in all model items to a different attribute def clicked(self, attribute): self.attribute_button.setText(attribute) values = self.get_values(self.data, attribute) colors = self.get_colors(self.data, attribute) for i in range(0, len(values)): self.model.setData(i, values[i], colors[i], MarkerModel.ValueRole) @staticmethod def get_positions(data): tmp = data.drop_duplicates('city').sort_values(by=['city']) positions = [[x, y] for x, y in zip(tmp['latitude'], tmp['longitude'])] return positions @staticmethod def get_names(data): tmp = data.drop_duplicates('city').sort_values(by=['city']) names = tmp['city'].values.tolist() return names # creates an ordered list of aggregated values of a specified attribute def get_values(self, data, attribute): data['datetime'] = pandas.to_datetime(data['datetime']) start_date = pandas.to_datetime(self.currentDate) end_date = start_date + datetime.timedelta(days=self.aggregation) tmp = data[data['datetime'] >= start_date] tmp = tmp[tmp['datetime'] <= end_date] values = tmp.groupby('city').apply( lambda x: x[attribute].mean()).values.round(2).tolist() return values @staticmethod def get_colors(data, attribute): tmp = data.groupby('city').agg({attribute: 'mean'}) max_value = round(tmp[attribute].max()) min_value = round(tmp[attribute].min()) diff = max_value - min_value step = round(1 / 6 * diff) if attribute == 'pressure': attribute_values = { 0: [255, 255, 255], 1: [204, 229, 255], 2: [102, 178, 255], 3: [0, 128, 255], 4: [0, 0, 255], 5: [0, 0, 102], 6: [0, 0, 51] } elif attribute == 'temperature': attribute_values = { 0: [0, 102, 204], 1: [102, 178, 255], 2: [204, 229, 255], 3: [255, 204, 204], 4: [255, 102, 102], 5: [204, 0, 0], 6: [102, 0, 0] } # TODO: create more suited colors for humidity and wind speed elif attribute == 'humidity': attribute_values = { 0: [0, 102, 204], 1: [102, 178, 255], 2: [204, 229, 255], 3: [255, 204, 204], 4: [255, 102, 102], 5: [204, 0, 0], 6: [102, 0, 0] } elif attribute == 'wind_speed': attribute_values = { 0: [0, 102, 204], 1: [102, 178, 255], 2: [204, 229, 255], 3: [255, 204, 204], 4: [255, 102, 102], 5: [204, 0, 0], 6: [102, 0, 0] } values = numpy.array([ min_value, min_value + 1 * step, min_value + 2 * step, min_value + 3 * step, min_value + 4 * step, min_value + 5 * step, max_value ]) tmp['distances'] = tmp[attribute].apply(lambda x: abs(x - values)) tmp['index'] = tmp['distances'].apply(lambda x: numpy.argmin(x)) tmp['color'] = tmp['index'].apply(lambda x: attribute_values.get(x)) colors = tmp['color'].tolist() colors_list = [] for color_tmp in colors: color = QColor(color_tmp[0], color_tmp[1], color_tmp[2], 255) colors_list.append(color) # returns QJSValue return colors_list def createAction(self, attribute): action = QAction(attribute) action.triggered.connect(self.clicked(attribute)) self.menu.addAction(action) return action
def create_interface(self): self.attribute_button.move(50, 0) # Create a Menu Option for Each Attribute self.add_attribute_to_menu(self.humidity_attribute, "humidity") self.add_attribute_to_menu(self.pressure_attribute, "pressure") self.add_attribute_to_menu(self.temperature_attribute, "temperature") self.add_attribute_to_menu(self.wind_speed_attribute, "wind_speed") self.attribute_button.setMenu(self.menu) self.attribute_button.resize(self.menu.width() + 50, self.attribute_button.height()) # Get self.slider from QML File self.slider = self.rootObject().findChild(QObject, "slider") # Set Date Pickers self.date_picker_start, self.date_picker_end = self.set_date_pickers( self.slider) self.date_picker_start.dateChanged.connect(lambda: self.change_date( self.slider, self.self.date_picker_start, self.date_picker_end)) self.date_picker_end.dateChanged.connect(lambda: self.change_date( self.slider, self.self.date_picker_start, self.date_picker_end)) # Label Holding the Current Date Selected by User self.date_label.move( self.slider.property("x") + (self.slider.width() / 2) - 100, self.slider.property("y") + 30) self.date_label.adjustSize() # Set Buttons Position self.previous_button.setStyleSheet("color: black") self.previous_button.move(self.slider.property("x"), self.slider.property("y") + 50) self.previous_button.adjustSize() self.next_button.setStyleSheet("color: black") self.next_button.move( self.slider.property("x") + self.slider.width() - 70, self.slider.property("y") + 50) self.next_button.adjustSize() jump_label = QLabel("self.slider jump (in days): ", self) jump_label.setStyleSheet("color: black") jump_label.move(self.date_label.x(), self.date_label.y() + 40) jump_label.adjustSize() self.jump_value = QLineEdit(self) self.jump_value.move(jump_label.x() + jump_label.width(), jump_label.y() - 5) self.jump_value.resize(35, self.jump_value.height()) self.jump_value.editingFinished.connect( lambda: self.slider.setProperty("stepSize", self.jump_value.text() )) agg_label = QLabel(self) agg_label.setStyleSheet("color: black") agg_label.move(self.date_label.x(), self.jump_value.y() + 40) agg_label.setText("mean (in days): ") agg_label.adjustSize() agg_value = QLineEdit(self) agg_value.move(self.jump_value.x(), agg_label.y() - 5) agg_value.resize(35, agg_value.height()) agg_value.editingFinished.connect( lambda: self.set_agg(agg_value.text())) # Initialize Visualization self.humidity_attribute.trigger() self.change_date(self.slider, self.date_picker_start, self.date_picker_end)
def ui_components(self): font = QFont("Roboto", 16) title_label = QLabel("Convert currency:", self) title_label.move(7, 27) title_label.setFont(font) title_label.adjustSize() to_be_converted = QLineEdit(self) to_be_converted.setPlaceholderText("Amount") to_be_converted.setFont(font) to_be_converted.move(7, 67) to_be_converted.setFixedWidth(230) valid = QDoubleValidator() to_be_converted.setValidator(valid) converted = QLineEdit(self) converted.setPlaceholderText("Converted Amount") converted.isEnabled = False converted.move(7, 107) converted.setFixedWidth(230) converted.setFont(font) converted.setValidator(valid) currency_list_1 = QComboBox(self) currency_list_1.addItem("USD") currency_list_1.addItem("TND") currency_list_1.addItem("EUR") currency_list_1.move(260, 66) currency_list_2 = QComboBox(self) currency_list_2.addItem("USD") currency_list_2.addItem("TND") currency_list_2.addItem("EUR") currency_list_2.move(260, 100) convert_btn = QPushButton("Convert", self) convert_btn.move(260, 140) menubar = QMenuBar(self) Info = menubar.addMenu("Info") exchange = Info.addAction("Exchange rates") exchange.triggered.connect(self.open_exchange_rates) def convertor(): if str(currency_list_1.currentText()) == "USD" or str( currency_list_2.currentText()) == "USD": # ============== USD AND TND ================== if str(currency_list_2.currentText()) == "TND": rate_usd_tnd = Exchanges().usd_tnd() converted_amount = float( to_be_converted.text()) * float(rate_usd_tnd) if to_be_converted != '': converted.setText(str(converted_amount)) if str(currency_list_1.currentText()) == "TND": rate_usd_tnd = Exchanges().usd_tnd() converted_amount = float(to_be_converted.text()) * float( 1 / rate_usd_tnd) if to_be_converted != '': converted.setText(str(converted_amount)) # =============== EUR AND USD ================= if str(currency_list_2.currentText()) == "EUR": rate_usd_eur = Exchanges().usd_eur() converted_amount = float( to_be_converted.text()) * float(rate_usd_eur) if to_be_converted != '': converted.setText(str(converted_amount)) if str(currency_list_1.currentText()) == "EUR": rate_usd_eur = Exchanges().usd_eur() converted_amount = float(to_be_converted.text()) * float( 1 / rate_usd_eur) if to_be_converted != '': converted.setText(str(converted_amount)) if (currency_list_1.currentText()) == "TND" or ( currency_list_2.currentText()) == "TND": if str(currency_list_2.currentText()) == "EUR": rate_tnd_eur = Exchanges().tnd_eur() converted_amount = float( to_be_converted.text()) * float(rate_tnd_eur) if to_be_converted != '': converted.setText(str(converted_amount)) if str(currency_list_1.currentText()) == "EUR": rate_tnd_eur = Exchanges().tnd_eur() converted_amount = float(to_be_converted.text()) * float( 1 / rate_tnd_eur) if to_be_converted != '': converted.setText(str(converted_amount)) convert_btn.clicked.connect(convertor)
class DeterministicScreen(QMainWindow): deter = 0 def __init__(self): super().__init__() self.setWindowTitle('Deterministic Queue') self.setGeometry(150, 150, 1000, 600) self.setFixedSize(1000, 600) self.center() self.setIcon() self.initUi() self.createBackArrow() self.initUi() def showDeterministicGraph(self): self.dete_graph = deterministic_graph.DeterministicGraphScreen() self.dete_graph.show() def handleSubmit(self): global deter st1 = self.lambdaQEditText.toPlainText( ) + " " + self.meoQEditText.toPlainText( ) + " " + self.capacityQEditText.toPlainText( ) + " " + self.alreadyPresentpeopleQEditText.toPlainText( ) + " " + self.nServersQEditText.toPlainText( ) + " " + self.timeQEditText.toPlainText() lam2 = 0 meo2 = 0 n = 0 if re.match(r"[0-9]+/[0-9]+\b", self.lambdaQEditText.toPlainText()): ar2 = re.split("/", self.lambdaQEditText.toPlainText()) lam2 = int(ar2[0]) / float(ar2[1]) n += 1 st1 = self.meoQEditText.toPlainText( ) + " " + self.capacityQEditText.toPlainText( ) + " " + self.alreadyPresentpeopleQEditText.toPlainText( ) + " " + self.nServersQEditText.toPlainText( ) + " " + self.timeQEditText.toPlainText() if re.match(r"[0-9]+/[0-9]+\b", self.meoQEditText.toPlainText()): ar2 = re.split("/", self.meoQEditText.toPlainText()) meo2 = int(ar2[0]) / float(ar2[1]) n += 1 if n != 1: st1 = self.capacityQEditText.toPlainText( ) + " " + self.alreadyPresentpeopleQEditText.toPlainText( ) + " " + self.nServersQEditText.toPlainText( ) + " " + self.timeQEditText.toPlainText() else: st1 = self.lambdaQEditText.toPlainText( ) + " " + self.capacityQEditText.toPlainText( ) + " " + self.alreadyPresentpeopleQEditText.toPlainText( ) + " " + self.nServersQEditText.toPlainText( ) + " " + self.timeQEditText.toPlainText() ar1 = re.search(r"[^\d\s.//]", st1) ar = re.findall(r"([0-9]+\.[0-9]+)|(\.[0-9]+)|([0-9]+)", st1) flag = 0 if (self.alreadyPresentpeopleQEditText.toPlainText() == self.capacityQEditText.toPlainText()): if (self.alreadyPresentpeopleQEditText.toPlainText() != "0"): flag = 1 if (len(ar) + n == 6 and ar1 == None and flag == 0): if lam2 == 0: lam2 = float(self.lambdaQEditText.toPlainText()) if meo2 == 0: meo2 = float(self.meoQEditText.toPlainText()) deter = QueueOperations.Deter( lam2, meo2, int(self.capacityQEditText.toPlainText()), int(self.alreadyPresentpeopleQEditText.toPlainText())) deter.tI() if (self.alreadyPresentpeopleQEditText.toPlainText() == "0" and self.capacityQEditText.toPlainText() == "0"): deter.ti = 0 self.resultLabel.setGeometry((self.width() / 2) - 70, 470, 300, 70) st = "Ti: " + "0" + ", n(" + self.timeQEditText.toPlainText( ) + "): " + str( deter.nTCase(float(self.timeQEditText.toPlainText()))) else: st = "Ti: " + str( deter.ti) + ", n(" + self.timeQEditText.toPlainText( ) + "): " + str( deter.nTCase(float(self.timeQEditText.toPlainText())) ) + ", Wqn(" + self.nServersQEditText.toPlainText( ) + "): " + str( deter.wqN(int(self.nServersQEditText.toPlainText()))) self.resultLabel.setText(st) self.drawButton.setVisible(True) self.resultLabel.setVisible(True) else: self.resultLabel.setGeometry((self.width() / 2) - 60, 480, 200, 100) self.resultLabel.setText("Invalid Input") self.drawButton.setVisible(False) self.resultLabel.setVisible(True) def initUi(self): self.lambdaLabel = QLabel('λ : ', self) self.lambdaLabel.setFont(QFont('Sanserif', 16)) self.lambdaLabel.move(100, 100) self.lambdaLabel.adjustSize() self.lambdaQEditText = QTextEdit(self) self.lambdaQEditText.setGeometry(140, 90, 200, 50) self.lambdaQEditText.setStyleSheet( "border: 1px solid; border-radius:15px; background-color: palette(base); " ) self.lambdaQEditText.setFont(QFont('Sanserif', 13)) self.lambdaQEditText.setAlignment(Qt.AlignCenter) self.lambdaQEditText.setPlaceholderText('arrival rate..') self.lambdaQEditText.setTextColor(QColor(255, 0, 0)) self.meoLabel = QLabel('μ : ', self) self.meoLabel.setFont(QFont('Sanserif', 16)) self.meoLabel.move(600, 100) self.meoLabel.adjustSize() self.meoQEditText = QTextEdit(self) self.meoQEditText.setGeometry(640, 90, 200, 50) self.meoQEditText.setStyleSheet( "border: 1px solid; border-radius:15px; background-color: palette(base); " ) self.meoQEditText.setFont(QFont('Sanserif', 13)) self.meoQEditText.setAlignment(Qt.AlignCenter) self.meoQEditText.setPlaceholderText('service rate..') self.meoQEditText.setTextColor(QColor(0, 0, 255)) self.nServersLabel = QLabel('n : ', self) self.nServersLabel.setFont(QFont('Sanserif', 16)) self.nServersLabel.move(350, 200) self.nServersLabel.adjustSize() self.nServersQEditText = QTextEdit(self) self.nServersQEditText.setGeometry(390, 190, 200, 50) self.nServersQEditText.setStyleSheet( "border: 1px solid; border-radius:15px; background-color: palette(base); " ) self.nServersQEditText.setFont(QFont('Sanserif', 13)) self.nServersQEditText.setAlignment(Qt.AlignCenter) self.nServersQEditText.setPlaceholderText('waiting for n..') self.nServersQEditText.setTextColor(QColor(0, 255, 0)) self.timeLabel = QLabel('t : ', self) self.timeLabel.setFont(QFont('Sanserif', 16)) self.timeLabel.move(100, 300) self.timeLabel.adjustSize() self.timeQEditText = QTextEdit(self) self.timeQEditText.setGeometry(140, 290, 200, 50) self.timeQEditText.setStyleSheet( "border: 1px solid; border-radius:15px; background-color: palette(base); " ) self.timeQEditText.setFont(QFont('Sanserif', 13)) self.timeQEditText.setAlignment(Qt.AlignCenter) self.timeQEditText.setPlaceholderText('enter the time..') self.timeQEditText.setTextColor(QColor(255, 0, 0)) self.capacityLabel = QLabel('k : ', self) self.capacityLabel.setFont(QFont('Sanserif', 16)) self.capacityLabel.move(600, 300) self.capacityLabel.adjustSize() self.capacityQEditText = QTextEdit(self) self.capacityQEditText.setGeometry(640, 290, 200, 50) self.capacityQEditText.setStyleSheet( "border: 1px solid; border-radius:15px; background-color: palette(base); " ) self.capacityQEditText.setFont(QFont('Sanserif', 13)) self.capacityQEditText.setAlignment(Qt.AlignCenter) self.capacityQEditText.setPlaceholderText('Capacity..') self.capacityQEditText.setTextColor(QColor(0, 0, 255)) self.alreadyPresentpeopleLabel = QLabel('M : ', self) self.alreadyPresentpeopleLabel.setFont(QFont('Sanserif', 16)) self.alreadyPresentpeopleLabel.move(350, 400) self.alreadyPresentpeopleLabel.adjustSize() self.alreadyPresentpeopleQEditText = QTextEdit(self) self.alreadyPresentpeopleQEditText.setGeometry(400, 390, 200, 50) self.alreadyPresentpeopleQEditText.setStyleSheet( "border: 1px solid; border-radius:15px; background-color: palette(base); " ) self.alreadyPresentpeopleQEditText.setFont(QFont('Sanserif', 13)) self.alreadyPresentpeopleQEditText.setAlignment(Qt.AlignCenter) self.alreadyPresentpeopleQEditText.setPlaceholderText( 'peresent people..') self.alreadyPresentpeopleQEditText.setTextColor(QColor(0, 255, 0)) self.submitButton = QPushButton('Submit', self) self.submitButton.setFont(QFont('Sanserif', 14)) self.submitButton.setStyleSheet( 'color:white;background-color:firebrick;border: 0px solid; border-radius:15px' ) self.submitButton.move((self.width() / 2) - 50, 460) self.submitButton.clicked.connect(self.handleSubmit) #out Label................ self.resultLabel = QLabel( '.............................................................', self) self.resultLabel.setFont(QFont('Sanserif', 14)) self.resultLabel.setStyleSheet('color:magenta') self.resultLabel.adjustSize() self.resultLabel.setVisible(False) # self.resultLabel.move((self.width()/2)-250,500) self.resultLabel.setGeometry((self.width() / 2) - 140, 470, 340, 70) self.drawButton = QPushButton('Draw', self) self.drawButton.setFont(QFont('Sanserif', 14)) self.drawButton.setStyleSheet( 'color:white;background-color:dodgerblue;border: 0px solid; border-radius:15px' ) self.drawButton.move((self.width() / 2) - 50, 550) self.drawButton.setVisible(False) self.drawButton.clicked.connect(self.showGraph) def createBackArrow(self): icon1 = QIcon('arrow_back.png') label1 = QLabel('Sample', self) pixmap1 = icon1.pixmap(20, 20, QIcon.Active, QIcon.On) label1.setPixmap(pixmap1) label1.move(25, 25) label1.adjustSize() label1.mousePressEvent = self.arrowbackClicked def arrowbackClicked(self, event): print('arrow back clicked') self.main = main.MainWindow() self.main.show() self.destroy() def center(self): qRect = self.frameGeometry() centerpoint = QDesktopWidget().availableGeometry().center() qRect.moveCenter(centerpoint) self.move(qRect.topLeft()) def setIcon(self): appIcon = QIcon('line.png') self.setWindowIcon(appIcon) def closeEvent(self, event): userInfo = QMessageBox.question(self, 'Closing ?', 'Do u want to quit ?', QMessageBox.Yes | QMessageBox.No) if userInfo == QMessageBox.Yes: event.accept() self.close() sys.exit(QApplication(sys.argv).exec_()) elif userInfo == QMessageBox.No: event.ignore() def showGraph(self): λ = 1 / 3 global deter arr = [deter.nTCase(n) for n in range(deter.ti + 40)] x = np.array(arr) m = int(self.alreadyPresentpeopleQEditText.toPlainText()) k = int(self.capacityQEditText.toPlainText()) names = [f'c{n}' for n in range(23)] #if m==0 and k!=0: # arrival=[n for n in range(int(1/deter.lambdda),(deter.ti)+((int(1/deter.lambdda))*5),int(1/deter.lambdda))] #else: # arrival=[n for n in range(0,(deter.ti)+((int(1/deter.lambdda))*5),int(1/deter.lambdda))] arrival = [ n for n in range(int(1 / deter.lambdda), (deter.ti) + ( (int(1 / deter.lambdda)) * 5), int(1 / deter.lambdda)) ] departures = [] if int(self.alreadyPresentpeopleQEditText.toPlainText()) == 0: if (self.capacityQEditText.toPlainText() == "0"): for n in range( int(1 / deter.lambdda) + 1, (deter.ti) + ((int(1 / deter.lambdda)) * 5)): if deter.is_departure(n): departures.append(n) else: for n in range( int(1 / deter.lambdda) + 1, (deter.ti) + ((int(1 / deter.lambdda)) * 5)): if deter.is_departure(n) and n < deter.ti: departures.append(n) if n > deter.ti and n % int(1 / deter.lambdda) == 0: departures.append(n) else: for n in range(0, (deter.ti) + ((int(1 / deter.lambdda)) * 5)): if m > 0: print(m) departures.append(n) m -= int(1 / deter.meu) if n % int(1 / deter.lambdda) == 0: m += 1 dates = [n // 2 for n in range(46)] x_values = arrival + departures y_values = [2 for n in range(len(arrival)) ] + [-2 for n in range(len(departures))] labels = [f'c{n}' for n in range(1, len(arrival))] levels = np.tile([4, 4, -5], int(np.ceil(len(dates) / 3)))[:len(dates)] # Create figure and plot a stem plot with the date fig, (ax, ax2) = plt.subplots(2, figsize=(23, 23)) ax.set(title="customers arrival and departure", xlabel="('time in seconds')") ax.vlines(x_values, 0, y_values, color="tab:blue") # The vertical stems. ax.xaxis.set_ticks(np.arange(min(x_values), max(x_values) + 1, 1.0)) ax.plot(x_values, np.zeros_like(x_values), "-o", color="k", markerfacecolor="w") # Baseline and markers on it. # annotate lines for d, l, r in zip(x_values, y_values, labels): ax.annotate(r, xy=(d, l), xytext=(-3, np.sign(l) * 3), textcoords="offset points", horizontalalignment="center", verticalalignment="bottom" if l > 0 else "top") # remove y axis and spines ax.get_yaxis().set_visible(False) # for spine in ["left", "top", "right"]: # ax.spines[spine].set_visible(False) ax.margins(y=0.2) ax2.step(range(deter.ti + 40), x, where='post') ax2.set(ylabel='number of customers', xlabel='time in seconds', title='number of custorms at each second') plt.grid(axis='x', color='0.95') plt.show() plt.show()
def _initalize_image_widgets(file_date, band, dtype): """Set up the various QT widgets used to display the plot""" # Set up display widgets try: QApplication(sys.argv + ['-platform', 'offscreen']) # So we can make widgets :) except RuntimeError as err: if "singleton" not in str(err): raise pg.setConfigOptions(background='#EEE', foreground='k') scale_font = QFont("Arial", 10) disp_widget = QWidget() disp_widget.setStyleSheet( 'background-color:rgba(0,255,0,255);padding:0px;margin:0px;') v_layout = QVBoxLayout() v_layout.setContentsMargins(0, 0, 0, 0) v_layout.setSpacing(0) view_box = pg.ViewBox(border={'width': 0}, ) plot_widget = pg.PlotWidget(disp_widget, viewBox=view_box) scale_widget = GradientWidget() scale_widget.setOrientation("Horizontal") scale_widget.setFont(scale_font) scale_widget.setStyleSheet("background-color:white;") scale_widget.setFixedWidth(950) date_label = QLabel() if band is None: band = "Cloud" date_label.setText( f"{file_date.strftime('%Y-%m-%d %H:%M:%S')} UTC {dtype} {band}") date_label.setStyleSheet( 'color:#eee; background-color:rgba(0, 0, 0, 0.4); padding:2px 7px;') date_label_font = date_label.font() date_label_font.setPointSize(9) date_label.setFont(date_label_font) date_label.adjustSize() v_layout.addWidget(plot_widget) disp_widget.setLayout(v_layout) plot_item = plot_widget.getPlotItem() plot_item.hideAxis('left') plot_item.hideAxis('bottom') plot_item.hideButtons() img_width = 1000 img_height = 800 view_size = QSize(img_width, img_height) view_widget = plot_item.getViewWidget() view_widget.parent().setFixedSize(view_size) view_widget.adjustSize() return (plot_item, scale_widget, disp_widget, date_label)
class ViolinGUI(QMainWindow): """Main Window Widget for ViolinGUI.""" style = { 'title': 'QLabel {font-size: 18pt; font-weight: 600}', 'header': 'QLabel {font-size: 12pt; font-weight: 520}', 'label': 'QLabel {font-size: 10pt}', 'button': 'QPushButton {font-size: 10pt}', 'run button': 'QPushButton {font-size: 18pt; font-weight: 600}', 'line edit': 'QLineEdit {font-size: 10pt}', 'checkbox': 'QCheckBox {font-size: 10pt}', 'drop down': 'QComboBox {font-size: 10pt}' } def __init__(self) -> None: """ViolinGUI Constructor. Defines all aspects of the GUI.""" # ## Setup section # Inherits from QMainWindow super().__init__() self.rootdir = get_project_root() # QMainWindow basic properties self.setWindowTitle("SCOUTS - Violins") self.setWindowIcon( QIcon( os.path.abspath(os.path.join(self.rootdir, 'src', 'scouts.ico')))) # Creates QWidget as QMainWindow's central widget self.page = QWidget(self) self.setCentralWidget(self.page) # Miscellaneous initialization values self.threadpool = QThreadPool() # Threadpool for workers self.population_df = None # DataFrame of whole population (raw data) self.summary_df = None # DataFrame indicating which SCOUTS output corresponds to which rule self.summary_path = None # path to all DataFrames generated by SCOUTS self.main_layout = QVBoxLayout(self.page) # Title section # Title self.title = QLabel(self.page) self.title.setText('SCOUTS - Violins') self.title.setStyleSheet(self.style['title']) self.title.adjustSize() self.main_layout.addWidget(self.title) # ## Input section # Input header self.input_header = QLabel(self.page) self.input_header.setText('Load data') self.input_header.setStyleSheet(self.style['header']) self.input_header.adjustSize() self.main_layout.addWidget(self.input_header) # Input/Output frame self.input_frame = QFrame(self.page) self.input_frame.setFrameShape(QFrame.StyledPanel) self.input_frame.setLayout(QFormLayout()) self.main_layout.addWidget(self.input_frame) # Raw data button self.input_button = QPushButton(self.page) self.input_button.setStyleSheet(self.style['button']) self.set_icon(self.input_button, 'x-office-spreadsheet') self.input_button.setObjectName('file') self.input_button.setText(' Load raw data file') self.input_button.setToolTip( 'Load raw data file (the file given to SCOUTS as the input file)') self.input_button.clicked.connect(self.get_path) # SCOUTS results button self.output_button = QPushButton(self.page) self.output_button.setStyleSheet(self.style['button']) self.set_icon(self.output_button, 'folder') self.output_button.setObjectName('folder') self.output_button.setText(' Load SCOUTS results') self.output_button.setToolTip( 'Load data from SCOUTS analysis ' '(the folder given to SCOUTS as the output folder)') self.output_button.clicked.connect(self.get_path) # Add widgets above to input frame Layout self.input_frame.layout().addRow(self.input_button) self.input_frame.layout().addRow(self.output_button) # ## Samples section # Samples header self.samples_header = QLabel(self.page) self.samples_header.setText('Select sample names') self.samples_header.setStyleSheet(self.style['header']) self.samples_header.adjustSize() self.main_layout.addWidget(self.samples_header) # Samples frame self.samples_frame = QFrame(self.page) self.samples_frame.setFrameShape(QFrame.StyledPanel) self.samples_frame.setLayout(QFormLayout()) self.main_layout.addWidget(self.samples_frame) # Samples label self.samples_label = QLabel(self.page) self.samples_label.setText( 'Write sample names delimited by semicolons below.\nEx: Control;Treat_01;Pac-03' ) self.samples_label.setStyleSheet(self.style['label']) # Sample names line edit self.sample_names = QLineEdit(self.page) self.sample_names.setStyleSheet(self.style['line edit']) # Add widgets above to samples frame Layout self.samples_frame.layout().addRow(self.samples_label) self.samples_frame.layout().addRow(self.sample_names) # ## Analysis section # Analysis header self.analysis_header = QLabel(self.page) self.analysis_header.setText('Plot parameters') self.analysis_header.setStyleSheet(self.style['header']) self.analysis_header.adjustSize() self.main_layout.addWidget(self.analysis_header) # Analysis frame self.analysis_frame = QFrame(self.page) self.analysis_frame.setFrameShape(QFrame.StyledPanel) self.analysis_frame.setLayout(QFormLayout()) self.main_layout.addWidget(self.analysis_frame) # Analysis labels self.analysis_label_01 = QLabel(self.page) self.analysis_label_01.setText('Compare') self.analysis_label_01.setStyleSheet(self.style['label']) self.analysis_label_02 = QLabel(self.page) self.analysis_label_02.setText('with') self.analysis_label_02.setStyleSheet(self.style['label']) self.analysis_label_03 = QLabel(self.page) self.analysis_label_03.setText('for marker') self.analysis_label_03.setStyleSheet(self.style['label']) self.analysis_label_04 = QLabel(self.page) self.analysis_label_04.setText('Outlier type') self.analysis_label_04.setStyleSheet(self.style['label']) # Analysis drop-down boxes self.drop_down_01 = QComboBox(self.page) self.drop_down_01.addItems([ 'whole population', 'non-outliers', 'top outliers', 'bottom outliers', 'none' ]) self.drop_down_01.setStyleSheet(self.style['drop down']) self.drop_down_01.setCurrentIndex(2) self.drop_down_02 = QComboBox(self.page) self.drop_down_02.addItems([ 'whole population', 'non-outliers', 'top outliers', 'bottom outliers', 'none' ]) self.drop_down_02.setStyleSheet(self.style['drop down']) self.drop_down_02.setCurrentIndex(0) self.drop_down_03 = QComboBox(self.page) self.drop_down_03.setStyleSheet(self.style['drop down']) self.drop_down_04 = QComboBox(self.page) self.drop_down_04.addItems(['OutS', 'OutR']) self.drop_down_04.setStyleSheet(self.style['drop down']) # Add widgets above to samples frame Layout self.analysis_frame.layout().addRow(self.analysis_label_01, self.drop_down_01) self.analysis_frame.layout().addRow(self.analysis_label_02, self.drop_down_02) self.analysis_frame.layout().addRow(self.analysis_label_03, self.drop_down_03) self.analysis_frame.layout().addRow(self.analysis_label_04, self.drop_down_04) self.legend_checkbox = QCheckBox(self.page) self.legend_checkbox.setText('Add legend to the plot') self.legend_checkbox.setStyleSheet(self.style['checkbox']) self.main_layout.addWidget(self.legend_checkbox) # Plot button (stand-alone) self.plot_button = QPushButton(self.page) self.set_icon(self.plot_button, 'system-run') self.plot_button.setText(' Plot') self.plot_button.setToolTip( 'Plot data after loading the input data and selecting parameters') self.plot_button.setStyleSheet(self.style['run button']) self.plot_button.setEnabled(False) self.plot_button.clicked.connect(self.run_plot) self.main_layout.addWidget(self.plot_button) # ## Secondary Window # This is used to plot the violins only self.secondary_window = QMainWindow(self) self.secondary_window.resize(720, 720) self.dynamic_canvas = DynamicCanvas(self.secondary_window, width=6, height=6, dpi=120) self.secondary_window.setCentralWidget(self.dynamic_canvas) self.secondary_window.addToolBar( NavBar(self.dynamic_canvas, self.secondary_window)) def set_icon(self, widget: QWidget, icon: str) -> None: """Associates an icon to a widget.""" i = QIcon() i.addPixmap( QPixmap( os.path.abspath( os.path.join(self.rootdir, 'src', 'default_icons', f'{icon}.svg')))) widget.setIcon(QIcon.fromTheme(icon, i)) def get_path(self) -> None: """Opens a dialog box and loads the corresponding data into memory, depending on the caller widget.""" options = QFileDialog.Options() options |= QFileDialog.DontUseNativeDialog query = None func = None if self.sender().objectName() == 'file': query, _ = QFileDialog.getOpenFileName(self, "Select file", "", "All Files (*)", options=options) func = self.load_scouts_input_data elif self.sender().objectName() == 'folder': query = QFileDialog.getExistingDirectory(self, "Select Directory", options=options) func = self.load_scouts_results if query: self.load_data(query, func) def load_data(self, query: str, func: Callable) -> None: """Loads input data into memory, while displaying a loading message as a separate worker.""" worker = Worker(func=func, query=query) message = self.loading_message() worker.signals.started.connect(message.show) worker.signals.started.connect(self.page.setDisabled) worker.signals.error.connect(self.generic_error_message) worker.signals.error.connect(message.destroy) worker.signals.failed.connect(self.plot_button.setDisabled) worker.signals.success.connect(message.destroy) worker.signals.success.connect(self.enable_plot) worker.signals.finished.connect(self.page.setEnabled) self.threadpool.start(worker) def loading_message(self) -> QDialog: """Returns the message box to be displayed while the user waits for the input data to load.""" message = QDialog(self) message.setWindowTitle('Loading') message.resize(300, 50) label = QLabel('loading DataFrame into memory...', message) label.setStyleSheet(self.style['label']) label.adjustSize() label.setAlignment(Qt.AlignCenter) label.move(int((message.width() - label.width()) / 2), int((message.height() - label.height()) / 2)) return message def load_scouts_input_data(self, query: str) -> None: """Loads data for whole population prior to SCOUTS into memory (used for plotting the whole population).""" try: self.population_df = pd.read_excel(query, index_col=0) except XLRDError: self.population_df = pd.read_csv(query, index_col=0) self.drop_down_03.clear() self.drop_down_03.addItems(list(self.population_df.columns)) self.drop_down_03.setCurrentIndex(0) def load_scouts_results(self, query: str) -> None: """Loads the SCOUTS summary file into memory, in order to dynamically locate SCOUTS output files later when the user chooses which data to plot.""" self.summary_df = pd.read_excel(os.path.join(query, 'summary.xlsx'), index_col=None) self.summary_path = query def enable_plot(self) -> None: """Enables plot button if all necessary files are placed in memory.""" if isinstance(self.summary_df, pd.DataFrame) and isinstance( self.population_df, pd.DataFrame): self.plot_button.setEnabled(True) def run_plot(self) -> None: """Sets and starts the plot worker.""" worker = Worker(func=self.plot) worker.signals.error.connect(self.generic_error_message) worker.signals.success.connect(self.secondary_window.show) self.threadpool.start(worker) def plot(self) -> None: """Logic for plotting data based on user selection of populations, markers, etc.""" # Clear figure currently on plot self.dynamic_canvas.axes.cla() # Initialize values and get parameters from GUI columns = ['sample', 'marker', 'population', 'expression'] samples = self.parse_sample_names() pop_01 = self.drop_down_01.currentText() pop_02 = self.drop_down_02.currentText() pops_to_analyse = [pop_01, pop_02] marker = self.drop_down_03.currentText() cutoff_from_reference = True if self.drop_down_04.currentText( ) == 'OutR' else False violin_df = pd.DataFrame(columns=columns) # Start fetching data from files # Whole population for pop in pops_to_analyse: if pop == 'whole population': for partial_df in self.yield_violin_values( df=self.population_df, population='whole population', samples=samples, marker=marker, columns=columns): violin_df = violin_df.append(partial_df) # Other comparisons elif pop != 'none': for file_number in self.yield_selected_file_numbers( summary_df=self.summary_df, population=pop, cutoff_from_reference=cutoff_from_reference, marker=marker): df_path = os.path.join(self.summary_path, 'data', f'{"%04d" % file_number}.') try: sample_df = pd.read_excel(df_path + 'xlsx', index_col=0) except FileNotFoundError: sample_df = pd.read_csv(df_path + 'csv', index_col=0) if not sample_df.empty: for partial_df in self.yield_violin_values( df=sample_df, population=pop, samples=samples, marker=marker, columns=columns): violin_df = violin_df.append(partial_df) # Plot data pops_to_analyse = [p for p in pops_to_analyse if p != 'none'] violin_df = violin_df[violin_df['marker'] == marker] for pop in pops_to_analyse: pop_subset = violin_df.loc[violin_df['population'] == pop] for sample in samples: sample_subset = pop_subset.loc[pop_subset['sample'] == sample] sat = 1.0 - samples.index(sample) / (len(samples) + 1) self.dynamic_canvas.update_figure( subset_by_sample=sample_subset, pop=pop, sat=sat, samples=samples) # Draw plotted data on canvas if self.legend_checkbox.isChecked(): self.dynamic_canvas.add_legend() self.dynamic_canvas.axes.set_title( f'{marker} expression - {self.drop_down_04.currentText()}') self.dynamic_canvas.fig.canvas.draw() def parse_sample_names(self) -> List[str]: """Parse sample names from the QLineEdit Widget.""" return self.sample_names.text().split(';') def generic_error_message(self, error: Tuple[Exception, str]) -> None: """Error message box used to display any error message (including traceback) for any uncaught errors.""" name, trace = error QMessageBox.critical( self, 'An error occurred!', f"Error: {str(name)}\n\nfull traceback:\n{trace}") def closeEvent(self, event: QEvent) -> None: """Defines the message box for when the user wants to quit ViolinGUI.""" title = 'Quit Application' mes = "Are you sure you want to quit?" reply = QMessageBox.question(self, title, mes, QMessageBox.Yes | QMessageBox.No, QMessageBox.No) if reply == QMessageBox.Yes: self.setEnabled(False) self.threadpool.waitForDone() event.accept() else: event.ignore() @staticmethod def yield_violin_values(df: pd.DataFrame, population: str, samples: List[str], marker: str, columns: List[str]) -> pd.DataFrame: """Returns a DataFrame from expression values, along with information of sample, marker and population. This DataFrame is appended to the violin plot DataFrame in order to simplify plotting the violins afterwards.""" for sample in samples: series = df.loc[df.index.str.contains(sample)].loc[:, marker] yield pd.DataFrame( { 'sample': sample, 'marker': marker, 'population': population, 'expression': series }, columns=columns) @staticmethod def yield_selected_file_numbers( summary_df: pd.DataFrame, population: str, cutoff_from_reference: bool, marker: str) -> Generator[pd.DataFrame, None, None]: """Yields file numbers from DataFrames resulting from SCOUTS analysis. DataFrames are yielded based on global values, i.e. the comparisons the user wants to perform.""" cutoff = 'sample' if cutoff_from_reference is True: cutoff = 'reference' for index, (file_number, cutoff_from, reference, outliers_for, category) in summary_df.iterrows(): if cutoff_from == cutoff and outliers_for == marker and category == population: yield file_number