class RadioBooleanFilter(QWidget, Control): """ Boolean filter (Only/Exclude) """ def __init__(self, tree, dataset, master, parent=None): QWidget.__init__(self, parent) Control.__init__(self, tree, dataset, master) self.setLayout(QVBoxLayout()) self.buttonGroup = QButtonGroup(self) self.values = [] for i, option in enumerate(tree.subelements_top("Option")): rb = QRadioButton(option.displayName, self) self.buttonGroup.addButton(rb) self.buttonGroup.setId(rb, i) self.layout().addWidget(rb) self.values.append(option.value) self.buttonGroup.button(0).setChecked(True) def value(self): return {"excluded": "%i" % self.buttonGroup.checkedId()} def get_filter(self): return self.tree.internalName, self.value() def query(self): return [("Filter", self.tree, self.value())] def setControlValue(self, name, value): for i, v in enumerate(self.values): if v == value: button = self.buttonGroup.button(i) button.setChecked(True) break
class SingleMethodModule(PreprocessorModule): Methods = NotImplemented DEFAULT_METHOD = NotImplemented def __init__(self, parent=None, **kwargs): super().__init__(parent, **kwargs) self.__method = self.DEFAULT_METHOD self.setLayout(QGridLayout()) self.__group = QButtonGroup(self, exclusive=True) self.__group.buttonClicked.connect(self.__method_rb_clicked) for method_id in range(len(self.Methods)): method = self.Methods[method_id] rb = QRadioButton(method.name) rb.setChecked(self.__method == method_id) rb.setToolTip(self.get_tooltip(method)) self.__group.addButton(rb, method_id) self.layout().addWidget(rb) @property def method(self) -> int: return self.__method def setParameters(self, params: Dict): self._set_method(params.get("method", self.DEFAULT_METHOD)) def _set_method(self, method: int): if self.__method != method: self.__method = method self.__group.button(method).setChecked(True) self.changed.emit() def __method_rb_clicked(self): self._set_method(self.__group.checkedId()) self.edited.emit() def parameters(self) -> Dict: return {"method": self.__method} def __repr__(self): return self.Methods[self.__method].name
class SingleMethodModule(PreprocessorModule): method_index = settings.Setting(0) initialize_methods = True def setup_method_layout(self): self.group = QButtonGroup(self, exclusive=True) if self.initialize_methods: self.methods = [method() for method in self.methods] for i, method in enumerate(self.methods): rb = QRadioButton(self, text=self.textify(method.name)) rb.setChecked(i == self.method_index) rb.setToolTip(self.get_tooltip(method)) self.group.addButton(rb, i) self.method_layout.addWidget(rb, i, 0) self.group.buttonClicked.connect(self.update_value) def get_value(self): self.method_index = self.group.checkedId() return self.methods[self.method_index]
class RemoveSparseEditor(BaseEditor): options = ["missing", "zeros"] def __init__(self, parent=None, **kwargs): super().__init__(parent, **kwargs) self.fixedThresh = 50 self.percThresh = 5 self.useFixedThreshold = False self.filter0 = True self.setLayout(QVBoxLayout()) self.layout().addWidget(QLabel("Remove features with too many")) options = ["missing values", "zeros"] self.filter_buttons = QButtonGroup(exclusive=True) self.filter_buttons.buttonClicked.connect(self.filterByClicked) for idx, option, in enumerate(options): btn = QRadioButton(self, text=option, checked=idx == 0) self.filter_buttons.addButton(btn, id=idx) self.layout().addWidget(btn) self.layout().addSpacing(20) filter_settings = QGroupBox(title='Threshold:', flat=True) filter_settings.setLayout(QFormLayout()) self.settings_buttons = QButtonGroup(exclusive=True) self.settings_buttons.buttonClicked.connect(self.filterSettingsClicked) btn_perc = QRadioButton(self, text='Percentage', checked=not self.useFixedThreshold) self.settings_buttons.addButton(btn_perc, id=0) self.percSpin = QSpinBox(minimum=0, maximum=100, value=self.percThresh, enabled=not self.useFixedThreshold) self.percSpin.valueChanged[int].connect(self.setPercThresh) self.percSpin.editingFinished.connect(self.edited) btn_fix = QRadioButton(self, text='Fixed', checked=self.useFixedThreshold) self.settings_buttons.addButton(btn_fix, id=1) self.fixedSpin = QSpinBox(minimum=0, maximum=1000000, value=self.fixedThresh, enabled=self.useFixedThreshold) self.fixedSpin.valueChanged[int].connect(self.setFixedThresh) self.fixedSpin.editingFinished.connect(self.edited) filter_settings.layout().addRow(btn_fix, self.fixedSpin) filter_settings.layout().addRow(btn_perc, self.percSpin) self.layout().addWidget(filter_settings) def filterSettingsClicked(self): self.setUseFixedThreshold(self.settings_buttons.checkedId()) self.percSpin.setEnabled(not self.useFixedThreshold) self.fixedSpin.setEnabled(self.useFixedThreshold) self.edited.emit() def filterByClicked(self): self.setFilter0(self.filter_buttons.checkedId()) def setFilter0(self, id_): if self.filter0 != id_: self.filter0 = id_ self.edited.emit() def setFixedThresh(self, thresh): if self.fixedThresh != thresh: self.fixedThresh = thresh self.fixedSpin.setValue(thresh) self.edited.emit() def setPercThresh(self, thresh): if self.percThresh != thresh: self.percThresh = thresh self.percSpin.setValue(thresh) self.edited.emit() def setUseFixedThreshold(self, val): if self.useFixedThreshold != val: self.useFixedThreshold = val self.edited.emit() def parameters(self): return { 'fixedThresh': self.fixedThresh, 'percThresh': self.percThresh, 'useFixedThreshold': self.useFixedThreshold, 'filter0': self.filter0 } def setParameters(self, params): self.setPercThresh(params.get('percThresh', 5)) self.setFixedThresh(params.get('fixedThresh', 50)) self.setUseFixedThreshold(params.get('useFixedThreshold', False)) self.setFilter0(params.get('filter0', True)) @staticmethod def createinstance(params): params = dict(params) filter0 = params.pop('filter0', True) useFixedThreshold = params.pop('useFixedThreshold', True) if useFixedThreshold: threshold = params.pop('fixedThresh', 50) else: threshold = params.pop('percThresh', 5) / 100 return RemoveSparse(threshold, filter0)
class SelectGenesEditor(ScBaseEditor): DEFAULT_N_GENS = 1000 DEFAULT_METHOD = SelectMostVariableGenes.Dispersion DEFAULT_COMPUTE_STATS = True DEFAULT_N_GROUPS = 20 def __init__(self, parent=None, **kwargs): super().__init__(parent, **kwargs) self.setLayout(QVBoxLayout()) self._n_genes = self.DEFAULT_N_GENS self._n_groups = self.DEFAULT_N_GROUPS form = QFormLayout() self.n_genes_spin = QSpinBox(minimum=1, maximum=10**6, value=self._n_genes) self.n_genes_spin.valueChanged[int].connect(self._set_n_genes) self.n_genes_spin.editingFinished.connect(self.edited) form.addRow("Number of genes:", self.n_genes_spin) self.layout().addLayout(form) disp_b = QRadioButton("Dispersion", checked=True) vari_b = QRadioButton("Variance") mean_b = QRadioButton("Mean") self.group = QButtonGroup() self.group.buttonClicked.connect(self._on_button_clicked) for i, button in enumerate([disp_b, vari_b, mean_b]): index = index_to_enum(SelectMostVariableGenes.Method, i).value self.group.addButton(button, index - 1) form.addRow(button) self.stats_check = QCheckBox("Compute statistics for", checked=self.DEFAULT_COMPUTE_STATS) self.stats_check.clicked.connect(self.edited) self.n_groups_spin = QSpinBox(minimum=1, value=self._n_groups) self.n_groups_spin.valueChanged[int].connect(self._set_n_groups) self.n_groups_spin.editingFinished.connect(self.edited) box = QHBoxLayout() box.addWidget(self.stats_check) box.addWidget(self.n_groups_spin) box.addWidget(QLabel("gene groups.")) box.addStretch() self.layout().addLayout(box) def _set_n_genes(self, n): if self._n_genes != n: self._n_genes = n self.n_genes_spin.setValue(n) self.changed.emit() def _set_n_groups(self, n): if self._n_groups != n: self._n_groups = n self.n_groups_spin.setValue(n) self.changed.emit() def _on_button_clicked(self): self.changed.emit() self.edited.emit() def setParameters(self, params): self._set_n_genes(params.get("n_genes", self.DEFAULT_N_GENS)) method = params.get("method", self.DEFAULT_METHOD) index = enum_to_index(SelectMostVariableGenes.Method, method) self.group.buttons()[index].setChecked(True) compute_stats = params.get("compute_stats", self.DEFAULT_COMPUTE_STATS) self.stats_check.setChecked(compute_stats) self._set_n_groups(params.get("n_groups", self.DEFAULT_N_GROUPS)) def parameters(self): method = index_to_enum(SelectMostVariableGenes.Method, self.group.checkedId()) return { "n_genes": self._n_genes, "method": method, "compute_stats": self.stats_check.isChecked(), "n_groups": self._n_groups } @staticmethod def createinstance(params): method = params.get("method", SelectGenesEditor.DEFAULT_METHOD) n_genes = params.get("n_genes", SelectGenesEditor.DEFAULT_N_GENS) compute_stats = params.get("compute_stats", SelectGenesEditor.DEFAULT_COMPUTE_STATS) n_groups = params.get("n_groups", SelectGenesEditor.DEFAULT_N_GROUPS) \ if compute_stats else None return SelectMostVariableGenes(method, n_genes, n_groups) def __repr__(self): method = self.group.button(self.group.checkedId()).text() text = "Method: {}, Number of Genes: {}".format(method, self._n_genes) if self.stats_check.isChecked(): text += ", Number of Groups: {}".format(self._n_groups) return text
class NormalizeEditor(ScBaseEditor): DEFAULT_GROUP_BY = False DEFAULT_GROUP_VAR = None DEFAULT_METHOD = Normalize.CPM def __init__(self, parent=None, master=None, **kwargs): super().__init__(parent, **kwargs) self._group_var = self.DEFAULT_GROUP_VAR self._master = master self._master.input_data_changed.connect(self._set_model) self.setLayout(QVBoxLayout()) form = QFormLayout() cpm_b = QRadioButton("Counts per million", checked=True) med_b = QRadioButton("Median") self.group = QButtonGroup() self.group.buttonClicked.connect(self._on_button_clicked) for i, button in enumerate([cpm_b, med_b]): index = index_to_enum(Normalize.Method, i).value self.group.addButton(button, index - 1) form.addRow(button) self.group_by_check = QCheckBox("Cell Groups: ", enabled=self.DEFAULT_GROUP_BY) self.group_by_check.clicked.connect(self.edited) self.group_by_combo = QComboBox(enabled=self.DEFAULT_GROUP_BY) self.group_by_model = DomainModel(order=(DomainModel.METAS, DomainModel.CLASSES), valid_types=DiscreteVariable, alphabetical=True) self.group_by_combo.setModel(self.group_by_model) self.group_by_combo.currentIndexChanged.connect(self.changed) self.group_by_combo.activated.connect(self.edited) form.addRow(self.group_by_check, self.group_by_combo) self.layout().addLayout(form) self._set_model() def _set_model(self): data = self._master.data self.group_by_model.set_domain(data and data.domain) enable = bool(self.group_by_model) self.group_by_check.setChecked(False) self.group_by_check.setEnabled(enable) self.group_by_combo.setEnabled(enable) if self.group_by_model: self.group_by_combo.setCurrentIndex(0) if self._group_var and self._group_var in data.domain: index = self.group_by_model.indexOf(self._group_var) self.group_by_combo.setCurrentIndex(index) else: self.group_by_combo.setCurrentText(None) def _on_button_clicked(self): self.changed.emit() self.edited.emit() def setParameters(self, params): method = params.get("method", self.DEFAULT_METHOD) index = enum_to_index(Normalize.Method, method) self.group.buttons()[index].setChecked(True) self._group_var = params.get("group_var", self.DEFAULT_GROUP_VAR) group = bool(self._group_var and self.group_by_model) if group: index = self.group_by_model.indexOf(self._group_var) self.group_by_combo.setCurrentIndex(index) group_by = params.get("group_by", self.DEFAULT_GROUP_BY) self.group_by_check.setChecked(group_by and group) def parameters(self): index = self.group_by_combo.currentIndex() group_var = self.group_by_model[index] if index > -1 else None group_by = self.group_by_check.isChecked() method = index_to_enum(Normalize.Method, self.group.checkedId()) return {"group_var": group_var, "group_by": group_by, "method": method} @staticmethod def createinstance(params): group_var = params.get("group_var") group_by = params.get("group_by", NormalizeEditor.DEFAULT_GROUP_BY) method = params.get("method", NormalizeEditor.DEFAULT_METHOD) return NormalizeGroups(group_var, method) \ if group_by and group_var else NormalizeSamples(method) def __repr__(self): method = self.group.button(self.group.checkedId()).text() index = self.group_by_combo.currentIndex() group_var = self.group_by_model[index] if index > -1 else None group_by = self.group_by_check.isChecked() group_text = ", Grouped by: {}".format(group_var) if group_by else "" return "Method: {}".format(method) + group_text