def createEditor(self, parent, _QStyleOptionViewItem, index): combo = QComboBox(parent) attr = index.model()[index.row()][0] combo.setModel(self._combo_continuous_model if attr.is_continuous else self._combo_discrete_model if attr.is_discrete else self._combo_string_model) return combo
def __init__(self, tree, dataset, master, parent=None): QComboBox.__init__(self, parent) Control.__init__(self, tree, dataset, master) self.setSelectionMode(QListView.ExtendedSelection) model = QStringListModel(self) self.setModel(model) self.setOptions(tree.subelements_top("Option"))
def __init__(self, *args): QComboBox.__init__(self, *args) self.paletteImg = [] self.cachedPalettes = [] ## self.setItemDelegate(PaletteItemDelegate(self, self)) size = self.sizeHint() size = QSize(size.width() * 2 / 3, size.height() * 2 / 3) self.setIconSize(size)
def __init__(self, *args, **kwargs): super().__init__(*args, **kwargs) layout = QFormLayout( fieldGrowthPolicy=QFormLayout.ExpandingFieldsGrow ) layout.setContentsMargins(0, 0, 0, 0) self.nameedit = QLineEdit( placeholderText="Name...", sizePolicy=QSizePolicy(QSizePolicy.Minimum, QSizePolicy.Fixed) ) self.expressionedit = QLineEdit( placeholderText="Expression..." ) self.attrs_model = itemmodels.VariableListModel( ["Select Feature"], parent=self) self.attributescb = QComboBox( minimumContentsLength=16, sizeAdjustPolicy=QComboBox.AdjustToMinimumContentsLengthWithIcon, sizePolicy=QSizePolicy(QSizePolicy.Minimum, QSizePolicy.Minimum) ) self.attributescb.setModel(self.attrs_model) sorted_funcs = sorted(self.FUNCTIONS) self.funcs_model = itemmodels.PyListModelTooltip() self.funcs_model.setParent(self) self.funcs_model[:] = chain(["Select Function"], sorted_funcs) self.funcs_model.tooltips[:] = chain( [''], [self.FUNCTIONS[func].__doc__ for func in sorted_funcs]) self.functionscb = QComboBox( minimumContentsLength=16, sizeAdjustPolicy=QComboBox.AdjustToMinimumContentsLengthWithIcon, sizePolicy=QSizePolicy(QSizePolicy.Minimum, QSizePolicy.Minimum)) self.functionscb.setModel(self.funcs_model) hbox = QHBoxLayout() hbox.addWidget(self.attributescb) hbox.addWidget(self.functionscb) layout.addRow(self.nameedit, self.expressionedit) layout.addRow(self.tr(""), hbox) self.setLayout(layout) self.nameedit.editingFinished.connect(self._invalidate) self.expressionedit.textChanged.connect(self._invalidate) self.attributescb.currentIndexChanged.connect(self.on_attrs_changed) self.functionscb.currentIndexChanged.connect(self.on_funcs_changed) self._modified = False
def __init__(self, tree, dataset, master, parent=None): QComboBox.__init__(self, parent) Control.__init__(self, tree, dataset, master) self.options = [] self.selectedIndex = 0 if getattr(tree, "graph", "0") == "1": self.setOptions(tree.subelements("Option")) else: self.setOptions(tree.subelements_top("Option")) self.currentIndexChanged[int].connect(self.onIndexChange)
class RecentPathsWComboMixin(RecentPathsWidgetMixin): """ Adds file combo handling to :obj:`RecentPathsWidgetMixin`. The mixin constructs a combo box `self.file_combo` and provides a method `set_file_list` for updating its content. The mixin also overloads the inherited `add_path` and `select_file` to call `set_file_list`. """ def __init__(self): super().__init__() self.file_combo = \ QComboBox(self, sizeAdjustPolicy=QComboBox.AdjustToContents) def add_path(self, filename): """Add (or move) a file name to the top of recent paths""" super().add_path(filename) self.set_file_list() def select_file(self, n): """Move the n-th file to the top of the list""" super().select_file(n) self.set_file_list() def set_file_list(self): """ Sets the items in the file list combo """ self._check_init() self.file_combo.clear() if not self.recent_paths: self.file_combo.addItem("(none)") self.file_combo.model().item(0).setEnabled(False) else: for i, recent in enumerate(self.recent_paths): self.file_combo.addItem(recent.basename) self.file_combo.model().item(i).setToolTip(recent.abspath) def workflowEnvChanged(self, key, value, oldvalue): super().workflowEnvChanged(key, value, oldvalue) if key == "basedir": self.set_file_list()
class DropDownRadioBooleanFilter(QWidget, Control): """Container for multiple boolean filters """ def __init__(self, tree, dataset, master, parent=None): QWidget.__init__(self, parent) Control.__init__(self, tree, dataset, master) self.setLayout(QHBoxLayout()) self.cb = QComboBox(self) self.layout().addWidget(self.cb) rblayout = QVBoxLayout() self.radioButtons = [QRadioButton("Only", self), QRadioButton("Excluded", self) ] for b in self.radioButtons: rblayout.addWidget(b) self.radioButtons[0].setChecked(True) self.layout().addLayout(rblayout) self.options = [] self.setOptions(tree.subelements_top("Option")) def setOptions(self, options): self.cb.clear() self.options = [] for option in options: self.cb.addItem(option.displayName) self.options.append(option) for op, rb in zip(self.options[0].subelements_top("Option"), self.radioButtons): rb.setText(op.displayName) rb.setChecked(getattr(op, "default", "false") == "true") def value(self): return {"excluded": "0" if self.radioButtons[0].isChecked() else "1"} def query(self): filter = self.options[self.cb.currentIndex()] filter = biomart.FilterDescription( self.tree.registry, "FilterDescription", filter.attributes, filter.children) return [("Filter", filter, self.value())] def setControlValue(self, name, value): for i, option in enumerate(self.options): if option.internalName == name: self.cb.setCurrentIndex(i) if value == "Only": self.radioButtons[0].setChecked(True)
def __init__(self, parent=None, **kwargs): super().__init__(parent, **kwargs) self.setLayout(QVBoxLayout()) form = QFormLayout() self.__centercb = QComboBox() self.__centercb.addItems(["No Centering", "Center by Mean", "Center by Median"]) self.__scalecb = QComboBox() self.__scalecb.addItems(["No scaling", "Scale by SD", "Scale by span"]) form.addRow("Center:", self.__centercb) form.addRow("Scale:", self.__scalecb) self.layout().addLayout(form) self.__centercb.currentIndexChanged.connect(self.changed) self.__scalecb.currentIndexChanged.connect(self.changed) self.__centercb.activated.connect(self.edited) self.__scalecb.activated.connect(self.edited)
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 = QComboBox( 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 set_new_operators(self, attr_combo, adding_all, selected_index=None, selected_values=None): oper_combo = QComboBox() oper_combo.row = attr_combo.row oper_combo.attr_combo = attr_combo var = self.data.domain[attr_combo.currentText()] oper_combo.addItems(self.operator_names[type(var)]) oper_combo.setCurrentIndex(selected_index or 0) self.cond_list.setCellWidget(oper_combo.row, 1, oper_combo) self.set_new_values(oper_combo, adding_all, selected_values) oper_combo.currentIndexChanged.connect( lambda _: self.set_new_values(oper_combo, False))
def __init__(self, tree, dataset, master, parent=None): QWidget.__init__(self, parent) Control.__init__(self, tree, dataset, master) self.setLayout(QVBoxLayout()) self.setContentsMargins(0, 0, 0, 0) self.cb = QComboBox() self.idsEdit = QPlainTextEdit() self.layout().addWidget(self.cb) self.layout().addWidget(self.idsEdit) self.options = [] self.setOptions(tree.subelements_top("Option"))
def __init__(self, parent=None, **kwargs): super().__init__(parent, **kwargs) self.setLayout(QVBoxLayout()) form = QFormLayout() self.__rand_type_cb = QComboBox() self.__rand_type_cb.addItems(["Classes", "Features", "Meta data"]) self.__rand_type_cb.currentIndexChanged.connect(self.changed) self.__rand_type_cb.activated.connect(self.edited) self.__rand_seed_ch = QCheckBox() self.__rand_seed_ch.clicked.connect(self.edited) form.addRow("Randomize:", self.__rand_type_cb) form.addRow("Replicable shuffling:", self.__rand_seed_ch) self.layout().addLayout(form)
class DropDownIdListFilter(QWidget, Control): """Container for multiple id list filters """ def __init__(self, tree, dataset, master, parent=None): QWidget.__init__(self, parent) Control.__init__(self, tree, dataset, master) self.setLayout(QVBoxLayout()) self.setContentsMargins(0, 0, 0, 0) self.cb = QComboBox() self.idsEdit = QPlainTextEdit() self.layout().addWidget(self.cb) self.layout().addWidget(self.idsEdit) self.options = [] self.setOptions(tree.subelements_top("Option")) def setOptions(self, options): self.cb.clear() self.options = [] for option in options: self.cb.addItem(option.displayName) self.options.append(option) def value(self): return str(self.idsEdit.toPlainText()).split() def query(self): filter = self.options[self.cb.currentIndex()] filter = biomart.FilterDescription( self.tree.registry, "FilterDescription", filter.attributes, filter.children) return [("Filter", filter, self.value())] def setControlValue(self, name, value): if isinstance(value, list): value = "\n".join(value) for i, op in enumerate(self.options): if name == op.internalName: self.cb.setCurrentIndex(i) self.idsEdit.setPlainText(value)
class Randomize(BaseEditor): RandomizeClasses, RandomizeAttributes, RandomizeMetas = _Randomize.Type def __init__(self, parent=None, **kwargs): super().__init__(parent, **kwargs) self.setLayout(QVBoxLayout()) form = QFormLayout() self.__rand_type_cb = QComboBox() self.__rand_type_cb.addItems(["Classes", "Features", "Meta data"]) self.__rand_type_cb.currentIndexChanged.connect(self.changed) self.__rand_type_cb.activated.connect(self.edited) self.__rand_seed_ch = QCheckBox() self.__rand_seed_ch.clicked.connect(self.edited) form.addRow("Randomize:", self.__rand_type_cb) form.addRow("Replicable shuffling:", self.__rand_seed_ch) self.layout().addLayout(form) def setParameters(self, params): rand_type = params.get("rand_type", Randomize.RandomizeClasses) self.__rand_type_cb.setCurrentIndex( enum_to_index(_Randomize.Type, rand_type)) self.__rand_seed_ch.setChecked(params.get("rand_seed", 1) or 0) def parameters(self): return {"rand_type": index_to_enum(_Randomize.Type, self.__rand_type_cb.currentIndex()), "rand_seed": 1 if self.__rand_seed_ch.isChecked() else None} @staticmethod def createinstance(params): rand_type = params.get("rand_type", Randomize.RandomizeClasses) rand_seed = params.get("rand_seed", 1) return _Randomize(rand_type=rand_type, rand_seed=rand_seed) def __repr__(self): return "{}, {}".format(self.__rand_type_cb.currentText(), "Replicable" if self.__rand_seed_ch.isChecked() else "Not replicable")
def __init__(self, tree, dataset, master, parent=None): QWidget.__init__(self, parent) Control.__init__(self, tree, dataset, master) self.setLayout(QHBoxLayout()) self.cb = QComboBox(self) self.layout().addWidget(self.cb) rblayout = QVBoxLayout() self.radioButtons = [QRadioButton("Only", self), QRadioButton("Excluded", self) ] for b in self.radioButtons: rblayout.addWidget(b) self.radioButtons[0].setChecked(True) self.layout().addLayout(rblayout) self.options = [] self.setOptions(tree.subelements_top("Option"))
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 = QComboBox( minimumContentsLength=12, sizeAdjustPolicy=QComboBox.AdjustToMinimumContentsLengthWithIcon) attr_combo.row = row for var in filter_visible(chain(self.data.domain.variables, self.data.domain.metas)): attr_combo.addItem(*gui.attributeItem(var)) attr_combo.setCurrentIndex(attr or 0) self.cond_list.setCellWidget(row, 0, attr_combo) 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 createEditor(self, parent, option, index): cb = QComboBox(parent) cb.setModel(self.sortingModel) cb.showPopup() return cb
class OWImpute(OWWidget): name = "Impute" description = "Impute missing values in the data table." icon = "icons/Impute.svg" priority = 2130 class Inputs: data = Input("Data", Orange.data.Table) learner = Input("Learner", Learner) class Outputs: data = Output("Data", Orange.data.Table) class Error(OWWidget.Error): imputation_failed = Msg("Imputation failed for '{}'") model_based_imputer_sparse = Msg("Model based imputer does not work for sparse data") DEFAULT_LEARNER = SimpleTreeLearner() METHODS = [AsDefault(), impute.DoNotImpute(), impute.Average(), impute.AsValue(), impute.Model(DEFAULT_LEARNER), impute.Random(), impute.DropInstances(), impute.Default()] DEFAULT, DO_NOT_IMPUTE, MODEL_BASED_IMPUTER, AS_INPUT = 0, 1, 4, 7 settingsHandler = settings.DomainContextHandler() _default_method_index = settings.Setting(DO_NOT_IMPUTE) variable_methods = settings.ContextSetting({}) autocommit = settings.Setting(True) want_main_area = False resizing_enabled = False def __init__(self): super().__init__() # copy METHODS (some are modified by the widget) self.methods = copy.deepcopy(OWImpute.METHODS) main_layout = QVBoxLayout() main_layout.setContentsMargins(10, 10, 10, 10) self.controlArea.layout().addLayout(main_layout) box = QGroupBox(title=self.tr("Default Method"), flat=False) box_layout = QVBoxLayout(box) main_layout.addWidget(box) button_group = QButtonGroup() button_group.buttonClicked[int].connect(self.set_default_method) for i, method in enumerate(self.methods): if not method.columns_only: button = QRadioButton(method.name) button.setChecked(i == self.default_method_index) button_group.addButton(button, i) box_layout.addWidget(button) self.default_button_group = button_group box = QGroupBox(title=self.tr("Individual Attribute Settings"), flat=False) main_layout.addWidget(box) horizontal_layout = QHBoxLayout(box) main_layout.addWidget(box) self.varview = QListView( selectionMode=QListView.ExtendedSelection ) self.varview.setItemDelegate(DisplayFormatDelegate()) self.varmodel = itemmodels.VariableListModel() self.varview.setModel(self.varmodel) self.varview.selectionModel().selectionChanged.connect( self._on_var_selection_changed ) self.selection = self.varview.selectionModel() horizontal_layout.addWidget(self.varview) method_layout = QVBoxLayout() horizontal_layout.addLayout(method_layout) button_group = QButtonGroup() for i, method in enumerate(self.methods): button = QRadioButton(text=method.name) button_group.addButton(button, i) method_layout.addWidget(button) self.value_combo = QComboBox( minimumContentsLength=8, sizeAdjustPolicy=QComboBox.AdjustToMinimumContentsLength, activated=self._on_value_selected ) self.value_double = QDoubleSpinBox( editingFinished=self._on_value_selected, minimum=-1000., maximum=1000., singleStep=.1, decimals=3, ) self.value_stack = value_stack = QStackedWidget() value_stack.addWidget(self.value_combo) value_stack.addWidget(self.value_double) method_layout.addWidget(value_stack) button_group.buttonClicked[int].connect( self.set_method_for_current_selection ) method_layout.addStretch(2) reset_button = QPushButton( "Restore All to Default", checked=False, checkable=False, clicked=self.reset_variable_methods, default=False, autoDefault=False) method_layout.addWidget(reset_button) self.variable_button_group = button_group box = gui.auto_commit( self.controlArea, self, "autocommit", "Apply", orientation=Qt.Horizontal, checkbox_label="Apply automatically") box.layout().insertSpacing(0, 80) box.layout().insertWidget(0, self.report_button) self.data = None self.learner = None self.modified = False self.default_method = self.methods[self.default_method_index] self.executor = qconcurrent.ThreadExecutor(self) self.__task = None @property def default_method_index(self): return self._default_method_index @default_method_index.setter def default_method_index(self, index): if self._default_method_index != index: self._default_method_index = index self.default_button_group.button(index).setChecked(True) self.default_method = self.methods[self.default_method_index] self.methods[self.DEFAULT].method = self.default_method # update variable view for index in map(self.varmodel.index, range(len(self.varmodel))): method = self.variable_methods.get( index.row(), self.methods[self.DEFAULT]) self.varmodel.setData(index, method, Qt.UserRole) self._invalidate() def set_default_method(self, index): """Set the current selected default imputation method. """ self.default_method_index = index @Inputs.data @check_sql_input def set_data(self, data): self.closeContext() self.varmodel[:] = [] self.variable_methods = {} self.modified = False self.data = data if data is not None: self.varmodel[:] = data.domain.variables self.openContext(data.domain) self.update_varview() self.unconditional_commit() @Inputs.learner def set_learner(self, learner): self.learner = learner or self.DEFAULT_LEARNER imputer = self.methods[self.MODEL_BASED_IMPUTER] imputer.learner = self.learner button = self.default_button_group.button(self.MODEL_BASED_IMPUTER) button.setText(imputer.name) variable_button = self.variable_button_group.button(self.MODEL_BASED_IMPUTER) variable_button.setText(imputer.name) if learner is not None: self.default_method_index = self.MODEL_BASED_IMPUTER self.update_varview() self.commit() def get_method_for_column(self, column_index): """Returns the imputation method for column by its index. """ if not isinstance(column_index, int): column_index = column_index.row() return self.variable_methods.get(column_index, self.methods[self.DEFAULT]) def _invalidate(self): self.modified = True if self.__task is not None: self.cancel() self.commit() def commit(self): self.cancel() self.warning() self.Error.imputation_failed.clear() self.Error.model_based_imputer_sparse.clear() if self.data is None or len(self.data) == 0 or len(self.varmodel) == 0: self.Outputs.data.send(self.data) self.modified = False return data = self.data impute_state = [ (i, var, self.variable_methods.get(i, self.default_method)) for i, var in enumerate(self.varmodel) ] def impute_one(method, var, data): # type: (impute.BaseImputeMethod, Variable, Table) -> Any if isinstance(method, impute.Model) and data.is_sparse(): raise SparseNotSupported() elif isinstance(method, impute.DropInstances): return RowMask(method(data, var)) elif not method.supports_variable(var): raise VariableNotSupported(var) else: return method(data, var) futures = [] for _, var, method in impute_state: f = self.executor.submit( impute_one, copy.deepcopy(method), var, data) futures.append(f) w = qconcurrent.FutureSetWatcher(futures) w.doneAll.connect(self.__commit_finish) w.progressChanged.connect(self.__progress_changed) self.__task = Task(futures, w) self.progressBarInit(processEvents=False) self.setBlocking(True) @Slot() def __commit_finish(self): assert QThread.currentThread() is self.thread() assert self.__task is not None futures = self.__task.futures assert len(futures) == len(self.varmodel) assert self.data is not None self.__task = None self.setBlocking(False) self.progressBarFinished() data = self.data attributes = [] class_vars = [] drop_mask = np.zeros(len(self.data), bool) for i, (var, fut) in enumerate(zip(self.varmodel, futures)): assert fut.done() newvar = [] try: res = fut.result() except SparseNotSupported: self.Error.model_based_imputer_sparse() # ?? break except VariableNotSupported: self.warning("Default method can not handle '{}'". format(var.name)) except Exception: # pylint: disable=broad-except log = logging.getLogger(__name__) log.info("Error for %s", var, exc_info=True) self.Error.imputation_failed(var.name) attributes = class_vars = None break else: if isinstance(res, RowMask): drop_mask |= res.mask newvar = var else: newvar = res if isinstance(newvar, Orange.data.Variable): newvar = [newvar] if i < len(data.domain.attributes): attributes.extend(newvar) else: class_vars.extend(newvar) if attributes is None: data = None else: domain = Orange.data.Domain(attributes, class_vars, data.domain.metas) try: data = self.data.from_table(domain, data[~drop_mask]) except Exception: # pylint: disable=broad-except log = logging.getLogger(__name__) log.info("Error", exc_info=True) self.Error.imputation_failed("Unknown") data = None self.Outputs.data.send(data) self.modified = False @Slot(int, int) def __progress_changed(self, n, d): assert QThread.currentThread() is self.thread() assert self.__task is not None self.progressBarSet(100. * n / d) def cancel(self): if self.__task is not None: task, self.__task = self.__task, None task.cancel() task.watcher.doneAll.disconnect(self.__commit_finish) task.watcher.progressChanged.disconnect(self.__progress_changed) concurrent.futures.wait(task.futures) task.watcher.flush() self.progressBarFinished() self.setBlocking(False) def onDeleteWidget(self): self.cancel() super().onDeleteWidget() def send_report(self): specific = [] for i, var in enumerate(self.varmodel): method = self.variable_methods.get(i, None) if method is not None: specific.append("{} ({})".format(var.name, str(method))) default = self.default_method.name if specific: self.report_items(( ("Default method", default), ("Specific imputers", ", ".join(specific)) )) else: self.report_items((("Method", default),)) def _on_var_selection_changed(self): indexes = self.selection.selectedIndexes() methods = [self.get_method_for_column(i.row()) for i in indexes] def method_key(method): """ Decompose method into its type and parameters. """ # The return value should be hashable and __eq__ comparable if isinstance(method, AsDefault): return AsDefault, (method.method,) elif isinstance(method, impute.Model): return impute.Model, (method.learner,) elif isinstance(method, impute.Default): return impute.Default, (method.default,) else: return type(method), None methods = set(method_key(m) for m in methods) selected_vars = [self.varmodel[index.row()] for index in indexes] has_discrete = any(var.is_discrete for var in selected_vars) fixed_value = None value_stack_enabled = False current_value_widget = None if len(methods) == 1: method_type, parameters = methods.pop() for i, m in enumerate(self.methods): if method_type == type(m): self.variable_button_group.button(i).setChecked(True) if method_type is impute.Default: (fixed_value,) = parameters elif self.variable_button_group.checkedButton() is not None: # Uncheck the current button self.variable_button_group.setExclusive(False) self.variable_button_group.checkedButton().setChecked(False) self.variable_button_group.setExclusive(True) assert self.variable_button_group.checkedButton() is None for method, button in zip(self.methods, self.variable_button_group.buttons()): enabled = all(method.supports_variable(var) for var in selected_vars) button.setEnabled(enabled) if not has_discrete: value_stack_enabled = True current_value_widget = self.value_double elif len(selected_vars) == 1: value_stack_enabled = True current_value_widget = self.value_combo self.value_combo.clear() self.value_combo.addItems(selected_vars[0].values) else: value_stack_enabled = False current_value_widget = None self.variable_button_group.button(self.AS_INPUT).setEnabled(False) self.value_stack.setEnabled(value_stack_enabled) if current_value_widget is not None: self.value_stack.setCurrentWidget(current_value_widget) if fixed_value is not None: if current_value_widget is self.value_combo: self.value_combo.setCurrentIndex(fixed_value) elif current_value_widget is self.value_double: self.value_double.setValue(fixed_value) else: assert False def set_method_for_current_selection(self, method_index): indexes = self.selection.selectedIndexes() self.set_method_for_indexes(indexes, method_index) def set_method_for_indexes(self, indexes, method_index): if method_index == self.DEFAULT: for index in indexes: self.variable_methods.pop(index.row(), None) elif method_index == OWImpute.AS_INPUT: current = self.value_stack.currentWidget() if current is self.value_combo: value = self.value_combo.currentIndex() else: value = self.value_double.value() for index in indexes: method = impute.Default(default=value) self.variable_methods[index.row()] = method else: method = self.methods[method_index] for index in indexes: self.variable_methods[index.row()] = method self.update_varview(indexes) self._invalidate() def update_varview(self, indexes=None): if indexes is None: indexes = map(self.varmodel.index, range(len(self.varmodel))) for index in indexes: self.varmodel.setData(index, self.get_method_for_column(index.row()), Qt.UserRole) def _on_value_selected(self): # The fixed 'Value' in the widget has been changed by the user. self.variable_button_group.button(self.AS_INPUT).setChecked(True) self.set_method_for_current_selection(self.AS_INPUT) def reset_variable_methods(self): indexes = list(map(self.varmodel.index, range(len(self.varmodel)))) self.set_method_for_indexes(indexes, self.DEFAULT) self.variable_button_group.button(self.DEFAULT).setChecked(True)
def __init__(self): super().__init__() self.data = None # type: Optional[Orange.data.Table] self.learner = None # type: Optional[Learner] self.default_learner = SimpleTreeLearner() self.modified = False self.executor = qconcurrent.ThreadExecutor(self) self.__task = None main_layout = QVBoxLayout() main_layout.setContentsMargins(10, 10, 10, 10) self.controlArea.layout().addLayout(main_layout) box = QGroupBox(title=self.tr("Default Method"), flat=False) box_layout = QVBoxLayout(box) main_layout.addWidget(box) button_group = QButtonGroup() button_group.buttonClicked[int].connect(self.set_default_method) for method, _ in list(METHODS.items())[1:-1]: imputer = self.create_imputer(method) button = QRadioButton(imputer.name) button.setChecked(method == self.default_method_index) button_group.addButton(button, method) box_layout.addWidget(button) self.default_button_group = button_group box = QGroupBox(title=self.tr("Individual Attribute Settings"), flat=False) main_layout.addWidget(box) horizontal_layout = QHBoxLayout(box) main_layout.addWidget(box) self.varview = QListView( selectionMode=QListView.ExtendedSelection, uniformItemSizes=True ) self.varview.setItemDelegate(DisplayFormatDelegate()) self.varmodel = itemmodels.VariableListModel() self.varview.setModel(self.varmodel) self.varview.selectionModel().selectionChanged.connect( self._on_var_selection_changed ) self.selection = self.varview.selectionModel() horizontal_layout.addWidget(self.varview) method_layout = QVBoxLayout() horizontal_layout.addLayout(method_layout) button_group = QButtonGroup() for method in Method: imputer = self.create_imputer(method) button = QRadioButton(text=imputer.name) button_group.addButton(button, method) method_layout.addWidget(button) self.value_combo = QComboBox( minimumContentsLength=8, sizeAdjustPolicy=QComboBox.AdjustToMinimumContentsLength, activated=self._on_value_selected ) self.value_double = QDoubleSpinBox( editingFinished=self._on_value_selected, minimum=-1000., maximum=1000., singleStep=.1, decimals=3, ) self.value_stack = value_stack = QStackedWidget() value_stack.addWidget(self.value_combo) value_stack.addWidget(self.value_double) method_layout.addWidget(value_stack) button_group.buttonClicked[int].connect( self.set_method_for_current_selection ) method_layout.addStretch(2) reset_button = QPushButton( "Restore All to Default", checked=False, checkable=False, clicked=self.reset_variable_state, default=False, autoDefault=False) method_layout.addWidget(reset_button) self.variable_button_group = button_group box = gui.auto_commit( self.controlArea, self, "autocommit", "Apply", orientation=Qt.Horizontal, checkbox_label="Apply automatically") box.button.setFixedWidth(180) box.layout().insertStretch(0)
class OWImpute(OWWidget): name = "Impute" description = "Impute missing values in the data table." icon = "icons/Impute.svg" priority = 2130 class Inputs: data = Input("Data", Orange.data.Table) learner = Input("Learner", Learner) class Outputs: data = Output("Data", Orange.data.Table) class Error(OWWidget.Error): imputation_failed = Msg("Imputation failed for '{}'") model_based_imputer_sparse = Msg("Model based imputer does not work for sparse data") settingsHandler = settings.DomainContextHandler() _default_method_index = settings.Setting(int(Method.Leave)) # type: int # Per-variable imputation state (synced in storeSpecificSettings) _variable_imputation_state = settings.ContextSetting({}) # type: VariableState autocommit = settings.Setting(True) want_main_area = False resizing_enabled = False def __init__(self): super().__init__() self.data = None # type: Optional[Orange.data.Table] self.learner = None # type: Optional[Learner] self.default_learner = SimpleTreeLearner() self.modified = False self.executor = qconcurrent.ThreadExecutor(self) self.__task = None main_layout = QVBoxLayout() main_layout.setContentsMargins(10, 10, 10, 10) self.controlArea.layout().addLayout(main_layout) box = QGroupBox(title=self.tr("Default Method"), flat=False) box_layout = QVBoxLayout(box) main_layout.addWidget(box) button_group = QButtonGroup() button_group.buttonClicked[int].connect(self.set_default_method) for method, _ in list(METHODS.items())[1:-1]: imputer = self.create_imputer(method) button = QRadioButton(imputer.name) button.setChecked(method == self.default_method_index) button_group.addButton(button, method) box_layout.addWidget(button) self.default_button_group = button_group box = QGroupBox(title=self.tr("Individual Attribute Settings"), flat=False) main_layout.addWidget(box) horizontal_layout = QHBoxLayout(box) main_layout.addWidget(box) self.varview = QListView( selectionMode=QListView.ExtendedSelection, uniformItemSizes=True ) self.varview.setItemDelegate(DisplayFormatDelegate()) self.varmodel = itemmodels.VariableListModel() self.varview.setModel(self.varmodel) self.varview.selectionModel().selectionChanged.connect( self._on_var_selection_changed ) self.selection = self.varview.selectionModel() horizontal_layout.addWidget(self.varview) method_layout = QVBoxLayout() horizontal_layout.addLayout(method_layout) button_group = QButtonGroup() for method in Method: imputer = self.create_imputer(method) button = QRadioButton(text=imputer.name) button_group.addButton(button, method) method_layout.addWidget(button) self.value_combo = QComboBox( minimumContentsLength=8, sizeAdjustPolicy=QComboBox.AdjustToMinimumContentsLength, activated=self._on_value_selected ) self.value_double = QDoubleSpinBox( editingFinished=self._on_value_selected, minimum=-1000., maximum=1000., singleStep=.1, decimals=3, ) self.value_stack = value_stack = QStackedWidget() value_stack.addWidget(self.value_combo) value_stack.addWidget(self.value_double) method_layout.addWidget(value_stack) button_group.buttonClicked[int].connect( self.set_method_for_current_selection ) method_layout.addStretch(2) reset_button = QPushButton( "Restore All to Default", checked=False, checkable=False, clicked=self.reset_variable_state, default=False, autoDefault=False) method_layout.addWidget(reset_button) self.variable_button_group = button_group box = gui.auto_commit( self.controlArea, self, "autocommit", "Apply", orientation=Qt.Horizontal, checkbox_label="Apply automatically") box.button.setFixedWidth(180) box.layout().insertStretch(0) def create_imputer(self, method, *args): # type: (Method, ...) -> impute.BaseImputeMethod if method == Method.Model: if self.learner is not None: return impute.Model(self.learner) else: return impute.Model(self.default_learner) elif method == Method.AsAboveSoBelow: assert self.default_method_index != Method.AsAboveSoBelow default = self.create_imputer(Method(self.default_method_index)) m = AsDefault() m.method = default return m else: return METHODS[method](*args) @property def default_method_index(self): return self._default_method_index @default_method_index.setter def default_method_index(self, index): if self._default_method_index != index: assert index != Method.AsAboveSoBelow self._default_method_index = index self.default_button_group.button(index).setChecked(True) # update variable view self.update_varview() self._invalidate() def set_default_method(self, index): """Set the current selected default imputation method. """ self.default_method_index = index @Inputs.data @check_sql_input def set_data(self, data): self.closeContext() self.varmodel[:] = [] self._variable_imputation_state = {} # type: VariableState self.modified = False self.data = data if data is not None: self.varmodel[:] = data.domain.variables self.openContext(data.domain) # restore per variable imputation state self._restore_state(self._variable_imputation_state) self.update_varview() self.unconditional_commit() @Inputs.learner def set_learner(self, learner): self.learner = learner or self.default_learner imputer = self.create_imputer(Method.Model) button = self.default_button_group.button(Method.Model) button.setText(imputer.name) variable_button = self.variable_button_group.button(Method.Model) variable_button.setText(imputer.name) if learner is not None: self.default_method_index = Method.Model self.update_varview() self.commit() def get_method_for_column(self, column_index): # type: (int) -> impute.BaseImputeMethod """ Return the imputation method for column by its index. """ assert 0 <= column_index < len(self.varmodel) idx = self.varmodel.index(column_index, 0) state = idx.data(StateRole) if state is None: state = (Method.AsAboveSoBelow, ()) return self.create_imputer(state[0], *state[1]) def _invalidate(self): self.modified = True if self.__task is not None: self.cancel() self.commit() def commit(self): self.cancel() self.warning() self.Error.imputation_failed.clear() self.Error.model_based_imputer_sparse.clear() if self.data is None or len(self.data) == 0 or len(self.varmodel) == 0: self.Outputs.data.send(self.data) self.modified = False return data = self.data impute_state = [ (i, var, self.get_method_for_column(i)) for i, var in enumerate(self.varmodel) ] # normalize to the effective method bypasing AsDefault impute_state = [ (i, var, m.method if isinstance(m, AsDefault) else m) for i, var, m in impute_state ] def impute_one(method, var, data): # type: (impute.BaseImputeMethod, Variable, Table) -> Any if isinstance(method, impute.Model) and data.is_sparse(): raise SparseNotSupported() elif isinstance(method, impute.DropInstances): return RowMask(method(data, var)) elif not method.supports_variable(var): raise VariableNotSupported(var) else: return method(data, var) futures = [] for _, var, method in impute_state: f = self.executor.submit( impute_one, copy.deepcopy(method), var, data) futures.append(f) w = qconcurrent.FutureSetWatcher(futures) w.doneAll.connect(self.__commit_finish) w.progressChanged.connect(self.__progress_changed) self.__task = Task(futures, w) self.progressBarInit(processEvents=False) self.setBlocking(True) @Slot() def __commit_finish(self): assert QThread.currentThread() is self.thread() assert self.__task is not None futures = self.__task.futures assert len(futures) == len(self.varmodel) assert self.data is not None self.__task = None self.setBlocking(False) self.progressBarFinished() data = self.data attributes = [] class_vars = [] drop_mask = np.zeros(len(self.data), bool) for i, (var, fut) in enumerate(zip(self.varmodel, futures)): assert fut.done() newvar = [] try: res = fut.result() except SparseNotSupported: self.Error.model_based_imputer_sparse() # ?? break except VariableNotSupported: self.warning("Default method can not handle '{}'". format(var.name)) except Exception: # pylint: disable=broad-except log = logging.getLogger(__name__) log.info("Error for %s", var, exc_info=True) self.Error.imputation_failed(var.name) attributes = class_vars = None break else: if isinstance(res, RowMask): drop_mask |= res.mask newvar = var else: newvar = res if isinstance(newvar, Orange.data.Variable): newvar = [newvar] if i < len(data.domain.attributes): attributes.extend(newvar) else: class_vars.extend(newvar) if attributes is None: data = None else: domain = Orange.data.Domain(attributes, class_vars, data.domain.metas) try: data = self.data.from_table(domain, data[~drop_mask]) except Exception: # pylint: disable=broad-except log = logging.getLogger(__name__) log.info("Error", exc_info=True) self.Error.imputation_failed("Unknown") data = None self.Outputs.data.send(data) self.modified = False @Slot(int, int) def __progress_changed(self, n, d): assert QThread.currentThread() is self.thread() assert self.__task is not None self.progressBarSet(100. * n / d) def cancel(self): if self.__task is not None: task, self.__task = self.__task, None task.cancel() task.watcher.doneAll.disconnect(self.__commit_finish) task.watcher.progressChanged.disconnect(self.__progress_changed) concurrent.futures.wait(task.futures) task.watcher.flush() self.progressBarFinished() self.setBlocking(False) def onDeleteWidget(self): self.cancel() super().onDeleteWidget() def send_report(self): specific = [] for i, var in enumerate(self.varmodel): method = self.get_method_for_column(i) if not isinstance(method, AsDefault): specific.append("{} ({})".format(var.name, str(method))) default = self.create_imputer(Method.AsAboveSoBelow) if specific: self.report_items(( ("Default method", default.name), ("Specific imputers", ", ".join(specific)) )) else: self.report_items((("Method", default.name),)) def _on_var_selection_changed(self): indexes = self.selection.selectedIndexes() defmethod = (Method.AsAboveSoBelow, ()) methods = [index.data(StateRole) for index in indexes] methods = [m if m is not None else defmethod for m in methods] methods = set(methods) selected_vars = [self.varmodel[index.row()] for index in indexes] has_discrete = any(var.is_discrete for var in selected_vars) fixed_value = None value_stack_enabled = False current_value_widget = None if len(methods) == 1: method_type, parameters = methods.pop() for m in Method: if method_type == m: self.variable_button_group.button(m).setChecked(True) if method_type == Method.Default: (fixed_value,) = parameters elif self.variable_button_group.checkedButton() is not None: # Uncheck the current button self.variable_button_group.setExclusive(False) self.variable_button_group.checkedButton().setChecked(False) self.variable_button_group.setExclusive(True) assert self.variable_button_group.checkedButton() is None # Update variable methods GUI enabled state based on selection. for method in Method: # use a default constructed imputer to query support imputer = self.create_imputer(method) enabled = all(imputer.supports_variable(var) for var in selected_vars) button = self.variable_button_group.button(method) button.setEnabled(enabled) # Update the "Value" edit GUI. if not has_discrete: # no discrete variables -> allow mass edit for all (continuous vars) value_stack_enabled = True current_value_widget = self.value_double elif len(selected_vars) == 1: # single discrete var -> enable and fill the values combo value_stack_enabled = True current_value_widget = self.value_combo self.value_combo.clear() self.value_combo.addItems(selected_vars[0].values) else: # mixed type selection -> disable value_stack_enabled = False current_value_widget = None self.variable_button_group.button(Method.Default).setEnabled(False) self.value_stack.setEnabled(value_stack_enabled) if current_value_widget is not None: self.value_stack.setCurrentWidget(current_value_widget) if fixed_value is not None: # set current value if current_value_widget is self.value_combo: self.value_combo.setCurrentIndex(fixed_value) elif current_value_widget is self.value_double: self.value_double.setValue(fixed_value) else: assert False def set_method_for_current_selection(self, method_index): # type: (Method) -> None indexes = self.selection.selectedIndexes() self.set_method_for_indexes(indexes, method_index) def set_method_for_indexes(self, indexes, method_index): # type: (List[QModelIndex], Method) -> None if method_index == Method.AsAboveSoBelow: for index in indexes: self.varmodel.setData(index, None, StateRole) elif method_index == Method.Default: current = self.value_stack.currentWidget() if current is self.value_combo: value = self.value_combo.currentIndex() else: value = self.value_double.value() for index in indexes: state = (int(Method.Default), (value,)) self.varmodel.setData(index, state, StateRole) else: state = (int(method_index), ()) for index in indexes: self.varmodel.setData(index, state, StateRole) self.update_varview(indexes) self._invalidate() def update_varview(self, indexes=None): if indexes is None: indexes = map(self.varmodel.index, range(len(self.varmodel))) for index in indexes: self.varmodel.setData( index, self.get_method_for_column(index.row()), DisplayMethodRole) def _on_value_selected(self): # The fixed 'Value' in the widget has been changed by the user. self.variable_button_group.button(Method.Default).setChecked(True) self.set_method_for_current_selection(Method.Default) def reset_variable_state(self): indexes = list(map(self.varmodel.index, range(len(self.varmodel)))) self.set_method_for_indexes(indexes, Method.AsAboveSoBelow) self.variable_button_group.button(Method.AsAboveSoBelow).setChecked(True) def _store_state(self): # type: () -> VariableState """ Save the current variable imputation state """ state = {} # type: VariableState for i, var in enumerate(self.varmodel): index = self.varmodel.index(i) m = index.data(StateRole) if m is not None: state[var_key(var)] = m return state def _restore_state(self, state): # type: (VariableState) -> None """ Restore the variable imputation state from the saved state """ def check(state): # check if state is a proper State if isinstance(state, tuple) and len(state) == 2: m, p = state if isinstance(m, int) and isinstance(p, tuple) and \ 0 <= m < len(Method): return True return False for i, var in enumerate(self.varmodel): m = state.get(var_key(var), None) if check(m): self.varmodel.setData(self.varmodel.index(i), m, StateRole) def storeSpecificSettings(self): self._variable_imputation_state = self._store_state() super().storeSpecificSettings()
def __init__(self): super().__init__() RecentPathsWComboMixin.__init__(self) self.domain = None self.data = None self.loaded_file = "" self.reader = None layout = QGridLayout() gui.widgetBox(self.controlArea, margin=0, orientation=layout) vbox = gui.radioButtons(None, self, "source", box=True, addSpace=True, callback=self.load_data, addToLayout=False) rb_button = gui.appendRadioButton(vbox, "File:", addToLayout=False) layout.addWidget(rb_button, 0, 0, Qt.AlignVCenter) box = gui.hBox(None, addToLayout=False, margin=0) box.setSizePolicy(Policy.MinimumExpanding, Policy.Fixed) self.file_combo.setSizePolicy(Policy.MinimumExpanding, Policy.Fixed) self.file_combo.activated[int].connect(self.select_file) box.layout().addWidget(self.file_combo) layout.addWidget(box, 0, 1) file_button = gui.button( None, self, '...', callback=self.browse_file, autoDefault=False) file_button.setIcon(self.style().standardIcon(QStyle.SP_DirOpenIcon)) file_button.setSizePolicy(Policy.Maximum, Policy.Fixed) layout.addWidget(file_button, 0, 2) reload_button = gui.button( None, self, "Reload", callback=self.load_data, autoDefault=False) reload_button.setIcon(self.style().standardIcon( QStyle.SP_BrowserReload)) reload_button.setSizePolicy(Policy.Fixed, Policy.Fixed) layout.addWidget(reload_button, 0, 3) self.sheet_box = gui.hBox(None, addToLayout=False, margin=0) self.sheet_combo = gui.comboBox(None, self, "xls_sheet", callback=self.select_sheet, sendSelectedValue=True,) self.sheet_combo.setSizePolicy( Policy.MinimumExpanding, Policy.Fixed) self.sheet_label = QLabel() self.sheet_label.setText('Sheet') self.sheet_label.setSizePolicy( Policy.MinimumExpanding, Policy.Fixed) self.sheet_box.layout().addWidget( self.sheet_label, Qt.AlignLeft) self.sheet_box.layout().addWidget( self.sheet_combo, Qt.AlignVCenter) layout.addWidget(self.sheet_box, 2, 1) self.sheet_box.hide() rb_button = gui.appendRadioButton(vbox, "URL:", addToLayout=False) layout.addWidget(rb_button, 3, 0, Qt.AlignVCenter) self.url_combo = url_combo = QComboBox() url_model = NamedURLModel(self.sheet_names) url_model.wrap(self.recent_urls) url_combo.setLineEdit(LineEditSelectOnFocus()) url_combo.setModel(url_model) url_combo.setSizePolicy(Policy.MinimumExpanding, Policy.Fixed) url_combo.setEditable(True) url_combo.setInsertPolicy(url_combo.InsertAtTop) url_edit = url_combo.lineEdit() l, t, r, b = url_edit.getTextMargins() url_edit.setTextMargins(l + 5, t, r, b) layout.addWidget(url_combo, 3, 1, 3, 3) url_combo.activated.connect(self._url_set) # whit completer we set that combo box is case sensitive when # matching the history completer = QCompleter() completer.setCaseSensitivity(Qt.CaseSensitive) url_combo.setCompleter(completer) box = gui.vBox(self.controlArea, "Info") self.infolabel = gui.widgetLabel(box, 'No data loaded.') self.warnings = gui.widgetLabel(box, '') box = gui.widgetBox(self.controlArea, "Columns (Double click to edit)") self.domain_editor = DomainEditor(self) self.editor_model = self.domain_editor.model() box.layout().addWidget(self.domain_editor) box = gui.hBox(self.controlArea) gui.button( box, self, "Browse documentation datasets", callback=lambda: self.browse_file(True), autoDefault=False) gui.rubber(box) gui.button( box, self, "Reset", callback=self.reset_domain_edit) self.apply_button = gui.button( box, self, "Apply", callback=self.apply_domain_edit) self.apply_button.setEnabled(False) self.apply_button.setFixedWidth(170) self.editor_model.dataChanged.connect( lambda: self.apply_button.setEnabled(True)) self.set_file_list() # Must not call open_file from within __init__. open_file # explicitly re-enters the event loop (by a progress bar) self.setAcceptDrops(True) if self.source == self.LOCAL_FILE: last_path = self.last_path() if last_path and os.path.exists(last_path) and \ os.path.getsize(last_path) > self.SIZE_LIMIT: self.Warning.file_too_big() return QTimer.singleShot(0, self.load_data)
def __init__(self): super().__init__() main_layout = QVBoxLayout() main_layout.setContentsMargins(10, 10, 10, 10) self.controlArea.layout().addLayout(main_layout) box = QGroupBox(title=self.tr("Default Method"), flat=False) box_layout = QVBoxLayout(box) main_layout.addWidget(box) button_group = QButtonGroup() button_group.buttonClicked[int].connect(self.set_default_method) for i, method in enumerate(self.METHODS): if not method.columns_only: button = QRadioButton(method.name) button.setChecked(i == self.default_method_index) button_group.addButton(button, i) box_layout.addWidget(button) self.default_button_group = button_group box = QGroupBox(title=self.tr("Individual Attribute Settings"), flat=False) main_layout.addWidget(box) horizontal_layout = QHBoxLayout(box) main_layout.addWidget(box) self.varview = QListView( selectionMode=QListView.ExtendedSelection ) self.varview.setItemDelegate(DisplayFormatDelegate()) self.varmodel = itemmodels.VariableListModel() self.varview.setModel(self.varmodel) self.varview.selectionModel().selectionChanged.connect( self._on_var_selection_changed ) self.selection = self.varview.selectionModel() horizontal_layout.addWidget(self.varview) method_layout = QVBoxLayout() horizontal_layout.addLayout(method_layout) button_group = QButtonGroup() for i, method in enumerate(self.METHODS): button = QRadioButton(text=method.name) button_group.addButton(button, i) method_layout.addWidget(button) self.value_combo = QComboBox( minimumContentsLength=8, sizeAdjustPolicy=QComboBox.AdjustToMinimumContentsLength, activated=self._on_value_selected ) self.value_combo.currentIndexChanged.connect(self._on_value_changed) self.value_double = QDoubleSpinBox( editingFinished=self._on_value_selected, minimum=-1000., maximum=1000., singleStep=.1, decimals=3, value=self.default_value ) self.value_stack = value_stack = QStackedLayout() value_stack.addWidget(self.value_combo) value_stack.addWidget(self.value_double) method_layout.addLayout(value_stack) button_group.buttonClicked[int].connect( self.set_method_for_current_selection ) method_layout.addStretch(2) reset_button = QPushButton( "Restore All to Default", checked=False, checkable=False, clicked=self.reset_variable_methods, default=False, autoDefault=False) method_layout.addWidget(reset_button) self.variable_button_group = button_group box = gui.auto_commit( self.controlArea, self, "autocommit", "Apply", orientation=Qt.Horizontal, checkbox_label="Apply automatically") box.layout().insertSpacing(0, 80) box.layout().insertWidget(0, self.report_button) self.data = None self.modified = False self.default_method = self.METHODS[self.default_method_index] self.update_varview()
def __init__(self): super().__init__() # Diagram update is in progress self._updating = False # Input update is in progress self._inputUpdate = False # All input tables have the same domain. self.samedomain = True # Input datasets in the order they were 'connected'. self.data = OrderedDict() # Extracted input item sets in the order they were 'connected' self.itemsets = OrderedDict() # GUI box = gui.vBox(self.controlArea, "Info") self.info = gui.widgetLabel(box, "No data on input.\n") self.identifiersBox = gui.radioButtonsInBox( self.controlArea, self, "useidentifiers", [], box="Data Instance Identifiers", callback=self._on_useidentifiersChanged, ) self.useequalityButton = gui.appendRadioButton(self.identifiersBox, "Use instance equality") self.useidentifiersButton = rb = gui.appendRadioButton(self.identifiersBox, "Use identifiers") self.inputsBox = gui.indentedBox(self.identifiersBox, sep=gui.checkButtonOffsetHint(rb)) self.inputsBox.setEnabled(bool(self.useidentifiers)) for i in range(5): box = gui.vBox(self.inputsBox, "Data set #%i" % (i + 1), addSpace=False) box.setFlat(True) model = itemmodels.VariableListModel(parent=self) cb = QComboBox(minimumContentsLength=12, sizeAdjustPolicy=QComboBox.AdjustToMinimumContentsLengthWithIcon) cb.setModel(model) cb.activated[int].connect(self._on_inputAttrActivated) box.setEnabled(False) # Store the combo in the box for later use. box.combo_box = cb box.layout().addWidget(cb) gui.rubber(self.controlArea) box = gui.vBox(self.controlArea, "Output") gui.checkBox(box, self, "output_duplicates", "Output duplicates", callback=lambda: self.commit()) gui.auto_commit(box, self, "autocommit", "Send Selection", "Send Automatically", box=False) # Main area view self.scene = QGraphicsScene() self.view = QGraphicsView(self.scene) self.view.setRenderHint(QPainter.Antialiasing) self.view.setBackgroundRole(QPalette.Window) self.view.setFrameStyle(QGraphicsView.StyledPanel) self.mainArea.layout().addWidget(self.view) self.vennwidget = VennDiagram() self.vennwidget.resize(400, 400) self.vennwidget.itemTextEdited.connect(self._on_itemTextEdited) self.scene.selectionChanged.connect(self._on_selectionChanged) self.scene.addItem(self.vennwidget) self.resize(self.controlArea.sizeHint().width() + 550, max(self.controlArea.sizeHint().height(), 550)) self._queue = []
class OWImportImages(widget.OWWidget): name = "Import Images" description = "Import images from a directory(s)" icon = "icons/ImportImages.svg" priority = 110 outputs = [("Data", Orange.data.Table)] #: list of recent paths recent_paths = settings.Setting([]) # type: List[RecentPath] currentPath = settings.Setting(None) want_main_area = False resizing_enabled = False Modality = Qt.ApplicationModal # Modality = Qt.WindowModal MaxRecentItems = 20 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)) def __initRecentItemsModel(self): if self.currentPath is not None and \ not os.path.isdir(self.currentPath): self.currentPath = None recent_paths = [] for item in self.recent_paths: if os.path.isdir(item.abspath): recent_paths.append(item) recent_paths = recent_paths[:OWImportImages.MaxRecentItems] recent_model = self.recent_cb.model() for pathitem in recent_paths: item = RecentPath_asqstandarditem(pathitem) recent_model.appendRow(item) self.recent_paths = recent_paths if self.currentPath is not None and \ os.path.isdir(self.currentPath) and self.recent_paths and \ os.path.samefile(self.currentPath, self.recent_paths[0].abspath): self.recent_cb.setCurrentIndex(0) else: self.currentPath = None self.recent_cb.setCurrentIndex(-1) self.__actions.reload.setEnabled(self.currentPath is not None) def customEvent(self, event): """Reimplemented.""" if event.type() == RuntimeEvent.Init: if self.__invalidated: try: self.start() finally: self.__invalidated = False super().customEvent(event) def __runOpenDialog(self): startdir = os.path.expanduser("~/") if self.recent_paths: startdir = os.path.dirname(self.recent_paths[0].abspath) if OWImportImages.Modality == Qt.WindowModal: dlg = QFileDialog( self, "Select Top Level Directory", startdir, acceptMode=QFileDialog.AcceptOpen, modal=True, ) dlg.setFileMode(QFileDialog.Directory) dlg.setOption(QFileDialog.ShowDirsOnly) dlg.setDirectory(startdir) dlg.setAttribute(Qt.WA_DeleteOnClose) @dlg.accepted.connect def on_accepted(): dirpath = dlg.selectedFiles() if dirpath: self.setCurrentPath(dirpath[0]) self.start() dlg.open() else: dirpath = QFileDialog.getExistingDirectory( self, "Select Top Level Directory", startdir ) if dirpath: self.setCurrentPath(dirpath) self.start() def __onRecentActivated(self, index): item = self.recent_cb.itemData(index) if item is None: return assert isinstance(item, RecentPath) self.setCurrentPath(item.abspath) self.start() def __updateInfo(self): if self.__state == State.NoState: text = "No image set selected" elif self.__state == State.Processing: text = "Processing" elif self.__state == State.Done: nvalid = self._n_image_data ncategories = self._n_image_categories n_skipped = self._n_skipped if ncategories < 2: text = "{} image{}".format(nvalid, "s" if nvalid != 1 else "") else: text = "{} images / {} categories".format(nvalid, ncategories) if n_skipped > 0: text = text + ", {} skipped".format(n_skipped) elif self.__state == State.Cancelled: text = "Cancelled" elif self.__state == State.Error: text = "Error state" else: assert False self.info_area.setText(text) if self.__state == State.Processing: self.infostack.setCurrentIndex(1) else: self.infostack.setCurrentIndex(0) def setCurrentPath(self, path): """ Set the current root image path to path If the path does not exists or is not a directory the current path is left unchanged Parameters ---------- path : str New root import path. Returns ------- status : bool True if the current root import path was successfully changed to path. """ if self.currentPath is not None and path is not None and \ os.path.isdir(self.currentPath) and os.path.isdir(path) and \ os.path.samefile(self.currentPath, path): return True success = True error = None if path is not None: if not os.path.exists(path): error = "'{}' does not exist".format(path) path = None success = False elif not os.path.isdir(path): error = "'{}' is not a directory".format(path) path = None success = False if error is not None: self.error(error) warnings.warn(error, UserWarning, stacklevel=3) else: self.error() if path is not None: newindex = self.addRecentPath(path) self.recent_cb.setCurrentIndex(newindex) if newindex >= 0: self.currentPath = path else: self.currentPath = None else: self.currentPath = None self.__actions.reload.setEnabled(self.currentPath is not None) if self.__state == State.Processing: self.cancel() return success def addRecentPath(self, path): """ Prepend a path entry to the list of recent paths If an entry with the same path already exists in the recent path list it is moved to the first place Parameters ---------- path : str """ existing = None for pathitem in self.recent_paths: try: if os.path.samefile(pathitem.abspath, path): existing = pathitem break except FileNotFoundError: # file not found if the `pathitem.abspath` no longer exists pass model = self.recent_cb.model() if existing is not None: selected_index = self.recent_paths.index(existing) assert model.item(selected_index).data(Qt.UserRole) is existing self.recent_paths.remove(existing) row = model.takeRow(selected_index) self.recent_paths.insert(0, existing) model.insertRow(0, row) else: item = RecentPath(path, None, None) self.recent_paths.insert(0, item) model.insertRow(0, RecentPath_asqstandarditem(item)) return 0 def __setRuntimeState(self, state): assert state in State self.setBlocking(state == State.Processing) message = "" if state == State.Processing: assert self.__state in [State.Done, State.NoState, State.Error, State.Cancelled] message = "Processing" elif state == State.Done: assert self.__state == State.Processing elif state == State.Cancelled: assert self.__state == State.Processing message = "Cancelled" elif state == State.Error: message = "Error during processing" elif state == State.NoState: message = "" else: assert False self.__state = state if self.__state == State.Processing: self.infostack.setCurrentIndex(1) else: self.infostack.setCurrentIndex(0) self.setStatusMessage(message) self.__updateInfo() def reload(self): """ Restart the image scan task """ if self.__state == State.Processing: self.cancel() self.data = None self.start() def start(self): """ Start/execute the image indexing operation """ self.error() self.__invalidated = False if self.currentPath is None: return if self.__state == State.Processing: assert self.__pendingTask is not None log.info("Starting a new task while one is in progress. " "Cancel the existing task (dir:'{}')" .format(self.__pendingTask.startdir)) self.cancel() startdir = self.currentPath self.__setRuntimeState(State.Processing) report_progress = methodinvoke( self, "__onReportProgress", (object,)) task = ImportImages(report_progress=report_progress) # collect the task state in one convenient place self.__pendingTask = taskstate = namespace( task=task, startdir=startdir, future=None, watcher=None, cancelled=False, cancel=None, ) def cancel(): # Cancel the task and disconnect if taskstate.future.cancel(): pass else: taskstate.task.cancelled = True taskstate.cancelled = True try: taskstate.future.result(timeout=3) except UserInterruptError: pass except TimeoutError: log.info("The task did not stop in in a timely manner") taskstate.watcher.finished.disconnect(self.__onRunFinished) taskstate.cancel = cancel def run_image_scan_task_interupt(): try: return task(startdir) except UserInterruptError: # Suppress interrupt errors, so they are not logged return taskstate.future = self.__executor.submit(run_image_scan_task_interupt) taskstate.watcher = FutureWatcher(taskstate.future) taskstate.watcher.finished.connect(self.__onRunFinished) @Slot() def __onRunFinished(self): assert QThread.currentThread() is self.thread() assert self.__state == State.Processing assert self.__pendingTask is not None assert self.sender() is self.__pendingTask.watcher assert self.__pendingTask.future.done() task = self.__pendingTask self.__pendingTask = None try: data, n_skipped = task.future.result() except Exception: sys.excepthook(*sys.exc_info()) state = State.Error data = None n_skipped = 0 self.error(traceback.format_exc()) else: state = State.Done self.error() if data: self._n_image_data = len(data) self._n_image_categories = len(data.domain.class_var.values)\ if data.domain.class_var else 0 else: self._n_image_data, self._n_image_categories = 0, 0 self.data = data self._n_skipped = n_skipped self.__setRuntimeState(state) self.commit() def cancel(self): """ Cancel current pending task (if any). """ if self.__state == State.Processing: assert self.__pendingTask is not None self.__pendingTask.cancel() self.__pendingTask = None self.__setRuntimeState(State.Cancelled) @Slot(object) def __onReportProgress(self, arg): # report on scan progress from a worker thread # arg must be a namespace(count: int, lastpath: str) assert QThread.currentThread() is self.thread() if self.__state == State.Processing: self.pathlabel.setText(prettyfypath(arg.lastpath)) def commit(self): """ Commit a Table from the collected image meta data. """ self.send("Data", self.data) def onDeleteWidget(self): self.cancel() self.__executor.shutdown(wait=True) self.__invalidated = False def eventFilter(self, receiver, event): # re-implemented from QWidget # intercept and process drag drop events on the recent directory # selection combo box def dirpath(event): # type: (QDropEvent) -> Optional[str] """Return the directory from a QDropEvent.""" data = event.mimeData() urls = data.urls() if len(urls) == 1: url = urls[0] path = url.toLocalFile() if path.endswith("/"): path = path[:-1] # remove last / if os.path.isdir(path): return path return None if receiver is self.recent_cb and \ event.type() in {QEvent.DragEnter, QEvent.DragMove, QEvent.Drop}: assert isinstance(event, QDropEvent) path = dirpath(event) if path is not None and event.possibleActions() & Qt.LinkAction: event.setDropAction(Qt.LinkAction) event.accept() if event.type() == QEvent.Drop: self.setCurrentPath(path) self.start() else: event.ignore() return True return super().eventFilter(receiver, event)
class Scale(BaseEditor): NoCentering, CenterMean, CenterMedian = 0, 1, 2 NoScaling, ScaleBySD, ScaleBySpan = 0, 1, 2 def __init__(self, parent=None, **kwargs): super().__init__(parent, **kwargs) self.setLayout(QVBoxLayout()) form = QFormLayout() self.__centercb = QComboBox() self.__centercb.addItems(["No Centering", "Center by Mean", "Center by Median"]) self.__scalecb = QComboBox() self.__scalecb.addItems(["No scaling", "Scale by SD", "Scale by span"]) form.addRow("Center:", self.__centercb) form.addRow("Scale:", self.__scalecb) self.layout().addLayout(form) self.__centercb.currentIndexChanged.connect(self.changed) self.__scalecb.currentIndexChanged.connect(self.changed) self.__centercb.activated.connect(self.edited) self.__scalecb.activated.connect(self.edited) def setParameters(self, params): center = params.get("center", _Scale.CenteringType.Mean) scale = params.get("scale", _Scale.ScalingType.Std) self.__centercb.setCurrentIndex(_enum_to_index(_Scale.CenteringType, center)) self.__scalecb.setCurrentIndex(_enum_to_index(_Scale.ScalingType, scale)) def parameters(self): return {"center": _index_to_enum(_Scale.CenteringType, self.__centercb.currentIndex()), "scale": _index_to_enum(_Scale.ScalingType, self.__scalecb.currentIndex())} @staticmethod def createinstance(params): center = params.get("center", _Scale.CenteringType.Mean) scale = params.get("scale", _Scale.ScalingType.Std) return _Scale(center=center, scale=scale) def __repr__(self): return "{}, {}".format(self.__centercb.currentText(), self.__scalecb.currentText())
class OWPubmed(OWWidget): name = 'Pubmed' description = 'Fetch data from Pubmed.' icon = 'icons/Pubmed.svg' priority = 140 outputs = [(Output.CORPUS, Corpus)] want_main_area = False resizing_enabled = False QT_DATE_FORMAT = 'yyyy-MM-dd' PY_DATE_FORMAT = '%Y-%m-%d' MIN_DATE = date(1800, 1, 1) # Settings. recent_emails = Setting([]) author = Setting('') pub_date_from = Setting('') pub_date_to = Setting('') recent_keywords = Setting([]) last_advanced_query = Setting('') num_records = Setting(1000) # Text includes checkboxes. includes_authors = Setting(True) includes_title = Setting(True) includes_mesh = Setting(True) includes_abstract = Setting(True) includes_url = Setting(True) class Warning(OWWidget.Warning): no_query = Msg('Please specify the keywords for this query.') class Error(OWWidget.Error): api_error = Msg('API error: {}.') def __init__(self): super().__init__() self.output_corpus = None self.pubmed_api = None self.progress = None self.email_is_valid = False self.record_count = 0 self.download_running = False # To hold all the controls. Makes access easier. self.pubmed_controls = [] h_box = gui.hBox(self.controlArea) label = gui.label(h_box, self, 'Email:') label.setMaximumSize(label.sizeHint()) # Drop-down for recent emails. self.email_combo = QComboBox(h_box) self.email_combo.setMinimumWidth(150) self.email_combo.setEditable(True) self.email_combo.lineEdit().textChanged.connect(self.sync_email) h_box.layout().addWidget(self.email_combo) self.email_combo.activated[int].connect(self.select_email) # RECORD SEARCH self.search_tabs = gui.tabWidget(self.controlArea) # --- Regular search --- regular_search_box = gui.widgetBox(self.controlArea, addSpace=True) # Author self.author_input = gui.lineEdit(regular_search_box, self, 'author', 'Author:', orientation=Qt.Horizontal) self.pubmed_controls.append(self.author_input) h_box = gui.hBox(regular_search_box) year_box = gui.widgetBox(h_box, orientation=Qt.Horizontal) min_date = QDate.fromString( self.MIN_DATE.strftime(self.PY_DATE_FORMAT), self.QT_DATE_FORMAT) if not self.pub_date_from: self.pub_date_from = self.MIN_DATE.strftime(self.PY_DATE_FORMAT) if not self.pub_date_to: self.pub_date_to = date.today().strftime(self.PY_DATE_FORMAT) self.date_from = QDateEdit(QDate.fromString(self.pub_date_from, self.QT_DATE_FORMAT), displayFormat=self.QT_DATE_FORMAT, minimumDate=min_date, calendarPopup=True) self.date_to = QDateEdit(QDate.fromString(self.pub_date_to, self.QT_DATE_FORMAT), displayFormat=self.QT_DATE_FORMAT, minimumDate=min_date, calendarPopup=True) self.date_from.dateChanged.connect(lambda date: setattr( self, 'pub_date_from', date.toString(self.QT_DATE_FORMAT))) self.date_to.dateChanged.connect(lambda date: setattr( self, 'pub_date_to', date.toString(self.QT_DATE_FORMAT))) self.pubmed_controls.append(self.date_from) self.pubmed_controls.append(self.date_to) gui.label(year_box, self, 'From:') year_box.layout().addWidget(self.date_from) gui.label(year_box, self, 'to:') year_box.layout().addWidget(self.date_to) # Keywords. h_box = gui.hBox(regular_search_box) label = gui.label(h_box, self, 'Query:') label.setMaximumSize(label.sizeHint()) self.keyword_combo = QComboBox(h_box) self.keyword_combo.setMinimumWidth(150) self.keyword_combo.setEditable(True) h_box.layout().addWidget(self.keyword_combo) self.keyword_combo.activated[int].connect(self.select_keywords) self.pubmed_controls.append(self.keyword_combo) tab_height = regular_search_box.sizeHint() regular_search_box.setMaximumSize(tab_height) # --- Advanced search --- advanced_search_box = gui.widgetBox(self.controlArea, addSpace=True) # Advanced search query. h_box = gui.hBox(advanced_search_box) self.advanced_query_input = QTextEdit(h_box) h_box.layout().addWidget(self.advanced_query_input) self.advanced_query_input.setMaximumSize(tab_height) self.pubmed_controls.append(self.advanced_query_input) gui.createTabPage(self.search_tabs, 'Regular search', regular_search_box) gui.createTabPage(self.search_tabs, 'Advanced search', advanced_search_box) # Search info label. self.search_info_label = gui.label(self.controlArea, self, 'Number of records found: /') # Search for records button. self.run_search_button = gui.button( self.controlArea, self, 'Find records', callback=self.run_search, tooltip='Performs a search for articles that fit the ' 'specified parameters.') self.pubmed_controls.append(self.run_search_button) h_line = QFrame() h_line.setFrameShape(QFrame.HLine) h_line.setFrameShadow(QFrame.Sunken) self.controlArea.layout().addWidget(h_line) # RECORD RETRIEVAL # Text includes box. text_includes_box = gui.widgetBox(self.controlArea, 'Text includes', addSpace=True) self.authors_checkbox = gui.checkBox(text_includes_box, self, 'includes_authors', 'Authors') self.title_checkbox = gui.checkBox(text_includes_box, self, 'includes_title', 'Article title') self.mesh_checkbox = gui.checkBox(text_includes_box, self, 'includes_mesh', 'Mesh headings') self.abstract_checkbox = gui.checkBox(text_includes_box, self, 'includes_abstract', 'Abstract') self.url_checkbox = gui.checkBox(text_includes_box, self, 'includes_url', 'URL') self.pubmed_controls.append(self.authors_checkbox) self.pubmed_controls.append(self.title_checkbox) self.pubmed_controls.append(self.mesh_checkbox) self.pubmed_controls.append(self.abstract_checkbox) self.pubmed_controls.append(self.url_checkbox) # Num. records. h_box = gui.hBox(self.controlArea) label = gui.label(h_box, self, 'Retrieve') label.setMaximumSize(label.sizeHint()) self.num_records_input = gui.spin(h_box, self, 'num_records', minv=1, maxv=100000) self.max_records_label = gui.label(h_box, self, 'records from /.') self.max_records_label.setMaximumSize( self.max_records_label.sizeHint()) self.pubmed_controls.append(self.num_records_input) # Download articles. # Search for records button. self.retrieve_records_button = gui.button( self.controlArea, self, 'Retrieve records', callback=self.retrieve_records, tooltip='Retrieves the specified documents.') self.pubmed_controls.append(self.retrieve_records_button) # Num. retrieved records info label. self.retrieval_info_label = gui.label( self.controlArea, self, 'Number of records retrieved: /') # Load the most recent emails. self.set_email_list() # Load the most recent queries. self.set_keyword_list() # Check the email and enable controls accordingly. if self.recent_emails: email = self.recent_emails[0] self.email_is_valid = validate_email(email) self.enable_controls() def sync_email(self): email = self.email_combo.currentText() self.email_is_valid = validate_email(email) self.enable_controls() def enable_controls(self): # Enable/disable controls accordingly. for control in self.pubmed_controls: control.setEnabled(self.email_is_valid) if self.pubmed_api is None or self.pubmed_api.search_record_count == 0: self.retrieve_records_button.setEnabled(False) if not self.email_is_valid: self.email_combo.setFocus() def run_search(self): self.Error.clear() self.Warning.clear() self.run_search_button.setEnabled(False) self.retrieve_records_button.setEnabled(False) # Add the email to history. email = self.email_combo.currentText() if email not in self.recent_emails: self.recent_emails.insert(0, email) # Check if the PubMed object is present. if self.pubmed_api is None: self.pubmed_api = Pubmed( email=email, progress_callback=self.api_progress_callback, error_callback=self.api_error_callback, ) if self.search_tabs.currentIndex() == 0: # Get query parameters. terms = self.keyword_combo.currentText().split() authors = self.author_input.text().split() error = self.pubmed_api._search_for_records( terms, authors, self.pub_date_from, self.pub_date_to) if error is not None: self.Error.api_error(str(error)) return if self.keyword_combo.currentText() not in self.recent_keywords: self.recent_keywords.insert(0, self.keyword_combo.currentText()) else: query = self.advanced_query_input.toPlainText() if not query: self.Warning.no_query() self.run_search_button.setEnabled(True) self.retrieve_records_button.setEnabled(True) return error = self.pubmed_api._search_for_records(advanced_query=query) if error is not None: self.Error.api_error(str(error)) return self.last_advanced_query = query self.enable_controls() self.update_search_info() def retrieve_records(self): self.Warning.clear() self.Error.clear() if self.pubmed_api is None: return if self.download_running: self.download_running = False self.run_search_button.setEnabled(True) self.retrieve_records_button.setText('Retrieve records') self.pubmed_api.stop_retrieving() return self.download_running = True self.run_search_button.setEnabled(False) self.output_corpus = None # Clear the old records. # Change the button label. self.retrieve_records_button.setText('Stop retrieving') # Text fields. text_includes_params = [ self.includes_authors, self.includes_title, self.includes_mesh, self.includes_abstract, self.includes_url, True, # Publication date field; included always. ] required_text_fields = [ field for field_name, field in zip( text_includes_params, PUBMED_TEXT_FIELDS) if field_name ] batch_size = min(Pubmed.MAX_BATCH_SIZE, self.num_records) + 1 with self.progressBar(self.num_records / batch_size) as progress: self.progress = progress self.output_corpus = self.pubmed_api._retrieve_records( self.num_records, required_text_fields) self.retrieve_records_button.setText('Retrieve records') self.download_running = False self.send(Output.CORPUS, self.output_corpus) self.update_retrieval_info() self.run_search_button.setEnabled(True) def api_progress_callback(self, start_at=None): if start_at is not None: self.progress.count = start_at else: self.progress.advance() def api_error_callback(self, error): self.Error.api_error(str(error)) if self.progress is not None: self.progress.finish() def update_search_info(self): max_records_count = min(self.pubmed_api.MAX_RECORDS, self.pubmed_api.search_record_count) self.search_info_label.setText( 'Number of retrievable records for ' 'this search query: {} '.format(max_records_count)) self.max_records_label.setText( 'records from {}.'.format(max_records_count)) self.max_records_label.setMaximumSize( self.max_records_label.sizeHint()) self.num_records_input.setMaximum(max_records_count) self.retrieve_records_button.setFocus() def update_retrieval_info(self): document_count = 0 if self.output_corpus is not None: document_count = len(self.output_corpus) self.retrieval_info_label.setText( 'Number of records retrieved: {} '.format(document_count)) self.retrieval_info_label.setMaximumSize( self.retrieval_info_label.sizeHint()) def select_email(self, n): if n < len(self.recent_emails): email = self.recent_emails[n] del self.recent_emails[n] self.recent_emails.insert(0, email) if len(self.recent_emails) > 0: self.set_email_list() def set_email_list(self): self.email_combo.clear() for email in self.recent_emails: self.email_combo.addItem(email) def select_keywords(self, n): if n < len(self.recent_keywords): keywords = self.recent_keywords[n] del self.recent_keywords[n] self.recent_keywords.insert(0, keywords) if len(self.recent_keywords) > 0: self.set_keyword_list() def set_keyword_list(self): self.keyword_combo.clear() if not self.recent_keywords: # Sample queries. self.recent_keywords.append('orchid') self.recent_keywords.append('hypertension') self.recent_keywords.append('blood pressure') self.recent_keywords.append('radiology') for keywords in self.recent_keywords: self.keyword_combo.addItem(keywords) def open_calendar(self, widget): cal_dlg = CalendarDialog(self, 'Date picker') if cal_dlg.exec_(): widget.setText(cal_dlg.picked_date)
def set_new_values(self, oper_combo, adding_all, selected_values=None): # def remove_children(): # for child in box.children()[1:]: # box.layout().removeWidget(child) # child.setParent(None) def add_textual(contents): le = gui.lineEdit(box, self, None, sizePolicy=QSizePolicy(QSizePolicy.Expanding, QSizePolicy.Expanding)) if contents: le.setText(contents) le.setAlignment(Qt.AlignRight) le.editingFinished.connect(self.conditions_changed) return le def add_numeric(contents): le = add_textual(contents) le.setValidator(OWSelectRows.QDoubleValidatorEmpty()) return le def add_datetime(contents): le = add_textual(contents) le.setValidator(QRegExpValidator(QRegExp(TimeVariable.REGEX))) return le var = self.data.domain[oper_combo.attr_combo.currentText()] box = self.cond_list.cellWidget(oper_combo.row, 2) if selected_values is not None: lc = list(selected_values) + ["", ""] lc = [str(x) for x in lc[:2]] else: lc = ["", ""] if box and vartype(var) == box.var_type: lc = self._get_lineedit_contents(box) + lc oper = oper_combo.currentIndex() if oper_combo.currentText() == "is defined": label = QLabel() label.var_type = vartype(var) self.cond_list.setCellWidget(oper_combo.row, 2, label) elif var.is_discrete: if oper_combo.currentText() == "is one of": if selected_values: lc = [x for x in list(selected_values)] button = DropDownToolButton(self, var, lc) button.var_type = vartype(var) self.cond_list.setCellWidget(oper_combo.row, 2, button) else: combo = QComboBox() combo.addItems([""] + var.values) if lc[0]: combo.setCurrentIndex(int(lc[0])) else: combo.setCurrentIndex(0) combo.var_type = vartype(var) self.cond_list.setCellWidget(oper_combo.row, 2, combo) combo.currentIndexChanged.connect(self.conditions_changed) else: box = gui.hBox(self, addToLayout=False) box.var_type = vartype(var) self.cond_list.setCellWidget(oper_combo.row, 2, box) if var.is_continuous: validator = add_datetime if isinstance(var, TimeVariable) else add_numeric box.controls = [validator(lc[0])] if oper > 5: gui.widgetLabel(box, " and ") box.controls.append(validator(lc[1])) elif var.is_string: box.controls = [add_textual(lc[0])] if oper in [6, 7]: gui.widgetLabel(box, " and ") box.controls.append(add_textual(lc[1])) else: box.controls = [] if not adding_all: self.conditions_changed()
class FileLoader(QWidget): activated = pyqtSignal() file_loaded = pyqtSignal() 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 browse(self): start_file = self.last_path() or os.path.expanduser("~/") formats = ["Text files (*.txt)", "All files (*)"] file_name, _ = QFileDialog.getOpenFileName( None, "Open...", start_file, ";;".join(formats), formats[0]) if not file_name: return self.add_path(file_name) self._activate() def _activate(self): self.activated.emit() self.file_loaded.emit() def set_current_file(self, path: str): if path: self.add_path(path) self.file_combo.setCurrentText(path) else: self.file_combo.setCurrentText("(none)") def get_current_file(self) -> Optional[RecentPath]: index = self.file_combo.currentIndex() if index >= len(self.recent_paths) or index < 0: return None path = self.recent_paths[index] return path if isinstance(path, RecentPath) else None def add_path(self, filename: str): recent = RecentPath.create(filename, []) if recent in self.recent_paths: self.recent_paths.remove(recent) self.recent_paths.insert(0, recent) self.set_file_list() def set_file_list(self): self.file_combo.clear() for i, recent in enumerate(self.recent_paths): self.file_combo.addItem(recent.basename) self.file_combo.model().item(i).setToolTip(recent.abspath) if not os.path.exists(recent.abspath): self.file_combo.setItemData(i, QBrush(Qt.red), Qt.TextColorRole) self.file_combo.addItem(_DEFAULT_NONE) def last_path(self) -> Optional[str]: return self.recent_paths[0].abspath if self.recent_paths else None
class Scale(BaseEditor): NoCentering, CenterMean, CenterMedian = 0, 1, 2 NoScaling, ScaleBySD, ScaleBySpan = 0, 1, 2 def __init__(self, parent=None, **kwargs): super().__init__(parent, **kwargs) self.setLayout(QVBoxLayout()) form = QFormLayout() self.__centercb = QComboBox() self.__centercb.addItems( ["No Centering", "Center by Mean", "Center by Median"]) self.__scalecb = QComboBox() self.__scalecb.addItems(["No scaling", "Scale by SD", "Scale by span"]) form.addRow("Center:", self.__centercb) form.addRow("Scale:", self.__scalecb) self.layout().addLayout(form) self.__centercb.currentIndexChanged.connect(self.changed) self.__scalecb.currentIndexChanged.connect(self.changed) self.__centercb.activated.connect(self.edited) self.__scalecb.activated.connect(self.edited) def setParameters(self, params): center = params.get("center", Scale.CenterMean) scale = params.get("scale", Scale.ScaleBySD) self.__centercb.setCurrentIndex(center) self.__scalecb.setCurrentIndex(scale) def parameters(self): return { "center": self.__centercb.currentIndex(), "scale": self.__scalecb.currentIndex() } @staticmethod def createinstance(params): center = params.get("center", Scale.CenterMean) scale = params.get("scale", Scale.ScaleBySD) if center == Scale.NoCentering: center = None elif center == Scale.CenterMean: center = _Scaling.mean elif center == Scale.CenterMedian: center = _Scaling.median else: assert False if scale == Scale.NoScaling: scale = None elif scale == Scale.ScaleBySD: scale = _Scaling.std elif scale == Scale.ScaleBySpan: scale = _Scaling.span else: assert False return _Scaling(center=center, scale=scale) def __repr__(self): return "{}, {}".format(self.__centercb.currentText(), self.__scalecb.currentText())
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 OWImportDocuments(widget.OWWidget): name = "Import Documents" description = "Import text documents from folders." icon = "icons/ImportDocuments.svg" priority = 110 class Outputs: data = Output("Corpus", Corpus, default=True) skipped_documents = Output("Skipped documents", Table) LOCAL_FILE, URL = range(2) source = settings.Setting(LOCAL_FILE) #: list of recent paths recent_paths: List[RecentPath] = settings.Setting([]) currentPath: Optional[str] = settings.Setting(None) recent_urls: List[str] = settings.Setting([]) lemma_cb = settings.Setting(True) pos_cb = settings.Setting(False) ner_cb = settings.Setting(False) want_main_area = False resizing_enabled = False Modality = Qt.ApplicationModal MaxRecentItems = 20 class Warning(widget.OWWidget.Warning): read_error = widget.Msg("{} couldn't be read.") def __init__(self): super().__init__() #: widget's runtime state self.__state = State.NoState self.base_corpus = None self.corpus = None self.n_text_categories = 0 self.n_text_data = 0 self.skipped_documents = [] self.is_conllu = False self.tokens = None self.pos = None self.ner = None self.__invalidated = False self.__pendingTask = None layout = QGridLayout() layout.setSpacing(4) gui.widgetBox(self.controlArea, orientation=layout, box='Source') source_box = gui.radioButtons(None, self, "source", box=True, callback=self.start, addToLayout=False) rb_button = gui.appendRadioButton(source_box, "Folder:", addToLayout=False) layout.addWidget(rb_button, 0, 0, Qt.AlignVCenter) box = gui.hBox(None, addToLayout=False, margin=0) box.setSizePolicy(QSizePolicy.MinimumExpanding, QSizePolicy.Fixed) self.recent_cb = QComboBox( sizeAdjustPolicy=QComboBox.AdjustToMinimumContentsLengthWithIcon, minimumContentsLength=16, acceptDrops=True) self.recent_cb.installEventFilter(self) self.recent_cb.activated[int].connect(self.__onRecentActivated) browseaction = QAction( "Open/Load Documents", self, iconText="\N{HORIZONTAL ELLIPSIS}", icon=self.style().standardIcon(QStyle.SP_DirOpenIcon), toolTip="Select a folder from which to load the documents") browseaction.triggered.connect(self.__runOpenDialog) reloadaction = QAction("Reload", self, icon=self.style().standardIcon( QStyle.SP_BrowserReload), toolTip="Reload current document 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, default=False, autoDefault=False, ) reloadbutton = QPushButton( reloadaction.iconText(), icon=reloadaction.icon(), clicked=reloadaction.trigger, default=False, autoDefault=False, ) box.layout().addWidget(self.recent_cb) layout.addWidget(box, 0, 1) layout.addWidget(browsebutton, 0, 2) layout.addWidget(reloadbutton, 0, 3) rb_button = gui.appendRadioButton(source_box, "URL:", addToLayout=False) layout.addWidget(rb_button, 3, 0, Qt.AlignVCenter) self.url_combo = url_combo = QComboBox() url_model = PyListModel() url_model.wrap(self.recent_urls) url_combo.setLineEdit(LineEditSelectOnFocus()) url_combo.setModel(url_model) url_combo.setSizePolicy(QSizePolicy.Ignored, QSizePolicy.Fixed) url_combo.setEditable(True) url_combo.setInsertPolicy(url_combo.InsertAtTop) url_edit = url_combo.lineEdit() m = url_edit.textMargins() url_edit.setTextMargins(m.left() + 5, m.top(), m.right(), m.bottom()) layout.addWidget(url_combo, 3, 1, 1, 3) url_combo.activated.connect(self._url_set) # whit completer we set that combo box is case sensitive when # matching the history completer = QCompleter() completer.setCaseSensitivity(Qt.CaseSensitive) url_combo.setCompleter(completer) self.addActions([browseaction, reloadaction]) reloadaction.changed.connect( lambda: reloadbutton.setEnabled(reloadaction.isEnabled())) box = gui.hBox(self.controlArea, "Conllu import options") gui.checkBox(box, self, "lemma_cb", "Lemma", callback=self.commit) gui.checkBox(box, self, "pos_cb", "POS tags", callback=self.commit) gui.checkBox(box, self, "ner_cb", "NER", callback=self.commit) self.controlArea.layout().addWidget(box) box = gui.vBox(self.controlArea, "Info") self.infostack = QStackedWidget() self.info_area = QLabel(text="No document set selected", wordWrap=True) self.progress_widget = QProgressBar(minimum=0, maximum=100) self.cancel_button = QPushButton( "Cancel", icon=self.style().standardIcon(QStyle.SP_DialogCancelButton), default=False, autoDefault=False, ) 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)) def _url_set(self): url = self.url_combo.currentText() pos = self.recent_urls.index(url) url = url.strip() if not urlparse(url).scheme: url = "http://" + url self.url_combo.setItemText(pos, url) self.recent_urls[pos] = url self.source = self.URL self.start() def __initRecentItemsModel(self): if self.currentPath is not None and \ not os.path.isdir(self.currentPath): self.currentPath = None recent_paths = [] for item in self.recent_paths: if os.path.isdir(item.abspath): recent_paths.append(item) recent_paths = recent_paths[:OWImportDocuments.MaxRecentItems] recent_model = self.recent_cb.model() for pathitem in recent_paths: item = RecentPath_asqstandarditem(pathitem) recent_model.appendRow(item) self.recent_paths = recent_paths if self.currentPath is not None and \ os.path.isdir(self.currentPath) and self.recent_paths and \ os.path.samefile(self.currentPath, self.recent_paths[0].abspath): self.recent_cb.setCurrentIndex(0) else: self.currentPath = None self.recent_cb.setCurrentIndex(-1) self.__actions.reload.setEnabled(self.currentPath is not None) def customEvent(self, event): """Reimplemented.""" if event.type() == RuntimeEvent.Init: if self.__invalidated: try: self.start() finally: self.__invalidated = False super().customEvent(event) def __runOpenDialog(self): startdir = os.path.expanduser("~/") if self.recent_paths: startdir = os.path.dirname(self.recent_paths[0].abspath) caption = "Select Top Level Folder" if OWImportDocuments.Modality == Qt.WindowModal: dlg = QFileDialog( self, caption, startdir, acceptMode=QFileDialog.AcceptOpen, modal=True, ) dlg.setFileMode(QFileDialog.Directory) dlg.setOption(QFileDialog.ShowDirsOnly) dlg.setDirectory(startdir) dlg.setAttribute(Qt.WA_DeleteOnClose) @dlg.accepted.connect def on_accepted(): dirpath = dlg.selectedFiles() if dirpath: self.setCurrentPath(dirpath[0]) self.start() dlg.open() else: dirpath = QFileDialog.getExistingDirectory(self, caption, startdir) if dirpath: self.setCurrentPath(dirpath) self.start() def __onRecentActivated(self, index): item = self.recent_cb.itemData(index) if item is None: return assert isinstance(item, RecentPath) self.setCurrentPath(item.abspath) self.start() def __updateInfo(self): if self.__state == State.NoState: text = "No document set selected" elif self.__state == State.Processing: text = "Processing" elif self.__state == State.Done: nvalid = self.n_text_data ncategories = self.n_text_categories n_skipped = len(self.skipped_documents) if ncategories < 2: text = "{} document{}".format(nvalid, "s" if nvalid != 1 else "") else: text = "{} documents / {} categories".format( nvalid, ncategories) if n_skipped > 0: text = text + ", {} skipped".format(n_skipped) elif self.__state == State.Cancelled: text = "Cancelled" elif self.__state == State.Error: text = "Error state" else: assert False self.info_area.setText(text) if self.__state == State.Processing: self.infostack.setCurrentIndex(1) else: self.infostack.setCurrentIndex(0) def setCurrentPath(self, path): """ Set the current root text path to path If the path does not exists or is not a directory the current path is left unchanged Parameters ---------- path : str New root import path. Returns ------- status : bool True if the current root import path was successfully changed to path. """ if self.currentPath is not None and path is not None and \ os.path.isdir(self.currentPath) and os.path.isdir(path) and \ os.path.samefile(self.currentPath, path) and \ self.source == self.LOCAL_FILE: return True success = True error = None if path is not None: if not os.path.exists(path): error = "'{}' does not exist".format(path) path = None success = False elif not os.path.isdir(path): error = "'{}' is not a folder".format(path) path = None success = False if error is not None: self.error(error) warnings.warn(error, UserWarning, stacklevel=3) else: self.error() if path is not None: newindex = self.addRecentPath(path) self.recent_cb.setCurrentIndex(newindex) if newindex >= 0: self.currentPath = path else: self.currentPath = None else: self.currentPath = None self.__actions.reload.setEnabled(self.currentPath is not None) if self.__state == State.Processing: self.cancel() self.source = self.LOCAL_FILE return success def addRecentPath(self, path): """ Prepend a path entry to the list of recent paths If an entry with the same path already exists in the recent path list it is moved to the first place Parameters ---------- path : str """ existing = None for pathitem in self.recent_paths: try: if os.path.samefile(pathitem.abspath, path): existing = pathitem break except FileNotFoundError: # file not found if the `pathitem.abspath` no longer exists pass model = self.recent_cb.model() if existing is not None: selected_index = self.recent_paths.index(existing) assert model.item(selected_index).data(Qt.UserRole) is existing self.recent_paths.remove(existing) row = model.takeRow(selected_index) self.recent_paths.insert(0, existing) model.insertRow(0, row) else: item = RecentPath(path, None, None) self.recent_paths.insert(0, item) model.insertRow(0, RecentPath_asqstandarditem(item)) return 0 def __setRuntimeState(self, state): assert state in State self.setBlocking(state == State.Processing) message = "" if state == State.Processing: assert self.__state in [ State.Done, State.NoState, State.Error, State.Cancelled ] message = "Processing" elif state == State.Done: assert self.__state == State.Processing elif state == State.Cancelled: assert self.__state == State.Processing message = "Cancelled" elif state == State.Error: message = "Error during processing" elif state == State.NoState: message = "" else: assert False self.__state = state if self.__state == State.Processing: self.infostack.setCurrentIndex(1) else: self.infostack.setCurrentIndex(0) self.setStatusMessage(message) self.__updateInfo() def reload(self): """ Restart the text scan task """ if self.__state == State.Processing: self.cancel() self.source = self.LOCAL_FILE self.corpus = None self.start() def start(self): """ Start/execute the text indexing operation """ self.error() self.Warning.clear() self.progress_widget.setValue(0) self.__invalidated = False startdir = self.currentPath if self.source == self.LOCAL_FILE \ else self.url_combo.currentText().strip() if not startdir: return if self.__state == State.Processing: assert self.__pendingTask is not None log.info("Starting a new task while one is in progress. " "Cancel the existing task (dir:'{}')".format( self.__pendingTask.startdir)) self.cancel() self.__setRuntimeState(State.Processing) report_progress = methodinvoke(self, "__onReportProgress", (object, )) task = ImportDocuments(startdir, self.source == self.URL, report_progress=report_progress) # collect the task state in one convenient place self.__pendingTask = taskstate = namespace( task=task, startdir=startdir, future=None, watcher=None, cancelled=False, cancel=None, ) def cancel(): # Cancel the task and disconnect if taskstate.future.cancel(): pass else: taskstate.task.cancelled = True taskstate.cancelled = True try: taskstate.future.result(timeout=0) except UserInterruptError: pass except TimeoutError: log.info("The task did not stop in in a timely manner") taskstate.watcher.finished.disconnect(self.__onRunFinished) taskstate.cancel = cancel def run_text_scan_task_interupt(): try: return task.run() except UserInterruptError: # Suppress interrupt errors, so they are not logged return taskstate.future = self.__executor.submit(run_text_scan_task_interupt) taskstate.watcher = FutureWatcher(taskstate.future) taskstate.watcher.finished.connect(self.__onRunFinished) @Slot() def __onRunFinished(self): assert QThread.currentThread() is self.thread() assert self.__state == State.Processing assert self.__pendingTask is not None assert self.sender() is self.__pendingTask.watcher assert self.__pendingTask.future.done() task = self.__pendingTask self.__pendingTask = None corpus, errors, lemmas, pos, ner, is_conllu = None, [], None, None, \ None, False try: corpus, errors, lemmas, pos, ner, is_conllu = task.future.result() except NoDocumentsException: state = State.Error self.error("Folder contains no readable files.") except Exception: sys.excepthook(*sys.exc_info()) state = State.Error self.error(traceback.format_exc()) else: state = State.Done self.error() if corpus: self.n_text_data = len(corpus) self.n_text_categories = len(corpus.domain.class_var.values) \ if corpus.domain.class_var else 0 self.base_corpus = self.corpus = corpus self.is_conllu = is_conllu self.tokens = lemmas self.pos = pos self.ner = ner if self.corpus: self.corpus.name = "Documents" self.skipped_documents = errors if len(errors): self.Warning.read_error( "Some files" if len(errors) > 1 else "One file") self.__setRuntimeState(state) self.commit() def cancel(self): """ Cancel current pending task (if any). """ if self.__state == State.Processing: assert self.__pendingTask is not None self.__pendingTask.cancel() self.__pendingTask = None self.__setRuntimeState(State.Cancelled) @Slot(object) def __onReportProgress(self, arg): # report on scan progress from a worker thread # arg must be a namespace(count: int, lastpath: str) assert QThread.currentThread() is self.thread() if self.__state == State.Processing: self.pathlabel.setText(prettifypath(arg.lastpath)) self.progress_widget.setValue(int(100 * arg.progress)) def add_features(self): lemma, pos, ner = self.lemma_cb, self.pos_cb, self.ner_cb if self.corpus is None: return self.corpus = self.base_corpus.copy() if lemma: self.corpus.store_tokens(self.tokens) if pos: tags = array(self.pos, dtype=object) self.corpus.pos_tags = tags if ner: var = StringVariable("named entities") self.corpus = self.corpus.add_column(var, self.ner) def commit(self): """ Create and commit a Corpus from the collected text meta data. """ if self.is_conllu: self.add_features() self.Outputs.data.send(self.corpus) if self.skipped_documents: skipped_table = (Table.from_list( SKIPPED_DOMAIN, [[x, os.path.join(self.currentPath, x)] for x in self.skipped_documents])) skipped_table.name = "Skipped documents" else: skipped_table = None self.Outputs.skipped_documents.send(skipped_table) def onDeleteWidget(self): self.cancel() self.__executor.shutdown(wait=True) self.__invalidated = False def eventFilter(self, receiver, event): # re-implemented from QWidget # intercept and process drag drop events on the recent directory # selection combo box def dirpath(event): # type: (QDropEvent) -> Optional[str] """Return the directory from a QDropEvent.""" data = event.mimeData() urls = data.urls() if len(urls) == 1: url = urls[0] path = url.toLocalFile() if os.path.isdir(path): return path return None if receiver is self.recent_cb and \ event.type() in {QEvent.DragEnter, QEvent.DragMove, QEvent.Drop}: assert isinstance(event, QDropEvent) path = dirpath(event) if path is not None and event.possibleActions() & Qt.LinkAction: event.setDropAction(Qt.LinkAction) event.accept() if event.type() == QEvent.Drop: self.setCurrentPath(path) self.start() else: event.ignore() return True return super().eventFilter(receiver, event) def send_report(self): if not self.currentPath: return items = [('Path', self.currentPath), ('Number of documents', self.n_text_data)] if self.n_text_categories: items += [('Categories', self.n_text_categories)] if self.skipped_documents: items += [('Number of skipped', len(self.skipped_documents))] self.report_items(items, )
class FeatureEditor(QFrame): FUNCTIONS = dict(chain([(key, val) for key, val in math.__dict__.items() if not key.startswith("_")], [(key, val) for key, val in builtins.__dict__.items() if key in {"str", "float", "int", "len", "abs", "max", "min"}])) featureChanged = Signal() featureEdited = Signal() modifiedChanged = Signal(bool) def __init__(self, *args, **kwargs): super().__init__(*args, **kwargs) layout = QFormLayout( fieldGrowthPolicy=QFormLayout.ExpandingFieldsGrow ) layout.setContentsMargins(0, 0, 0, 0) self.nameedit = QLineEdit( placeholderText="Name...", sizePolicy=QSizePolicy(QSizePolicy.Minimum, QSizePolicy.Fixed) ) self.expressionedit = QLineEdit( placeholderText="Expression..." ) self.attrs_model = itemmodels.VariableListModel( ["Select Feature"], parent=self) self.attributescb = QComboBox( minimumContentsLength=16, sizeAdjustPolicy=QComboBox.AdjustToMinimumContentsLengthWithIcon, sizePolicy=QSizePolicy(QSizePolicy.Minimum, QSizePolicy.Minimum) ) self.attributescb.setModel(self.attrs_model) sorted_funcs = sorted(self.FUNCTIONS) self.funcs_model = itemmodels.PyListModelTooltip() self.funcs_model.setParent(self) self.funcs_model[:] = chain(["Select Function"], sorted_funcs) self.funcs_model.tooltips[:] = chain( [''], [self.FUNCTIONS[func].__doc__ for func in sorted_funcs]) self.functionscb = QComboBox( minimumContentsLength=16, sizeAdjustPolicy=QComboBox.AdjustToMinimumContentsLengthWithIcon, sizePolicy=QSizePolicy(QSizePolicy.Minimum, QSizePolicy.Minimum)) self.functionscb.setModel(self.funcs_model) hbox = QHBoxLayout() hbox.addWidget(self.attributescb) hbox.addWidget(self.functionscb) layout.addRow(self.nameedit, self.expressionedit) layout.addRow(self.tr(""), hbox) self.setLayout(layout) self.nameedit.editingFinished.connect(self._invalidate) self.expressionedit.textChanged.connect(self._invalidate) self.attributescb.currentIndexChanged.connect(self.on_attrs_changed) self.functionscb.currentIndexChanged.connect(self.on_funcs_changed) self._modified = False def setModified(self, modified): if not type(modified) is bool: raise TypeError if self._modified != modified: self._modified = modified self.modifiedChanged.emit(modified) def modified(self): return self._modified modified = Property(bool, modified, setModified, notify=modifiedChanged) def setEditorData(self, data, domain): self.nameedit.setText(data.name) self.expressionedit.setText(data.expression) self.setModified(False) self.featureChanged.emit() self.attrs_model[:] = ["Select Feature"] if domain is not None and (domain or domain.metas): self.attrs_model[:] += chain(domain.attributes, domain.class_vars, domain.metas) def editorData(self): return FeatureDescriptor(name=self.nameedit.text(), expression=self.nameedit.text()) def _invalidate(self): self.setModified(True) self.featureEdited.emit() self.featureChanged.emit() def on_attrs_changed(self): index = self.attributescb.currentIndex() if index > 0: attr = sanitized_name(self.attrs_model[index].name) self.insert_into_expression(attr) self.attributescb.setCurrentIndex(0) def on_funcs_changed(self): index = self.functionscb.currentIndex() if index > 0: func = self.funcs_model[index] if func in ["atan2", "fmod", "ldexp", "log", "pow", "copysign", "hypot"]: self.insert_into_expression(func + "(,)") self.expressionedit.cursorBackward(False, 2) elif func in ["e", "pi"]: self.insert_into_expression(func) else: self.insert_into_expression(func + "()") self.expressionedit.cursorBackward(False) self.functionscb.setCurrentIndex(0) def insert_into_expression(self, what): cp = self.expressionedit.cursorPosition() ct = self.expressionedit.text() text = ct[:cp] + what + ct[cp:] self.expressionedit.setText(text) self.expressionedit.setFocus()
def __init__(self): super().__init__() self.output_corpus = None self.pubmed_api = None self.progress = None self.email_is_valid = False self.record_count = 0 self.download_running = False # To hold all the controls. Makes access easier. self.pubmed_controls = [] h_box = gui.hBox(self.controlArea) label = gui.label(h_box, self, 'Email:') label.setMaximumSize(label.sizeHint()) # Drop-down for recent emails. self.email_combo = QComboBox(h_box) self.email_combo.setMinimumWidth(150) self.email_combo.setEditable(True) self.email_combo.lineEdit().textChanged.connect(self.sync_email) h_box.layout().addWidget(self.email_combo) self.email_combo.activated[int].connect(self.select_email) # RECORD SEARCH self.search_tabs = gui.tabWidget(self.controlArea) # --- Regular search --- regular_search_box = gui.widgetBox(self.controlArea, addSpace=True) # Author self.author_input = gui.lineEdit(regular_search_box, self, 'author', 'Author:', orientation=Qt.Horizontal) self.pubmed_controls.append(self.author_input) h_box = gui.hBox(regular_search_box) year_box = gui.widgetBox(h_box, orientation=Qt.Horizontal) min_date = QDate.fromString( self.MIN_DATE.strftime(self.PY_DATE_FORMAT), self.QT_DATE_FORMAT) if not self.pub_date_from: self.pub_date_from = self.MIN_DATE.strftime(self.PY_DATE_FORMAT) if not self.pub_date_to: self.pub_date_to = date.today().strftime(self.PY_DATE_FORMAT) self.date_from = QDateEdit(QDate.fromString(self.pub_date_from, self.QT_DATE_FORMAT), displayFormat=self.QT_DATE_FORMAT, minimumDate=min_date, calendarPopup=True) self.date_to = QDateEdit(QDate.fromString(self.pub_date_to, self.QT_DATE_FORMAT), displayFormat=self.QT_DATE_FORMAT, minimumDate=min_date, calendarPopup=True) self.date_from.dateChanged.connect(lambda date: setattr( self, 'pub_date_from', date.toString(self.QT_DATE_FORMAT))) self.date_to.dateChanged.connect(lambda date: setattr( self, 'pub_date_to', date.toString(self.QT_DATE_FORMAT))) self.pubmed_controls.append(self.date_from) self.pubmed_controls.append(self.date_to) gui.label(year_box, self, 'From:') year_box.layout().addWidget(self.date_from) gui.label(year_box, self, 'to:') year_box.layout().addWidget(self.date_to) # Keywords. h_box = gui.hBox(regular_search_box) label = gui.label(h_box, self, 'Query:') label.setMaximumSize(label.sizeHint()) self.keyword_combo = QComboBox(h_box) self.keyword_combo.setMinimumWidth(150) self.keyword_combo.setEditable(True) h_box.layout().addWidget(self.keyword_combo) self.keyword_combo.activated[int].connect(self.select_keywords) self.pubmed_controls.append(self.keyword_combo) tab_height = regular_search_box.sizeHint() regular_search_box.setMaximumSize(tab_height) # --- Advanced search --- advanced_search_box = gui.widgetBox(self.controlArea, addSpace=True) # Advanced search query. h_box = gui.hBox(advanced_search_box) self.advanced_query_input = QTextEdit(h_box) h_box.layout().addWidget(self.advanced_query_input) self.advanced_query_input.setMaximumSize(tab_height) self.pubmed_controls.append(self.advanced_query_input) gui.createTabPage(self.search_tabs, 'Regular search', regular_search_box) gui.createTabPage(self.search_tabs, 'Advanced search', advanced_search_box) # Search info label. self.search_info_label = gui.label(self.controlArea, self, 'Number of records found: /') # Search for records button. self.run_search_button = gui.button( self.controlArea, self, 'Find records', callback=self.run_search, tooltip='Performs a search for articles that fit the ' 'specified parameters.') self.pubmed_controls.append(self.run_search_button) h_line = QFrame() h_line.setFrameShape(QFrame.HLine) h_line.setFrameShadow(QFrame.Sunken) self.controlArea.layout().addWidget(h_line) # RECORD RETRIEVAL # Text includes box. text_includes_box = gui.widgetBox(self.controlArea, 'Text includes', addSpace=True) self.authors_checkbox = gui.checkBox(text_includes_box, self, 'includes_authors', 'Authors') self.title_checkbox = gui.checkBox(text_includes_box, self, 'includes_title', 'Article title') self.mesh_checkbox = gui.checkBox(text_includes_box, self, 'includes_mesh', 'Mesh headings') self.abstract_checkbox = gui.checkBox(text_includes_box, self, 'includes_abstract', 'Abstract') self.url_checkbox = gui.checkBox(text_includes_box, self, 'includes_url', 'URL') self.pubmed_controls.append(self.authors_checkbox) self.pubmed_controls.append(self.title_checkbox) self.pubmed_controls.append(self.mesh_checkbox) self.pubmed_controls.append(self.abstract_checkbox) self.pubmed_controls.append(self.url_checkbox) # Num. records. h_box = gui.hBox(self.controlArea) label = gui.label(h_box, self, 'Retrieve') label.setMaximumSize(label.sizeHint()) self.num_records_input = gui.spin(h_box, self, 'num_records', minv=1, maxv=100000) self.max_records_label = gui.label(h_box, self, 'records from /.') self.max_records_label.setMaximumSize( self.max_records_label.sizeHint()) self.pubmed_controls.append(self.num_records_input) # Download articles. # Search for records button. self.retrieve_records_button = gui.button( self.controlArea, self, 'Retrieve records', callback=self.retrieve_records, tooltip='Retrieves the specified documents.') self.pubmed_controls.append(self.retrieve_records_button) # Num. retrieved records info label. self.retrieval_info_label = gui.label( self.controlArea, self, 'Number of records retrieved: /') # Load the most recent emails. self.set_email_list() # Load the most recent queries. self.set_keyword_list() # Check the email and enable controls accordingly. if self.recent_emails: email = self.recent_emails[0] self.email_is_valid = validate_email(email) self.enable_controls()
class OWImpute(OWWidget): name = "Impute" description = "Impute missing values in the data table." icon = "icons/Impute.svg" priority = 2130 inputs = [("Data", Orange.data.Table, "set_data"), ("Learner", Learner, "set_learner")] outputs = [("Data", Orange.data.Table)] DEFAULT_LEARNER = SimpleTreeLearner() METHODS = [AsDefault(), impute.DoNotImpute(), impute.Average(), impute.AsValue(), impute.Model(DEFAULT_LEARNER), impute.Random(), impute.DropInstances(), impute.Default()] DEFAULT, DO_NOT_IMPUTE, MODEL_BASED_IMPUTER, AS_INPUT = 0, 1, 4, 7 settingsHandler = settings.DomainContextHandler() _default_method_index = settings.Setting(DO_NOT_IMPUTE) variable_methods = settings.ContextSetting({}) autocommit = settings.Setting(False) default_value = settings.Setting(0.) want_main_area = False resizing_enabled = False def __init__(self): super().__init__() main_layout = QVBoxLayout() main_layout.setContentsMargins(10, 10, 10, 10) self.controlArea.layout().addLayout(main_layout) box = QGroupBox(title=self.tr("Default Method"), flat=False) box_layout = QVBoxLayout(box) main_layout.addWidget(box) button_group = QButtonGroup() button_group.buttonClicked[int].connect(self.set_default_method) for i, method in enumerate(self.METHODS): if not method.columns_only: button = QRadioButton(method.name) button.setChecked(i == self.default_method_index) button_group.addButton(button, i) box_layout.addWidget(button) self.default_button_group = button_group box = QGroupBox(title=self.tr("Individual Attribute Settings"), flat=False) main_layout.addWidget(box) horizontal_layout = QHBoxLayout(box) main_layout.addWidget(box) self.varview = QListView( selectionMode=QListView.ExtendedSelection ) self.varview.setItemDelegate(DisplayFormatDelegate()) self.varmodel = itemmodels.VariableListModel() self.varview.setModel(self.varmodel) self.varview.selectionModel().selectionChanged.connect( self._on_var_selection_changed ) self.selection = self.varview.selectionModel() horizontal_layout.addWidget(self.varview) method_layout = QVBoxLayout() horizontal_layout.addLayout(method_layout) button_group = QButtonGroup() for i, method in enumerate(self.METHODS): button = QRadioButton(text=method.name) button_group.addButton(button, i) method_layout.addWidget(button) self.value_combo = QComboBox( minimumContentsLength=8, sizeAdjustPolicy=QComboBox.AdjustToMinimumContentsLength, activated=self._on_value_selected ) self.value_combo.currentIndexChanged.connect(self._on_value_changed) self.value_double = QDoubleSpinBox( editingFinished=self._on_value_selected, minimum=-1000., maximum=1000., singleStep=.1, decimals=3, value=self.default_value ) self.value_stack = value_stack = QStackedLayout() value_stack.addWidget(self.value_combo) value_stack.addWidget(self.value_double) method_layout.addLayout(value_stack) button_group.buttonClicked[int].connect( self.set_method_for_current_selection ) method_layout.addStretch(2) reset_button = QPushButton( "Restore All to Default", checked=False, checkable=False, clicked=self.reset_variable_methods, default=False, autoDefault=False) method_layout.addWidget(reset_button) self.variable_button_group = button_group box = gui.auto_commit( self.controlArea, self, "autocommit", "Apply", orientation=Qt.Horizontal, checkbox_label="Apply automatically") box.layout().insertSpacing(0, 80) box.layout().insertWidget(0, self.report_button) self.data = None self.modified = False self.default_method = self.METHODS[self.default_method_index] self.update_varview() @property def default_method_index(self): return self._default_method_index @default_method_index.setter def default_method_index(self, index): if self._default_method_index != index: self._default_method_index = index self.default_button_group.button(index).setChecked(True) self.default_method = self.METHODS[self.default_method_index] self.METHODS[self.DEFAULT].method = self.default_method # update variable view for index in map(self.varmodel.index, range(len(self.varmodel))): self.varmodel.setData(index, self.variable_methods.get(index.row(), self.METHODS[self.DEFAULT]), Qt.UserRole) self._invalidate() def set_default_method(self, index): """Set the current selected default imputation method. """ self.default_method_index = index @check_sql_input def set_data(self, data): self.closeContext() self.varmodel[:] = [] self.variable_methods = {} self.modified = False self.data = data if data is not None: self.varmodel[:] = data.domain.variables self.openContext(data.domain) self.update_varview() self.unconditional_commit() def set_learner(self, learner): self.learner = learner or self.DEFAULT_LEARNER imputer = self.METHODS[self.MODEL_BASED_IMPUTER] imputer.learner = self.learner button = self.default_button_group.button(self.MODEL_BASED_IMPUTER) button.setText(imputer.name) variable_button = self.variable_button_group.button(self.MODEL_BASED_IMPUTER) variable_button.setText(imputer.name) if learner is not None: self.default_method_index = self.MODEL_BASED_IMPUTER self.commit() def get_method_for_column(self, column_index): """Returns the imputation method for column by its index. """ if not isinstance(column_index, int): column_index = column_index.row() return self.variable_methods.get(column_index, self.METHODS[self.DEFAULT]) def _invalidate(self): self.modified = True self.commit() def commit(self): data = self.data if self.data is not None: if not len(self.data): self.send("Data", self.data) self.modified = False return drop_mask = np.zeros(len(self.data), bool) attributes = [] class_vars = [] self.warning() with self.progressBar(len(self.varmodel)) as progress: for i, var in enumerate(self.varmodel): method = self.variable_methods.get(i, self.default_method) if not method.supports_variable(var): self.warning("Default method can not handle '{}'". format(var.name)) elif isinstance(method, impute.DropInstances): drop_mask |= method(self.data, var) else: var = method(self.data, var) if isinstance(var, Orange.data.Variable): var = [var] if i < len(self.data.domain.attributes): attributes.extend(var) else: class_vars.extend(var) progress.advance() domain = Orange.data.Domain(attributes, class_vars, self.data.domain.metas) data = self.data.from_table(domain, self.data[~drop_mask]) self.send("Data", data) self.modified = False def send_report(self): specific = [] for i, var in enumerate(self.varmodel): method = self.variable_methods.get(i, None) if method is not None: specific.append("{} ({})".format(var.name, str(method))) default = self.default_method.name if specific: self.report_items(( ("Default method", default), ("Specific imputers", ", ".join(specific)) )) else: self.report_items((("Method", default),)) def _on_var_selection_changed(self): indexes = self.selection.selectedIndexes() methods = set(self.get_method_for_column(i.row()).name for i in indexes) selected_vars = [self.varmodel[index.row()] for index in indexes] has_discrete = any(var.is_discrete for var in selected_vars) if len(methods) == 1: method = methods.pop() for i, m in enumerate(self.METHODS): if method == m.name: self.variable_button_group.button(i).setChecked(True) elif self.variable_button_group.checkedButton() is not None: self.variable_button_group.setExclusive(False) self.variable_button_group.checkedButton().setChecked(False) self.variable_button_group.setExclusive(True) for method, button in zip(self.METHODS, self.variable_button_group.buttons()): enabled = all(method.supports_variable(var) for var in selected_vars) button.setEnabled(enabled) if not has_discrete: self.value_stack.setEnabled(True) self.value_stack.setCurrentWidget(self.value_double) self._on_value_changed() elif len(selected_vars) == 1: self.value_stack.setEnabled(True) self.value_stack.setCurrentWidget(self.value_combo) self.value_combo.clear() self.value_combo.addItems(selected_vars[0].values) self._on_value_changed() else: self.variable_button_group.button(self.AS_INPUT).setEnabled(False) self.value_stack.setEnabled(False) def set_method_for_current_selection(self, method_index): indexes = self.selection.selectedIndexes() self.set_method_for_indexes(indexes, method_index) def set_method_for_indexes(self, indexes, method_index): if method_index == self.DEFAULT: for index in indexes: self.variable_methods.pop(index, None) else: method = self.METHODS[method_index].copy() for index in indexes: self.variable_methods[index.row()] = method self.update_varview(indexes) self._invalidate() def update_varview(self, indexes=None): if indexes is None: indexes = map(self.varmodel.index, range(len(self.varmodel))) for index in indexes: self.varmodel.setData(index, self.get_method_for_column(index.row()), Qt.UserRole) def _on_value_selected(self): self.variable_button_group.button(self.AS_INPUT).setChecked(True) self._on_value_changed() def _on_value_changed(self): widget = self.value_stack.currentWidget() if widget is self.value_combo: value = self.value_combo.currentText() else: value = self.value_double.value() self.default_value = value self.METHODS[self.AS_INPUT].default = value index = self.variable_button_group.checkedId() if index == self.AS_INPUT: self.set_method_for_current_selection(index) def reset_variable_methods(self): indexes = map(self.varmodel.index, range(len(self.varmodel))) self.set_method_for_indexes(indexes, self.DEFAULT) self.variable_button_group.button(self.DEFAULT).setChecked(True)
class Scale(BaseEditor): NoCentering, CenterMean, CenterMedian = 0, 1, 2 NoScaling, ScaleBySD, ScaleBySpan = 0, 1, 2 def __init__(self, parent=None, **kwargs): super().__init__(parent, **kwargs) self.setLayout(QVBoxLayout()) form = QFormLayout() self.__centercb = QComboBox() self.__centercb.addItems( ["No Centering", "Center by Mean", "Center by Median"]) self.__scalecb = QComboBox() self.__scalecb.addItems(["No scaling", "Scale by SD", "Scale by span"]) form.addRow("Center:", self.__centercb) form.addRow("Scale:", self.__scalecb) self.layout().addLayout(form) self.__centercb.currentIndexChanged.connect(self.changed) self.__scalecb.currentIndexChanged.connect(self.changed) self.__centercb.activated.connect(self.edited) self.__scalecb.activated.connect(self.edited) def setParameters(self, params): center = params.get("center", _Scale.CenteringType.Mean) scale = params.get("scale", _Scale.ScalingType.Std) self.__centercb.setCurrentIndex( _enum_to_index(_Scale.CenteringType, center)) self.__scalecb.setCurrentIndex( _enum_to_index(_Scale.ScalingType, scale)) def parameters(self): return { "center": _index_to_enum(_Scale.CenteringType, self.__centercb.currentIndex()), "scale": _index_to_enum(_Scale.ScalingType, self.__scalecb.currentIndex()) } @staticmethod def createinstance(params): center = params.get("center", _Scale.CenteringType.Mean) scale = params.get("scale", _Scale.ScalingType.Std) return _Scale(center=center, scale=scale) def __repr__(self): return "{}, {}".format(self.__centercb.currentText(), self.__scalecb.currentText())
def __setupUi(self): """Set up the UI. """ if self.__macUnified: self.tab = QToolBar() self.addToolBar(Qt.TopToolBarArea, self.tab) self.setUnifiedTitleAndToolBarOnMac(True) # This does not seem to work self.setWindowFlags(self.windowFlags() & \ ~Qt.MacWindowToolBarButtonHint) self.tab.actionTriggered[QAction].connect( self.__macOnToolBarAction ) central = QStackedWidget() central.setSizePolicy(QSizePolicy.Fixed, QSizePolicy.Fixed) else: self.tab = central = QTabWidget(self) self.stack = central self.setCentralWidget(central) # General Tab tab = QWidget() self.addTab(tab, self.tr("General"), toolTip=self.tr("General Options")) form = QFormLayout() tab.setSizePolicy(QSizePolicy.Fixed, QSizePolicy.Fixed) nodes = QWidget(self, objectName="nodes") nodes.setLayout(QVBoxLayout()) nodes.layout().setContentsMargins(0, 0, 0, 0) cb_anim = QCheckBox( self.tr("Enable node animations"), objectName="enable-node-animations", toolTip=self.tr("Enable shadow and ping animations for nodes " "in the workflow.") ) self.bind(cb_anim, "checked", "schemeedit/enable-node-animations") nodes.layout().addWidget(cb_anim) form.addRow(self.tr("Nodes"), nodes) links = QWidget(self, objectName="links") links.setLayout(QVBoxLayout()) links.layout().setContentsMargins(0, 0, 0, 0) cb_show = QCheckBox( self.tr("Show channel names between widgets"), objectName="show-channel-names", toolTip=self.tr("Show source and sink channel names " "over the links.") ) self.bind(cb_show, "checked", "schemeedit/show-channel-names") links.layout().addWidget(cb_show) form.addRow(self.tr("Links"), links) quickmenu = QWidget(self, objectName="quickmenu-options") quickmenu.setLayout(QVBoxLayout()) quickmenu.layout().setContentsMargins(0, 0, 0, 0) cb1 = QCheckBox(self.tr("On double click"), toolTip=self.tr("Open quick menu on a double click " "on an empty spot in the canvas")) cb2 = QCheckBox(self.tr("On right click"), toolTip=self.tr("Open quick menu on a right click " "on an empty spot in the canvas")) cb3 = QCheckBox(self.tr("On space key press"), toolTip=self.tr("On Space key press while the mouse" "is hovering over the canvas.")) cb4 = QCheckBox(self.tr("On any key press"), toolTip=self.tr("On any key press while the mouse" "is hovering over the canvas.")) self.bind(cb1, "checked", "quickmenu/trigger-on-double-click") self.bind(cb2, "checked", "quickmenu/trigger-on-right-click") self.bind(cb3, "checked", "quickmenu/trigger-on-space-key") self.bind(cb4, "checked", "quickmenu/trigger-on-any-key") quickmenu.layout().addWidget(cb1) quickmenu.layout().addWidget(cb2) quickmenu.layout().addWidget(cb3) quickmenu.layout().addWidget(cb4) form.addRow(self.tr("Open quick menu on"), quickmenu) startup = QWidget(self, objectName="startup-group") startup.setLayout(QVBoxLayout()) startup.layout().setContentsMargins(0, 0, 0, 0) cb_splash = QCheckBox(self.tr("Show splash screen"), self, objectName="show-splash-screen") cb_welcome = QCheckBox(self.tr("Show welcome screen"), self, objectName="show-welcome-screen") cb_updates = QCheckBox(self.tr("Check for updates"), self, objectName="check-updates") self.bind(cb_splash, "checked", "startup/show-splash-screen") self.bind(cb_welcome, "checked", "startup/show-welcome-screen") self.bind(cb_updates, "checked", "startup/check-updates") startup.layout().addWidget(cb_splash) startup.layout().addWidget(cb_welcome) startup.layout().addWidget(cb_updates) form.addRow(self.tr("On startup"), startup) toolbox = QWidget(self, objectName="toolbox-group") toolbox.setLayout(QVBoxLayout()) toolbox.layout().setContentsMargins(0, 0, 0, 0) exclusive = QCheckBox(self.tr("Only one tab can be open at a time")) self.bind(exclusive, "checked", "mainwindow/toolbox-dock-exclusive") toolbox.layout().addWidget(exclusive) form.addRow(self.tr("Tool box"), toolbox) tab.setLayout(form) # Output Tab tab = QWidget() self.addTab(tab, self.tr("Output"), toolTip="Output Redirection") form = QFormLayout() box = QWidget() layout = QVBoxLayout() layout.setContentsMargins(0, 0, 0, 0) combo = QComboBox() combo.addItems([self.tr("Critical"), self.tr("Error"), self.tr("Warn"), self.tr("Info"), self.tr("Debug")]) self.bind(combo, "currentIndex", "logging/level") layout.addWidget(combo) box.setLayout(layout) form.addRow(self.tr("Logging"), box) box = QWidget() layout = QVBoxLayout() layout.setContentsMargins(0, 0, 0, 0) cb1 = QCheckBox(self.tr("Open in external browser"), objectName="open-in-external-browser") self.bind(cb1, "checked", "help/open-in-external-browser") layout.addWidget(cb1) box.setLayout(layout) form.addRow(self.tr("Help window"), box) tab.setLayout(form) # Error Reporting Tab tab = QWidget() self.addTab(tab, self.tr("Error Reporting"), toolTip="Settings related to error reporting") form = QFormLayout() line_edit_mid = QLineEdit() self.bind(line_edit_mid, "text", "error-reporting/machine-id") form.addRow("Machine ID:", line_edit_mid) tab.setLayout(form) # Add-ons Tab tab = QWidget() self.addTab(tab, self.tr("Add-ons"), toolTip="Settings related to add-on installation") form = QFormLayout() conda = QWidget(self, objectName="conda-group") conda.setLayout(QVBoxLayout()) conda.layout().setContentsMargins(0, 0, 0, 0) cb_conda_install = QCheckBox(self.tr("Install add-ons with conda"), self, objectName="allow-conda-experimental") self.bind(cb_conda_install, "checked", "add-ons/allow-conda-experimental") conda.layout().addWidget(cb_conda_install) form.addRow(self.tr("Conda"), conda) tab.setLayout(form) if self.__macUnified: # Need some sensible size otherwise mac unified toolbar 'takes' # the space that should be used for layout of the contents self.adjustSize()
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() if path: 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): super().__init__() #: widget's runtime state self.__state = State.NoState self.base_corpus = None self.corpus = None self.n_text_categories = 0 self.n_text_data = 0 self.skipped_documents = [] self.is_conllu = False self.tokens = None self.pos = None self.ner = None self.__invalidated = False self.__pendingTask = None layout = QGridLayout() layout.setSpacing(4) gui.widgetBox(self.controlArea, orientation=layout, box='Source') source_box = gui.radioButtons(None, self, "source", box=True, callback=self.start, addToLayout=False) rb_button = gui.appendRadioButton(source_box, "Folder:", addToLayout=False) layout.addWidget(rb_button, 0, 0, Qt.AlignVCenter) box = gui.hBox(None, addToLayout=False, margin=0) box.setSizePolicy(QSizePolicy.MinimumExpanding, QSizePolicy.Fixed) self.recent_cb = QComboBox( sizeAdjustPolicy=QComboBox.AdjustToMinimumContentsLengthWithIcon, minimumContentsLength=16, acceptDrops=True) self.recent_cb.installEventFilter(self) self.recent_cb.activated[int].connect(self.__onRecentActivated) browseaction = QAction( "Open/Load Documents", self, iconText="\N{HORIZONTAL ELLIPSIS}", icon=self.style().standardIcon(QStyle.SP_DirOpenIcon), toolTip="Select a folder from which to load the documents") browseaction.triggered.connect(self.__runOpenDialog) reloadaction = QAction("Reload", self, icon=self.style().standardIcon( QStyle.SP_BrowserReload), toolTip="Reload current document 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, default=False, autoDefault=False, ) reloadbutton = QPushButton( reloadaction.iconText(), icon=reloadaction.icon(), clicked=reloadaction.trigger, default=False, autoDefault=False, ) box.layout().addWidget(self.recent_cb) layout.addWidget(box, 0, 1) layout.addWidget(browsebutton, 0, 2) layout.addWidget(reloadbutton, 0, 3) rb_button = gui.appendRadioButton(source_box, "URL:", addToLayout=False) layout.addWidget(rb_button, 3, 0, Qt.AlignVCenter) self.url_combo = url_combo = QComboBox() url_model = PyListModel() url_model.wrap(self.recent_urls) url_combo.setLineEdit(LineEditSelectOnFocus()) url_combo.setModel(url_model) url_combo.setSizePolicy(QSizePolicy.Ignored, QSizePolicy.Fixed) url_combo.setEditable(True) url_combo.setInsertPolicy(url_combo.InsertAtTop) url_edit = url_combo.lineEdit() m = url_edit.textMargins() url_edit.setTextMargins(m.left() + 5, m.top(), m.right(), m.bottom()) layout.addWidget(url_combo, 3, 1, 1, 3) url_combo.activated.connect(self._url_set) # whit completer we set that combo box is case sensitive when # matching the history completer = QCompleter() completer.setCaseSensitivity(Qt.CaseSensitive) url_combo.setCompleter(completer) self.addActions([browseaction, reloadaction]) reloadaction.changed.connect( lambda: reloadbutton.setEnabled(reloadaction.isEnabled())) box = gui.hBox(self.controlArea, "Conllu import options") gui.checkBox(box, self, "lemma_cb", "Lemma", callback=self.commit) gui.checkBox(box, self, "pos_cb", "POS tags", callback=self.commit) gui.checkBox(box, self, "ner_cb", "NER", callback=self.commit) self.controlArea.layout().addWidget(box) box = gui.vBox(self.controlArea, "Info") self.infostack = QStackedWidget() self.info_area = QLabel(text="No document set selected", wordWrap=True) self.progress_widget = QProgressBar(minimum=0, maximum=100) self.cancel_button = QPushButton( "Cancel", icon=self.style().standardIcon(QStyle.SP_DialogCancelButton), default=False, autoDefault=False, ) 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 OWSql(OWWidget): name = "SQL Table" id = "orange.widgets.data.sql" description = "Load data set from SQL." icon = "icons/SQLTable.svg" priority = 30 category = "Data" keywords = ["data", "file", "load", "read", "SQL"] class Outputs: data = Output("Data", Table, doc="Attribute-valued data set read from the input file.") settings_version = 2 want_main_area = False resizing_enabled = False host = Setting(None) port = Setting(None) database = Setting(None) schema = Setting(None) username = "" password = "" table = Setting(None) sql = Setting("") guess_values = Setting(True) download = Setting(False) materialize = Setting(False) materialize_table_name = Setting("") class Information(OWWidget.Information): data_sampled = Msg("Data description was generated from a sample.") class Error(OWWidget.Error): connection = Msg("{}") no_backends = Msg("Please install a backend to use this widget") missing_extension = Msg("Database is missing extension{}: {}") def __init__(self): super().__init__() self.backend = None self.data_desc_table = None self.database_desc = None vbox = gui.vBox(self.controlArea, "Server", addSpace=True) box = gui.vBox(vbox) self.backends = BackendModel(Backend.available_backends()) self.backendcombo = QComboBox(box) if len(self.backends): self.backendcombo.setModel(self.backends) else: self.Error.no_backends() box.setEnabled(False) box.layout().addWidget(self.backendcombo) self.servertext = QLineEdit(box) self.servertext.setPlaceholderText('Server') self.servertext.setToolTip('Server') self.servertext.editingFinished.connect(self._load_credentials) if self.host: self.servertext.setText(self.host if not self.port else '{}:{}'.format(self.host, self.port)) box.layout().addWidget(self.servertext) self.databasetext = QLineEdit(box) self.databasetext.setPlaceholderText('Database[/Schema]') self.databasetext.setToolTip('Database or optionally Database/Schema') if self.database: self.databasetext.setText( self.database if not self.schema else '{}/{}'.format(self.database, self.schema)) box.layout().addWidget(self.databasetext) self.usernametext = QLineEdit(box) self.usernametext.setPlaceholderText('Username') self.usernametext.setToolTip('Username') box.layout().addWidget(self.usernametext) self.passwordtext = QLineEdit(box) self.passwordtext.setPlaceholderText('Password') self.passwordtext.setToolTip('Password') self.passwordtext.setEchoMode(QLineEdit.Password) box.layout().addWidget(self.passwordtext) self._load_credentials() self.tables = TableModel() tables = gui.hBox(box) self.tablecombo = QComboBox( minimumContentsLength=35, sizeAdjustPolicy=QComboBox.AdjustToMinimumContentsLength ) self.tablecombo.setModel(self.tables) self.tablecombo.setToolTip('table') tables.layout().addWidget(self.tablecombo) self.connect() index = self.tablecombo.findText(str(self.table)) if index != -1: self.tablecombo.setCurrentIndex(index) # set up the callback to select_table in case of selection change self.tablecombo.activated[int].connect(self.select_table) self.connectbutton = gui.button( tables, self, '↻', callback=self.connect) self.connectbutton.setSizePolicy( QSizePolicy.Fixed, QSizePolicy.Fixed) tables.layout().addWidget(self.connectbutton) self.custom_sql = gui.vBox(box) self.custom_sql.setVisible(False) self.sqltext = QTextEdit(self.custom_sql) self.sqltext.setPlainText(self.sql) self.custom_sql.layout().addWidget(self.sqltext) mt = gui.hBox(self.custom_sql) cb = gui.checkBox(mt, self, 'materialize', 'Materialize to table ') cb.setToolTip('Save results of the query in a table') le = gui.lineEdit(mt, self, 'materialize_table_name') le.setToolTip('Save results of the query in a table') self.executebtn = gui.button( self.custom_sql, self, 'Execute', callback=self.open_table) box.layout().addWidget(self.custom_sql) gui.checkBox(box, self, "guess_values", "Auto-discover categorical variables", callback=self.open_table) gui.checkBox(box, self, "download", "Download data to local memory", callback=self.open_table) gui.rubber(self.buttonsArea) QTimer.singleShot(0, self.select_table) def _load_credentials(self): self._parse_host_port() cm = self._credential_manager(self.host, self.port) self.username = cm.username self.password = cm.password if self.username: self.usernametext.setText(self.username) if self.password: self.passwordtext.setText(self.password) def _save_credentials(self): cm = self._credential_manager(self.host, self.port) cm.username = self.username or '' cm.password = self.password or '' def _credential_manager(self, host, port): return CredentialManager("SQL Table: {}:{}".format(host, port)) def error(self, id=0, text=""): super().error(id, text) err_style = 'QLineEdit {border: 2px solid red;}' if 'server' in text or 'host' in text: self.servertext.setStyleSheet(err_style) else: self.servertext.setStyleSheet('') if 'role' in text: self.usernametext.setStyleSheet(err_style) else: self.usernametext.setStyleSheet('') if 'database' in text: self.databasetext.setStyleSheet(err_style) else: self.databasetext.setStyleSheet('') def _parse_host_port(self): hostport = self.servertext.text().split(':') self.host = hostport[0] self.port = hostport[1] if len(hostport) == 2 else None def connect(self): self._parse_host_port() self.database, _, self.schema = self.databasetext.text().partition('/') self.username = self.usernametext.text() or None self.password = self.passwordtext.text() or None try: if self.backendcombo.currentIndex() < 0: return backend = self.backends[self.backendcombo.currentIndex()] self.backend = backend(dict( host=self.host, port=self.port, database=self.database, user=self.username, password=self.password )) self.Error.connection.clear() self._save_credentials() self.database_desc = OrderedDict(( ("Host", self.host), ("Port", self.port), ("Database", self.database), ("User name", self.username) )) self.refresh_tables() except BackendError as err: error = str(err).split('\n')[0] self.Error.connection(error) self.database_desc = self.data_desc_table = None self.tablecombo.clear() def refresh_tables(self): self.tables.clear() self.Error.missing_extension.clear() if self.backend is None: self.data_desc_table = None return self.tables.append("Select a table") self.tables.append("Custom SQL") self.tables.extend(self.backend.list_tables(self.schema)) # Called on tablecombo selection change: def select_table(self): curIdx = self.tablecombo.currentIndex() if self.tablecombo.itemText(curIdx) != "Custom SQL": self.custom_sql.setVisible(False) return self.open_table() else: self.custom_sql.setVisible(True) self.data_desc_table = None self.database_desc["Table"] = "(None)" self.table = None if len(str(self.sql)) > 14: return self.open_table() #self.Error.missing_extension( # 's' if len(missing) > 1 else '', # ', '.join(missing), # shown=missing) def open_table(self): table = self.get_table() self.data_desc_table = table self.Outputs.data.send(table) def get_table(self): curIdx = self.tablecombo.currentIndex() if curIdx <= 0: if self.database_desc: self.database_desc["Table"] = "(None)" self.data_desc_table = None return if self.tablecombo.itemText(curIdx) != "Custom SQL": self.table = self.tables[self.tablecombo.currentIndex()] self.database_desc["Table"] = self.table if "Query" in self.database_desc: del self.database_desc["Query"] what = self.table else: what = self.sql = self.sqltext.toPlainText() self.table = "Custom SQL" if self.materialize: import psycopg2 if not self.materialize_table_name: self.Error.connection( "Specify a table name to materialize the query") return try: with self.backend.execute_sql_query("DROP TABLE IF EXISTS " + self.materialize_table_name): pass with self.backend.execute_sql_query("CREATE TABLE " + self.materialize_table_name + " AS " + self.sql): pass with self.backend.execute_sql_query("ANALYZE " + self.materialize_table_name): pass except (psycopg2.ProgrammingError, BackendError) as ex: self.Error.connection(str(ex)) return try: table = SqlTable(dict(host=self.host, port=self.port, database=self.database, user=self.username, password=self.password), what, backend=type(self.backend), inspect_values=False) except BackendError as ex: self.Error.connection(str(ex)) return self.Error.connection.clear() sample = False if table.approx_len() > LARGE_TABLE and self.guess_values: confirm = QMessageBox(self) confirm.setIcon(QMessageBox.Warning) confirm.setText("Attribute discovery might take " "a long time on large tables.\n" "Do you want to auto discover attributes?") confirm.addButton("Yes", QMessageBox.YesRole) no_button = confirm.addButton("No", QMessageBox.NoRole) sample_button = confirm.addButton("Yes, on a sample", QMessageBox.YesRole) confirm.exec() if confirm.clickedButton() == no_button: self.guess_values = False elif confirm.clickedButton() == sample_button: sample = True self.Information.clear() if self.guess_values: QApplication.setOverrideCursor(QCursor(Qt.WaitCursor)) if sample: s = table.sample_time(1) domain = s.get_domain(inspect_values=True) self.Information.data_sampled() else: domain = table.get_domain(inspect_values=True) QApplication.restoreOverrideCursor() table.domain = domain if self.download: if table.approx_len() > MAX_DL_LIMIT: QMessageBox.warning( self, 'Warning', "Data is too big to download.\n" "Consider using the Data Sampler widget to download " "a sample instead.") self.download = False elif table.approx_len() > AUTO_DL_LIMIT: confirm = QMessageBox.question( self, 'Question', "Data appears to be big. Do you really " "want to download it to local memory?", QMessageBox.Yes | QMessageBox.No, QMessageBox.No) if confirm == QMessageBox.No: self.download = False if self.download: table.download_data(MAX_DL_LIMIT) table = Table(table) return table def send_report(self): if not self.database_desc: self.report_paragraph("No database connection.") return self.report_items("Database", self.database_desc) if self.data_desc_table: self.report_items("Data", report.describe_data(self.data_desc_table)) @classmethod def migrate_settings(cls, settings, version): if version < 2: # Until Orange version 3.4.4 username and password had been stored # in Settings. cm = cls._credential_manager(settings["host"], settings["port"]) cm.username = settings["username"] cm.password = settings["password"]
def __init__(self): super().__init__() self.backend = None self.data_desc_table = None self.database_desc = None vbox = gui.vBox(self.controlArea, "Server", addSpace=True) box = gui.vBox(vbox) self.backends = BackendModel(Backend.available_backends()) self.backendcombo = QComboBox(box) if len(self.backends): self.backendcombo.setModel(self.backends) else: self.Error.no_backends() box.setEnabled(False) box.layout().addWidget(self.backendcombo) self.servertext = QLineEdit(box) self.servertext.setPlaceholderText('Server') self.servertext.setToolTip('Server') self.servertext.editingFinished.connect(self._load_credentials) if self.host: self.servertext.setText(self.host if not self.port else '{}:{}'.format(self.host, self.port)) box.layout().addWidget(self.servertext) self.databasetext = QLineEdit(box) self.databasetext.setPlaceholderText('Database[/Schema]') self.databasetext.setToolTip('Database or optionally Database/Schema') if self.database: self.databasetext.setText( self.database if not self.schema else '{}/{}'.format(self.database, self.schema)) box.layout().addWidget(self.databasetext) self.usernametext = QLineEdit(box) self.usernametext.setPlaceholderText('Username') self.usernametext.setToolTip('Username') box.layout().addWidget(self.usernametext) self.passwordtext = QLineEdit(box) self.passwordtext.setPlaceholderText('Password') self.passwordtext.setToolTip('Password') self.passwordtext.setEchoMode(QLineEdit.Password) box.layout().addWidget(self.passwordtext) self._load_credentials() self.tables = TableModel() tables = gui.hBox(box) self.tablecombo = QComboBox( minimumContentsLength=35, sizeAdjustPolicy=QComboBox.AdjustToMinimumContentsLength ) self.tablecombo.setModel(self.tables) self.tablecombo.setToolTip('table') tables.layout().addWidget(self.tablecombo) self.connect() index = self.tablecombo.findText(str(self.table)) if index != -1: self.tablecombo.setCurrentIndex(index) # set up the callback to select_table in case of selection change self.tablecombo.activated[int].connect(self.select_table) self.connectbutton = gui.button( tables, self, '↻', callback=self.connect) self.connectbutton.setSizePolicy( QSizePolicy.Fixed, QSizePolicy.Fixed) tables.layout().addWidget(self.connectbutton) self.custom_sql = gui.vBox(box) self.custom_sql.setVisible(False) self.sqltext = QTextEdit(self.custom_sql) self.sqltext.setPlainText(self.sql) self.custom_sql.layout().addWidget(self.sqltext) mt = gui.hBox(self.custom_sql) cb = gui.checkBox(mt, self, 'materialize', 'Materialize to table ') cb.setToolTip('Save results of the query in a table') le = gui.lineEdit(mt, self, 'materialize_table_name') le.setToolTip('Save results of the query in a table') self.executebtn = gui.button( self.custom_sql, self, 'Execute', callback=self.open_table) box.layout().addWidget(self.custom_sql) gui.checkBox(box, self, "guess_values", "Auto-discover categorical variables", callback=self.open_table) gui.checkBox(box, self, "download", "Download data to local memory", callback=self.open_table) gui.rubber(self.buttonsArea) QTimer.singleShot(0, self.select_table)
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 __init__(self): super().__init__() self.file_combo = \ QComboBox(self, sizeAdjustPolicy=QComboBox.AdjustToContents)
def createEditor(self, parent, _QStyleOptionViewItem, index): combo = QComboBox(parent) combo.setModel(self._combo_model) return combo