def test_clear(self): model = PyListModel([1, 2, 3, 2, 4]) model.clear() self.assertSequenceEqual(model, []) self.assertEqual(len(model), len(model._other_data)) model.clear() self.assertSequenceEqual(model, []) self.assertEqual(len(model), len(model._other_data))
class OWQuickSelect(widget.OWWidget): name = 'Quick Select' icon = 'icons/QuickSelect.svg' description = 'Select instances with specific feature value.' class Inputs: data = widget.Input("Data", Table) class Outputs: matching = widget.Output("Matching Data", Table, default=True) unmatched = widget.Output("Unmatched Data", Table) annotated = widget.Output(ANNOTATED_DATA_SIGNAL_NAME, Table) class Error(widget.OWWidget.Error): no_categorical = Msg("No categorical variables") want_main_area = False resizing_enabled = False settingsHandler = settings.DomainContextHandler() variable = settings.ContextSetting(None) pending_value = settings.ContextSetting("") def __init__(self): super().__init__() # This is not a setting because openContext cannot retrieve it before # filling the combo. Settings store this as pending_value self.value = "" self.data = None self.n_matched = None form = QFormLayout() gui.widgetBox(self.controlArea, orientation=form) self.var_model = DomainModel(order=DomainModel.MIXED, valid_types=DiscreteVariable) var_combo = gui.comboBox(None, self, "variable", contentsLength=50, model=self.var_model, callback=self._on_variable_changed) self.value_model = PyListModel() value_combo = gui.comboBox(None, self, "value", label="Value: ", model=self.value_model, callback=self._on_value_changed, contentsLength=50, sizePolicy=(QSizePolicy.MinimumExpanding, QSizePolicy.Fixed)) form.addRow("Variable:", var_combo) form.addRow("Value:", value_combo) @Inputs.data def set_data(self, data): self.closeContext() self.data = data self.Error.no_categorical.clear() # TODO: Check that contexts are retrieved properly, also when removing # and re-adding a connection if data: self.var_model.set_domain(data.domain) self.info.set_input_summary(len(data), format_summary_details(data)) if not self.var_model.rowCount(): self.data = None self.Error.no_categorical() else: self.var_model.set_domain(None) self.info.set_input_summary(self.info.NoInput) self.variable = self.var_model[0] if self.data else None self.openContext(self.data) self.set_value_list() if self.variable and self.pending_value in self.variable.values: self.value = self.pending_value self.commit() def set_value_list(self): if self.variable is None: self.value_model.clear() self.value = "" else: self.value_model[:] = self.variable.values self.value = self.value_model[0] if self.variable.values else "" def _on_variable_changed(self): self.set_value_list() self.commit() def _on_value_changed(self): self.pending_value = self.value self.commit() def commit(self): if not (self.data and self.variable and self.value): annotated = matching = unmatched = None self.n_matched = None else: column = self.data.get_column_view(self.variable)[0] valind = self.variable.values.index(self.value) mask = column == valind annotated = create_annotated_table(self.data, np.flatnonzero(mask)) matching = self.data[mask] unmatched = self.data[~mask] self.n_matched = len(matching) self.Outputs.matching.send(matching) self.Outputs.unmatched.send(unmatched) self.Outputs.annotated.send(annotated) def send_report(self): if not self.data: return self.report_items( "", [("Filter", f"{self.variable.name} = '{self.value}'"), ("Matching instances", f"{self.n_matched} (out of {len(self.data)})")])