def __init__(self, parent=None): super().__init__(parent, Qt.CustomizeWindowHint | Qt.FramelessWindowHint | Qt.Window | Qt.WindowStaysOnTopHint | Qt.X11BypassWindowManagerHint) self.setAttribute(Qt.WA_DeleteOnClose) self.installEventFilter(self) self.setMouseTracking(True) self._band = QRubberBand(QRubberBand.Rectangle, self) self._resize_origin = None self._drag_mask = 0 self._origin = None self.selected_image = None # Window background desktop = QApplication.desktop() if is_qt5(): g = desktop.geometry() self._snapshot = QPixmap(g.width(), g.height()) painter = QPainter(self._snapshot) for screen in QApplication.screens(): g = screen.geometry() painter.drawPixmap(g, screen.grabWindow(0, g.x(), g.y(), g.width(), g.height())) painter.end() else: self._snapshot = QPixmap.grabWindow(desktop.winId(), 0, 0, desktop.width(), desktop.height()) self.setGeometry(desktop.geometry()) self._darken = self._snapshot.copy() painter = QPainter(self._darken) brush = QBrush(QColor(0, 0, 0, 128)) painter.setBrush(brush) painter.drawRect(self._darken.rect()) painter.end() # Buttons self._buttons = QWidget(self) self._button_layout = QHBoxLayout(self._buttons) self._button_layout.setSpacing(0) self._button_layout.setContentsMargins(0, 0, 0, 0) self._button_layout.setContentsMargins(0, 0, 0, 0) self.save_as = QPushButton(self.tr('Save As')) self.save_as.pressed.connect(self.save_image_as) self.save_as.setCursor(Qt.ArrowCursor) self._button_layout.addWidget(self.save_as) self.copy = QPushButton(self.tr('Copy')) self.copy.pressed.connect(self.copy_to_clipboard) self.copy.setCursor(Qt.ArrowCursor) self._button_layout.addWidget(self.copy) self.share = QPushButton(self.tr('Share')) self.share.pressed.connect(self.share_selection) self.share.setCursor(Qt.ArrowCursor) self._button_layout.addWidget(self.share) self._buttons.hide()
def __init__(self, parent=None, acceptDrops=True, **kwargs): super().__init__(parent, acceptDrops=acceptDrops, **kwargs) self.setLayout(QVBoxLayout()) self.addonwidget = AddonManagerWidget() self.addonwidget.layout().setContentsMargins(0, 0, 0, 0) self.layout().addWidget(self.addonwidget) buttons = QDialogButtonBox( orientation=Qt.Horizontal, standardButtons=QDialogButtonBox.Ok | QDialogButtonBox.Cancel, ) addmore = QPushButton( "Add more...", toolTip="Add an add-on not listed below", autoDefault=False ) self.addonwidget.tophlayout.addWidget(addmore) addmore.clicked.connect(self.__run_add_package_dialog) buttons.accepted.connect(self.__accepted) buttons.rejected.connect(self.reject) self.layout().addWidget(buttons) self.__progress = None # type: Optional[QProgressDialog] self.__executor = ThreadPoolExecutor(max_workers=1) # The installer thread self.__thread = None # The installer object self.__installer = None self.__add_package_by_name_dialog = None # type: Optional[QDialog]
def add_row(self, attr=None, condition_type=None, condition_value=None): model = self.cond_list.model() row = model.rowCount() model.insertRow(row) attr_combo = gui.OrangeComboBox( minimumContentsLength=12, sizeAdjustPolicy=QComboBox.AdjustToMinimumContentsLengthWithIcon, ) attr_combo.row = row for var in self._visible_variables(self.data.domain): attr_combo.addItem(*gui.attributeItem(var)) attr_combo.setCurrentIndex(attr or 0) self.cond_list.setCellWidget(row, 0, attr_combo) index = QPersistentModelIndex(model.index(row, 3)) temp_button = QPushButton( "×", self, flat=True, styleSheet="* {font-size: 16pt; color: silver}" "*:hover {color: black}", ) temp_button.clicked.connect(lambda: self.remove_one(index.row())) self.cond_list.setCellWidget(row, 3, temp_button) self.remove_all_button.setDisabled(False) self.set_new_operators(attr_combo, attr is not None, condition_type, condition_value) attr_combo.currentIndexChanged.connect( lambda _: self.set_new_operators(attr_combo, False)) self.cond_list.resizeRowToContents(row)
def __init__(self): self.data = None self.plots = [] self.configs = [] self.forecasts = OrderedDict() self.varmodel = VariableListModel(parent=self) icon = QIcon(join(dirname(__file__), 'icons', 'LineChart-plus.png')) self.add_button = button = QPushButton(icon, ' &Add plot', self) button.clicked.connect(self.add_plot) self.controlArea.layout().addWidget(button) self.configsArea = gui.vBox(self.controlArea) self.controlArea.layout().addStretch(1) # TODO: allow selecting ranges that are sent to output as subset table self.chart = highstock = Highstock(self, highchart='StockChart') self.mainArea.layout().addWidget(highstock) # highstock.evalJS('Highcharts.setOptions({navigator: {enabled:false}});') highstock.chart( # For some reason, these options don't work as global opts applied at Highstock init time # Disable top range selector rangeSelector_enabled=False, rangeSelector_inputEnabled=False, # Disable bottom miniview navigator (it doesn't update) navigator_enabled=False, ) QTimer.singleShot(0, self.add_plot) self.chart.add_legend()
def add_row(self, attr=None, condition_type=None, condition_value=None): model = self.cond_list.model() row = model.rowCount() model.insertRow(row) attr_combo = ComboBoxSearch( minimumContentsLength=12, sizeAdjustPolicy=QComboBox.AdjustToMinimumContentsLengthWithIcon) attr_combo.setModel(self.variable_model) attr_combo.row = row attr_combo.setCurrentIndex(self.variable_model.indexOf(attr) if attr else len(self.AllTypes) + 1) self.cond_list.setCellWidget(row, 0, attr_combo) index = QPersistentModelIndex(model.index(row, 3)) temp_button = QPushButton('×', self, flat=True, styleSheet='* {font-size: 16pt; color: silver}' '*:hover {color: black}') temp_button.clicked.connect(lambda: self.remove_one(index.row())) self.cond_list.setCellWidget(row, 3, temp_button) self.remove_all_button.setDisabled(False) self.set_new_operators(attr_combo, attr is not None, condition_type, condition_value) attr_combo.currentIndexChanged.connect( lambda _: self.set_new_operators(attr_combo, False)) self.cond_list.resizeRowToContents(row)
def _setup_layout(self): self.controlArea.setMinimumWidth(self.controlArea.sizeHint().width()) self.layout().setSizeConstraint(QLayout.SetFixedSize) widget_box = widgetBox(self.controlArea, 'Info') self.input_data_info = widgetLabel(widget_box, self._NO_DATA_INFO_TEXT) self.connection_info = widgetLabel(widget_box, "") widget_box = widgetBox(self.controlArea, 'Settings') self.cb_image_attr = comboBox(widget=widget_box, master=self, value='cb_image_attr_current_id', label='Image attribute:', orientation=Qt.Horizontal, callback=self._cb_image_attr_changed) self.cb_embedder = comboBox(widget=widget_box, master=self, value='cb_embedder_current_id', label='Embedder:', orientation=Qt.Horizontal, callback=self._cb_embedder_changed) self.cb_embedder.setModel( VariableListModel( [EMBEDDERS_INFO[e]['name'] for e in self.embedders])) if not self.cb_embedder_current_id < len(self.embedders): self.cb_embedder_current_id = 0 self.cb_embedder.setCurrentIndex(self.cb_embedder_current_id) current_embedder = self.embedders[self.cb_embedder_current_id] self.embedder_info = widgetLabel( widget_box, EMBEDDERS_INFO[current_embedder]['description']) self.auto_commit_widget = auto_commit(widget=self.controlArea, master=self, value='_auto_apply', label='Apply', commit=self.commit) self.cancel_button = QPushButton( 'Cancel', icon=self.style().standardIcon(QStyle.SP_DialogCancelButton), ) self.cancel_button.clicked.connect(self.cancel) hbox = hBox(self.controlArea) hbox.layout().addWidget(self.cancel_button) self.cancel_button.hide()
def __init__(self, parent=None): super(FileUploadHelper, self).__init__( parent, Qt.Window | Qt.WindowTitleHint | Qt.CustomizeWindowHint | Qt.WindowCloseButtonHint | Qt.WindowMaximizeButtonHint) self.setAttribute(Qt.WA_DeleteOnClose) self.setWindowTitle('Add new file') self.info_state = INFO_FILE_SCHEMA self.layout = QVBoxLayout(self) # domain selection combobox self.domain_selection = QComboBox() self.domain_selection.addItems(self.supported_domains.keys()) self.domain_selection.currentIndexChanged.connect( self.__on_domain_selection) self.__create_selection_row('Domain: ', self.domain_selection) # domain selection combobox self.hierarchy_selection = QComboBox() self.hierarchy_selection.addItems(self.hierarchies.keys()) self.layout.addWidget(self.hierarchy_selection, alignment=Qt.AlignVCenter) self.__on_domain_selection() # select organism self.organism_selection = QComboBox() self.organism_selection.addItems(self.supported_organisms) self.__create_selection_row('Organism: ', self.organism_selection) # title self.line_edit_title = QLineEdit() self.__create_selection_row('Title: ', self.line_edit_title) # tags self.line_edit_tags = QLineEdit() self.__create_selection_row('Tags (comma-separated): ', self.line_edit_tags) # file selector self.file_info = QLabel() self.file_select_btn = QPushButton('Select File', self) self.file_select_btn.clicked.connect(self.__handle_file_selector) self.__create_selection_row(' ', self.file_select_btn) # add file info section self.layout.addWidget(self.file_info, alignment=Qt.AlignCenter) self.layout.addStretch(1) # Ok and Cancel buttons self.buttons = QDialogButtonBox( QDialogButtonBox.Ok | QDialogButtonBox.Cancel, Qt.Horizontal, self) self.layout.addWidget(self.buttons, alignment=Qt.AlignJustify) self.buttons.accepted.connect(self.__accept) self.buttons.rejected.connect(self.__close) # path to a selected file self.file_path = None
def addButton(self, button, *rolearg): """ addButton(QAbstractButton, ButtonRole) addButton(str, ButtonRole) addButton(StandardButton) Add and return a button """ stdbutton = None if isinstance(button, QAbstractButton): if len(rolearg) != 1: raise TypeError( "Wrong number of arguments for " "addButton(QAbstractButton, role)" ) role = rolearg[0] elif isinstance(button, MessageWidget.StandardButton): if len(rolearg) != 0: raise TypeError( "Wrong number of arguments for " "addButton(StandardButton)" ) stdbutton = button if button == MessageWidget.Ok: role = MessageWidget.AcceptRole button = QPushButton("Ok", default=False, autoDefault=False) elif button == MessageWidget.Close: role = MessageWidget.RejectRole # button = QPushButton( # default=False, autoDefault=False, flat=True, # icon=QIcon(self.style().standardIcon( # QStyle.SP_TitleBarCloseButton))) button = SimpleButton( icon=QIcon(self.style().standardIcon(QStyle.SP_TitleBarCloseButton)) ) elif button == MessageWidget.Help: role = MessageWidget.HelpRole button = QPushButton("Help", default=False, autoDefault=False) elif isinstance(button, str): if len(rolearg) != 1: raise TypeError( "Wrong number of arguments for " "addButton(str, ButtonRole)" ) role = rolearg[0] button = QPushButton(button, default=False, autoDefault=False) if sys.platform == "darwin": button.setAttribute(Qt.WA_MacSmallSize) self.__buttons.append(MessageWidget._Button(button, role, stdbutton)) button.clicked.connect(self.__button_clicked) self.__relayout() return button
def __init__(self, master, model): QDialog.__init__(self) self.master = master self.setWindowFlags(Qt.Tool) self.setLayout(QVBoxLayout()) self.setWindowTitle("Hidden Axes") btns_area = gui.widgetBox(self, addSpace=0, spacing=9, orientation=Qt.Horizontal, sizePolicy=QSizePolicy(*SIZE_POLICY_FIXED)) self.btn_add = QPushButton("Add", autoDefault=False, sizePolicy=QSizePolicy(*SIZE_POLICY_FIXED)) self.btn_add.clicked.connect(self._add) self.btn_cancel = QPushButton( "Cancel", autoDefault=False, sizePolicy=QSizePolicy(*SIZE_POLICY_FIXED)) self.btn_cancel.clicked.connect(self._cancel) btns_area.layout().addWidget(self.btn_add) btns_area.layout().addWidget(self.btn_cancel) filter_edit, view = variables_filter(model=model) self.view_other = view view.setMinimumSize(QSize(30, 60)) view.setSizePolicy(*SIZE_POLICY_ADAPTING) view.viewport().setAcceptDrops(True) self.layout().addWidget(filter_edit) self.layout().addWidget(view) self.layout().addWidget(btns_area) master = self.master box = master.box master.master.setEnabled(False) self.move(box.mapToGlobal(QPoint(0, box.pos().y() + box.height()))) self.setFixedWidth(master.master.controlArea.width()) self.setMinimumHeight(300) self.show() self.raise_() self.activateWindow()
def __init__(self): self.data = None self.classifier = None self.selected = None self.model = CustomRuleViewerTableModel(parent=self) self.model.set_horizontal_header_labels([ "IF conditions", "", "THEN class", "Distribution", "Probabilities [%]", "Quality", "Length" ]) self.proxy_model = QSortFilterProxyModel(parent=self) self.proxy_model.setSourceModel(self.model) self.proxy_model.setSortRole(self.model.SortRole) self.view = gui.TableView(self, wordWrap=False) self.view.setModel(self.proxy_model) self.view.verticalHeader().setVisible(True) self.view.horizontalHeader().setStretchLastSection(False) self.view.selectionModel().selectionChanged.connect(self.commit) self.dist_item_delegate = DistributionItemDelegate(self) self.view.setItemDelegateForColumn(3, self.dist_item_delegate) self.mainArea.layout().setContentsMargins(0, 0, 0, 0) self.mainArea.layout().addWidget(self.view) bottom_box = gui.hBox(widget=self.mainArea, box=None, margin=0, spacing=0) original_order_button = QPushButton("Restore original order", autoDefault=False) original_order_button.setFixedWidth(180) bottom_box.layout().addWidget(original_order_button) original_order_button.clicked.connect(self.restore_original_order) gui.separator(bottom_box, width=5, height=0) gui.checkBox(widget=bottom_box, master=self, value="compact_view", label="Compact view", callback=self.on_update) self.report_button.setFixedWidth(180) bottom_box.layout().addWidget(self.report_button)
def __init__(self, flags, *args, **kwargs): super().__init__(flags, *args, **kwargs) self.cm: CredentialManager = CredentialManager(CREDENTIAL_MANAGER_SERVICE) self.setWindowTitle('Sign in') self.setFixedSize(400, 250) self.server_cb_label = QLabel('Server *') self.server_cb = QComboBox(self) self.server_cb.addItems(RESOLWE_URLS) self.server_cb.setEditable(True) self.username_label = QLabel('Username *') self.username_line_edit = QLineEdit(self) self.username_line_edit.setPlaceholderText('Enter correct username') self.username_line_edit.returnPressed.connect(self.sign_in) self.username_line_edit.textChanged.connect(self.handle_sign_in_btn) self.password_label = QLabel('Password *') self.password_line_edit = QLineEdit(self) self.password_line_edit.setPlaceholderText('Enter correct password') self.password_line_edit.returnPressed.connect(self.sign_in) self.password_line_edit.textChanged.connect(self.handle_sign_in_btn) self.password_line_edit.setEchoMode(QLineEdit.Password) self.sign_in_btn = QPushButton('Sign in', self) self.sign_in_btn.setDisabled(True) self.sign_in_btn.clicked.connect(self.sign_in) self.error_msg = QLabel('Unable to log in with provided credentials.') self.error_msg.setStyleSheet('color:red') self.error_msg.hide() layout = QVBoxLayout(self) layout.addWidget(self.server_cb_label) layout.addWidget(self.server_cb) layout.addWidget(self.username_label) layout.addWidget(self.username_line_edit) layout.addWidget(self.password_label) layout.addWidget(self.password_line_edit) layout.addWidget(self.error_msg) layout.addStretch() layout.addWidget(self.sign_in_btn) self.resolwe_instance = None
def __init__(self, parent): super(AddLightUI, self).__init__() self.title = 'Create Lighting Element' self.setLayout(QVBoxLayout(self)) self.parent = parent self.light = Light(name='', outputPin=0, enabled=False, icon=Config.faIcon('lightbulb'), strobe=False) self._nameControl = LineEdit('Name', self) self._nameControl.kb.connect(self.showOSK) self._outputPinControlLabel = QLabel('Output Pin', self) self._outputPinControl = QComboBox(self) for _pin in self.parent.availablePins(): self._outputPinControl.addItem(str(_pin)) self._outputPinControl.setCurrentIndex( self._outputPinControl.findText(str(self.light.outputPin))) self._enabledControl = QCheckBox('Enabled', self) self._iconControlLabel = QLabel('Icon', self) self._iconControl = QComboBox(self) for _key in Config.icons['lights'].keys(): icon = Config.icon('lights', _key) self._iconControl.addItem(icon['name'], _key) self._iconControl.setItemIcon(self._iconControl.count() - 1, QIcon(icon['path'])) self._strobeControl = QCheckBox('Strobe', self) self._addLightBtn = QPushButton('Add Lighting Element', self) self._addLightBtn.clicked.connect(self.__createLightBtnAction) self._cancelBtn = QPushButton('Cancel', self) self._cancelBtn.clicked.connect(self.__cancel) _layout = [['_nameControl'], ['_outputPinControlLabel', '_outputPinControl'], ['_enabledControl', '_strobeControl'], ['_iconControlLabel', '_iconControl'], ['_addLightBtn', '_cancelBtn']] for _list in _layout: _panel = QWidget(self) _panel.setLayout(QHBoxLayout(_panel)) _panel.layout().setAlignment(Qt.AlignCenter) for _control in _list: _panel.layout().addWidget(eval('self.%s' % _control)) self.layout().addWidget(_panel)
def _setup_layout(self): self.controlArea.setMinimumWidth(self.controlArea.sizeHint().width()) self.layout().setSizeConstraint(QLayout.SetFixedSize) widget_box = widgetBox(self.controlArea, 'Info') self.input_data_info = widgetLabel(widget_box, self._NO_DATA_INFO_TEXT) self.connection_info = widgetLabel(widget_box, "") widget_box = widgetBox(self.controlArea, 'Settings') self.cb_image_attr = comboBox( widget=widget_box, master=self, value='cb_image_attr_current_id', label='Image attribute:', orientation=Qt.Horizontal, callback=self._cb_image_attr_changed ) self.cb_embedder = comboBox( widget=widget_box, master=self, value='cb_embedder_current_id', label='Embedder:', orientation=Qt.Horizontal, callback=self._cb_embedder_changed ) names = [EMBEDDERS_INFO[e]['name'] + (" (local)" if EMBEDDERS_INFO[e].get("is_local") else "") for e in self.embedders] self.cb_embedder.setModel(VariableListModel(names)) if not self.cb_embedder_current_id < len(self.embedders): self.cb_embedder_current_id = 0 self.cb_embedder.setCurrentIndex(self.cb_embedder_current_id) current_embedder = self.embedders[self.cb_embedder_current_id] self.embedder_info = widgetLabel( widget_box, EMBEDDERS_INFO[current_embedder]['description'] ) self.auto_commit_widget = auto_commit( widget=self.controlArea, master=self, value='_auto_apply', label='Apply', commit=self.commit ) self.cancel_button = QPushButton( 'Cancel', icon=self.style().standardIcon(QStyle.SP_DialogCancelButton), ) self.cancel_button.clicked.connect(self.cancel) hbox = hBox(self.controlArea) hbox.layout().addWidget(self.cancel_button) self.cancel_button.setDisabled(True)
def __init__(self, owwidget, ax, varmodel): QWidget.__init__(self, owwidget) gui.OWComponent.__init__(self) self.ax = ax self.view = view = QListView( self, selectionMode=QTreeWidget.ExtendedSelection, ) view.setModel(varmodel) selection = view.selectionModel() selection.selectionChanged.connect(self.selection_changed) box = QVBoxLayout(self) box.setContentsMargins(0, 0, 0, 0) self.setLayout(box) hbox = gui.hBox(self) gui.comboBox( hbox, self, "plot_type", label="类型:", orientation="horizontal", items=("线", "折线", "柱", "面积", "样条曲线"), sendSelectedValue=True, callback=lambda: self.sigType.emit(ax, self.plot_types[self. plot_type]), ) gui.rubber(hbox) self.button_close = button = QPushButton( "×", hbox, visible=False, minimumSize=QSize(20, 20), maximumSize=QSize(20, 20), styleSheet=""" QPushButton { font-weight: bold; font-size:14pt; margin:0; padding:0; }""", ) button.clicked.connect(lambda: self.sigClosed.emit(ax, self)) hbox.layout().addWidget(button) gui.checkBox( self, self, "is_logarithmic", "对数轴", callback=lambda: self.sigLogarithmic.emit(ax, self.is_logarithmic), ) box.addWidget(view)
def __init__(self): super().__init__() self.recent_paths = [] self.file_combo = QComboBox() self.file_combo.setMinimumWidth(80) self.file_combo.activated.connect(self._activate) self.browse_btn = QPushButton("...") icon = self.style().standardIcon(QStyle.SP_DirOpenIcon) self.browse_btn.setIcon(icon) self.browse_btn.setSizePolicy(QSizePolicy.Maximum, QSizePolicy.Fixed) self.browse_btn.clicked.connect(self.browse) self.load_btn = QPushButton("") icon = self.style().standardIcon(QStyle.SP_BrowserReload) self.load_btn.setIcon(icon) self.load_btn.setSizePolicy(QSizePolicy.Maximum, QSizePolicy.Fixed) self.load_btn.setAutoDefault(True) self.load_btn.clicked.connect(self.file_loaded)
def __init__(self): self.data = None # List of all features (model for ComboBox) self.features = itemmodels.VariableListModel( ["Select Feature"], parent=self) box = gui.vBox(self.controlArea, "Select ") self.features_widget = QComboBox( self.controlArea, minimumContentsLength=16, sizeAdjustPolicy=QComboBox.AdjustToMinimumContentsLengthWithIcon, sizePolicy=QSizePolicy(QSizePolicy.Minimum, QSizePolicy.Minimum) ) self.features_widget.setModel(self.features) self.features_widget.currentIndexChanged.connect(self.feature_changed) self.button = QPushButton("Split") self.button.clicked.connect(self.split) self.button.setEnabled(False) box.layout().addWidget(self.features_widget) box.layout().addWidget(self.button)
def __init__(self): self.data = None self.classifier = None self.selected = None self.model = CustomRuleViewerTableModel(parent=self) self.model.set_horizontal_header_labels( ["IF conditions", "", "THEN class", "Distribution", "Probabilities [%]", "Quality", "Length"]) self.proxy_model = QSortFilterProxyModel(parent=self) self.proxy_model.setSourceModel(self.model) self.proxy_model.setSortRole(self.model.SortRole) self.view = gui.TableView(self, wordWrap=False) self.view.setModel(self.proxy_model) self.view.verticalHeader().setVisible(True) self.view.horizontalHeader().setStretchLastSection(False) self.view.selectionModel().selectionChanged.connect(self.commit) self.dist_item_delegate = DistributionItemDelegate(self) self.view.setItemDelegateForColumn(3, self.dist_item_delegate) self.mainArea.layout().setContentsMargins(0, 0, 0, 0) self.mainArea.layout().addWidget(self.view) bottom_box = gui.hBox(widget=self.mainArea, box=None, margin=0, spacing=0) original_order_button = QPushButton( "Restore original order", autoDefault=False) original_order_button.setFixedWidth(180) bottom_box.layout().addWidget(original_order_button) original_order_button.clicked.connect(self.restore_original_order) gui.separator(bottom_box, width=5, height=0) gui.checkBox(widget=bottom_box, master=self, value="compact_view", label="Compact view", callback=self.on_update) self.report_button.setFixedWidth(180) bottom_box.layout().addWidget(self.report_button)
def _setup_layout(self): self.controlArea.setMinimumWidth(self.sizeHint().width()) self.layout().setSizeConstraint(QLayout.SetFixedSize) widget_box = widgetBox(self.controlArea, 'Settings') self.language_cb = comboBox(widget=widget_box, master=self, value='language', label='Language: ', orientation=Qt.Horizontal, items=self.languages, callback=self._option_changed, searchable=True) self.language_cb.setCurrentText("English") self.aggregator_cb = comboBox(widget=widget_box, master=self, value='aggregator', label='Aggregator: ', orientation=Qt.Horizontal, items=self.aggregators, callback=self._option_changed) self.auto_commit_widget = auto_commit(widget=self.controlArea, master=self, value='_auto_apply', label='Apply', commit=self.commit, box=False) self.cancel_button = QPushButton('Cancel', icon=self.style().standardIcon( QStyle.SP_DialogCancelButton)) self.cancel_button.clicked.connect(self.cancel) hbox = hBox(self.controlArea) hbox.layout().addWidget(self.cancel_button) self.cancel_button.setDisabled(True)
def __init__(self, rWidget=None): super(OSK, self).__init__() self.showFullScreen() self._rWidget = rWidget self.layout = QVBoxLayout(self) self.currentText = QLabel(self) self.currentText.setAlignment(Qt.AlignCenter) if rWidget is not None: self.currentText.setText(rWidget.text()) self.layout.addWidget(self.currentText) keyLayout = [['1', '2', '3', '4', '5', '6', '7', '8', '9', '0', '-'], ['q', 'w', 'e', 'r', 't', 'y', 'u', 'i', 'o', 'p'], ['a', 's', 'd', 'f', 'g', 'h', 'j', 'k', 'l'], ['z', 'x', 'c', 'v', 'b', 'n', 'm']] for l in keyLayout: panel = QWidget(self) panel.layout = QHBoxLayout(panel) for key in l: button = OSKKey(key, self, parent=self) panel.layout.addWidget(button) self.layout.addWidget(panel) contolPanel = QWidget(self) contolPanel.layout = QHBoxLayout(contolPanel) self._shift = QPushButton('Shift', self) self._shift.setCheckable(True) self._shift.setFixedWidth(150) contolPanel.layout.addWidget(self._shift) spaceBar = OSKKey('space', self, parent=self) spaceBar.rKey = ' ' spaceBar.setFixedWidth(2 * self.window().geometry().width() / 3) contolPanel.layout.addWidget(spaceBar) bkspc = OSKKey('delete', self, parent=self) bkspc.rKey = '<<' contolPanel.layout.addWidget(bkspc) self.layout.addWidget(contolPanel) self.closeButton = QPushButton("OK", self) self.closeButton.clicked.connect(self.__closeButtonAction) self.layout.addWidget(self.closeButton)
def __init__(self, parent=None, **kwargs): super().__init__(parent, acceptDrops=True, **kwargs) self.setLayout(QVBoxLayout()) self.layout().setContentsMargins(0, 0, 0, 0) self.addonwidget = AddonManagerWidget() self.layout().addWidget(self.addonwidget) info_bar = QWidget() info_layout = QHBoxLayout() info_bar.setLayout(info_layout) self.layout().addWidget(info_bar) buttons = QDialogButtonBox( orientation=Qt.Horizontal, standardButtons=QDialogButtonBox.Ok | QDialogButtonBox.Cancel, ) buttons.button(QDialogButtonBox.Ok).setText("确定") buttons.button(QDialogButtonBox.Cancel).setText("取消") addmore = QPushButton( "添加更多...", toolTip="添加一个未出现在列表中的附加组件", autoDefault=False ) self.addonwidget.tophlayout.addWidget(addmore) addmore.clicked.connect(self.__run_add_package_dialog) buttons.accepted.connect(self.__accepted) buttons.rejected.connect(self.reject) self.layout().addWidget(buttons) self._executor = concurrent.futures.ThreadPoolExecutor(max_workers=1) if AddonManagerDialog._packages is None: self._f_pypi_addons = self._executor.submit(list_available_versions) else: self._f_pypi_addons = concurrent.futures.Future() self._f_pypi_addons.set_result(AddonManagerDialog._packages) self._f_pypi_addons.add_done_callback( method_queued(self._set_packages, (object,)) ) self.__progress = None # type: Optional[QProgressDialog] self.__thread = None self.__installer = None if not self._f_pypi_addons.done(): self.__progressDialog()
def __init__(self, owwidget, ax, varmodel): QWidget.__init__(self, owwidget) gui.OWComponent.__init__(self) self.ax = ax self.view = view = QListView( self, selectionMode=QTreeWidget.ExtendedSelection, ) view.setModel(varmodel) selection = view.selectionModel() selection.selectionChanged.connect(self.selection_changed) box = QVBoxLayout(self) box.setContentsMargins(0, 0, 0, 0) self.setLayout(box) hbox = gui.hBox(self) gui.comboBox(hbox, self, 'plot_type', label='Type:', orientation='horizontal', items=('line', 'step line', 'column', 'area', 'spline'), sendSelectedValue=True, callback=lambda: self.sigType.emit(ax, self.plot_type)) gui.rubber(hbox) self.button_close = button = QPushButton('×', hbox, visible=False, minimumSize=QSize(20, 20), maximumSize=QSize(20, 20), styleSheet=''' QPushButton { font-weight: bold; font-size:14pt; margin:0; padding:0; }''') button.clicked.connect(lambda: self.sigClosed.emit(ax, self)) hbox.layout().addWidget(button) gui.checkBox( self, self, "is_logarithmic", "Logarithmic axis", callback=self.on_logarithmic, ) box.addWidget(view)
def addButton(self, button, *rolearg): """ addButton(QAbstractButton, ButtonRole) addButton(str, ButtonRole) addButton(StandardButton) Add and return a button """ stdbutton = None if isinstance(button, QAbstractButton): if len(rolearg) != 1: raise TypeError("Wrong number of arguments for " "addButton(QAbstractButton, role)") role = rolearg[0] elif isinstance(button, NotificationMessageWidget.StandardButton): if rolearg: raise TypeError("Wrong number of arguments for " "addButton(StandardButton)") stdbutton = button if button == NotificationMessageWidget.Ok: role = NotificationMessageWidget.AcceptRole button = QPushButton(self._acceptLabel, default=False, autoDefault=False) elif button == NotificationMessageWidget.Close: role = NotificationMessageWidget.RejectRole button = QPushButton(self._rejectLabel, default=False, autoDefault=False) elif isinstance(button, str): if len(rolearg) != 1: raise TypeError("Wrong number of arguments for " "addButton(str, ButtonRole)") role = rolearg[0] button = QPushButton(button, default=False, autoDefault=False) if sys.platform == "darwin": button.setAttribute(Qt.WA_MacSmallSize) self._buttons.append( NotificationMessageWidget._Button(button, role, stdbutton)) button.clicked.connect(self._button_clicked) self._relayout() return button
def addButton(self, button, *rolearg): """ addButton(QAbstractButton, ButtonRole) addButton(str, ButtonRole) addButton(StandardButton) Add and return a button """ stdbutton = None if isinstance(button, QAbstractButton): if len(rolearg) != 1: raise TypeError("Wrong number of arguments for " "addButton(QAbstractButton, role)") role = rolearg[0] elif isinstance(button, MessageWidget.StandardButton): if len(rolearg) != 0: raise TypeError("Wrong number of arguments for " "addButton(StandardButton)") stdbutton = button if button == MessageWidget.Ok: role = MessageWidget.AcceptRole button = QPushButton("Ok", default=False, autoDefault=False) elif button == MessageWidget.Close: role = MessageWidget.RejectRole # button = QPushButton( # default=False, autoDefault=False, flat=True, # icon=QIcon(self.style().standardIcon( # QStyle.SP_TitleBarCloseButton))) button = SimpleButton( icon=QIcon( self.style().standardIcon( QStyle.SP_TitleBarCloseButton))) elif button == MessageWidget.Help: role = MessageWidget.HelpRole button = QPushButton("Help", default=False, autoDefault=False) elif isinstance(button, str): if len(rolearg) != 1: raise TypeError("Wrong number of arguments for " "addButton(str, ButtonRole)") role = rolearg[0] button = QPushButton(button, default=False, autoDefault=False) if sys.platform == "darwin": button.setAttribute(Qt.WA_MacSmallSize) self.__buttons.append(MessageWidget._Button(button, role, stdbutton)) button.clicked.connect(self.__button_clicked) self.__relayout() return button
def __init__(self, parent=None): super().__init__(parent) self.setTitle(self.name) self.setLayout(QVBoxLayout()) hbox = gui.hBox(self) self.add_standard_parameters(hbox) gui.separator(hbox, 20) gui.rubber(hbox) self.add_specific_parameters(hbox) self.error = QLabel() self.error.setHidden(True) self.layout().addWidget(self.error) self.trash_button = trash = QPushButton( self, icon=self.style().standardIcon(QStyle.SP_DockWidgetCloseButton)) trash.setGeometry(0, 20, 15, 15) trash.setFlat(True) trash.setHidden(True) trash.clicked.connect(self.on_trash_clicked)
def __init__(self): grid = QGridLayout() self.dir_label = QLabel("目录:", self) self.browse_button = QPushButton( "…", icon=self.style().standardIcon(QStyle.SP_DirOpenIcon), toolTip="Browse filesystem", autoDefault=False, ) self.browse_button.clicked.connect(self.browse) grid.addWidget(self.dir_label, 0, 1, 1, 1) grid.addWidget(self.browse_button, 0, 2, 1, 1) self.controlArea.layout().addLayout(grid) box = gui.widgetBox(self.controlArea, "Info", addSpace=False) self.summary_text = QTextBrowser( verticalScrollBarPolicy=Qt.ScrollBarAsNeeded, readOnly=True, ) self.summary_text.viewport().setBackgroundRole(QPalette.NoRole) self.summary_text.setFrameStyle(QTextBrowser.NoFrame) self.summary_text.setMinimumHeight(self.fontMetrics().ascent() * 2 + 4) self.summary_text.viewport().setAutoFillBackground(False) box.layout().addWidget(self.summary_text)
def __init__(self, title, text, parent=None): super().__init__(parent) self.setLayout(QVBoxLayout()) self.title_le = QLineEdit() self.title_le.setPlaceholderText("Document title") self.title_le.setText(title) self.title_le.editingFinished.connect(self._on_text_changed) self.text_area = CustomQPlainTextEdit() self.text_area.setPlaceholderText("Document text") self.text_area.setPlainText(text) self.text_area.editingFinished.connect(self._on_text_changed) remove_button = QPushButton("x") remove_button.setFixedWidth(35) remove_button.setFocusPolicy(Qt.NoFocus) remove_button.clicked.connect(self._on_remove_clicked) box = gui.hBox(self) box.layout().addWidget(self.title_le) box.layout().addWidget(remove_button) self.layout().addWidget(self.text_area)
class OWImageEmbedding(OWWidget): name = "Image Embedding" description = "Image embedding through deep neural networks." icon = "icons/ImageEmbedding.svg" priority = 150 want_main_area = False _auto_apply = Setting(default=True) class Inputs: images = Input('Images', Table) class Outputs: embeddings = Output('Embeddings', Table, default=True) skipped_images = Output('Skipped Images', Table) cb_image_attr_current_id = Setting(default=0) cb_embedder_current_id = Setting(default=0) _NO_DATA_INFO_TEXT = "No data on input." def __init__(self): super().__init__() self.embedders = sorted(list(EMBEDDERS_INFO), key=lambda k: EMBEDDERS_INFO[k]['order']) self._image_attributes = None self._input_data = None self._log = logging.getLogger(__name__) self._task = None self._setup_layout() self._image_embedder = None self._executor = concurrent.futures.ThreadPoolExecutor(max_workers=1) self.setBlocking(True) QTimer.singleShot(0, self._init_server_connection) def _setup_layout(self): self.controlArea.setMinimumWidth(self.controlArea.sizeHint().width()) self.layout().setSizeConstraint(QLayout.SetFixedSize) widget_box = widgetBox(self.controlArea, 'Info') self.input_data_info = widgetLabel(widget_box, self._NO_DATA_INFO_TEXT) self.connection_info = widgetLabel(widget_box, "") widget_box = widgetBox(self.controlArea, 'Settings') self.cb_image_attr = comboBox( widget=widget_box, master=self, value='cb_image_attr_current_id', label='Image attribute:', orientation=Qt.Horizontal, callback=self._cb_image_attr_changed ) self.cb_embedder = comboBox( widget=widget_box, master=self, value='cb_embedder_current_id', label='Embedder:', orientation=Qt.Horizontal, callback=self._cb_embedder_changed ) names = [EMBEDDERS_INFO[e]['name'] + (" (local)" if EMBEDDERS_INFO[e].get("is_local") else "") for e in self.embedders] self.cb_embedder.setModel(VariableListModel(names)) if not self.cb_embedder_current_id < len(self.embedders): self.cb_embedder_current_id = 0 self.cb_embedder.setCurrentIndex(self.cb_embedder_current_id) current_embedder = self.embedders[self.cb_embedder_current_id] self.embedder_info = widgetLabel( widget_box, EMBEDDERS_INFO[current_embedder]['description'] ) self.auto_commit_widget = auto_commit( widget=self.controlArea, master=self, value='_auto_apply', label='Apply', commit=self.commit ) self.cancel_button = QPushButton( 'Cancel', icon=self.style().standardIcon(QStyle.SP_DialogCancelButton), ) self.cancel_button.clicked.connect(self.cancel) hbox = hBox(self.controlArea) hbox.layout().addWidget(self.cancel_button) self.cancel_button.setDisabled(True) def _init_server_connection(self): self.setBlocking(False) self._image_embedder = ImageEmbedder( model=self.embedders[self.cb_embedder_current_id], layer='penultimate' ) self._set_server_info( self._image_embedder.is_connected_to_server() ) @Inputs.images def set_data(self, data): if not data: self._input_data = None self.Outputs.embeddings.send(None) self.Outputs.skipped_images.send(None) self.input_data_info.setText(self._NO_DATA_INFO_TEXT) return self._image_attributes = ImageEmbedder.filter_image_attributes(data) if not self._image_attributes: input_data_info_text = ( "Data with {:d} instances, but without image attributes." .format(len(data))) input_data_info_text.format(input_data_info_text) self.input_data_info.setText(input_data_info_text) self._input_data = None return if not self.cb_image_attr_current_id < len(self._image_attributes): self.cb_image_attr_current_id = 0 self.cb_image_attr.setModel(VariableListModel(self._image_attributes)) self.cb_image_attr.setCurrentIndex(self.cb_image_attr_current_id) self._input_data = data self.input_data_info.setText( "Data with {:d} instances.".format(len(data))) self._cb_image_attr_changed() def _cb_image_attr_changed(self): self.commit() def _cb_embedder_changed(self): current_embedder = self.embedders[self.cb_embedder_current_id] self._image_embedder = ImageEmbedder( model=current_embedder, layer='penultimate' ) self.embedder_info.setText( EMBEDDERS_INFO[current_embedder]['description']) if self._input_data: self.input_data_info.setText( "Data with {:d} instances.".format(len(self._input_data))) self.commit() else: self.input_data_info.setText(self._NO_DATA_INFO_TEXT) self._set_server_info(self._image_embedder.is_connected_to_server()) def commit(self): if self._task is not None: self.cancel() if self._image_embedder is None: self._set_server_info(connected=False) return if not self._image_attributes or self._input_data is None: self.Outputs.embeddings.send(None) self.Outputs.skipped_images.send(None) return self._set_server_info(connected=True) self.cancel_button.setDisabled(False) self.cb_image_attr.setDisabled(True) self.cb_embedder.setDisabled(True) file_paths_attr = self._image_attributes[self.cb_image_attr_current_id] file_paths = self._input_data[:, file_paths_attr].metas.flatten() origin = file_paths_attr.attributes.get("origin", "") if urlparse(origin).scheme in ("http", "https", "ftp", "data") and \ origin[-1] != "/": origin += "/" assert file_paths_attr.is_string assert file_paths.dtype == np.dtype('O') file_paths_mask = file_paths == file_paths_attr.Unknown file_paths_valid = file_paths[~file_paths_mask] for i, a in enumerate(file_paths_valid): urlparts = urlparse(a) if urlparts.scheme not in ("http", "https", "ftp", "data"): if urlparse(origin).scheme in ("http", "https", "ftp", "data"): file_paths_valid[i] = urljoin(origin, a) else: file_paths_valid[i] = os.path.join(origin, a) ticks = iter(np.linspace(0.0, 100.0, file_paths_valid.size)) set_progress = qconcurrent.methodinvoke( self, "__progress_set", (float,)) def advance(success=True): if success: set_progress(next(ticks)) def cancel(): task.future.cancel() task.cancelled = True task.embedder.set_canceled(True) embedder = self._image_embedder def run_embedding(paths): return embedder( file_paths=paths, image_processed_callback=advance) self.auto_commit_widget.setDisabled(True) self.progressBarInit(processEvents=None) self.progressBarSet(0.0, processEvents=None) self.setBlocking(True) f = self._executor.submit(run_embedding, file_paths_valid) f.add_done_callback( qconcurrent.methodinvoke(self, "__set_results", (object,))) task = self._task = namespace( file_paths_mask=file_paths_mask, file_paths_valid=file_paths_valid, file_paths=file_paths, embedder=embedder, cancelled=False, cancel=cancel, future=f, ) self._log.debug("Starting embedding task for %i images", file_paths.size) return @Slot(float) def __progress_set(self, value): assert self.thread() is QThread.currentThread() if self._task is not None: self.progressBarSet(value) @Slot(object) def __set_results(self, f): assert self.thread() is QThread.currentThread() if self._task is None or self._task.future is not f: self._log.info("Reaping stale task") return assert f.done() task, self._task = self._task, None self.auto_commit_widget.setDisabled(False) self.cancel_button.setDisabled(True) self.cb_image_attr.setDisabled(False) self.cb_embedder.setDisabled(False) self.progressBarFinished(processEvents=None) self.setBlocking(False) try: embeddings = f.result() except ConnectionError: self._log.exception("Error", exc_info=True) self.Outputs.embeddings.send(None) self.Outputs.skipped_images.send(None) self._set_server_info(connected=False) return except Exception as err: self._log.exception("Error", exc_info=True) self.error( "\n".join(traceback.format_exception_only(type(err), err))) self.Outputs.embeddings.send(None) self.Outputs.skipped_images.send(None) return assert self._input_data is not None assert len(self._input_data) == len(task.file_paths_mask) # Missing paths/urls were filtered out. Restore the full embeddings # array from information stored in task.file_path_mask ... embeddings_all = [None] * len(task.file_paths_mask) for i, embedding in zip(np.flatnonzero(~task.file_paths_mask), embeddings): embeddings_all[i] = embedding embeddings_all = np.array(embeddings_all) self._send_output_signals(embeddings_all) def _send_output_signals(self, embeddings): embedded_images, skipped_images, num_skipped =\ ImageEmbedder.prepare_output_data(self._input_data, embeddings) self.Outputs.embeddings.send(embedded_images) self.Outputs.skipped_images.send(skipped_images) if num_skipped is not 0: self.input_data_info.setText( "Data with {:d} instances, {:d} images skipped.".format( len(self._input_data), num_skipped)) def _set_server_info(self, connected): self.clear_messages() if self._image_embedder is None: return if connected: self.connection_info.setText("Connected to server.") elif self._image_embedder.is_local_embedder(): self.connection_info.setText("Using local embedder.") else: self.connection_info.setText("Not connected to server.") self.warning("Click Apply to try again.") def onDeleteWidget(self): self.cancel() super().onDeleteWidget() if self._image_embedder is not None: self._image_embedder.__exit__(None, None, None) def cancel(self): if self._task is not None: task, self._task = self._task, None task.cancel() # wait until done try: task.future.exception() except qconcurrent.CancelledError: pass self.auto_commit_widget.setDisabled(False) self.cancel_button.setDisabled(True) self.progressBarFinished(processEvents=None) self.setBlocking(False) self.cb_image_attr.setDisabled(False) self.cb_embedder.setDisabled(False) self._image_embedder.set_canceled(False) # reset the connection. connected = self._image_embedder.reconnect_to_server() self._set_server_info(connected=connected)
class OWCodeViewer(OWWidget): name = "Code Viewer" description = "Display" icon = "icons/Code.svg" priority = 10 keywords = ["source", "code", "display", "programming"] directory = "" show_configuration = False class Inputs: data = Input("Source Code", Orange.data.Table) #class Outputs: # sample = Output("Sampled Data", Orange.data.Table) want_main_area = False def __init__(self): super().__init__() # GUI box = gui.widgetBox(self.controlArea, "Info") self.infoLabel = gui.widgetLabel(box, '') #self.display_no_source_selected() self.code_editor = CodeEditorTextEdit() self.controlArea.layout().addWidget(self.code_editor) self.configMoreButton = QPushButton("Configuration") self.configMoreButton.setCheckable(True) self.configMoreButton.clicked.connect( self.switch_configuration_visibility) self.controlArea.layout().addWidget(self.configMoreButton) self.configurationBox = gui.widgetBox(self.controlArea, "Configuration") gui.lineEdit(self.configurationBox, self, 'directory', 'Source Directory', callback=self.directory_changed) self.refresh_configuration_box() #Test data #self.directory = "C:\\Code\\samples\\juliet-test-suite\\" #self.set_data(Table("orangecode/test.csv")) def switch_configuration_visibility(self, e): self.show_configuration = not (self.show_configuration) self.refresh_configuration_box() def refresh_configuration_box(self): if (self.show_configuration): self.configMoreButton.setText("Configuration <<") self.configurationBox.show() else: self.configMoreButton.setText("Configuration >>") self.configurationBox.hide() @Inputs.data def set_data(self, dataset): if dataset is not None: if (len(dataset) < 1): self.display_no_source_selected() else: #import code #code.interact(local=dict(globals(), **locals())) self.process_line(dataset[0]) else: self.display_no_source_selected() def directory_changed(self): self.code_editor.setPlainText("") self.update_source_file() def process_line(self, line): """ The extraction is based on values to avoid manual configuration. """ self.source_file = "" self.source_line = -1 #code.interact(local=locals()) all_attributes_index = [] #Guessing based on values for var in itertools.chain(line.domain.attributes, line.domain.metas): i = line.domain.index(var.name) #print("{} -> {}".format(var.name,i)) all_attributes_index.append(i) for attribute_index in all_attributes_index: try: line[attribute_index] except IndexError: print("More attributes than values on line {}".format(line)) continue if (line[attribute_index] is not None): val = line[attribute_index].value if type(val) is str: val_parts = val.split(":") if (len(val_parts) == 2): if (val_parts[1].isnumeric()): self.source_file = val_parts[0] self.source_line = int(val_parts[1]) self.update_source_file() def update_source_file(self): if (self.source_file != ""): #Update highlighter filename, extension = os.path.splitext(self.source_file) self.code_editor.set_highlighter(extension) try: with open(self.directory + "/" + self.source_file, 'r') as file: code = file.read() self.code_editor.setPlainText(code) self.display_source_file() except IOError: _, err, _ = sys.exc_info() self.display_error(str(err)) else: self.display_no_source_selected() return if (self.source_line != -1): #print(self.source_line) block = self.code_editor.document().findBlockByLineNumber( self.source_line - 1) self.code_editor.setTextCursor(QTextCursor(block)) self.code_editor.moveCursor(QTextCursor.EndOfBlock) def is_source_file(self, value): #print(value.__class__.__name__) if not (isinstance(value, str)): return False for extension in [ '.java', '.c', '.cpp', '.py', '.js', '.ruby', '.jsp' ]: if (value.endswith(extension)): return True return False # Information display def display_no_source_selected(self): self.infoLabel.setText('No source file selected') def display_file_not_found(self): self.infoLabel.setText('Source file not found') def display_error(self, message): self.infoLabel.setText('An error has occured: ' + message) def display_source_file(self): filename = self.source_file.split("/")[-1].split("\\")[-1] line = ("" if self.source_line == -1 else " ~ Line: <b>" + str(self.source_line) + "</b>") self.infoLabel.setText("Source file: <b>{}</b> {}".format( filename, line))
def __init__(self, parent): QWidget.__init__(self) OWComponent.__init__(self, parent) SelectionGroupMixin.__init__(self) self.parent = parent self.selection_type = SELECTMANY self.saving_enabled = True self.selection_enabled = True self.viewtype = INDIVIDUAL # required bt InteractiveViewBox self.highlighted = None self.data_points = None self.data_values = None self.data_imagepixels = None self.plotview = pg.PlotWidget(background="w", viewBox=InteractiveViewBox(self)) self.plot = self.plotview.getPlotItem() self.plot.scene().installEventFilter( HelpEventDelegate(self.help_event, self)) layout = QVBoxLayout() self.setLayout(layout) self.layout().setContentsMargins(0, 0, 0, 0) self.layout().addWidget(self.plotview) self.img = ImageItemNan() self.img.setOpts(axisOrder='row-major') self.plot.addItem(self.img) self.plot.vb.setAspectLocked() self.plot.scene().sigMouseMoved.connect(self.plot.vb.mouseMovedEvent) layout = QGridLayout() self.plotview.setLayout(layout) self.button = QPushButton("Menu", self.plotview) self.button.setAutoDefault(False) layout.setRowStretch(1, 1) layout.setColumnStretch(1, 1) layout.addWidget(self.button, 0, 0) view_menu = MenuFocus(self) self.button.setMenu(view_menu) # prepare interface according to the new context self.parent.contextAboutToBeOpened.connect(lambda x: self.init_interface_data(x[0])) actions = [] zoom_in = QAction( "Zoom in", self, triggered=self.plot.vb.set_mode_zooming ) zoom_in.setShortcuts([Qt.Key_Z, QKeySequence(QKeySequence.ZoomIn)]) zoom_in.setShortcutContext(Qt.WidgetWithChildrenShortcut) actions.append(zoom_in) zoom_fit = QAction( "Zoom to fit", self, triggered=lambda x: (self.plot.vb.autoRange(), self.plot.vb.set_mode_panning()) ) zoom_fit.setShortcuts([Qt.Key_Backspace, QKeySequence(Qt.ControlModifier | Qt.Key_0)]) zoom_fit.setShortcutContext(Qt.WidgetWithChildrenShortcut) actions.append(zoom_fit) select_square = QAction( "Select (square)", self, triggered=self.plot.vb.set_mode_select_square, ) select_square.setShortcuts([Qt.Key_S]) select_square.setShortcutContext(Qt.WidgetWithChildrenShortcut) actions.append(select_square) select_polygon = QAction( "Select (polygon)", self, triggered=self.plot.vb.set_mode_select_polygon, ) select_polygon.setShortcuts([Qt.Key_P]) select_polygon.setShortcutContext(Qt.WidgetWithChildrenShortcut) actions.append(select_polygon) if self.saving_enabled: save_graph = QAction( "Save graph", self, triggered=self.save_graph, ) save_graph.setShortcuts([QKeySequence(Qt.ControlModifier | Qt.Key_I)]) actions.append(save_graph) view_menu.addActions(actions) self.addActions(actions) common_options = dict( labelWidth=50, orientation=Qt.Horizontal, sendSelectedValue=True, valueType=str) choose_xy = QWidgetAction(self) box = gui.vBox(self) box.setFocusPolicy(Qt.TabFocus) self.xy_model = DomainModel(DomainModel.METAS | DomainModel.CLASSES, valid_types=DomainModel.PRIMITIVE) self.cb_attr_x = gui.comboBox( box, self, "attr_x", label="Axis x:", callback=self.update_attr, model=self.xy_model, **common_options) self.cb_attr_y = gui.comboBox( box, self, "attr_y", label="Axis y:", callback=self.update_attr, model=self.xy_model, **common_options) box.setFocusProxy(self.cb_attr_x) self.color_cb = gui.comboBox(box, self, "palette_index", label="Color:", labelWidth=50, orientation=Qt.Horizontal) self.color_cb.setIconSize(QSize(64, 16)) palettes = _color_palettes self.palette_index = min(self.palette_index, len(palettes) - 1) model = color_palette_model(palettes, self.color_cb.iconSize()) model.setParent(self) self.color_cb.setModel(model) self.color_cb.activated.connect(self.update_color_schema) self.color_cb.setCurrentIndex(self.palette_index) form = QFormLayout( formAlignment=Qt.AlignLeft, labelAlignment=Qt.AlignLeft, fieldGrowthPolicy=QFormLayout.AllNonFixedFieldsGrow ) def limit_changed(): self.update_levels() self.reset_thresholds() self._level_low_le = lineEditDecimalOrNone(self, self, "level_low", callback=limit_changed) self._level_low_le.validator().setDefault(0) form.addRow("Low limit:", self._level_low_le) self._level_high_le = lineEditDecimalOrNone(self, self, "level_high", callback=limit_changed) self._level_high_le.validator().setDefault(1) form.addRow("High limit:", self._level_high_le) lowslider = gui.hSlider( box, self, "threshold_low", minValue=0.0, maxValue=1.0, step=0.05, ticks=True, intOnly=False, createLabel=False, callback=self.update_levels) highslider = gui.hSlider( box, self, "threshold_high", minValue=0.0, maxValue=1.0, step=0.05, ticks=True, intOnly=False, createLabel=False, callback=self.update_levels) form.addRow("Low:", lowslider) form.addRow("High:", highslider) box.layout().addLayout(form) choose_xy.setDefaultWidget(box) view_menu.addAction(choose_xy) self.markings_integral = [] self.lsx = None # info about the X axis self.lsy = None # info about the Y axis self.data = None self.data_ids = {}
class FileWidget(QWidget): on_open = pyqtSignal(str) # TODO consider removing directory_aliases since it is not used any more def __init__(self, dialog_title='', dialog_format='', start_dir=os.path.expanduser('~/'), icon_size=(12, 20), minimal_width=200, browse_label='Browse', on_open=None, reload_button=True, reload_label='Reload', recent_files=None, directory_aliases=None, allow_empty=True, empty_file_label='(none)'): """ Creates a widget with a button for file loading and an optional combo box for recent files and reload buttons. Args: dialog_title (str): The title of the dialog. dialog_format (str): Formats for the dialog. start_dir (str): A directory to start from. icon_size (int, int): The size of buttons' icons. on_open (callable): A callback function that accepts filepath as the only argument. reload_button (bool): Whether to show reload button. reload_label (str): The text displayed on the reload button. recent_files (List[str]): List of recent files. directory_aliases (dict): An {alias: dir} dictionary for fast directories' access. allow_empty (bool): Whether empty path is allowed. """ super().__init__() self.dialog_title = dialog_title self.dialog_format = dialog_format self.start_dir = start_dir # Recent files should also contain `empty_file_label` so # when (none) is selected this is stored in settings. self.recent_files = recent_files if recent_files is not None else [] self.directory_aliases = directory_aliases or {} self.allow_empty = allow_empty self.empty_file_label = empty_file_label if self.empty_file_label not in self.recent_files \ and (self.allow_empty or not self.recent_files): self.recent_files.append(self.empty_file_label) self.check_existence() self.on_open.connect(on_open) layout = QHBoxLayout(self) layout.setContentsMargins(0, 0, 0, 0) if recent_files is not None: self.file_combo = QComboBox() self.file_combo.setMinimumWidth(minimal_width) self.file_combo.activated[int].connect(self.select) self.update_combo() layout.addWidget(self.file_combo) self.browse_button = QPushButton(browse_label) self.browse_button.setFocusPolicy(Qt.NoFocus) self.browse_button.clicked.connect(self.browse) self.browse_button.setIcon(self.style() .standardIcon(QStyle.SP_DirOpenIcon)) self.browse_button.setIconSize(QSize(*icon_size)) self.browse_button.setSizePolicy(QSizePolicy.Fixed, QSizePolicy.Fixed) layout.addWidget(self.browse_button) if reload_button: self.reload_button = QPushButton(reload_label) self.reload_button.setFocusPolicy(Qt.NoFocus) self.reload_button.clicked.connect(self.reload) self.reload_button.setIcon(self.style() .standardIcon(QStyle.SP_BrowserReload)) self.reload_button.setSizePolicy(QSizePolicy.Fixed, QSizePolicy.Fixed) self.reload_button.setIconSize(QSize(*icon_size)) layout.addWidget(self.reload_button) def browse(self, start_dir=None): start_dir = start_dir or self.start_dir path, _ = QFileDialog().getOpenFileName(self, self.dialog_title, start_dir, self.dialog_format) if path and self.recent_files is not None: if path in self.recent_files: self.recent_files.remove(path) self.recent_files.insert(0, path) self.update_combo() if path: self.open_file(path) def select(self, n): name = self.file_combo.currentText() if name == self.empty_file_label: del self.recent_files[n] self.recent_files.insert(0, self.empty_file_label) self.update_combo() self.open_file(self.empty_file_label) elif name in self.directory_aliases: self.browse(self.directory_aliases[name]) elif n < len(self.recent_files): name = self.recent_files[n] del self.recent_files[n] self.recent_files.insert(0, name) self.update_combo() self.open_file(self.recent_files[0]) def update_combo(self): """ Sync combo values to the changes in self.recent_files. """ if self.recent_files is not None: self.file_combo.clear() for i, file in enumerate(self.recent_files): # remove (none) when we have some files and allow_empty=False if file == self.empty_file_label and \ not self.allow_empty and len(self.recent_files) > 1: del self.recent_files[i] else: self.file_combo.addItem(os.path.split(file)[1]) for alias in self.directory_aliases.keys(): self.file_combo.addItem(alias) def reload(self): if self.recent_files: self.select(0) def check_existence(self): if self.recent_files: to_remove = [] for file in self.recent_files: doc_path = os.path.join(get_sample_corpora_dir(), file) exists = any(os.path.exists(f) for f in [file, doc_path]) if file != self.empty_file_label and not exists: to_remove.append(file) for file in to_remove: self.recent_files.remove(file) def open_file(self, path): self.on_open.emit(path if path != self.empty_file_label else '') def get_selected_filename(self): if self.recent_files: return self.recent_files[0] else: return self.empty_file_label
class OWFeatureConstructor(OWWidget): name = "Feature Constructor" description = "Construct new features (data columns) from a set of " \ "existing features in the input data set." icon = "icons/FeatureConstructor.svg" inputs = [("Data", Orange.data.Table, "setData")] outputs = [("Data", Orange.data.Table)] want_main_area = False settingsHandler = FeatureConstructorSettingsHandler() descriptors = ContextSetting([]) currentIndex = ContextSetting(-1) EDITORS = [ (ContinuousDescriptor, ContinuousFeatureEditor), (DiscreteDescriptor, DiscreteFeatureEditor), (StringDescriptor, StringFeatureEditor) ] class Error(OWWidget.Error): more_values_needed = Msg("Discrete feature {} needs more values.") invalid_expressions = Msg("Invalid expressions: {}.") def __init__(self): super().__init__() self.data = None self.editors = {} box = gui.vBox(self.controlArea, "Variable Definitions") toplayout = QHBoxLayout() toplayout.setContentsMargins(0, 0, 0, 0) box.layout().addLayout(toplayout) self.editorstack = QStackedWidget( sizePolicy=QSizePolicy(QSizePolicy.MinimumExpanding, QSizePolicy.MinimumExpanding) ) for descclass, editorclass in self.EDITORS: editor = editorclass() editor.featureChanged.connect(self._on_modified) self.editors[descclass] = editor self.editorstack.addWidget(editor) self.editorstack.setEnabled(False) buttonlayout = QVBoxLayout(spacing=10) buttonlayout.setContentsMargins(0, 0, 0, 0) self.addbutton = QPushButton( "New", toolTip="Create a new variable", minimumWidth=120, shortcut=QKeySequence.New ) def unique_name(fmt, reserved): candidates = (fmt.format(i) for i in count(1)) return next(c for c in candidates if c not in reserved) def reserved_names(): varnames = [] if self.data is not None: varnames = [var.name for var in self.data.domain.variables + self.data.domain.metas] varnames += [desc.name for desc in self.featuremodel] return set(varnames) def generate_newname(fmt): return unique_name(fmt, reserved_names()) menu = QMenu(self.addbutton) cont = menu.addAction("Continuous") cont.triggered.connect( lambda: self.addFeature( ContinuousDescriptor(generate_newname("X{}"), "", 3)) ) disc = menu.addAction("Discrete") disc.triggered.connect( lambda: self.addFeature( DiscreteDescriptor(generate_newname("D{}"), "", ("A", "B"), -1, False)) ) string = menu.addAction("String") string.triggered.connect( lambda: self.addFeature( StringDescriptor(generate_newname("S{}"), "")) ) menu.addSeparator() self.duplicateaction = menu.addAction("Duplicate Selected Variable") self.duplicateaction.triggered.connect(self.duplicateFeature) self.duplicateaction.setEnabled(False) self.addbutton.setMenu(menu) self.removebutton = QPushButton( "Remove", toolTip="Remove selected variable", minimumWidth=120, shortcut=QKeySequence.Delete ) self.removebutton.clicked.connect(self.removeSelectedFeature) buttonlayout.addWidget(self.addbutton) buttonlayout.addWidget(self.removebutton) buttonlayout.addStretch(10) toplayout.addLayout(buttonlayout, 0) toplayout.addWidget(self.editorstack, 10) # Layout for the list view layout = QVBoxLayout(spacing=1, margin=0) self.featuremodel = DescriptorModel(parent=self) self.featureview = QListView( minimumWidth=200, sizePolicy=QSizePolicy(QSizePolicy.Minimum, QSizePolicy.MinimumExpanding) ) self.featureview.setItemDelegate(FeatureItemDelegate(self)) self.featureview.setModel(self.featuremodel) self.featureview.selectionModel().selectionChanged.connect( self._on_selectedVariableChanged ) layout.addWidget(self.featureview) box.layout().addLayout(layout, 1) box = gui.hBox(self.controlArea) box.layout().addWidget(self.report_button) self.report_button.setMinimumWidth(180) gui.rubber(box) commit = gui.button(box, self, "Send", callback=self.apply, default=True) commit.setMinimumWidth(180) def setCurrentIndex(self, index): index = min(index, len(self.featuremodel) - 1) self.currentIndex = index if index >= 0: itemmodels.select_row(self.featureview, index) desc = self.featuremodel[min(index, len(self.featuremodel) - 1)] editor = self.editors[type(desc)] self.editorstack.setCurrentWidget(editor) editor.setEditorData(desc, self.data.domain if self.data else None) self.editorstack.setEnabled(index >= 0) self.duplicateaction.setEnabled(index >= 0) self.removebutton.setEnabled(index >= 0) def _on_selectedVariableChanged(self, selected, *_): index = selected_row(self.featureview) if index is not None: self.setCurrentIndex(index) else: self.setCurrentIndex(-1) def _on_modified(self): if self.currentIndex >= 0: editor = self.editorstack.currentWidget() self.featuremodel[self.currentIndex] = editor.editorData() self.descriptors = list(self.featuremodel) def setDescriptors(self, descriptors): """ Set a list of variable descriptors to edit. """ self.descriptors = descriptors self.featuremodel[:] = list(self.descriptors) @check_sql_input def setData(self, data=None): """Set the input dataset.""" self.closeContext() self.data = data if self.data is not None: descriptors = list(self.descriptors) currindex = self.currentIndex self.descriptors = [] self.currentIndex = -1 self.openContext(data) if descriptors != self.descriptors or \ self.currentIndex != currindex: # disconnect from the selection model while reseting the model selmodel = self.featureview.selectionModel() selmodel.selectionChanged.disconnect( self._on_selectedVariableChanged) self.featuremodel[:] = list(self.descriptors) self.setCurrentIndex(self.currentIndex) selmodel.selectionChanged.connect( self._on_selectedVariableChanged) self.editorstack.setEnabled(self.currentIndex >= 0) def handleNewSignals(self): if self.data is not None: self.apply() else: self.send("Data", None) def addFeature(self, descriptor): self.featuremodel.append(descriptor) self.setCurrentIndex(len(self.featuremodel) - 1) editor = self.editorstack.currentWidget() editor.nameedit.setFocus() editor.nameedit.selectAll() def removeFeature(self, index): del self.featuremodel[index] index = selected_row(self.featureview) if index is not None: self.setCurrentIndex(index) elif index is None and len(self.featuremodel) > 0: # Deleting the last item clears selection self.setCurrentIndex(len(self.featuremodel) - 1) def removeSelectedFeature(self): if self.currentIndex >= 0: self.removeFeature(self.currentIndex) def duplicateFeature(self): desc = self.featuremodel[self.currentIndex] self.addFeature(copy.deepcopy(desc)) def check_attrs_values(self, attr, data): for i in range(len(data)): for var in attr: if not math.isnan(data[i, var]) \ and int(data[i, var]) >= len(var.values): return var.name return None def _validate_descriptors(self, desc): def validate(source): try: return validate_exp(ast.parse(source, mode="eval")) except Exception: return False final = [] invalid = [] for d in desc: if validate(d.expression): final.append(d) else: final.append(d._replace(expression="")) invalid.append(d) if invalid: self.Error.invalid_expressions(", ".join(s.name for s in invalid)) return final def apply(self): self.Error.clear() if self.data is None: return desc = list(self.featuremodel) desc = self._validate_descriptors(desc) source_vars = tuple(self.data.domain) + self.data.domain.metas new_variables = construct_variables(desc, source_vars) attrs = [var for var in new_variables if var.is_primitive()] metas = [var for var in new_variables if not var.is_primitive()] new_domain = Orange.data.Domain( self.data.domain.attributes + tuple(attrs), self.data.domain.class_vars, metas=self.data.domain.metas + tuple(metas) ) try: data = Orange.data.Table(new_domain, self.data) except Exception as err: log = logging.getLogger(__name__) log.error("", exc_info=True) self.error("".join(format_exception_only(type(err), err)).rstrip()) return disc_attrs_not_ok = self.check_attrs_values( [var for var in attrs if var.is_discrete], data) if disc_attrs_not_ok: self.Error.more_values_needed(disc_attrs_not_ok) return self.send("Data", data) def send_report(self): items = OrderedDict() for feature in self.featuremodel: if isinstance(feature, DiscreteDescriptor): items[feature.name] = "{} (discrete with values {}{})".format( feature.expression, feature.values, "; ordered" * feature.ordered) elif isinstance(feature, ContinuousDescriptor): items[feature.name] = "{} (numeric)".format(feature.expression) else: items[feature.name] = "{} (text)".format(feature.expression) self.report_items( report.plural("Constructed feature{s}", len(items)), items)
def __init__(self, data): icon = QApplication.style().standardIcon(QStyle.SP_MessageBoxWarning) F = self.DataField def _finished(*, key=(data.get(F.MODULE), data.get(F.WIDGET_MODULE)), filename=data.get(F.WIDGET_SCHEME)): self._cache.add(key) try: os.remove(filename) except Exception: pass super().__init__(None, Qt.Window, modal=True, sizeGripEnabled=True, windowIcon=icon, windowTitle='Unexpected Error', finished=_finished) self._data = data layout = QVBoxLayout(self) self.setLayout(layout) labels = QWidget(self) labels_layout = QHBoxLayout(self) labels.setLayout(labels_layout) labels_layout.addWidget(QLabel(pixmap=icon.pixmap(50, 50))) labels_layout.addWidget( QLabel('The program encountered an unexpected error. Please<br>' 'report it anonymously to the developers.<br><br>' 'The following data will be reported:')) labels_layout.addStretch(1) layout.addWidget(labels) font = QFont('Monospace', 10) font.setStyleHint(QFont.Monospace) font.setFixedPitch(True) textbrowser = QTextBrowser(self, font=font, openLinks=False, lineWrapMode=QTextBrowser.NoWrap, anchorClicked=QDesktopServices.openUrl) layout.addWidget(textbrowser) def _reload_text(): add_scheme = cb.isChecked() settings.setValue('error-reporting/add-scheme', add_scheme) lines = ['<table>'] for k, v in data.items(): if k.startswith('_'): continue _v, v = v, escape(str(v)) if k == F.WIDGET_SCHEME: if not add_scheme: continue v = '<a href="{}">{}</a>'.format( urljoin('file:', pathname2url(_v)), v) if k in (F.STACK_TRACE, F.LOCALS): v = v.replace('\n', '<br>').replace(' ', ' ') lines.append( '<tr><th align="left">{}:</th><td>{}</td></tr>'.format( k, v)) lines.append('</table>') textbrowser.setHtml(''.join(lines)) settings = QSettings() cb = QCheckBox('Include workflow (data will NOT be transmitted)', self, checked=settings.value('error-reporting/add-scheme', True, type=bool)) cb.stateChanged.connect(_reload_text) _reload_text() layout.addWidget(cb) buttons = QWidget(self) buttons_layout = QHBoxLayout(self) buttons.setLayout(buttons_layout) buttons_layout.addWidget( QPushButton('Send Report (Thanks!)', default=True, clicked=self.accept)) buttons_layout.addWidget( QPushButton("Don't Send", default=False, clicked=self.reject)) layout.addWidget(buttons)
class LineScanPlot(QWidget, OWComponent, SelectionGroupMixin, ImageColorSettingMixin, ImageZoomMixin): attr_x = ContextSetting(None) gamma = Setting(0) selection_changed = Signal() def __init__(self, parent): QWidget.__init__(self) OWComponent.__init__(self, parent) SelectionGroupMixin.__init__(self) ImageColorSettingMixin.__init__(self) self.parent = parent self.selection_type = SELECTMANY self.saving_enabled = True self.selection_enabled = True self.viewtype = INDIVIDUAL # required bt InteractiveViewBox self.highlighted = None self.data_points = None self.data_imagepixels = None self.plotview = pg.PlotWidget(background="w", viewBox=InteractiveViewBox(self)) self.plot = self.plotview.getPlotItem() self.plot.scene().installEventFilter( HelpEventDelegate(self.help_event, self)) layout = QVBoxLayout() self.setLayout(layout) self.layout().setContentsMargins(0, 0, 0, 0) self.layout().addWidget(self.plotview) self.img = ImageItemNan() self.img.setOpts(axisOrder='row-major') self.plot.addItem(self.img) self.plot.scene().sigMouseMoved.connect(self.plot.vb.mouseMovedEvent) layout = QGridLayout() self.plotview.setLayout(layout) self.button = QPushButton("Menu", self.plotview) self.button.setAutoDefault(False) layout.setRowStretch(1, 1) layout.setColumnStretch(1, 1) layout.addWidget(self.button, 0, 0) view_menu = MenuFocus(self) self.button.setMenu(view_menu) # prepare interface according to the new context self.parent.contextAboutToBeOpened.connect(lambda x: self.init_interface_data(x[0])) self.add_zoom_actions(view_menu) common_options = dict( labelWidth=50, orientation=Qt.Horizontal, sendSelectedValue=True, valueType=str) choose_xy = QWidgetAction(self) box = gui.vBox(self) box.setFocusPolicy(Qt.TabFocus) self.xy_model = DomainModel(DomainModel.METAS | DomainModel.CLASSES, valid_types=DomainModel.PRIMITIVE, placeholder="Position (index)") self.cb_attr_x = gui.comboBox( box, self, "attr_x", label="Axis x:", callback=self.update_attr, model=self.xy_model, **common_options) box.setFocusProxy(self.cb_attr_x) box.layout().addWidget(self.color_settings_box()) choose_xy.setDefaultWidget(box) view_menu.addAction(choose_xy) self.lsx = None # info about the X axis self.lsy = None # info about the Y axis self.data = None self.data_ids = {} def init_interface_data(self, data): same_domain = (self.data and data and data.domain == self.data.domain) if not same_domain: self.init_attr_values(data) def help_event(self, ev): pos = self.plot.vb.mapSceneToView(ev.scenePos()) sel, wavenumber_ind = self._points_at_pos(pos) prepared = [] if sel is not None: prepared.append(str(self.wavenumbers[wavenumber_ind])) for d in self.data[sel]: variables = [v for v in self.data.domain.metas + self.data.domain.class_vars if v not in [self.attr_x]] features = ['{} = {}'.format(attr.name, d[attr]) for attr in variables] features.append('value = {}'.format(d[wavenumber_ind])) prepared.append("\n".join(features)) text = "\n\n".join(prepared) if text: text = ('<span style="white-space:pre">{}</span>' .format(escape(text))) QToolTip.showText(ev.screenPos(), text, widget=self.plotview) return True else: return False def update_attr(self): self.update_view() def init_attr_values(self, data): domain = data.domain if data is not None else None self.xy_model.set_domain(domain) self.attr_x = self.xy_model[0] if self.xy_model else None def set_data(self, data): if data: self.data = data self.data_ids = {e: i for i, e in enumerate(data.ids)} self.restore_selection_settings() else: self.data = None self.data_ids = {} def update_view(self): self.img.clear() self.img.setSelection(None) self.lsx = None self.lsy = None self.wavenumbers = None self.data_xs = None self.data_imagepixels = None if self.data and len(self.data.domain.attributes): if self.attr_x is not None: xat = self.data.domain[self.attr_x] ndom = Domain([xat]) datam = Table(ndom, self.data) coorx = datam.X[:, 0] else: coorx = np.arange(len(self.data)) self.lsx = lsx = values_to_linspace(coorx) self.data_xs = coorx self.wavenumbers = wavenumbers = getx(self.data) self.lsy = lsy = values_to_linspace(wavenumbers) # set data imdata = np.ones((lsy[2], lsx[2])) * float("nan") xindex = index_values(coorx, lsx) yindex = index_values(wavenumbers, lsy) for xind, d in zip(xindex, self.data.X): imdata[yindex, xind] = d self.data_imagepixels = xindex self.img.setImage(imdata, autoLevels=False) self.img.setLevels([0, 1]) self.update_levels() self.update_color_schema() # shift centres of the pixels so that the axes are useful shiftx = _shift(lsx) shifty = _shift(lsy) left = lsx[0] - shiftx bottom = lsy[0] - shifty width = (lsx[1]-lsx[0]) + 2*shiftx height = (lsy[1]-lsy[0]) + 2*shifty self.img.setRect(QRectF(left, bottom, width, height)) self.refresh_img_selection() def refresh_img_selection(self): selected_px = np.zeros((self.lsy[2], self.lsx[2]), dtype=np.uint8) selected_px[:, self.data_imagepixels] = self.selection_group self.img.setSelection(selected_px) def make_selection(self, selected, add): """Add selected indices to the selection.""" add_to_group, add_group, remove = selection_modifiers() if self.data and self.lsx and self.lsy: if add_to_group: # both keys - need to test it before add_group selnum = np.max(self.selection_group) elif add_group: selnum = np.max(self.selection_group) + 1 elif remove: selnum = 0 else: self.selection_group *= 0 selnum = 1 if selected is not None: self.selection_group[selected] = selnum self.refresh_img_selection() self.prepare_settings_for_saving() self.selection_changed.emit() def _points_at_pos(self, pos): if self.data and self.lsx and self.lsy: x, y = pos.x(), pos.y() x_distance = np.abs(self.data_xs - x) sel = (x_distance < _shift(self.lsx)) wavenumber_distance = np.abs(self.wavenumbers - y) wavenumber_ind = np.argmin(wavenumber_distance) return sel, wavenumber_ind return None, None def select_by_click(self, pos, add): sel, _ = self._points_at_pos(pos) self.make_selection(sel, add)
def __init__(self): super().__init__() #: widget's runtime state self.__state = State.NoState self.data = None self._n_image_categories = 0 self._n_image_data = 0 self._n_skipped = 0 self.__invalidated = False self.__pendingTask = None vbox = gui.vBox(self.controlArea) hbox = gui.hBox(vbox) self.recent_cb = QComboBox( sizeAdjustPolicy=QComboBox.AdjustToMinimumContentsLengthWithIcon, minimumContentsLength=16, acceptDrops=True ) self.recent_cb.installEventFilter(self) self.recent_cb.activated[int].connect(self.__onRecentActivated) icons = standard_icons(self) browseaction = QAction( "Open/Load Images", self, iconText="\N{HORIZONTAL ELLIPSIS}", icon=icons.dir_open_icon, toolTip="Select a directory from which to load the images" ) browseaction.triggered.connect(self.__runOpenDialog) reloadaction = QAction( "Reload", self, icon=icons.reload_icon, toolTip="Reload current image set" ) reloadaction.triggered.connect(self.reload) self.__actions = namespace( browse=browseaction, reload=reloadaction, ) browsebutton = QPushButton( browseaction.iconText(), icon=browseaction.icon(), toolTip=browseaction.toolTip(), clicked=browseaction.trigger ) reloadbutton = QPushButton( reloadaction.iconText(), icon=reloadaction.icon(), clicked=reloadaction.trigger, default=True, ) hbox.layout().addWidget(self.recent_cb) hbox.layout().addWidget(browsebutton) hbox.layout().addWidget(reloadbutton) self.addActions([browseaction, reloadaction]) reloadaction.changed.connect( lambda: reloadbutton.setEnabled(reloadaction.isEnabled()) ) box = gui.vBox(vbox, "Info") self.infostack = QStackedWidget() self.info_area = QLabel( text="No image set selected", wordWrap=True ) self.progress_widget = QProgressBar( minimum=0, maximum=0 ) self.cancel_button = QPushButton( "Cancel", icon=icons.cancel_icon, ) self.cancel_button.clicked.connect(self.cancel) w = QWidget() vlayout = QVBoxLayout() vlayout.setContentsMargins(0, 0, 0, 0) hlayout = QHBoxLayout() hlayout.setContentsMargins(0, 0, 0, 0) hlayout.addWidget(self.progress_widget) hlayout.addWidget(self.cancel_button) vlayout.addLayout(hlayout) self.pathlabel = TextLabel() self.pathlabel.setTextElideMode(Qt.ElideMiddle) self.pathlabel.setAttribute(Qt.WA_MacSmallSize) vlayout.addWidget(self.pathlabel) w.setLayout(vlayout) self.infostack.addWidget(self.info_area) self.infostack.addWidget(w) box.layout().addWidget(self.infostack) self.__initRecentItemsModel() self.__invalidated = True self.__executor = ThreadExecutor(self) QApplication.postEvent(self, QEvent(RuntimeEvent.Init))
class FileWidget(QWidget): on_open = pyqtSignal(str) def __init__(self, dialog_title='', dialog_format='', start_dir=os.path.expanduser('~/'), icon_size=(12, 20), minimal_width=200, browse_label='Browse', on_open=None, reload_button=True, reload_label='Reload', recent_files=None, directory_aliases=None, allow_empty=True, empty_file_label='(none)'): """ Creates a widget with a button for file loading and an optional combo box for recent files and reload buttons. Args: dialog_title (str): The title of the dialog. dialog_format (str): Formats for the dialog. start_dir (str): A directory to start from. icon_size (int, int): The size of buttons' icons. on_open (callable): A callback function that accepts filepath as the only argument. reload_button (bool): Whether to show reload button. reload_label (str): The text displayed on the reload button. recent_files (List[str]): List of recent files. directory_aliases (dict): An {alias: dir} dictionary for fast directories' access. allow_empty (bool): Whether empty path is allowed. """ super().__init__() self.dialog_title = dialog_title self.dialog_format = dialog_format self.start_dir = start_dir self.recent_files = recent_files self.directory_aliases = directory_aliases or {} self.check_existence() self.on_open.connect(on_open) self.allow_empty = allow_empty self.empty_file_label = empty_file_label layout = QHBoxLayout(self) layout.setContentsMargins(0, 0, 0, 0) if recent_files is not None: self.file_combo = QComboBox() self.file_combo.setMinimumWidth(minimal_width) self.file_combo.activated[int].connect(self.select) self.update_combo() layout.addWidget(self.file_combo) self.browse_button = QPushButton(browse_label) self.browse_button.setFocusPolicy(Qt.NoFocus) self.browse_button.clicked.connect(self.browse) self.browse_button.setIcon(self.style() .standardIcon(QStyle.SP_DirOpenIcon)) self.browse_button.setIconSize(QSize(*icon_size)) self.browse_button.setSizePolicy(QSizePolicy.Fixed, QSizePolicy.Fixed) layout.addWidget(self.browse_button) if reload_button: self.reload_button = QPushButton(reload_label) self.reload_button.setFocusPolicy(Qt.NoFocus) self.reload_button.clicked.connect(self.reload) self.reload_button.setIcon(self.style() .standardIcon(QStyle.SP_BrowserReload)) self.reload_button.setSizePolicy(QSizePolicy.Fixed, QSizePolicy.Fixed) self.reload_button.setIconSize(QSize(*icon_size)) layout.addWidget(self.reload_button) def browse(self, start_dir=None): start_dir = start_dir or self.start_dir path, _ = QFileDialog().getOpenFileName(self, self.dialog_title, start_dir, self.dialog_format) if path and self.recent_files is not None: if path in self.recent_files: self.recent_files.remove(path) self.recent_files.insert(0, path) self.update_combo() self.open_file(path) def select(self, n): name = self.file_combo.currentText() if n < len(self.recent_files): name = self.recent_files[n] del self.recent_files[n] self.recent_files.insert(0, name) self.open_file(self.recent_files[0]) self.update_combo() elif name == self.empty_file_label: self.open_file(self.empty_file_label) elif name in self.directory_aliases: self.browse(self.directory_aliases[name]) def update_combo(self): if self.recent_files is not None: self.file_combo.clear() for file in self.recent_files: self.file_combo.addItem(os.path.split(file)[1]) if self.allow_empty or not self.recent_files: self.file_combo.addItem(self.empty_file_label) for alias in self.directory_aliases.keys(): self.file_combo.addItem(alias) def reload(self): if self.recent_files: self.select(0) def check_existence(self): if self.recent_files: to_remove = [ file for file in self.recent_files if not os.path.exists(file) ] for file in to_remove: self.recent_files.remove(file) def open_file(self, path): try: self.on_open.emit(path if path != self.empty_file_label else '') except (OSError, IOError): self.loading_error_signal.emit('Could not open "{}".' .format(path))
def __init__(self, dialog_title='', dialog_format='', start_dir=os.path.expanduser('~/'), icon_size=(12, 20), minimal_width=200, browse_label='Browse', on_open=None, reload_button=True, reload_label='Reload', recent_files=None, directory_aliases=None, allow_empty=True, empty_file_label='(none)'): """ Creates a widget with a button for file loading and an optional combo box for recent files and reload buttons. Args: dialog_title (str): The title of the dialog. dialog_format (str): Formats for the dialog. start_dir (str): A directory to start from. icon_size (int, int): The size of buttons' icons. on_open (callable): A callback function that accepts filepath as the only argument. reload_button (bool): Whether to show reload button. reload_label (str): The text displayed on the reload button. recent_files (List[str]): List of recent files. directory_aliases (dict): An {alias: dir} dictionary for fast directories' access. allow_empty (bool): Whether empty path is allowed. """ super().__init__() self.dialog_title = dialog_title self.dialog_format = dialog_format self.start_dir = start_dir self.recent_files = recent_files self.directory_aliases = directory_aliases or {} self.check_existence() self.on_open.connect(on_open) self.allow_empty = allow_empty self.empty_file_label = empty_file_label layout = QHBoxLayout(self) layout.setContentsMargins(0, 0, 0, 0) if recent_files is not None: self.file_combo = QComboBox() self.file_combo.setMinimumWidth(minimal_width) self.file_combo.activated[int].connect(self.select) self.update_combo() layout.addWidget(self.file_combo) self.browse_button = QPushButton(browse_label) self.browse_button.setFocusPolicy(Qt.NoFocus) self.browse_button.clicked.connect(self.browse) self.browse_button.setIcon(self.style() .standardIcon(QStyle.SP_DirOpenIcon)) self.browse_button.setIconSize(QSize(*icon_size)) self.browse_button.setSizePolicy(QSizePolicy.Fixed, QSizePolicy.Fixed) layout.addWidget(self.browse_button) if reload_button: self.reload_button = QPushButton(reload_label) self.reload_button.setFocusPolicy(Qt.NoFocus) self.reload_button.clicked.connect(self.reload) self.reload_button.setIcon(self.style() .standardIcon(QStyle.SP_BrowserReload)) self.reload_button.setSizePolicy(QSizePolicy.Fixed, QSizePolicy.Fixed) self.reload_button.setIconSize(QSize(*icon_size)) layout.addWidget(self.reload_button)
class ImagePlot(QWidget, OWComponent, SelectionGroupMixin, ImageColorSettingMixin, ImageZoomMixin): attr_x = ContextSetting(None) attr_y = ContextSetting(None) gamma = Setting(0) selection_changed = Signal() def __init__(self, parent): QWidget.__init__(self) OWComponent.__init__(self, parent) SelectionGroupMixin.__init__(self) ImageColorSettingMixin.__init__(self) ImageZoomMixin.__init__(self) self.parent = parent self.selection_type = SELECTMANY self.saving_enabled = True self.selection_enabled = True self.viewtype = INDIVIDUAL # required bt InteractiveViewBox self.highlighted = None self.data_points = None self.data_values = None self.data_imagepixels = None self.plotview = pg.PlotWidget(background="w", viewBox=InteractiveViewBox(self)) self.plot = self.plotview.getPlotItem() self.plot.scene().installEventFilter( HelpEventDelegate(self.help_event, self)) layout = QVBoxLayout() self.setLayout(layout) self.layout().setContentsMargins(0, 0, 0, 0) self.layout().addWidget(self.plotview) self.img = ImageItemNan() self.img.setOpts(axisOrder='row-major') self.plot.addItem(self.img) self.plot.vb.setAspectLocked() self.plot.scene().sigMouseMoved.connect(self.plot.vb.mouseMovedEvent) layout = QGridLayout() self.plotview.setLayout(layout) self.button = QPushButton("Menu", self.plotview) self.button.setAutoDefault(False) layout.setRowStretch(1, 1) layout.setColumnStretch(1, 1) layout.addWidget(self.button, 0, 0) view_menu = MenuFocus(self) self.button.setMenu(view_menu) # prepare interface according to the new context self.parent.contextAboutToBeOpened.connect(lambda x: self.init_interface_data(x[0])) actions = [] self.add_zoom_actions(view_menu) select_square = QAction( "Select (square)", self, triggered=self.plot.vb.set_mode_select_square, ) select_square.setShortcuts([Qt.Key_S]) select_square.setShortcutContext(Qt.WidgetWithChildrenShortcut) actions.append(select_square) select_polygon = QAction( "Select (polygon)", self, triggered=self.plot.vb.set_mode_select_polygon, ) select_polygon.setShortcuts([Qt.Key_P]) select_polygon.setShortcutContext(Qt.WidgetWithChildrenShortcut) actions.append(select_polygon) if self.saving_enabled: save_graph = QAction( "Save graph", self, triggered=self.save_graph, ) save_graph.setShortcuts([QKeySequence(Qt.ControlModifier | Qt.Key_I)]) actions.append(save_graph) view_menu.addActions(actions) self.addActions(actions) common_options = dict( labelWidth=50, orientation=Qt.Horizontal, sendSelectedValue=True, valueType=str) choose_xy = QWidgetAction(self) box = gui.vBox(self) box.setFocusPolicy(Qt.TabFocus) self.xy_model = DomainModel(DomainModel.METAS | DomainModel.CLASSES, valid_types=DomainModel.PRIMITIVE) self.cb_attr_x = gui.comboBox( box, self, "attr_x", label="Axis x:", callback=self.update_attr, model=self.xy_model, **common_options) self.cb_attr_y = gui.comboBox( box, self, "attr_y", label="Axis y:", callback=self.update_attr, model=self.xy_model, **common_options) box.setFocusProxy(self.cb_attr_x) box.layout().addWidget(self.color_settings_box()) choose_xy.setDefaultWidget(box) view_menu.addAction(choose_xy) self.markings_integral = [] self.lsx = None # info about the X axis self.lsy = None # info about the Y axis self.data = None self.data_ids = {} def init_interface_data(self, data): same_domain = (self.data and data and data.domain == self.data.domain) if not same_domain: self.init_attr_values(data) def help_event(self, ev): pos = self.plot.vb.mapSceneToView(ev.scenePos()) sel = self._points_at_pos(pos) prepared = [] if sel is not None: data, vals, points = self.data[sel], self.data_values[sel], self.data_points[sel] for d, v, p in zip(data, vals, points): basic = "({}, {}): {}".format(p[0], p[1], v) variables = [v for v in self.data.domain.metas + self.data.domain.class_vars if v not in [self.attr_x, self.attr_y]] features = ['{} = {}'.format(attr.name, d[attr]) for attr in variables] prepared.append("\n".join([basic] + features)) text = "\n\n".join(prepared) if text: text = ('<span style="white-space:pre">{}</span>' .format(escape(text))) QToolTip.showText(ev.screenPos(), text, widget=self.plotview) return True else: return False def update_attr(self): self.update_view() def init_attr_values(self, data): domain = data.domain if data is not None else None self.xy_model.set_domain(domain) self.attr_x = self.xy_model[0] if self.xy_model else None self.attr_y = self.xy_model[1] if len(self.xy_model) >= 2 \ else self.attr_x def save_graph(self): saveplot.save_plot(self.plotview, self.parent.graph_writers) def set_data(self, data): if data: self.data = data self.data_ids = {e: i for i, e in enumerate(data.ids)} self.restore_selection_settings() else: self.data = None self.data_ids = {} def refresh_markings(self, di): refresh_integral_markings([{"draw": di}], self.markings_integral, self.parent.curveplot) def update_view(self): self.img.clear() self.img.setSelection(None) self.lsx = None self.lsy = None self.data_points = None self.data_values = None self.data_imagepixels = None if self.data and self.attr_x and self.attr_y: xat = self.data.domain[self.attr_x] yat = self.data.domain[self.attr_y] ndom = Orange.data.Domain([xat, yat]) datam = Orange.data.Table(ndom, self.data) coorx = datam.X[:, 0] coory = datam.X[:, 1] self.data_points = datam.X self.lsx = lsx = values_to_linspace(coorx) self.lsy = lsy = values_to_linspace(coory) if lsx[-1] * lsy[-1] > IMAGE_TOO_BIG: self.parent.Error.image_too_big(lsx[-1], lsy[-1]) return else: self.parent.Error.image_too_big.clear() di = {} if self.parent.value_type == 0: # integrals imethod = self.parent.integration_methods[self.parent.integration_method] if imethod != Integrate.PeakAt: datai = Integrate(methods=imethod, limits=[[self.parent.lowlim, self.parent.highlim]])(self.data) else: datai = Integrate(methods=imethod, limits=[[self.parent.choose, self.parent.choose]])(self.data) if np.any(self.parent.curveplot.selection_group): # curveplot can have a subset of curves on the input> match IDs ind = np.flatnonzero(self.parent.curveplot.selection_group)[0] dind = self.data_ids[self.parent.curveplot.data[ind].id] di = datai.domain.attributes[0].compute_value.draw_info(self.data[dind:dind+1]) d = datai.X[:, 0] else: dat = self.data.domain[self.parent.attr_value] ndom = Orange.data.Domain([dat]) d = Orange.data.Table(ndom, self.data).X[:, 0] self.refresh_markings(di) # set data imdata = np.ones((lsy[2], lsx[2])) * float("nan") xindex = index_values(coorx, lsx) yindex = index_values(coory, lsy) imdata[yindex, xindex] = d self.data_values = d self.data_imagepixels = np.vstack((yindex, xindex)).T self.img.setImage(imdata, autoLevels=False) self.img.setLevels([0, 1]) self.update_levels() self.update_color_schema() # shift centres of the pixels so that the axes are useful shiftx = _shift(lsx) shifty = _shift(lsy) left = lsx[0] - shiftx bottom = lsy[0] - shifty width = (lsx[1]-lsx[0]) + 2*shiftx height = (lsy[1]-lsy[0]) + 2*shifty self.img.setRect(QRectF(left, bottom, width, height)) self.refresh_img_selection() def refresh_img_selection(self): selected_px = np.zeros((self.lsy[2], self.lsx[2]), dtype=np.uint8) selected_px[self.data_imagepixels[:, 0], self.data_imagepixels[:, 1]] = self.selection_group self.img.setSelection(selected_px) def make_selection(self, selected, add): """Add selected indices to the selection.""" add_to_group, add_group, remove = selection_modifiers() if self.data and self.lsx and self.lsy: if add_to_group: # both keys - need to test it before add_group selnum = np.max(self.selection_group) elif add_group: selnum = np.max(self.selection_group) + 1 elif remove: selnum = 0 else: self.selection_group *= 0 selnum = 1 if selected is not None: self.selection_group[selected] = selnum self.refresh_img_selection() self.prepare_settings_for_saving() self.selection_changed.emit() def select_square(self, p1, p2, add): """ Select elements within a square drawn by the user. A selection needs to contain whole pixels """ x1, y1 = p1.x(), p1.y() x2, y2 = p2.x(), p2.y() polygon = [QPointF(x1, y1), QPointF(x2, y1), QPointF(x2, y2), QPointF(x1, y2), QPointF(x1, y1)] self.select_polygon(polygon, add) def select_polygon(self, polygon, add): """ Select by a polygon which has to contain whole pixels. """ if self.data and self.lsx and self.lsy: polygon = [(p.x(), p.y()) for p in polygon] # a polygon should contain all pixel shiftx = _shift(self.lsx) shifty = _shift(self.lsy) points_edges = [self.data_points + [[shiftx, shifty]], self.data_points + [[-shiftx, shifty]], self.data_points + [[shiftx, -shifty]], self.data_points + [[-shiftx, -shifty]]] inp = in_polygon(points_edges[0], polygon) for p in points_edges[1:]: inp *= in_polygon(p, polygon) self.make_selection(inp, add) def _points_at_pos(self, pos): if self.data and self.lsx and self.lsy: x, y = pos.x(), pos.y() distance = np.abs(self.data_points - [[x, y]]) sel = (distance[:, 0] < _shift(self.lsx)) * (distance[:, 1] < _shift(self.lsy)) return sel def select_by_click(self, pos, add): sel = self._points_at_pos(pos) self.make_selection(sel, add)
def __init__(self, parent): QWidget.__init__(self) OWComponent.__init__(self, parent) SelectionGroupMixin.__init__(self) ImageColorSettingMixin.__init__(self) self.parent = parent self.selection_type = SELECTMANY self.saving_enabled = True self.selection_enabled = True self.viewtype = INDIVIDUAL # required bt InteractiveViewBox self.highlighted = None self.data_points = None self.data_imagepixels = None self.plotview = pg.PlotWidget(background="w", viewBox=InteractiveViewBox(self)) self.plot = self.plotview.getPlotItem() self.plot.scene().installEventFilter( HelpEventDelegate(self.help_event, self)) layout = QVBoxLayout() self.setLayout(layout) self.layout().setContentsMargins(0, 0, 0, 0) self.layout().addWidget(self.plotview) self.img = ImageItemNan() self.img.setOpts(axisOrder='row-major') self.plot.addItem(self.img) self.plot.scene().sigMouseMoved.connect(self.plot.vb.mouseMovedEvent) layout = QGridLayout() self.plotview.setLayout(layout) self.button = QPushButton("Menu", self.plotview) self.button.setAutoDefault(False) layout.setRowStretch(1, 1) layout.setColumnStretch(1, 1) layout.addWidget(self.button, 0, 0) view_menu = MenuFocus(self) self.button.setMenu(view_menu) # prepare interface according to the new context self.parent.contextAboutToBeOpened.connect(lambda x: self.init_interface_data(x[0])) self.add_zoom_actions(view_menu) common_options = dict( labelWidth=50, orientation=Qt.Horizontal, sendSelectedValue=True, valueType=str) choose_xy = QWidgetAction(self) box = gui.vBox(self) box.setFocusPolicy(Qt.TabFocus) self.xy_model = DomainModel(DomainModel.METAS | DomainModel.CLASSES, valid_types=DomainModel.PRIMITIVE, placeholder="Position (index)") self.cb_attr_x = gui.comboBox( box, self, "attr_x", label="Axis x:", callback=self.update_attr, model=self.xy_model, **common_options) box.setFocusProxy(self.cb_attr_x) box.layout().addWidget(self.color_settings_box()) choose_xy.setDefaultWidget(box) view_menu.addAction(choose_xy) self.lsx = None # info about the X axis self.lsy = None # info about the Y axis self.data = None self.data_ids = {}
def __init__(self): super().__init__() #: widget's runtime state self.__state = State.NoState self.data = None self._n_image_categories = 0 self._n_image_data = 0 self._n_skipped = 0 self.__invalidated = False self.__pendingTask = None vbox = gui.vBox(self.controlArea) hbox = gui.hBox(vbox) self.recent_cb = QComboBox( sizeAdjustPolicy=QComboBox.AdjustToMinimumContentsLengthWithIcon, minimumContentsLength=16, acceptDrops=True) self.recent_cb.installEventFilter(self) self.recent_cb.activated[int].connect(self.__onRecentActivated) icons = standard_icons(self) browseaction = QAction( "Open/Load Images", self, iconText="\N{HORIZONTAL ELLIPSIS}", icon=icons.dir_open_icon, toolTip="Select a directory from which to load the images") browseaction.triggered.connect(self.__runOpenDialog) reloadaction = QAction("Reload", self, icon=icons.reload_icon, toolTip="Reload current image set") reloadaction.triggered.connect(self.reload) self.__actions = namespace( browse=browseaction, reload=reloadaction, ) browsebutton = QPushButton(browseaction.iconText(), icon=browseaction.icon(), toolTip=browseaction.toolTip(), clicked=browseaction.trigger) reloadbutton = QPushButton( reloadaction.iconText(), icon=reloadaction.icon(), clicked=reloadaction.trigger, default=True, ) hbox.layout().addWidget(self.recent_cb) hbox.layout().addWidget(browsebutton) hbox.layout().addWidget(reloadbutton) self.addActions([browseaction, reloadaction]) reloadaction.changed.connect( lambda: reloadbutton.setEnabled(reloadaction.isEnabled())) box = gui.vBox(vbox, "Info") self.infostack = QStackedWidget() self.info_area = QLabel(text="No image set selected", wordWrap=True) self.progress_widget = QProgressBar(minimum=0, maximum=0) self.cancel_button = QPushButton( "Cancel", icon=icons.cancel_icon, ) self.cancel_button.clicked.connect(self.cancel) w = QWidget() vlayout = QVBoxLayout() vlayout.setContentsMargins(0, 0, 0, 0) hlayout = QHBoxLayout() hlayout.setContentsMargins(0, 0, 0, 0) hlayout.addWidget(self.progress_widget) hlayout.addWidget(self.cancel_button) vlayout.addLayout(hlayout) self.pathlabel = TextLabel() self.pathlabel.setTextElideMode(Qt.ElideMiddle) self.pathlabel.setAttribute(Qt.WA_MacSmallSize) vlayout.addWidget(self.pathlabel) w.setLayout(vlayout) self.infostack.addWidget(self.info_area) self.infostack.addWidget(w) box.layout().addWidget(self.infostack) self.__initRecentItemsModel() self.__invalidated = True self.__executor = ThreadExecutor(self) QApplication.postEvent(self, QEvent(RuntimeEvent.Init))
class OWFeatureConstructor(OWWidget): name = "Feature Constructor" description = "Construct new features (data columns) from a set of " \ "existing features in the input data set." icon = "icons/FeatureConstructor.svg" class Inputs: data = Input("Data", Orange.data.Table) class Outputs: data = Output("Data", Orange.data.Table) want_main_area = False settingsHandler = FeatureConstructorHandler() descriptors = ContextSetting([]) currentIndex = ContextSetting(-1) EDITORS = [ (ContinuousDescriptor, ContinuousFeatureEditor), (DiscreteDescriptor, DiscreteFeatureEditor), (StringDescriptor, StringFeatureEditor) ] class Error(OWWidget.Error): more_values_needed = Msg("Categorical feature {} needs more values.") invalid_expressions = Msg("Invalid expressions: {}.") def __init__(self): super().__init__() self.data = None self.editors = {} box = gui.vBox(self.controlArea, "Variable Definitions") toplayout = QHBoxLayout() toplayout.setContentsMargins(0, 0, 0, 0) box.layout().addLayout(toplayout) self.editorstack = QStackedWidget( sizePolicy=QSizePolicy(QSizePolicy.MinimumExpanding, QSizePolicy.MinimumExpanding) ) for descclass, editorclass in self.EDITORS: editor = editorclass() editor.featureChanged.connect(self._on_modified) self.editors[descclass] = editor self.editorstack.addWidget(editor) self.editorstack.setEnabled(False) buttonlayout = QVBoxLayout(spacing=10) buttonlayout.setContentsMargins(0, 0, 0, 0) self.addbutton = QPushButton( "New", toolTip="Create a new variable", minimumWidth=120, shortcut=QKeySequence.New ) def unique_name(fmt, reserved): candidates = (fmt.format(i) for i in count(1)) return next(c for c in candidates if c not in reserved) def reserved_names(): varnames = [] if self.data is not None: varnames = [var.name for var in self.data.domain.variables + self.data.domain.metas] varnames += [desc.name for desc in self.featuremodel] return set(varnames) def generate_newname(fmt): return unique_name(fmt, reserved_names()) menu = QMenu(self.addbutton) cont = menu.addAction("Numeric") cont.triggered.connect( lambda: self.addFeature( ContinuousDescriptor(generate_newname("X{}"), "", 3)) ) disc = menu.addAction("Categorical") disc.triggered.connect( lambda: self.addFeature( DiscreteDescriptor(generate_newname("D{}"), "", ("A", "B"), -1, False)) ) string = menu.addAction("Text") string.triggered.connect( lambda: self.addFeature( StringDescriptor(generate_newname("S{}"), "")) ) menu.addSeparator() self.duplicateaction = menu.addAction("Duplicate Selected Variable") self.duplicateaction.triggered.connect(self.duplicateFeature) self.duplicateaction.setEnabled(False) self.addbutton.setMenu(menu) self.removebutton = QPushButton( "Remove", toolTip="Remove selected variable", minimumWidth=120, shortcut=QKeySequence.Delete ) self.removebutton.clicked.connect(self.removeSelectedFeature) buttonlayout.addWidget(self.addbutton) buttonlayout.addWidget(self.removebutton) buttonlayout.addStretch(10) toplayout.addLayout(buttonlayout, 0) toplayout.addWidget(self.editorstack, 10) # Layout for the list view layout = QVBoxLayout(spacing=1, margin=0) self.featuremodel = DescriptorModel(parent=self) self.featureview = QListView( minimumWidth=200, sizePolicy=QSizePolicy(QSizePolicy.Minimum, QSizePolicy.MinimumExpanding) ) self.featureview.setItemDelegate(FeatureItemDelegate(self)) self.featureview.setModel(self.featuremodel) self.featureview.selectionModel().selectionChanged.connect( self._on_selectedVariableChanged ) layout.addWidget(self.featureview) box.layout().addLayout(layout, 1) box = gui.hBox(self.controlArea) gui.rubber(box) commit = gui.button(box, self, "Send", callback=self.apply, default=True) commit.setMinimumWidth(180) def setCurrentIndex(self, index): index = min(index, len(self.featuremodel) - 1) self.currentIndex = index if index >= 0: itemmodels.select_row(self.featureview, index) desc = self.featuremodel[min(index, len(self.featuremodel) - 1)] editor = self.editors[type(desc)] self.editorstack.setCurrentWidget(editor) editor.setEditorData(desc, self.data.domain if self.data else None) self.editorstack.setEnabled(index >= 0) self.duplicateaction.setEnabled(index >= 0) self.removebutton.setEnabled(index >= 0) def _on_selectedVariableChanged(self, selected, *_): index = selected_row(self.featureview) if index is not None: self.setCurrentIndex(index) else: self.setCurrentIndex(-1) def _on_modified(self): if self.currentIndex >= 0: editor = self.editorstack.currentWidget() self.featuremodel[self.currentIndex] = editor.editorData() self.descriptors = list(self.featuremodel) def setDescriptors(self, descriptors): """ Set a list of variable descriptors to edit. """ self.descriptors = descriptors self.featuremodel[:] = list(self.descriptors) @Inputs.data @check_sql_input def setData(self, data=None): """Set the input dataset.""" self.closeContext() self.data = data if self.data is not None: descriptors = list(self.descriptors) currindex = self.currentIndex self.descriptors = [] self.currentIndex = -1 self.openContext(data) if descriptors != self.descriptors or \ self.currentIndex != currindex: # disconnect from the selection model while reseting the model selmodel = self.featureview.selectionModel() selmodel.selectionChanged.disconnect( self._on_selectedVariableChanged) self.featuremodel[:] = list(self.descriptors) self.setCurrentIndex(self.currentIndex) selmodel.selectionChanged.connect( self._on_selectedVariableChanged) self.editorstack.setEnabled(self.currentIndex >= 0) def handleNewSignals(self): if self.data is not None: self.apply() else: self.Outputs.data.send(None) def addFeature(self, descriptor): self.featuremodel.append(descriptor) self.setCurrentIndex(len(self.featuremodel) - 1) editor = self.editorstack.currentWidget() editor.nameedit.setFocus() editor.nameedit.selectAll() def removeFeature(self, index): del self.featuremodel[index] index = selected_row(self.featureview) if index is not None: self.setCurrentIndex(index) elif index is None and len(self.featuremodel) > 0: # Deleting the last item clears selection self.setCurrentIndex(len(self.featuremodel) - 1) def removeSelectedFeature(self): if self.currentIndex >= 0: self.removeFeature(self.currentIndex) def duplicateFeature(self): desc = self.featuremodel[self.currentIndex] self.addFeature(copy.deepcopy(desc)) def check_attrs_values(self, attr, data): for i in range(len(data)): for var in attr: if not math.isnan(data[i, var]) \ and int(data[i, var]) >= len(var.values): return var.name return None def _validate_descriptors(self, desc): def validate(source): try: return validate_exp(ast.parse(source, mode="eval")) except Exception: return False final = [] invalid = [] for d in desc: if validate(d.expression): final.append(d) else: final.append(d._replace(expression="")) invalid.append(d) if invalid: self.Error.invalid_expressions(", ".join(s.name for s in invalid)) return final def apply(self): self.Error.clear() if self.data is None: return desc = list(self.featuremodel) desc = self._validate_descriptors(desc) source_vars = self.data.domain.variables + self.data.domain.metas new_variables = construct_variables(desc, source_vars) attrs = [var for var in new_variables if var.is_primitive()] metas = [var for var in new_variables if not var.is_primitive()] new_domain = Orange.data.Domain( self.data.domain.attributes + tuple(attrs), self.data.domain.class_vars, metas=self.data.domain.metas + tuple(metas) ) try: data = self.data.transform(new_domain) except Exception as err: log = logging.getLogger(__name__) log.error("", exc_info=True) self.error("".join(format_exception_only(type(err), err)).rstrip()) return disc_attrs_not_ok = self.check_attrs_values( [var for var in attrs if var.is_discrete], data) if disc_attrs_not_ok: self.Error.more_values_needed(disc_attrs_not_ok) return self.Outputs.data.send(data) def send_report(self): items = OrderedDict() for feature in self.featuremodel: if isinstance(feature, DiscreteDescriptor): items[feature.name] = "{} (categorical with values {}{})".format( feature.expression, feature.values, "; ordered" * feature.ordered) elif isinstance(feature, ContinuousDescriptor): items[feature.name] = "{} (numeric)".format(feature.expression) else: items[feature.name] = "{} (text)".format(feature.expression) self.report_items( report.plural("Constructed feature{s}", len(items)), items)
def get_button(label, callback): button = QPushButton(label, self) button.setFlat(True) button.setFixedWidth(12) button.clicked.connect(callback) return button
def __init__(self): super().__init__() self.data = None self.editors = {} box = gui.vBox(self.controlArea, "Variable Definitions") toplayout = QHBoxLayout() toplayout.setContentsMargins(0, 0, 0, 0) box.layout().addLayout(toplayout) self.editorstack = QStackedWidget( sizePolicy=QSizePolicy(QSizePolicy.MinimumExpanding, QSizePolicy.MinimumExpanding) ) for descclass, editorclass in self.EDITORS: editor = editorclass() editor.featureChanged.connect(self._on_modified) self.editors[descclass] = editor self.editorstack.addWidget(editor) self.editorstack.setEnabled(False) buttonlayout = QVBoxLayout(spacing=10) buttonlayout.setContentsMargins(0, 0, 0, 0) self.addbutton = QPushButton( "New", toolTip="Create a new variable", minimumWidth=120, shortcut=QKeySequence.New ) def unique_name(fmt, reserved): candidates = (fmt.format(i) for i in count(1)) return next(c for c in candidates if c not in reserved) def reserved_names(): varnames = [] if self.data is not None: varnames = [var.name for var in self.data.domain.variables + self.data.domain.metas] varnames += [desc.name for desc in self.featuremodel] return set(varnames) def generate_newname(fmt): return unique_name(fmt, reserved_names()) menu = QMenu(self.addbutton) cont = menu.addAction("Numeric") cont.triggered.connect( lambda: self.addFeature( ContinuousDescriptor(generate_newname("X{}"), "", 3)) ) disc = menu.addAction("Categorical") disc.triggered.connect( lambda: self.addFeature( DiscreteDescriptor(generate_newname("D{}"), "", ("A", "B"), -1, False)) ) string = menu.addAction("Text") string.triggered.connect( lambda: self.addFeature( StringDescriptor(generate_newname("S{}"), "")) ) menu.addSeparator() self.duplicateaction = menu.addAction("Duplicate Selected Variable") self.duplicateaction.triggered.connect(self.duplicateFeature) self.duplicateaction.setEnabled(False) self.addbutton.setMenu(menu) self.removebutton = QPushButton( "Remove", toolTip="Remove selected variable", minimumWidth=120, shortcut=QKeySequence.Delete ) self.removebutton.clicked.connect(self.removeSelectedFeature) buttonlayout.addWidget(self.addbutton) buttonlayout.addWidget(self.removebutton) buttonlayout.addStretch(10) toplayout.addLayout(buttonlayout, 0) toplayout.addWidget(self.editorstack, 10) # Layout for the list view layout = QVBoxLayout(spacing=1, margin=0) self.featuremodel = DescriptorModel(parent=self) self.featureview = QListView( minimumWidth=200, sizePolicy=QSizePolicy(QSizePolicy.Minimum, QSizePolicy.MinimumExpanding) ) self.featureview.setItemDelegate(FeatureItemDelegate(self)) self.featureview.setModel(self.featuremodel) self.featureview.selectionModel().selectionChanged.connect( self._on_selectedVariableChanged ) layout.addWidget(self.featureview) box.layout().addLayout(layout, 1) box = gui.hBox(self.controlArea) gui.rubber(box) commit = gui.button(box, self, "Send", callback=self.apply, default=True) commit.setMinimumWidth(180)
def __init__(self): super().__init__() self.data = None self.editors = {} box = gui.vBox(self.controlArea, "Variable Definitions") toplayout = QHBoxLayout() toplayout.setContentsMargins(0, 0, 0, 0) box.layout().addLayout(toplayout) self.editorstack = QStackedWidget( sizePolicy=QSizePolicy(QSizePolicy.MinimumExpanding, QSizePolicy.MinimumExpanding) ) for descclass, editorclass in self.EDITORS: editor = editorclass() editor.featureChanged.connect(self._on_modified) self.editors[descclass] = editor self.editorstack.addWidget(editor) self.editorstack.setEnabled(False) buttonlayout = QVBoxLayout(spacing=10) buttonlayout.setContentsMargins(0, 0, 0, 0) self.addbutton = QPushButton( "New", toolTip="Create a new variable", minimumWidth=120, shortcut=QKeySequence.New ) def unique_name(fmt, reserved): candidates = (fmt.format(i) for i in count(1)) return next(c for c in candidates if c not in reserved) def reserved_names(): varnames = [] if self.data is not None: varnames = [var.name for var in self.data.domain.variables + self.data.domain.metas] varnames += [desc.name for desc in self.featuremodel] return set(varnames) def generate_newname(fmt): return unique_name(fmt, reserved_names()) menu = QMenu(self.addbutton) cont = menu.addAction("Continuous") cont.triggered.connect( lambda: self.addFeature( ContinuousDescriptor(generate_newname("X{}"), "", 3)) ) disc = menu.addAction("Discrete") disc.triggered.connect( lambda: self.addFeature( DiscreteDescriptor(generate_newname("D{}"), "", ("A", "B"), -1, False)) ) string = menu.addAction("String") string.triggered.connect( lambda: self.addFeature( StringDescriptor(generate_newname("S{}"), "")) ) menu.addSeparator() self.duplicateaction = menu.addAction("Duplicate Selected Variable") self.duplicateaction.triggered.connect(self.duplicateFeature) self.duplicateaction.setEnabled(False) self.addbutton.setMenu(menu) self.removebutton = QPushButton( "Remove", toolTip="Remove selected variable", minimumWidth=120, shortcut=QKeySequence.Delete ) self.removebutton.clicked.connect(self.removeSelectedFeature) buttonlayout.addWidget(self.addbutton) buttonlayout.addWidget(self.removebutton) buttonlayout.addStretch(10) toplayout.addLayout(buttonlayout, 0) toplayout.addWidget(self.editorstack, 10) # Layout for the list view layout = QVBoxLayout(spacing=1, margin=0) self.featuremodel = DescriptorModel(parent=self) self.featureview = QListView( minimumWidth=200, sizePolicy=QSizePolicy(QSizePolicy.Minimum, QSizePolicy.MinimumExpanding) ) self.featureview.setItemDelegate(FeatureItemDelegate(self)) self.featureview.setModel(self.featuremodel) self.featureview.selectionModel().selectionChanged.connect( self._on_selectedVariableChanged ) layout.addWidget(self.featureview) box.layout().addLayout(layout, 1) box = gui.hBox(self.controlArea) box.layout().addWidget(self.report_button) self.report_button.setMinimumWidth(180) gui.rubber(box) commit = gui.button(box, self, "Send", callback=self.apply, default=True) commit.setMinimumWidth(180)
def __init__(self, parent): QWidget.__init__(self) OWComponent.__init__(self, parent) SelectionGroupMixin.__init__(self) ImageColorSettingMixin.__init__(self) ImageZoomMixin.__init__(self) self.parent = parent self.selection_type = SELECTMANY self.saving_enabled = True self.selection_enabled = True self.viewtype = INDIVIDUAL # required bt InteractiveViewBox self.highlighted = None self.data_points = None self.data_values = None self.data_imagepixels = None self.plotview = pg.PlotWidget(background="w", viewBox=InteractiveViewBox(self)) self.plot = self.plotview.getPlotItem() self.plot.scene().installEventFilter( HelpEventDelegate(self.help_event, self)) layout = QVBoxLayout() self.setLayout(layout) self.layout().setContentsMargins(0, 0, 0, 0) self.layout().addWidget(self.plotview) self.img = ImageItemNan() self.img.setOpts(axisOrder='row-major') self.plot.addItem(self.img) self.plot.vb.setAspectLocked() self.plot.scene().sigMouseMoved.connect(self.plot.vb.mouseMovedEvent) layout = QGridLayout() self.plotview.setLayout(layout) self.button = QPushButton("Menu", self.plotview) self.button.setAutoDefault(False) layout.setRowStretch(1, 1) layout.setColumnStretch(1, 1) layout.addWidget(self.button, 0, 0) view_menu = MenuFocus(self) self.button.setMenu(view_menu) # prepare interface according to the new context self.parent.contextAboutToBeOpened.connect(lambda x: self.init_interface_data(x[0])) actions = [] self.add_zoom_actions(view_menu) select_square = QAction( "Select (square)", self, triggered=self.plot.vb.set_mode_select_square, ) select_square.setShortcuts([Qt.Key_S]) select_square.setShortcutContext(Qt.WidgetWithChildrenShortcut) actions.append(select_square) select_polygon = QAction( "Select (polygon)", self, triggered=self.plot.vb.set_mode_select_polygon, ) select_polygon.setShortcuts([Qt.Key_P]) select_polygon.setShortcutContext(Qt.WidgetWithChildrenShortcut) actions.append(select_polygon) if self.saving_enabled: save_graph = QAction( "Save graph", self, triggered=self.save_graph, ) save_graph.setShortcuts([QKeySequence(Qt.ControlModifier | Qt.Key_I)]) actions.append(save_graph) view_menu.addActions(actions) self.addActions(actions) common_options = dict( labelWidth=50, orientation=Qt.Horizontal, sendSelectedValue=True, valueType=str) choose_xy = QWidgetAction(self) box = gui.vBox(self) box.setFocusPolicy(Qt.TabFocus) self.xy_model = DomainModel(DomainModel.METAS | DomainModel.CLASSES, valid_types=DomainModel.PRIMITIVE) self.cb_attr_x = gui.comboBox( box, self, "attr_x", label="Axis x:", callback=self.update_attr, model=self.xy_model, **common_options) self.cb_attr_y = gui.comboBox( box, self, "attr_y", label="Axis y:", callback=self.update_attr, model=self.xy_model, **common_options) box.setFocusProxy(self.cb_attr_x) box.layout().addWidget(self.color_settings_box()) choose_xy.setDefaultWidget(box) view_menu.addAction(choose_xy) self.markings_integral = [] self.lsx = None # info about the X axis self.lsy = None # info about the Y axis self.data = None self.data_ids = {}
class OSK(QWidget): def __init__(self, rWidget=None): super(OSK, self).__init__() self.showFullScreen() self._rWidget = rWidget self.layout = QVBoxLayout(self) self.currentText = QLabel(self) self.currentText.setAlignment(Qt.AlignCenter) if rWidget is not None: self.currentText.setText(rWidget.text()) self.layout.addWidget(self.currentText) keyLayout = [['1', '2', '3', '4', '5', '6', '7', '8', '9', '0', '-'], ['q', 'w', 'e', 'r', 't', 'y', 'u', 'i', 'o', 'p'], ['a', 's', 'd', 'f', 'g', 'h', 'j', 'k', 'l'], ['z', 'x', 'c', 'v', 'b', 'n', 'm']] for l in keyLayout: panel = QWidget(self) panel.layout = QHBoxLayout(panel) for key in l: button = OSKKey(key, self, parent=self) panel.layout.addWidget(button) self.layout.addWidget(panel) contolPanel = QWidget(self) contolPanel.layout = QHBoxLayout(contolPanel) self._shift = QPushButton('Shift', self) self._shift.setCheckable(True) self._shift.setFixedWidth(150) contolPanel.layout.addWidget(self._shift) spaceBar = OSKKey('space', self, parent=self) spaceBar.rKey = ' ' spaceBar.setFixedWidth(2 * self.window().geometry().width() / 3) contolPanel.layout.addWidget(spaceBar) bkspc = OSKKey('delete', self, parent=self) bkspc.rKey = '<<' contolPanel.layout.addWidget(bkspc) self.layout.addWidget(contolPanel) self.closeButton = QPushButton("OK", self) self.closeButton.clicked.connect(self.__closeButtonAction) self.layout.addWidget(self.closeButton) def onClick(self, key): if self.rWidget is not None: if key == '<<': self.rWidget.setText(self.rWidget.text()[:-1]) elif self._shift.isChecked(): self.rWidget.setText(self.rWidget.text() + key.upper()) self._shift.setChecked(False) else: self.rWidget.setText(self.rWidget.text() + key) self.currentText.setText(self.rWidget.text()) def __closeButtonAction(self): self.parent().hide() @property def rWidget(self): return self._rWidget @rWidget.setter def rWidget(self, value): if not isinstance(value, QWidget) and value is not None: raise TypeError( "Supplied return Widget is not of type QWidget: %s" % type(value).__name__) else: self._rWidget = value self.currentText.setText(value.text())
def __init__(self): super().__init__() self._current_path = "" icon_open_dir = self.style().standardIcon(QStyle.SP_DirOpenIcon) # Top grid with file selection combo box grid = QGridLayout() lb = QLabel("File:") lb.setSizePolicy(QSizePolicy.Fixed, QSizePolicy.Fixed) self.recent_combo = cb = QComboBox( sizeAdjustPolicy=QComboBox.AdjustToMinimumContentsLengthWithIcon, minimumContentsLength=20, toolTip="Select a recent file") self.recent_model = cb.model() # type: QStandardItemModel self.recent_combo.activated[int].connect(self._select_recent) browse = QPushButton("...", autoDefault=False, icon=icon_open_dir, clicked=self.browse) # reload = QPushButton("Reload", autoDefault=False, icon=icon_reload) grid.addWidget(lb, 0, 0, Qt.AlignVCenter) grid.addWidget(cb, 0, 1) grid.addWidget(browse, 0, 2) # grid.addWidget(reload, 0, 3) self.summary_label = label = QLabel("", self) label.ensurePolished() f = label.font() if f.pointSizeF() != -1: f.setPointSizeF(f.pointSizeF() * 5 / 6) else: f.setPixelSize(f.pixelSize() * 5 / 6) label.setFont(f) grid.addWidget(label, 1, 1, 1, 3) self.controlArea.layout().addLayout(grid) box = gui.widgetBox(self.controlArea, "Headers and Row Labels", spacing=-1) hl = QHBoxLayout() hl.setContentsMargins(0, 0, 0, 0) self.header_rows_spin = spin = QSpinBox(box, minimum=0, maximum=3, value=self._header_rows_count, keyboardTracking=False) spin.valueChanged.connect(self.set_header_rows_count) hl.addWidget(QLabel("Data starts with", box)) hl.addWidget(self.header_rows_spin) hl.addWidget(QLabel("header row(s)", box)) hl.addStretch(10) box.layout().addLayout(hl) hl = QHBoxLayout() hl.setContentsMargins(0, 0, 0, 0) self.header_cols_spin = spin = QSpinBox(box, minimum=0, maximum=3, value=self._header_cols_count, keyboardTracking=False) spin.valueChanged.connect(self.set_header_cols_count) hl.addWidget(QLabel("First", box)) hl.addWidget(self.header_cols_spin) hl.addWidget(QLabel("column(s) are row labels", box)) hl.addStretch(10) box.layout().addLayout(hl) self.data_struct_box = box = gui.widgetBox(self.controlArea, "Input Data Structure") gui.radioButtons(box, self, "_cells_in_rows", [ "Genes in rows, samples in columns", "Samples in rows, genes in columns" ], callback=self._invalidate) box = gui.widgetBox(self.controlArea, "Sample Data", spacing=-1) grid = QGridLayout() grid.setContentsMargins(0, 0, 0, 0) box.layout().addLayout(grid) self.sample_rows_cb = cb = QCheckBox(checked=self._sample_rows_enabled) spin = QSpinBox(minimum=0, maximum=100, value=self._sample_rows_p, enabled=self._sample_rows_enabled) spin.valueChanged.connect(self.set_sample_rows_p) suffix = QLabel("% of Samples", enabled=self._sample_rows_enabled) cb.toggled.connect(self.set_sample_rows_enabled) cb.toggled.connect(spin.setEnabled) cb.toggled.connect(suffix.setEnabled) grid.addWidget(cb, 0, 0) grid.addWidget(spin, 0, 1) grid.addWidget(suffix, 0, 2) self.sample_cols_cb = cb = QCheckBox(checked=self._sample_cols_enabled) spin = QSpinBox(minimum=0, maximum=100, value=self._sample_cols_p, enabled=self._sample_cols_enabled) spin.valueChanged.connect(self.set_sample_cols_p) suffix = QLabel("% of genes", enabled=self._sample_cols_enabled) cb.toggled.connect(self.set_sample_cols_enabled) cb.toggled.connect(spin.setEnabled) cb.toggled.connect(suffix.setEnabled) grid.addWidget(cb, 1, 0) grid.addWidget(spin, 1, 1) grid.addWidget(suffix, 1, 2) grid.setColumnStretch(3, 10) self.annotation_files_box = box = gui.widgetBox( self.controlArea, "Cell && Gene Annotation Files") form = QFormLayout( formAlignment=Qt.AlignLeft, rowWrapPolicy=QFormLayout.WrapAllRows, ) box.layout().addLayout(form) self.row_annotations_cb = cb = QCheckBox( "Cell annotations", checked=self._row_annotations_enabled) self._row_annotations_w = w = QWidget( enabled=self._row_annotations_enabled) cb.toggled.connect(self.set_row_annotations_enabled) cb.toggled.connect(w.setEnabled) hl = QHBoxLayout() hl.setContentsMargins(0, 0, 0, 0) w.setLayout(hl) self.row_annotations_combo = QComboBox( sizeAdjustPolicy=QComboBox.AdjustToMinimumContentsLengthWithIcon, minimumContentsLength=18) self.row_annotations_combo.activated.connect(self._invalidate) hl.addWidget(self.row_annotations_combo) hl.addWidget( QPushButton("...", box, autoDefault=False, icon=icon_open_dir, clicked=self.browse_row_annotations)) # hl.addWidget(QPushButton("Reload", box, autoDefault=False, # icon=icon_reload)) form.addRow(cb, w) self.col_annotations_cb = cb = QCheckBox( "Gene annotations", checked=self._col_annotations_enabled) self._col_annotations_w = w = QWidget( enabled=self._col_annotations_enabled) cb.toggled.connect(self.set_col_annotations_enabled) cb.toggled.connect(w.setEnabled) hl = QHBoxLayout() hl.setContentsMargins(0, 0, 0, 0) w.setLayout(hl) self.col_annotations_combo = QComboBox( sizeAdjustPolicy=QComboBox.AdjustToMinimumContentsLengthWithIcon, minimumContentsLength=18) self.col_annotations_combo.activated.connect(self._invalidate) hl.addWidget(self.col_annotations_combo) hl.addWidget( QPushButton("...", box, autoDefault=False, icon=icon_open_dir, clicked=self.browse_col_annotations)) # hl.addWidget(QPushButton("Reload", box, autoDefault=False, # icon=icon_reload)) form.addRow(cb, w) self.controlArea.layout().addStretch(10) self.load_data_button = button = VariableTextPushButton( "Load data", autoDefault=True, textChoiceList=["Load data", "Reload"]) self.load_data_button.setAutoDefault(True) button.clicked.connect(self.commit, Qt.QueuedConnection) self.controlArea.layout().addWidget(button, alignment=Qt.AlignRight) init_recent_paths_model( self.recent_model, [RecentPath.create(p, []) for p in self._recent], ) init_recent_paths_model( self.row_annotations_combo.model(), [RecentPath.create(p, []) for p in self._recent_row_annotations]) init_recent_paths_model( self.col_annotations_combo.model(), [RecentPath.create(p, []) for p in self._recent_col_annotations]) self._update_summary() self._update_warning() if self._last_path != "" and os.path.exists(self._last_path): self.set_current_path(self._last_path) else: self.recent_combo.setCurrentIndex(-1)
def __init__(self, parent=None, filename=None): super(MainForm, self).__init__(parent) self.view = GraphicsView() background = QPixmap(filename) # assume screnshots were taken on the same system stamper is being used on # DPI check might be more robust, can be added if needed background.setDevicePixelRatio(self.devicePixelRatioF()) self.filename = os.path.splitext(filename)[0] if ("-%s" % ORG) in self.filename: self.filename = self.filename[:-len(ORG)-5] + ".png" # self.view.setBackgroundBrush(QBrush(background)) # self.view.setCacheMode(QGraphicsView.CacheBackground) # self.view.setDragMode(QGraphicsView.ScrollHandDrag) self.scene = QGraphicsScene(self) self.scene.addPixmap(background) global scene scene = self.scene self.view.dialog = self self.view.setScene(self.scene) self.prevPoint = QPoint() self.lastStamp = -1 buttonLayout = QVBoxLayout() for text, slot in ( ("&Tag", self.addTag), ("Align &bottom", self.alignBottom), ("Align &left", self.alignLeft), ("&Save", self.save), ("&Quit", self.accept)): button = QPushButton(text) button.clicked.connect(slot) if not MAC: button.setFocusPolicy(Qt.NoFocus) self.lineedit.returnPressed.connect(self.updateUi) if text == "&Save": buttonLayout.addStretch(5) if text == "&Quit": buttonLayout.addStretch(1) buttonLayout.addWidget(button) buttonLayout.addStretch() size = background.size() / background.devicePixelRatioF() self.view.resize(size.width(), size.height()) self.scene.setSceneRect(0, 0, size.width(), size.height()) self.view.setSizePolicy(QSizePolicy.Fixed, QSizePolicy.Fixed) layout = QHBoxLayout() layout.addWidget(self.view, 1) layout.addLayout(buttonLayout) self.setLayout(layout) self.setWindowTitle(AppName) info_name = self.filename + "-" + TAG + ".txt" if os.path.exists(info_name): for tag, x, y in [line.strip().split("\t") for line in open(info_name, "rt").readlines()]: self.addTag(int(tag), QPointF(int(x), int(y)), adjust_position=False) global Dirty; Dirty=False self.show() self.raise_()
class Screenshot(QDialog): def __init__(self, parent=None): super().__init__(parent, Qt.CustomizeWindowHint | Qt.FramelessWindowHint | Qt.Window | Qt.WindowStaysOnTopHint | Qt.X11BypassWindowManagerHint) self.setAttribute(Qt.WA_DeleteOnClose) self.installEventFilter(self) self.setMouseTracking(True) self._band = QRubberBand(QRubberBand.Rectangle, self) self._resize_origin = None self._drag_mask = 0 self._origin = None self.selected_image = None # Window background desktop = QApplication.desktop() if is_qt5(): g = desktop.geometry() self._snapshot = QPixmap(g.width(), g.height()) painter = QPainter(self._snapshot) for screen in QApplication.screens(): g = screen.geometry() painter.drawPixmap(g, screen.grabWindow(0, g.x(), g.y(), g.width(), g.height())) painter.end() else: self._snapshot = QPixmap.grabWindow(desktop.winId(), 0, 0, desktop.width(), desktop.height()) self.setGeometry(desktop.geometry()) self._darken = self._snapshot.copy() painter = QPainter(self._darken) brush = QBrush(QColor(0, 0, 0, 128)) painter.setBrush(brush) painter.drawRect(self._darken.rect()) painter.end() # Buttons self._buttons = QWidget(self) self._button_layout = QHBoxLayout(self._buttons) self._button_layout.setSpacing(0) self._button_layout.setContentsMargins(0, 0, 0, 0) self._button_layout.setContentsMargins(0, 0, 0, 0) self.save_as = QPushButton(self.tr('Save As')) self.save_as.pressed.connect(self.save_image_as) self.save_as.setCursor(Qt.ArrowCursor) self._button_layout.addWidget(self.save_as) self.copy = QPushButton(self.tr('Copy')) self.copy.pressed.connect(self.copy_to_clipboard) self.copy.setCursor(Qt.ArrowCursor) self._button_layout.addWidget(self.copy) self.share = QPushButton(self.tr('Share')) self.share.pressed.connect(self.share_selection) self.share.setCursor(Qt.ArrowCursor) self._button_layout.addWidget(self.share) self._buttons.hide() def paintEvent(self, _): painter = QPainter(self) painter.drawPixmap(0, 0, self._darken) if self._band.isVisible(): br = self._band.geometry() r = QRect(br.topLeft(), br.bottomRight()) painter.drawPixmap(r, self._snapshot.copy(r)) def get_selection(self): return self._snapshot.copy(self._band.geometry()) def save_image_as(self): img = self.get_selection().toImage() if img.isNull(): QMessageBox.critical(self, self.tr('Error'), self.tr('No image was selected!')) return self.hide() formats = { self.tr('Portable Network Graphics (*.png)'): 'png', self.tr('Joint Photographic Experts Group (*.jpg *.jpeg)'): 'jpg', self.tr('Graphics Interchange Format (*.gif)'): 'gif', self.tr('Bitmap (*.bmp)'): 'bmp', self.tr('All Images (*.png *.jpg *.gif *.bmp)'): 'all' } file_format = None destination = QFileDialog.getSaveFileName(self, 'Save image', '', ';;'.join(formats.keys())) if isinstance(destination, tuple): destination, file_format = destination file_format = formats[file_format] if file_format == 'all': file_format = None if not file_format: file_format = destination.rsplit('.', 1)[-1] if destination: if file_format not in formats.values(): file_format = 'png' if not destination.endswith('.' + file_format): destination += '.' + file_format img.save(destination, file_format, 0 if file_format == 'png' else 90) self.reject() def copy_to_clipboard(self): img = self.get_selection() if img.isNull(): QMessageBox.critical(self, self.tr('Error'), self.tr('No image was selected!')) return QApplication.clipboard().setPixmap(img) self.reject() def share_selection(self): self.selected_image = self.get_selection() self.accept() def eventFilter(self, obj, e): if e.type() == QEvent.Enter: self.activateWindow() if e.type() == QEvent.KeyPress and e.key() == Qt.Key_Escape: self.reject() return True return super().eventFilter(obj, e) def mousePressEvent(self, event): if self.update_cursor_shape(event.pos(), event.button() == Qt.LeftButton): self._resize_origin = event.pos() else: self._origin = event.pos() if not self._band.isVisible(): self._band.setGeometry(QRect(self._origin, self._origin)) self._band.show() super().mousePressEvent(event) def mouseMoveEvent(self, event): p = event.pos() mouse_down = event.buttons() & Qt.LeftButton if mouse_down: m = self._drag_mask wr = self.rect() if m: g = self._band.geometry() d = p - self._resize_origin if d.x() or d.y(): if m == RESIZE_DRAG: g.translate(d) else: if m & RESIZE_LEFT: g.translate(d.x(), 0) g.setWidth(g.width() - d.x()) elif m & RESIZE_RIGHT: g.setWidth(g.width() + d.x()) if m & RESIZE_TOP: g.translate(0, d.y()) g.setHeight(g.height() - d.y()) elif m & RESIZE_BOTTOM: g.setHeight(g.height() + d.y()) self._resize_origin = p # Contain in the screen px = min(max(g.topLeft().x(), 0), wr.width() - g.width()) py = min(max(g.topLeft().y(), 0), wr.height() - g.height()) g.moveTo(px, py) else: g = QRect(self._origin, p).normalized() self._band.setGeometry(g) br = self._band.geometry() x = (br.width() / 2 - self._buttons.width() / 2) + br.left() # buttons at center of band x = max(0, min(x, wr.width() - self._buttons.width())) # prevent going off-screen if (wr.height() - br.bottom()) > self._buttons.height(): # if at bottom y = br.bottom() else: y = max(0, br.top() - self._buttons.height()) self._buttons.move(x, y) self._buttons.show() self.repaint() else: self.update_cursor_shape(p, mouse_down) self._drag_mask = self.get_drag_mask(p) super().mouseMoveEvent(event) def mouseReleaseEvent(self, event): self.update_cursor_shape(event.pos(), False) super().mouseReleaseEvent(event) def update_cursor_shape(self, p, mouse_down): m = self.get_drag_mask(p) if m == RESIZE_DRAG: self.setCursor(Qt.ClosedHandCursor if mouse_down else Qt.OpenHandCursor) elif (m & RESIZE_LEFT and m & RESIZE_TOP) or (m & RESIZE_RIGHT and m & RESIZE_BOTTOM): self.setCursor(Qt.SizeFDiagCursor) elif (m & RESIZE_LEFT and m & RESIZE_BOTTOM) or (m & RESIZE_RIGHT and m & RESIZE_TOP): self.setCursor(Qt.SizeBDiagCursor) elif m & RESIZE_LEFT or m & RESIZE_RIGHT: self.setCursor(Qt.SizeHorCursor) elif m & RESIZE_TOP or m & RESIZE_BOTTOM: self.setCursor(Qt.SizeVerCursor) else: self.setCursor(Qt.ArrowCursor) return False return True def get_drag_mask(self, p): br = self._band.geometry() if br.contains(p): def is_hovering(x): return 0 <= x <= 10 m = 0 m |= RESIZE_LEFT if is_hovering(p.x() - br.left()) else 0 m |= RESIZE_RIGHT if is_hovering(br.right() - p.x()) else 0 m |= RESIZE_BOTTOM if is_hovering(br.bottom() - p.y()) else 0 m |= RESIZE_TOP if is_hovering(p.y() - br.top()) else 0 if m: return m return RESIZE_DRAG return 0