Пример #1
0
 def _set_annotation_files(self):
     dir_name, _ = os.path.split(self._file_name)
     genes_path = os.path.join(dir_name, "genes.tsv")
     if os.path.isfile(genes_path):
         self.col_annotation_file = RecentPath.create(genes_path, [])
     barcodes_path = os.path.join(dir_name, "barcodes.tsv")
     if os.path.isfile(barcodes_path):
         self.row_annotation_file = RecentPath.create(barcodes_path, [])
    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.create(path, self._search_paths())
            self.recent_paths.insert(0, item)
            model.insertRow(0, RecentPath_asqstandarditem(item))
        return 0
Пример #3
0
    def set_current_path(self, path):
        if samepath(self._current_path, path):
            return

        model = self.recent_model
        index = -1
        pathitem = None
        for i in range(model.rowCount()):
            item = model.item(i)
            data = item.data(Qt.UserRole) if item is not None else None
            if isinstance(data, RecentPath) and samepath(path, data.abspath):
                index, pathitem = i, data
                break

        rpaths = []

        if pathitem is None:
            assert index == -1
            pathitem = RecentPath.create(path, rpaths)

        if index != -1:
            item = model.takeRow(index)
        else:
            item = RecentPath_asqstandarditem(pathitem)

        model.insertRow(0, item)
        self._current_path = path
        self.recent_combo.setCurrentIndex(0)

        self._data_loader = get_data_loader(path)
        self._update_summary()
        self.setup_gui()
        self._invalidate()
Пример #4
0
 def add_path(self, filename, reader):
     """Add (or move) a file name to the top of recent paths"""
     self._check_init()
     recent = RecentPath.create(filename, self._search_paths())
     if reader is not None:
         recent.file_format = reader.qualified_name()
     self.recent_paths.append(recent)
Пример #5
0
    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.create(path, self._search_paths())
            self.recent_paths.insert(0, item)
            model.insertRow(0, RecentPath_asqstandarditem(item))
        return 0
 def _relocate_recent_files(self):
     search_paths = self._search_paths()
     rec = []
     for recent in self.recent_paths:
         kwargs = dict(
             title=recent.title, sheet=recent.sheet,
             file_format=recent.file_format)
         resolved = recent.resolve(search_paths)
         if resolved is not None:
             rec.append(
                 RecentPath.create(resolved.abspath, search_paths, **kwargs))
         else:
             rec.append(recent)
     # change the list in-place for the case the widgets wraps this list
     self.recent_paths[:] = rec
Пример #7
0
    def browse_col_annotations(self):
        dlg = QFileDialog(self,
                          acceptMode=QFileDialog.AcceptOpen,
                          fileMode=QFileDialog.ExistingFile)
        filters = AnnotationFormats
        dlg.setNameFilters(filters)

        if filters:
            dlg.selectNameFilter(filters[0])
        if dlg.exec_() == QFileDialog.Accepted:
            filename = dlg.selectedFiles()[0]
            m = self.col_annotations_combo.model()  # type: QStandardItemModel
            pathitem = RecentPath.create(filename, [])
            index = insert_recent_path(m, pathitem)
            self.col_annotations_combo.setCurrentIndex(index)
            self._invalidate()
Пример #8
0
 def _relocate_recent_files(self):
     search_paths = self._search_paths()
     rec = []
     for recent in self.recent_paths:
         kwargs = dict(title=recent.title,
                       sheet=recent.sheet,
                       file_format=recent.file_format)
         resolved = recent.resolve(search_paths)
         if resolved is not None:
             rec.append(
                 RecentPath.create(resolved.abspath, search_paths,
                                   **kwargs))
         else:
             rec.append(recent)
     # change the list in-place for the case the widgets wraps this list
     self.recent_paths[:] = rec
Пример #9
0
    def set_current_path(self, path):
        if samepath(self._current_path, path):
            return

        model = self.recent_model
        index = -1
        pathitem = None
        for i in range(model.rowCount()):
            item = model.item(i)
            data = item.data(Qt.UserRole) if item is not None else None
            if isinstance(data, RecentPath) and samepath(path, data.abspath):
                index, pathitem = i, data
                break

        rpaths = []

        if pathitem is None:
            assert index == -1
            pathitem = RecentPath.create(path, rpaths)

        if index != -1:
            item = model.takeRow(index)
        else:
            item = RecentPath_asqstandarditem(pathitem)
        # TODO: Restore or guess load options

        if path.endswith(".count"):
            self.set_header_rows_count(1)
            self.set_header_cols_count(1)
            enabled = False
        else:
            enabled = True

        self.header_rows_spin.setEnabled(enabled)
        self.header_cols_spin.setEnabled(enabled)

        model.insertRow(0, item)
        self._current_path = path
        self.recent_combo.setCurrentIndex(0)
        self._update_summary()
        self._invalidate()
Пример #10
0
    def __init__(self, file_name=""):
        # file parameters
        self._file_name = file_name
        self._recent_path = RecentPath.create(file_name, [])
        self.file_size = None
        self.n_rows = None
        self.n_cols = None
        self.sparsity = None
        self._set_file_size()
        self._set_file_parameters()

        # reading parameters
        self._leading_cols = 0
        self._leading_rows = 0
        self._use_rows_mask = None
        self._use_cols_mask = None
        self._row_annot_header = 0
        self._row_annot_columns = None
        self._col_annot_header = 0
        self._col_annot_columns = None

        # GUI parameters
        self.FIXED_FORMAT = True
        self.ENABLE_ANNOTATIONS = True
        self.header_rows_count = None
        self.header_cols_count = None
        self.transposed = None
        self.sample_rows_enabled = None
        self.sample_cols_enabled = None
        self.sample_rows_p = None
        self.sample_cols_p = None
        self.row_annotations_enabled = True
        self.row_annotation_file = None  # type: RecentPath
        self.col_annotations_enabled = True
        self.col_annotation_file = None  # type: RecentPath

        # errors
        self.errors = {}  # type: Dict[str, Tuple]
        self.__reset_error_messages()
Пример #11
0
    def set_current_path(self, path):
        if samepath(self._current_path, path):
            return

        model = self.recent_model
        index = -1
        pathitem = None
        for i in range(model.rowCount()):
            item = model.item(i)
            data = item.data(Qt.UserRole) if item is not None else None
            if isinstance(data, RecentPath) and samepath(path, data.abspath):
                index, pathitem = i, data
                break

        rpaths = []

        if pathitem is None:
            assert index == -1
            pathitem = RecentPath.create(path, rpaths)

        if index != -1:
            item = model.takeRow(index)
        else:
            item = RecentPath_asqstandarditem(pathitem)

        opts = infer_options(path)

        if path.endswith(".count"):
            self.set_header_rows_count(1)
            self.set_header_cols_count(1)
            fixed_format = False
        elif path.endswith(".mtx"):
            self.set_header_rows_count(0)
            self.set_header_cols_count(0)
            fixed_format = False
            self._cells_in_rows = False
        else:
            fixed_format = True

        if opts.transposed is not None:
            self._cells_in_rows = not opts.transposed

        self.data_struct_box.setEnabled(fixed_format)
        self.header_rows_spin.setEnabled(fixed_format)
        self.header_cols_spin.setEnabled(fixed_format)

        model.insertRow(0, item)
        self._current_path = path
        self.recent_combo.setCurrentIndex(0)
        self._update_summary()

        if opts.row_annotation_file is not None:
            index = insert_recent_path(
                self.row_annotations_combo.model(),
                RecentPath.create(opts.row_annotation_file, []))
            self.row_annotations_combo.setCurrentIndex(index)
            self.set_row_annotations_enabled(True)
        else:
            self.row_annotations_combo.setCurrentIndex(-1)

        if opts.column_annotation_file is not None:
            index = insert_recent_path(
                self.col_annotations_combo.model(),
                RecentPath.create(opts.column_annotation_file, []))
            self.col_annotations_combo.setCurrentIndex(index)
            self.set_col_annotations_enabled(True)
        else:
            self.col_annotations_combo.setCurrentIndex(-1)

        if path.endswith(".mtx") \
                and opts.row_annotation_file is not None \
                and opts.column_annotation_file is not None \
                and os.path.basename(opts.row_annotation_file) == "barcodes.tsv" \
                and os.path.basename(opts.column_annotation_file) == "genes.tsv":
            # 10x gene-barcode matrix
            # TODO: The genes/barcodes files should be unconditionally loaded
            # alongside the mtx. The row/col annotations might be used to
            # specify additional sources. For the time being they are put in
            # the corresponding comboboxes and made uneditable.
            self.annotation_files_box.setEnabled(False)
        else:
            self.annotation_files_box.setEnabled(True)

        self._invalidate()
Пример #12
0
    def __init__(self):
        super().__init__()
        self._current_path = ""
        icon_open_dir = self.style().standardIcon(QStyle.SP_DirOpenIcon)

        # Top grid with file selection combo box
        grid = QGridLayout()
        lb = QLabel("File:")
        lb.setSizePolicy(QSizePolicy.Fixed, QSizePolicy.Fixed)
        self.recent_combo = cb = QComboBox(
            sizeAdjustPolicy=QComboBox.AdjustToMinimumContentsLengthWithIcon,
            minimumContentsLength=20,
            toolTip="Select a recent file")
        self.recent_model = cb.model()  # type: QStandardItemModel
        self.recent_combo.activated[int].connect(self._select_recent)

        browse = QPushButton("...",
                             autoDefault=False,
                             icon=icon_open_dir,
                             clicked=self.browse)

        # reload = QPushButton("Reload", autoDefault=False, icon=icon_reload)

        grid.addWidget(lb, 0, 0, Qt.AlignVCenter)
        grid.addWidget(cb, 0, 1)
        grid.addWidget(browse, 0, 2)
        # grid.addWidget(reload, 0, 3)

        self.summary_label = label = QLabel("", self)
        label.ensurePolished()
        f = label.font()
        if f.pointSizeF() != -1:
            f.setPointSizeF(f.pointSizeF() * 5 / 6)
        else:
            f.setPixelSize(f.pixelSize() * 5 / 6)
        label.setFont(f)
        grid.addWidget(label, 1, 1, 1, 3)

        self.controlArea.layout().addLayout(grid)

        box = gui.widgetBox(self.controlArea,
                            "Headers and Row Labels",
                            spacing=-1)
        hl = QHBoxLayout()
        hl.setContentsMargins(0, 0, 0, 0)
        self.header_rows_spin = spin = QSpinBox(box,
                                                minimum=0,
                                                maximum=3,
                                                value=self._header_rows_count,
                                                keyboardTracking=False)
        spin.valueChanged.connect(self.set_header_rows_count)
        hl.addWidget(QLabel("Data starts with", box))
        hl.addWidget(self.header_rows_spin)
        hl.addWidget(QLabel("header row(s)", box))
        hl.addStretch(10)
        box.layout().addLayout(hl)

        hl = QHBoxLayout()
        hl.setContentsMargins(0, 0, 0, 0)
        self.header_cols_spin = spin = QSpinBox(box,
                                                minimum=0,
                                                maximum=3,
                                                value=self._header_cols_count,
                                                keyboardTracking=False)
        spin.valueChanged.connect(self.set_header_cols_count)

        hl.addWidget(QLabel("First", box))
        hl.addWidget(self.header_cols_spin)
        hl.addWidget(QLabel("column(s) are row labels", box))
        hl.addStretch(10)
        box.layout().addLayout(hl)

        self.data_struct_box = box = gui.widgetBox(self.controlArea,
                                                   "Input Data Structure")
        gui.radioButtons(box,
                         self,
                         "_cells_in_rows", [
                             "Genes in rows, samples in columns",
                             "Samples in rows, genes in columns"
                         ],
                         callback=self._invalidate)

        box = gui.widgetBox(self.controlArea, "Sample Data", spacing=-1)

        grid = QGridLayout()
        grid.setContentsMargins(0, 0, 0, 0)
        box.layout().addLayout(grid)

        self.sample_rows_cb = cb = QCheckBox(checked=self._sample_rows_enabled)

        spin = QSpinBox(minimum=0,
                        maximum=100,
                        value=self._sample_rows_p,
                        enabled=self._sample_rows_enabled)
        spin.valueChanged.connect(self.set_sample_rows_p)
        suffix = QLabel("% of Samples", enabled=self._sample_rows_enabled)
        cb.toggled.connect(self.set_sample_rows_enabled)
        cb.toggled.connect(spin.setEnabled)
        cb.toggled.connect(suffix.setEnabled)

        grid.addWidget(cb, 0, 0)
        grid.addWidget(spin, 0, 1)
        grid.addWidget(suffix, 0, 2)

        self.sample_cols_cb = cb = QCheckBox(checked=self._sample_cols_enabled)
        spin = QSpinBox(minimum=0,
                        maximum=100,
                        value=self._sample_cols_p,
                        enabled=self._sample_cols_enabled)
        spin.valueChanged.connect(self.set_sample_cols_p)
        suffix = QLabel("% of genes", enabled=self._sample_cols_enabled)
        cb.toggled.connect(self.set_sample_cols_enabled)
        cb.toggled.connect(spin.setEnabled)
        cb.toggled.connect(suffix.setEnabled)

        grid.addWidget(cb, 1, 0)
        grid.addWidget(spin, 1, 1)
        grid.addWidget(suffix, 1, 2)
        grid.setColumnStretch(3, 10)

        self.annotation_files_box = box = gui.widgetBox(
            self.controlArea, "Cell && Gene Annotation Files")
        form = QFormLayout(
            formAlignment=Qt.AlignLeft,
            rowWrapPolicy=QFormLayout.WrapAllRows,
        )
        box.layout().addLayout(form)

        self.row_annotations_cb = cb = QCheckBox(
            "Cell annotations", checked=self._row_annotations_enabled)
        self._row_annotations_w = w = QWidget(
            enabled=self._row_annotations_enabled)
        cb.toggled.connect(self.set_row_annotations_enabled)
        cb.toggled.connect(w.setEnabled)
        hl = QHBoxLayout()
        hl.setContentsMargins(0, 0, 0, 0)
        w.setLayout(hl)
        self.row_annotations_combo = QComboBox(
            sizeAdjustPolicy=QComboBox.AdjustToMinimumContentsLengthWithIcon,
            minimumContentsLength=18)
        self.row_annotations_combo.activated.connect(self._invalidate)
        hl.addWidget(self.row_annotations_combo)
        hl.addWidget(
            QPushButton("...",
                        box,
                        autoDefault=False,
                        icon=icon_open_dir,
                        clicked=self.browse_row_annotations))
        # hl.addWidget(QPushButton("Reload", box, autoDefault=False,
        #                          icon=icon_reload))
        form.addRow(cb, w)

        self.col_annotations_cb = cb = QCheckBox(
            "Gene annotations", checked=self._col_annotations_enabled)
        self._col_annotations_w = w = QWidget(
            enabled=self._col_annotations_enabled)
        cb.toggled.connect(self.set_col_annotations_enabled)
        cb.toggled.connect(w.setEnabled)
        hl = QHBoxLayout()
        hl.setContentsMargins(0, 0, 0, 0)
        w.setLayout(hl)
        self.col_annotations_combo = QComboBox(
            sizeAdjustPolicy=QComboBox.AdjustToMinimumContentsLengthWithIcon,
            minimumContentsLength=18)
        self.col_annotations_combo.activated.connect(self._invalidate)
        hl.addWidget(self.col_annotations_combo)
        hl.addWidget(
            QPushButton("...",
                        box,
                        autoDefault=False,
                        icon=icon_open_dir,
                        clicked=self.browse_col_annotations))
        # hl.addWidget(QPushButton("Reload", box, autoDefault=False,
        #                          icon=icon_reload))
        form.addRow(cb, w)

        self.controlArea.layout().addStretch(10)
        self.load_data_button = button = VariableTextPushButton(
            "Load data",
            autoDefault=True,
            textChoiceList=["Load data", "Reload"])
        self.load_data_button.setAutoDefault(True)
        button.clicked.connect(self.commit, Qt.QueuedConnection)
        self.controlArea.layout().addWidget(button, alignment=Qt.AlignRight)

        init_recent_paths_model(
            self.recent_model,
            [RecentPath.create(p, []) for p in self._recent],
        )
        init_recent_paths_model(
            self.row_annotations_combo.model(),
            [RecentPath.create(p, []) for p in self._recent_row_annotations])
        init_recent_paths_model(
            self.col_annotations_combo.model(),
            [RecentPath.create(p, []) for p in self._recent_col_annotations])
        self._update_summary()
        self._update_warning()

        if self._last_path != "" and os.path.exists(self._last_path):
            self.set_current_path(self._last_path)
        else:
            self.recent_combo.setCurrentIndex(-1)
Пример #13
0
 def _set_annotation_files(self):
     dir_name, basename = os.path.split(self._file_name)
     basename_no_ext, _ = os.path.splitext(basename)
     meta_path = os.path.join(dir_name, basename_no_ext + ".meta")
     if os.path.isfile(meta_path):
         self.row_annotation_file = RecentPath.create(meta_path, [])
Пример #14
0
    def setup_gui(self):
        """ Use loader predefined values. If the value is None, set
        loader's parameter to widget's setting value.
        """
        loader = self._data_loader
        if loader.header_rows_count is not None:
            self.set_header_rows_count(loader.header_rows_count, False)
        else:
            loader.header_rows_count = self._header_rows_count

        if loader.header_cols_count is not None:
            self.set_header_cols_count(loader.header_cols_count, False)
        else:
            loader.header_cols_count = self._header_cols_count

        if loader.transposed is not None:
            self._cells_in_rows = not loader.transposed
        else:
            loader.transposed = not self._cells_in_rows

        if loader.sample_rows_enabled is not None:
            self.set_sample_rows_enabled(loader.sample_rows_enabled, False)
        else:
            loader.sample_rows_enabled = self._sample_rows_enabled

        if loader.sample_cols_enabled is not None:
            self.set_sample_cols_enabled(loader.sample_cols_enabled, False)
        else:
            loader.sample_cols_enabled = self._sample_cols_enabled

        if loader.sample_rows_p is not None:
            self.set_sample_rows_p(loader.sample_rows_p, False)
        else:
            loader.sample_rows_p = self._sample_rows_p

        if loader.sample_cols_p is not None:
            self.set_sample_cols_p(loader.sample_cols_p, False)
        else:
            loader.sample_cols_p = self._sample_cols_p

        if loader.row_annotation_file is not None:
            index = insert_recent_path(
                self.row_annotations_combo.model(),
                RecentPath.create(loader.row_annotation_file, []))
            self.row_annotations_combo.setCurrentIndex(index)
            self.set_row_annotations_enabled(loader.row_annotations_enabled,
                                             False)
        else:
            self.row_annotations_combo.setCurrentIndex(-1)
            self.set_row_annotations_enabled(False, False)

        if loader.col_annotation_file is not None:
            index = insert_recent_path(
                self.col_annotations_combo.model(),
                RecentPath.create(loader.col_annotation_file, []))
            self.col_annotations_combo.setCurrentIndex(index)
            self.set_col_annotations_enabled(loader.col_annotations_enabled,
                                             False)
        else:
            self.col_annotations_combo.setCurrentIndex(-1)
            self.set_col_annotations_enabled(False, False)

        self.header_rows_spin.setEnabled(loader.FIXED_FORMAT)
        self.header_cols_spin.setEnabled(loader.FIXED_FORMAT)
        self.data_struct_box.setEnabled(loader.FIXED_FORMAT)

        self.annotation_files_box.setEnabled(loader.ENABLE_ANNOTATIONS)
Пример #15
0
 def add_path(self, filename):
     recent = RecentPath.create(filename, self._search_paths())
     self.recent_paths.append(recent)
Пример #16
0
 def relocate_path(self, path):
     basedir = self.workflowEnv().get("basedir", None)
     if not basedir or not path:
         return path
     return RecentPath.create(path.abspath, [("basedir", basedir)])
Пример #17
0
 def add_path(self, filename, reader=None):
     recent = RecentPath.create(filename, self._search_paths())
     if reader is not None:
         recent.file_format = reader.qualified_name()
     self.recent_paths.append(recent)
Пример #18
0
 def add_path(self, filename, reader=None):
     recent = RecentPath.create(filename, self._search_paths())
     if reader is not None:
         recent.file_format = reader.qualified_name()
     self.recent_paths.append(recent)