class RemoveSparseEditor(BaseEditor): def __init__(self, parent=None, **kwargs): super().__init__(parent, **kwargs) self.setLayout(QVBoxLayout()) self.sparse_thresh = 5 form = QFormLayout() self.cspin = QSpinBox(minimum=1, maximum=100, value=self.sparse_thresh) self.cspin.valueChanged[int].connect(self.setThresh) self.cspin.editingFinished.connect(self.edited) form.addRow("Min % of nonzero values:", self.cspin) self.layout().addLayout(form) def setThresh(self, thresh): if self.sparse_thresh != thresh: self.sparse_thresh = thresh self.cspin.setValue(thresh) self.changed.emit() def parameters(self): return {'sparse_thresh': self.sparse_thresh} def setParameters(self, params): self.setThresh(params.get('sparse_thresh', 5)) @staticmethod def createinstance(params): params = dict(params) threshold = params.pop('sparse_thresh', 5) return RemoveSparse(threshold=threshold / 100)
class PCA(BaseEditor): def __init__(self, parent=None, **kwargs): super().__init__(parent, **kwargs) self.setLayout(QVBoxLayout()) self.n_components = 10 form = QFormLayout() self.cspin = QSpinBox(minimum=1, value=self.n_components) self.cspin.valueChanged[int].connect(self.setC) self.cspin.editingFinished.connect(self.edited) form.addRow("Components:", self.cspin) self.layout().addLayout(form) def setParameters(self, params): self.n_components = params.get("n_components", 10) def parameters(self): return {"n_components": self.n_components} def setC(self, n_components): if self.n_components != n_components: self.n_components = n_components self.cspin.setValue(n_components) self.changed.emit() @staticmethod def createinstance(params): n_components = params.get("n_components", 10) return ProjectPCA(n_components=n_components) def __repr__(self): return "Components: {}".format(self.cspin.value())
class AbsoluteRelativeSpinBox(QWidget): editingFinished = pyqtSignal() valueChanged = pyqtSignal() def __init__(self, *args, **kwargs): super().__init__(*args) layout = QStackedLayout(self) self.double_spin = QDoubleSpinBox() self.double_spin.valueChanged.connect(self.double_value_changed) self.double_spin.editingFinished.connect(self.double_editing_finished) layout.addWidget(self.double_spin) self.int_spin = QSpinBox() self.int_spin.setMaximum(10**4) self.int_spin.valueChanged.connect(self.int_value_changed) self.int_spin.editingFinished.connect(self.int_editing_finished) layout.addWidget(self.int_spin) self.setValue(kwargs.get('value', 0.)) def double_value_changed(self): if self.double_spin.value() > 1: self.layout().setCurrentIndex(1) self.int_spin.setValue(self.double_spin.value()) self.valueChanged.emit() def double_editing_finished(self): if self.double_spin.value() <= 1.: self.editingFinished.emit() def int_value_changed(self): if self.int_spin.value() == 0: self.layout().setCurrentIndex(0) self.double_spin.setValue(1. - self.double_spin.singleStep()) # There is no need to emit valueChanged signal. def int_editing_finished(self): if self.int_spin.value() > 0: self.editingFinished.emit() def value(self): return self.int_spin.value() or self.double_spin.value() def setValue(self, value): if isinstance(value, int): self.layout().setCurrentIndex(1) self.int_spin.setValue(value) else: self.layout().setCurrentIndex(0) self.double_spin.setValue(value) def setSingleStep(self, step): if isinstance(step, float): self.double_spin.setSingleStep(step) else: self.int_spin.setSingleStep(step)
class AbsoluteRelativeSpinBox(QWidget): editingFinished = pyqtSignal() valueChanged = pyqtSignal() def __init__(self, *args, **kwargs): super().__init__(*args) layout = QStackedLayout(self) self.double_spin = QDoubleSpinBox() self.double_spin.valueChanged.connect(self.double_value_changed) self.double_spin.editingFinished.connect(self.double_editing_finished) layout.addWidget(self.double_spin) self.int_spin = QSpinBox() self.int_spin.setMaximum(10 ** 4) self.int_spin.valueChanged.connect(self.int_value_changed) self.int_spin.editingFinished.connect(self.int_editing_finished) layout.addWidget(self.int_spin) self.setValue(kwargs.get('value', 0.)) def double_value_changed(self): if self.double_spin.value() > 1: self.layout().setCurrentIndex(1) self.int_spin.setValue(self.double_spin.value()) self.valueChanged.emit() def double_editing_finished(self): if self.double_spin.value() <= 1.: self.editingFinished.emit() def int_value_changed(self): if self.int_spin.value() == 0: self.layout().setCurrentIndex(0) self.double_spin.setValue(1. - self.double_spin.singleStep()) # There is no need to emit valueChanged signal. def int_editing_finished(self): if self.int_spin.value() > 0: self.editingFinished.emit() def value(self): return self.int_spin.value() or self.double_spin.value() def setValue(self, value): if isinstance(value, int): self.layout().setCurrentIndex(1) self.int_spin.setValue(value) else: self.layout().setCurrentIndex(0) self.double_spin.setValue(value) def setSingleStep(self, step): if isinstance(step, float): self.double_spin.setSingleStep(step) else: self.int_spin.setSingleStep(step)
class CUR(BaseEditor): def __init__(self, parent=None, **kwargs): super().__init__(parent, **kwargs) self.setLayout(QVBoxLayout()) self.rank = 10 self.max_error = 1 form = QFormLayout() self.rspin = QSpinBox(minimum=2, maximum=1000000, value=self.rank) self.rspin.valueChanged[int].connect(self.setR) self.rspin.editingFinished.connect(self.edited) self.espin = QDoubleSpinBox(minimum=0.1, maximum=100.0, singleStep=0.1, value=self.max_error) self.espin.valueChanged[float].connect(self.setE) self.espin.editingFinished.connect(self.edited) form.addRow("Rank:", self.rspin) form.addRow("Relative error:", self.espin) self.layout().addLayout(form) def setParameters(self, params): self.setR(params.get("rank", 10)) self.setE(params.get("max_error", 1)) def parameters(self): return {"rank": self.rank, "max_error": self.max_error} def setR(self, rank): if self.rank != rank: self.rank = rank self.rspin.setValue(rank) self.changed.emit() def setE(self, max_error): if self.max_error != max_error: self.max_error = max_error self.espin.setValue(max_error) self.changed.emit() @staticmethod def createinstance(params): rank = params.get("rank", 10) max_error = params.get("max_error", 1) return ProjectCUR(rank=rank, max_error=max_error) def __repr__(self): return "Rank: {}, Relative error: {}".format(self.rspin.value(), self.espin.value())
class CUR(BaseEditor): def __init__(self, parent=None, **kwargs): super().__init__(parent, **kwargs) self.setLayout(QVBoxLayout()) self.rank = 10 self.max_error = 1 form = QFormLayout() self.rspin = QSpinBox(minimum=2, value=self.rank) self.rspin.valueChanged[int].connect(self.setR) self.rspin.editingFinished.connect(self.edited) self.espin = QDoubleSpinBox( minimum=0.1, maximum=100.0, singleStep=0.1, value=self.max_error) self.espin.valueChanged[float].connect(self.setE) self.espin.editingFinished.connect(self.edited) form.addRow("Rank:", self.rspin) form.addRow("Relative error:", self.espin) self.layout().addLayout(form) def setParameters(self, params): self.setR(params.get("rank", 10)) self.setE(params.get("max_error", 1)) def parameters(self): return {"rank": self.rank, "max_error": self.max_error} def setR(self, rank): if self.rank != rank: self.rank = rank self.rspin.setValue(rank) self.changed.emit() def setE(self, max_error): if self.max_error != max_error: self.max_error = max_error self.espin.setValue(max_error) self.changed.emit() @staticmethod def createinstance(params): rank = params.get("rank", 10) max_error = params.get("max_error", 1) return ProjectCUR(rank=rank, max_error=max_error) def __repr__(self): return "Rank: {}, Relative error: {}".format(self.rspin.value(), self.espin.value())
class DropoutEditor(ScBaseEditor): DEFAULT_N_GENES = 1000 def __init__(self, parent=None, **kwargs): super().__init__(parent, **kwargs) self.setLayout(QVBoxLayout()) self._n_genes = self.DEFAULT_N_GENES 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) 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 setParameters(self, params): self._set_n_genes(params.get("n_genes", self.DEFAULT_N_GENES)) def parameters(self): return {"n_genes": self._n_genes} @staticmethod def createinstance(params): n_genes = params.get("n_genes", DropoutEditor.DEFAULT_N_GENES) return DropoutGeneSelection(n_genes) def __repr__(self): return "Number of Genes: {}".format(self._n_genes)
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)
def _(spin: QSpinBox, value: int): spin.setValue(value)
class ControlBoundingSlider(ControlBase): def __init__(self, *args, **kwargs): self._horizontal = kwargs.get('horizontal', True) self._show_spinboxes = kwargs.get('show_spinboxes', True) ControlBase.__init__(self, *args, **kwargs) self.min = kwargs.get('min', kwargs.get('minimum', 0)) self.max = kwargs.get('max', kwargs.get('maximum', 100)) self.value = kwargs.get('default', [10,20]) self.__update() def init_form(self): self._boundingbox = GaugeWidgetHorizontal() if self._horizontal else GaugeWidgetVertical() self._boundingbox.changed_event = self.__update if self._show_spinboxes: self._form = hwidget = QWidget() if self._horizontal: hlayout = QHBoxLayout() else: hlayout = QVBoxLayout() if _api.USED_API == _api.QT_API_PYQT5: hlayout.setContentsMargins(0,0,0,0) elif _api.USED_API == _api.QT_API_PYQT4: hlayout.setMargin(0) hwidget.setLayout(hlayout) self._min_spinbox = QSpinBox() self._min_spinbox.valueChanged.connect(self.__min_spinbox_changed) self._min_spinbox.setMaximumWidth(95) self._max_spinbox = QSpinBox() self._max_spinbox.valueChanged.connect(self.__max_spinbox_changed) self._max_spinbox.setMaximumWidth(95) if self._horizontal: hlayout.addWidget(self._min_spinbox) else: hlayout.addWidget(self._max_spinbox) hlayout.addWidget(self._boundingbox) if self._horizontal: hlayout.addWidget(self._max_spinbox) else: hlayout.addWidget(self._min_spinbox) else: self._form = self._boundingbox super(ControlBoundingSlider, self).init_form() def __max_spinbox_changed(self, value): if value < self._boundingbox._minVal: return if hasattr(self, '_is_updating_spinboxes'): return self.scale = self.__find_scale_factor(value) self._boundingbox._maxVal = value self._boundingbox.repaint() self.changed_event() def __min_spinbox_changed(self, value): if value > self._boundingbox._maxVal: return if hasattr(self, '_is_updating_spinboxes'): return self.scale = self.__find_scale_factor(value) self._boundingbox._minVal = value self._boundingbox.repaint() self.changed_event() def __update(self): l, h = self._boundingbox._minVal, self._boundingbox._maxVal self._is_updating_spinboxes = True self._min_spinbox.setValue(l) self._max_spinbox.setValue(h) del self._is_updating_spinboxes self.changed_event() def changed_event(self): pass def __find_scale_factor(self, value): scale = 1.0 new_value = value while abs(new_value) < 0.0: scale *= 10.0 new_value = value * scale return scale def load_form(self, data, path=None): """ Load a value from the dict variable @param data: dictionary with the value of the Control """ self.convert_2_int = data.get('convert-int', self.convert_2_int) self.scale = data.get('scale', self.scale) self.max = data.get('max', self.max) self.min = data.get('min', self.min) self.value = data.get('value', self.value) def save_form(self, data, path=None): """ Save a value to dict variable @param data: dictionary with to where the value of the Control will be added """ data['value'] = self.value data['max'] = self.max data['min'] = self.min data['scale'] = self.scale data['convert-int'] = self.convert_2_int return data ########################################################################## ############ Properties ################################################## ########################################################################## @property def value(self): return self._boundingbox._minVal, self._boundingbox._maxVal @value.setter def value(self, value): self.scale = self.__find_scale_factor(value[0]) self._boundingbox._minVal, self._boundingbox._maxVal = value[0], value[1] if hasattr(self, '_min_spinbox'): self._min_spinbox.setValue(value[0]) if hasattr(self, '_max_spinbox'): self._max_spinbox.setValue(value[1]) ControlBase.value.fset(self, value) self._boundingbox.repaint() @property def min(self): return self._boundingbox._lower @min.setter def min(self, value): self._boundingbox._lower = value self._boundingbox.repaint() if hasattr(self, '_min_spinbox'): self._min_spinbox.setMinimum(value) if hasattr(self, '_max_spinbox'): self._max_spinbox.setMinimum(value) @property def max(self): return self._boundingbox._higher @max.setter def max(self, value): self._boundingbox._higher = value self._boundingbox.repaint() if hasattr(self, '_min_spinbox'): self._min_spinbox.setMaximum(value) if hasattr(self, '_max_spinbox'): self._max_spinbox.setMaximum(value) @property def scale(self): return self._boundingbox.scale @scale.setter def scale(self, value): self._boundingbox.scale = value @property def convert_2_int(self): return not self._boundingbox._use_float @convert_2_int.setter def convert_2_int(self, value): self._boundingbox._use_float = not value
class ControlBoundingSlider(ControlBase): def __init__(self, label="", default=[20, 40], min=0, max=100, horizontal=False, helptext=None, show_spinboxes=True): self._horizontal = horizontal self._show_spinboxes = show_spinboxes ControlBase.__init__(self, label, default, helptext=helptext) self.min = min self.max = max self.value = default self.__update() def init_form(self): self._boundingbox = GaugeWidgetHorizontal( ) if self._horizontal else GaugeWidgetVertical() self._boundingbox.changed_event = self.__update if self._show_spinboxes: self._form = hwidget = QWidget() if self._horizontal: hlayout = QHBoxLayout() else: hlayout = QVBoxLayout() if conf.PYFORMS_USE_QT5: hlayout.setContentsMargins(0, 0, 0, 0) else: hlayout.setMargin(0) hwidget.setLayout(hlayout) self._min_spinbox = QSpinBox() self._min_spinbox.valueChanged.connect(self.__min_spinbox_changed) self._min_spinbox.setMaximumWidth(95) self._max_spinbox = QSpinBox() self._max_spinbox.valueChanged.connect(self.__max_spinbox_changed) self._max_spinbox.setMaximumWidth(95) if self._horizontal: hlayout.addWidget(self._min_spinbox) else: hlayout.addWidget(self._max_spinbox) hlayout.addWidget(self._boundingbox) if self._horizontal: hlayout.addWidget(self._max_spinbox) else: hlayout.addWidget(self._min_spinbox) else: self._form = self._boundingbox super(ControlBoundingSlider, self).init_form() def __max_spinbox_changed(self, value): if value < self._boundingbox._minVal: return if hasattr(self, '_is_updating_spinboxes'): return self.scale = self.__find_scale_factor(value) self._boundingbox._maxVal = value self._boundingbox.repaint() self.changed_event() def __min_spinbox_changed(self, value): if value > self._boundingbox._maxVal: return if hasattr(self, '_is_updating_spinboxes'): return self.scale = self.__find_scale_factor(value) self._boundingbox._minVal = value self._boundingbox.repaint() self.changed_event() def __update(self): l, h = self._boundingbox._minVal, self._boundingbox._maxVal self._is_updating_spinboxes = True self._min_spinbox.setValue(l) self._max_spinbox.setValue(h) del self._is_updating_spinboxes self.changed_event() def changed_event(self): pass def __find_scale_factor(self, value): scale = 1.0 new_value = value while abs(new_value) < 0.0: scale *= 10.0 new_value = value * scale return scale ########################################################################## ############ Properties ################################################## ########################################################################## @property def value(self): return self._boundingbox._minVal, self._boundingbox._maxVal @value.setter def value(self, value): ControlBase.value.fset(self, value) self.scale = self.__find_scale_factor(value[0]) self._boundingbox._minVal, self._boundingbox._maxVal = value[0], value[ 1] if hasattr(self, '_min_spinbox'): self._min_spinbox.setValue(value[0]) if hasattr(self, '_max_spinbox'): self._max_spinbox.setValue(value[1]) self._boundingbox.repaint() @property def min(self): return self._boundingbox._lower @min.setter def min(self, value): self._boundingbox._lower = value self._boundingbox.repaint() if hasattr(self, '_min_spinbox'): self._min_spinbox.setMinimum(value) if hasattr(self, '_max_spinbox'): self._max_spinbox.setMinimum(value) @property def max(self): return self._boundingbox._higher @max.setter def max(self, value): self._boundingbox._higher = value self._boundingbox.repaint() if hasattr(self, '_min_spinbox'): self._min_spinbox.setMaximum(value) if hasattr(self, '_max_spinbox'): self._max_spinbox.setMaximum(value) @property def scale(self): return self._boundingbox.scale @scale.setter def scale(self, value): self._boundingbox.scale = value @property def convert_2_int(self): return not self._boundingbox._use_float @convert_2_int.setter def convert_2_int(self, value): self._boundingbox._use_float = not value
class FilteringModule(MultipleMethodModule): Stopwords, Lexicon, Regexp, DocFreq, DummyDocFreq, MostFreq = range(6) Methods = { Stopwords: StopwordsFilter, Lexicon: LexiconFilter, Regexp: RegexpFilter, DocFreq: FrequencyFilter, DummyDocFreq: FrequencyFilter, MostFreq: MostFrequentTokensFilter } DEFAULT_METHODS = [Stopwords] DEFAULT_LANG = "English" DEFAULT_NONE = None DEFAULT_PATTERN = "\.|,|:|;|!|\?|\(|\)|\||\+|\'|\"|‘|’|“|”|\'|" \ "\’|…|\-|–|—|\$|&|\*|>|<|\/|\[|\]" DEFAULT_FREQ_TYPE = 0 # 0 - relative freq, 1 - absolute freq DEFAULT_REL_START, DEFAULT_REL_END, REL_MIN, REL_MAX = 0.1, 0.9, 0, 1 DEFAULT_ABS_START, DEFAULT_ABS_END, ABS_MIN, ABS_MAX = 1, 10, 0, 10000 DEFAULT_N_TOKEN = 100 def __init__(self, parent=None, **kwargs): super().__init__(parent, **kwargs) self.__sw_lang = self.DEFAULT_LANG self.__sw_file = self.DEFAULT_NONE self.__lx_file = self.DEFAULT_NONE self.__pattern = self.DEFAULT_PATTERN self.__freq_type = self.DEFAULT_FREQ_TYPE self.__rel_freq_st = self.DEFAULT_REL_START self.__rel_freq_en = self.DEFAULT_REL_END self.__abs_freq_st = self.DEFAULT_ABS_START self.__abs_freq_en = self.DEFAULT_ABS_END self.__n_token = self.DEFAULT_N_TOKEN self.__invalidated = False self.__combo = ComboBox(self, [_DEFAULT_NONE] + StopwordsFilter.supported_languages(), self.__sw_lang, self.__set_language) self.__sw_loader = FileLoader() self.__sw_loader.set_file_list() self.__sw_loader.activated.connect(self.__sw_loader_activated) self.__sw_loader.file_loaded.connect(self.__sw_invalidate) self.__lx_loader = FileLoader() self.__lx_loader.set_file_list() self.__lx_loader.activated.connect(self.__lx_loader_activated) self.__lx_loader.file_loaded.connect(self.__lx_invalidate) validator = RegexpFilter.validate_regexp self.__edit = ValidatedLineEdit(self.__pattern, validator) self.__edit.editingFinished.connect(self.__edit_finished) rel_freq_rb = QRadioButton("相对:") abs_freq_rb = QRadioButton("绝对:") self.__freq_group = group = QButtonGroup(self, exclusive=True) group.addButton(rel_freq_rb, 0) group.addButton(abs_freq_rb, 1) group.buttonClicked.connect(self.__freq_group_clicked) group.button(self.__freq_type).setChecked(True) self.__rel_range_spins = RangeDoubleSpins(self.__rel_freq_st, 0.05, self.__rel_freq_en, self.REL_MIN, self.REL_MAX, self.__set_rel_freq_start, self.__set_rel_freq_end, self.__rel_spins_edited) self.__abs_range_spins = RangeSpins(self.__abs_freq_st, 1, self.__abs_freq_en, self.ABS_MIN, self.ABS_MAX, self.__set_abs_freq_start, self.__set_abs_freq_end, self.__abs_spins_edited) self.__spin_n = QSpinBox(minimum=1, maximum=10**6, value=self.__n_token) self.__spin_n.editingFinished.connect(self.__spin_n_edited) self.__spin_n.valueChanged.connect(self.changed) self.layout().addWidget(self.__combo, self.Stopwords, 1) self.layout().addWidget(self.__sw_loader.file_combo, self.Stopwords, 2, 1, 2) self.layout().addWidget(self.__sw_loader.browse_btn, self.Stopwords, 4) self.layout().addWidget(self.__sw_loader.load_btn, self.Stopwords, 5) self.layout().addWidget(self.__lx_loader.file_combo, self.Lexicon, 2, 1, 2) self.layout().addWidget(self.__lx_loader.browse_btn, self.Lexicon, 4) self.layout().addWidget(self.__lx_loader.load_btn, self.Lexicon, 5) self.layout().addWidget(self.__edit, self.Regexp, 1, 1, 5) spins = self.__rel_range_spins.spins() self.layout().addWidget(rel_freq_rb, self.DocFreq, 1) self.layout().addWidget(spins[0], self.DocFreq, 2) self.layout().addWidget(spins[1], self.DocFreq, 3) spins = self.__abs_range_spins.spins() self.layout().addWidget(abs_freq_rb, self.DummyDocFreq, 1) self.layout().addWidget(spins[0], self.DummyDocFreq, 2) self.layout().addWidget(spins[1], self.DummyDocFreq, 3) title = self.layout().itemAtPosition(self.DummyDocFreq, 0).widget() title.hide() self.layout().addWidget(self.__spin_n, self.MostFreq, 1) self.layout().setColumnStretch(3, 1) def __sw_loader_activated(self): self.__sw_file = self.__sw_loader.get_current_file() self.changed.emit() if self.Stopwords in self.methods: self.edited.emit() def __sw_invalidate(self): if self.Stopwords in self.methods and self.__sw_file: self.__invalidated = random.random() self.edited.emit() def __lx_loader_activated(self): self.__lx_file = self.__lx_loader.get_current_file() self.changed.emit() if self.Lexicon in self.methods: self.edited.emit() def __lx_invalidate(self): if self.Lexicon in self.methods and self.__lx_file: self.__invalidated = random.random() self.edited.emit() def __edit_finished(self): pattern = self.__edit.text() if self.__pattern != pattern: self.__set_pattern(pattern) if self.Regexp in self.methods: self.edited.emit() def __freq_group_clicked(self): i = self.__freq_group.checkedId() if self.__freq_type != i: self.__set_freq_type(i) if self.DocFreq in self.methods: self.edited.emit() def __rel_spins_edited(self): if self.DocFreq in self.methods and self.__freq_type == 0: self.edited.emit() def __abs_spins_edited(self): if self.DocFreq in self.methods and self.__freq_type == 1: self.edited.emit() def __spin_n_edited(self): n = self.__spin_n.value() if self.__n_token != n: self.__set_n_tokens(n) if self.MostFreq in self.methods: self.edited.emit() def setParameters(self, params: Dict): super().setParameters(params) self.__set_language(params.get("language", self.DEFAULT_LANG)) self.__set_sw_path(params.get("sw_path", self.DEFAULT_NONE), params.get("sw_list", [])) self.__set_lx_path(params.get("lx_path", self.DEFAULT_NONE), params.get("lx_list", [])) self.__set_pattern(params.get("pattern", self.DEFAULT_PATTERN)) self.__set_freq_type(params.get("freq_type", self.DEFAULT_FREQ_TYPE)) self.__set_rel_freq_range( params.get("rel_start", self.DEFAULT_REL_START), params.get("rel_end", self.DEFAULT_REL_END)) self.__set_abs_freq_range( params.get("abs_start", self.DEFAULT_ABS_START), params.get("abs_end", self.DEFAULT_ABS_END)) self.__set_n_tokens(params.get("n_tokens", self.DEFAULT_N_TOKEN)) self.__invalidated = False def __set_language(self, language: str): if self.__sw_lang != language: self.__sw_lang = language self.__combo.setCurrentText(language) self.changed.emit() if self.Stopwords in self.methods: self.edited.emit() def __set_sw_path(self, path: RecentPath, paths: List[RecentPath] = []): self.__sw_loader.recent_paths = paths self.__sw_loader.set_file_list() self.__sw_loader.set_current_file(_to_abspath(path)) self.__sw_file = self.__sw_loader.get_current_file() def __set_lx_path(self, path: RecentPath, paths: List[RecentPath] = []): self.__lx_loader.recent_paths = paths self.__lx_loader.set_file_list() self.__lx_loader.set_current_file(_to_abspath(path)) self.__lx_file = self.__lx_loader.get_current_file() def __set_pattern(self, pattern: str): if self.__pattern != pattern: self.__pattern = pattern self.__edit.setText(pattern) self.changed.emit() def __set_freq_type(self, freq_type: int): if self.__freq_type != freq_type: self.__freq_type = freq_type self.__freq_group.button(self.__freq_type).setChecked(True) self.changed.emit() def __set_rel_freq_range(self, start: float, end: float): self.__set_rel_freq_start(start) self.__set_rel_freq_end(end) self.__rel_range_spins.set_range(start, end) def __set_rel_freq_start(self, n: float): if self.__rel_freq_st != n: self.__rel_freq_st = n self.changed.emit() def __set_rel_freq_end(self, n: float): if self.__rel_freq_en != n: self.__rel_freq_en = n self.changed.emit() def __set_abs_freq_range(self, start: int, end: int): self.__set_abs_freq_start(start) self.__set_abs_freq_end(end) self.__abs_range_spins.set_range(start, end) def __set_abs_freq_start(self, n: int): if self.__abs_freq_st != n: self.__abs_freq_st = n self.changed.emit() def __set_abs_freq_end(self, n: int): if self.__abs_freq_en != n: self.__abs_freq_en = n self.changed.emit() def __set_n_tokens(self, n: int): if self.__n_token != n: self.__n_token = n self.__spin_n.setValue(n) self.changed.emit() def parameters(self) -> Dict: params = super().parameters() params.update({ "language": self.__sw_lang, "sw_path": self.__sw_file, "sw_list": self.__sw_loader.recent_paths, "lx_path": self.__lx_file, "lx_list": self.__lx_loader.recent_paths, "pattern": self.__pattern, "freq_type": self.__freq_type, "rel_start": self.__rel_freq_st, "rel_end": self.__rel_freq_en, "abs_start": self.__abs_freq_st, "abs_end": self.__abs_freq_en, "n_tokens": self.__n_token, "invalidated": self.__invalidated }) return params @staticmethod def createinstance(params: Dict) -> List[BaseTokenFilter]: def map_none(s): return "" if s == _DEFAULT_NONE else s methods = params.get("methods", FilteringModule.DEFAULT_METHODS) filters = [] if FilteringModule.Stopwords in methods: lang = params.get("language", FilteringModule.DEFAULT_LANG) path = params.get("sw_path", FilteringModule.DEFAULT_NONE) filters.append( StopwordsFilter(language=map_none(lang), path=_to_abspath(path))) if FilteringModule.Lexicon in methods: path = params.get("lx_path", FilteringModule.DEFAULT_NONE) filters.append(LexiconFilter(path=_to_abspath(path))) if FilteringModule.Regexp in methods: pattern = params.get("pattern", FilteringModule.DEFAULT_PATTERN) filters.append(RegexpFilter(pattern=pattern)) if FilteringModule.DocFreq in methods: if params.get("freq_type", FilteringModule.DEFAULT_FREQ_TYPE) == 0: st = params.get("rel_start", FilteringModule.DEFAULT_REL_START) end = params.get("rel_end", FilteringModule.DEFAULT_REL_END) else: st = params.get("abs_start", FilteringModule.DEFAULT_ABS_START) end = params.get("abs_end", FilteringModule.DEFAULT_ABS_END) filters.append(FrequencyFilter(min_df=st, max_df=end)) if FilteringModule.MostFreq in methods: n = params.get("n_tokens", FilteringModule.DEFAULT_N_TOKEN) filters.append(MostFrequentTokensFilter(keep_n=n)) return filters def __repr__(self): texts = [] for method in self.methods: if method == self.Stopwords: append = f"Language: {self.__sw_lang}, " \ f"File: {_to_abspath(self.__sw_file)}" elif method == self.Lexicon: append = f"File: {_to_abspath(self.__lx_file)}" elif method == self.Regexp: append = f"{self.__pattern}" elif method == self.DocFreq: if self.__freq_type == 0: append = f"[{self.__rel_freq_st}, {self.__rel_freq_en}]" else: append = f"[{self.__abs_freq_st}, {self.__abs_freq_en}]" elif method == self.MostFreq: append = f"{self.__n_token}" texts.append(f"{self.Methods[method].name} ({append})") return ", ".join(texts)
class ControlBoundingSlider(ControlBase): """ .. image:: https://raw.githubusercontent.com/UmSenhorQualquer/pyforms/master/tutorials/Controls4Docs/ControlBoundingSlider.png """ def __init__(self, *args, **kwargs): """ :param tupple default: The default value is a list containing in the first element the lower value and in the second element the upper value. Default = [20,40]. :param bool horizontal: Flag indicating if the Bounding slider should be draw horizontally or vertically. Default = True. :param bool show_spinboxes: Show or hide the spinboxes. Default = True :param float minimum: Defines the minimum value that can be selected. :param float maximum: Defines the maximum value that can be selected. :param bool convert_2_int: Flag to define if the control should return floats or integers. """ self._horizontal = kwargs.get('horizontal', True) self._show_spinboxes = kwargs.get('show_spinboxes', True) ControlBase.__init__(self, *args, **kwargs) self.min = kwargs.get('min', kwargs.get('minimum', 0)) self.max = kwargs.get('max', kwargs.get('maximum', 100)) self.value = kwargs.get('default', [10,20]) self.convert_2_int = kwargs.get('convert_2_int', False) self.__update() def init_form(self): self._boundingbox = GaugeWidgetHorizontal() if self._horizontal else GaugeWidgetVertical() self._boundingbox.changed_event = self.__update if self._show_spinboxes: self._form = hwidget = QWidget() if self._horizontal: hlayout = QHBoxLayout() else: hlayout = QVBoxLayout() if _api.USED_API == _api.QT_API_PYQT5: hlayout.setContentsMargins(0,0,0,0) elif _api.USED_API == _api.QT_API_PYQT4: hlayout.setMargin(0) if self._label is not None: self._controllabel = QLabel(self.form) hlayout.addWidget(self._controllabel) self._controllabel.setAccessibleName('ControlBoundingSlider-label') self.label = self._label else: self._controllabel = None hwidget.setLayout(hlayout) self._min_spinbox = QSpinBox() self._min_spinbox.valueChanged.connect(self.__min_spinbox_changed) self._min_spinbox.setMaximumWidth(95) self._max_spinbox = QSpinBox() self._max_spinbox.valueChanged.connect(self.__max_spinbox_changed) self._max_spinbox.setMaximumWidth(95) if self._horizontal: hlayout.addWidget(self._min_spinbox) else: hlayout.addWidget(self._max_spinbox) hlayout.addWidget(self._boundingbox) if self._horizontal: hlayout.addWidget(self._max_spinbox) else: hlayout.addWidget(self._min_spinbox) else: self._form = self._boundingbox super(ControlBoundingSlider, self).init_form() def __max_spinbox_changed(self, value): if value < self._boundingbox._minVal: return if hasattr(self, '_is_updating_spinboxes'): return self.scale = self.__find_scale_factor(value) self._boundingbox._maxVal = value self._boundingbox.repaint() self.changed_event() def __min_spinbox_changed(self, value): if value > self._boundingbox._maxVal: return if hasattr(self, '_is_updating_spinboxes'): return self.scale = self.__find_scale_factor(value) self._boundingbox._minVal = value self._boundingbox.repaint() self.changed_event() def __update(self): l, h = self._boundingbox._minVal, self._boundingbox._maxVal self._is_updating_spinboxes = True if self._show_spinboxes: self._min_spinbox.setValue(l) self._max_spinbox.setValue(h) del self._is_updating_spinboxes self.changed_event() def changed_event(self): pass def __find_scale_factor(self, value): scale = 1.0 new_value = value while abs(new_value) < 0.0: scale *= 10.0 new_value = value * scale return scale def load_form(self, data, path=None): """ Load a value from the dict variable @param data: dictionary with the value of the Control """ self.convert_2_int = data.get('convert-int', self.convert_2_int) self.scale = data.get('scale', self.scale) self.max = data.get('max', self.max) self.min = data.get('min', self.min) self.value = data.get('value', self.value) def save_form(self, data, path=None): """ Save a value to dict variable @param data: dictionary with to where the value of the Control will be added """ data['value'] = self.value data['max'] = self.max data['min'] = self.min data['scale'] = self.scale data['convert-int'] = self.convert_2_int return data ########################################################################## ############ Properties ################################################## ########################################################################## @property def label(self): return self._controllabel.getText() @label.setter def label(self, value): self._controllabel.setText(value) @property def value(self): """ Sets and gets the control value. It should be a list or tuple of 2 values. """ return self._boundingbox._minVal, self._boundingbox._maxVal @value.setter def value(self, value): self.scale = self.__find_scale_factor(value[0]) self._boundingbox._minVal, self._boundingbox._maxVal = value[0], value[1] if hasattr(self, '_min_spinbox'): self._min_spinbox.setValue(value[0]) if hasattr(self, '_max_spinbox'): self._max_spinbox.setValue(value[1]) ControlBase.value.fset(self, value) self._boundingbox.repaint() @property def min(self): """ Sets and gets the minimum value possible. """ return self._boundingbox._lower @min.setter def min(self, value): self._boundingbox._lower = value self._boundingbox.repaint() if hasattr(self, '_min_spinbox'): self._min_spinbox.setMinimum(value) if hasattr(self, '_max_spinbox'): self._max_spinbox.setMinimum(value) @property def max(self): """ Sets and gets the maximum value possible. """ return self._boundingbox._higher @max.setter def max(self, value): self._boundingbox._higher = value self._boundingbox.repaint() if hasattr(self, '_min_spinbox'): self._min_spinbox.setMaximum(value) if hasattr(self, '_max_spinbox'): self._max_spinbox.setMaximum(value) @property def scale(self): """ Sets and gets the scale value. """ return self._boundingbox.scale @scale.setter def scale(self, value): self._boundingbox.scale = value @property def convert_2_int(self): """ Flag to define if the control should return floats or integers. """ return not self._boundingbox._use_float @convert_2_int.setter def convert_2_int(self, value): self._boundingbox._use_float = not value
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 StandardizeEditor(ScBaseEditor): DEFAULT_LOWER_CLIP = False DEFAULT_UPPER_CLIP = False DEFAULT_LOWER_BOUND = -10 DEFAULT_UPPER_BOUND = 10 def __init__(self, parent=None, **kwargs): super().__init__(parent, **kwargs) self._lower_bound = self.DEFAULT_LOWER_BOUND self._upper_bound = self.DEFAULT_UPPER_BOUND self.setLayout(QVBoxLayout()) box = QGroupBox(title="Clipping", flat=True) form = QFormLayout() self.lower_check = QCheckBox("Lower Bound: ") self.lower_check.clicked.connect(self.edited) self.lower_spin = QSpinBox(minimum=-99, maximum=0, value=self._lower_bound) self.lower_spin.valueChanged[int].connect(self._set_lower_bound) self.lower_spin.editingFinished.connect(self.edited) self.upper_check = QCheckBox("Upper Bound: ") self.upper_check.clicked.connect(self.edited) self.upper_spin = QSpinBox(value=self._upper_bound) self.upper_spin.valueChanged[int].connect(self._set_upper_bound) self.upper_spin.editingFinished.connect(self.edited) form.addRow(self.lower_check, self.lower_spin) form.addRow(self.upper_check, self.upper_spin) box.setLayout(form) self.layout().addWidget(box) def _set_lower_bound(self, x): if self._lower_bound != x: self._lower_bound = x self.lower_spin.setValue(x) self.changed.emit() def _set_upper_bound(self, x): if self._upper_bound != x: self._upper_bound = x self.upper_spin.setValue(x) self.changed.emit() def setParameters(self, params): lower_clip = params.get("lower_clip", self.DEFAULT_LOWER_CLIP) self.lower_check.setChecked(lower_clip) self._set_lower_bound(params.get("lower", self.DEFAULT_LOWER_BOUND)) upper_clip = params.get("upper_clip", self.DEFAULT_UPPER_CLIP) self.upper_check.setChecked(upper_clip) self._set_upper_bound(params.get("upper", self.DEFAULT_UPPER_BOUND)) def parameters(self): return { "lower_clip": self.lower_check.isChecked(), "lower": self._lower_bound, "upper_clip": self.upper_check.isChecked(), "upper": self._upper_bound } @staticmethod def createinstance(params): lower, upper = None, None if params.get("lower_clip", StandardizeEditor.DEFAULT_LOWER_CLIP): lower = params.get("lower", StandardizeEditor.DEFAULT_LOWER_BOUND) if params.get("upper_clip", StandardizeEditor.DEFAULT_UPPER_CLIP): upper = params.get("upper", StandardizeEditor.DEFAULT_UPPER_BOUND) return Standardize(lower, upper) def __repr__(self): clips = [] if self.lower_check.isChecked(): clips.append("Lower Bound: {}".format(self.lower_spin.value())) if self.upper_check.isChecked(): clips.append("Upper Bound: {}".format(self.upper_spin.value())) return ", ".join(clips) if clips else "No Clipping"