diff --git a/gffquant/__init__.py b/gffquant/__init__.py index f3a023d6..0f42e1ec 100644 --- a/gffquant/__init__.py +++ b/gffquant/__init__.py @@ -5,7 +5,7 @@ from enum import Enum, auto, unique -__version__ = "2.18.5" +__version__ = "2.18.6" __tool__ = "gffquant" diff --git a/gffquant/annotation/count_annotator.py b/gffquant/annotation/count_annotator.py index feb96b92..d47b2e40 100644 --- a/gffquant/annotation/count_annotator.py +++ b/gffquant/annotation/count_annotator.py @@ -286,6 +286,8 @@ def annotate(self, refmgr, db, count_manager, gene_group_db=False): if self.strand_specific else None ) + grouped_counts = {} + for rid in set(count_manager.uniq_seqcounts).union( count_manager.ambig_seqcounts ): @@ -305,24 +307,28 @@ def annotate(self, refmgr, db, count_manager, gene_group_db=False): if gene_group_db: ref_tokens = ref.split(".") gene_id, ggroup_id = ".".join(ref_tokens[:-1]), ref_tokens[-1] + grouped_counts.setdefault(ggroup_id, np.zeros(self.bins)) + grouped_counts[ggroup_id] += counts else: - ggroup_id, gene_id = ref, ref + gene_id = ref + region_annotation = db.query_sequence(gene_id) + if region_annotation is not None: + _, _, region_annotation = region_annotation + self.distribute_feature_counts(counts, region_annotation) + else: + self.unannotated_counts += counts[:4] gcounts = self.gene_counts.setdefault(gene_id, np.zeros(self.bins)) gcounts += counts self.total_gene_counts += counts[:4] - region_annotation = db.query_sequence(ggroup_id) - if region_annotation is not None: - _, _, region_annotation = region_annotation - # logger.info( - # "GCAnnotator: Distributing counts of Gene %s (group=%s) %s %s", - # gene_id, ggroup_id, counts[0], counts[2], - # ) - self.distribute_feature_counts(counts, region_annotation) - - else: - # logger.info("GCAnnotator: Gene %s (group=%s) has no information in database.", gene_id, ggroup_id) + for group_id, counts in grouped_counts.items(): + if group_id == "0": self.unannotated_counts += counts[:4] + else: + region_annotation = db.query_sequence(int(group_id, 16), grouped_db=True,) + if region_annotation is not None: + _, _, region_annotation = region_annotation + self.distribute_feature_counts(counts, region_annotation) self.calculate_scaling_factors() diff --git a/gffquant/db/annotation_db.py b/gffquant/db/annotation_db.py index 6623a444..c9615b5c 100644 --- a/gffquant/db/annotation_db.py +++ b/gffquant/db/annotation_db.py @@ -48,7 +48,7 @@ def from_db(cls, db_path, in_memory=True): return SQL_ADM(db_path) @abstractmethod - def query_sequence_internal(self, seqid, start=None, end=None): + def query_sequence_internal(self, seqid, start=None, end=None, grouped_db=False,): ... @abstractmethod @@ -59,17 +59,22 @@ def get_features(self, category_id): def get_categories(self): ... - def query_sequence(self, seqid, start=None, end=None): + def query_sequence(self, seqid, start=None, end=None, grouped_db=False,): """ Returns strand, seq-feature id (e.g. contig id), functional categories """ - db_sequence = self.query_sequence_internal(seqid, start=start, end=end) + db_sequence = self.query_sequence_internal(seqid, start=start, end=end, grouped_db=grouped_db,) if db_sequence is None: return None + + strand = getattr(db_sequence, "strand", None) + featureid = getattr(db_sequence, "feature_id", None) + categories = tuple() for cat_features in db_sequence.annotation_str.strip().split(";"): category, features = cat_features.split("=") categories += ((category, tuple(feature.strip() for feature in features.split(",") if feature.strip())),) - return db_sequence.strand, db_sequence.featureid, categories + + return strand, featureid, categories @abstractmethod def query_feature(self, feature_id): @@ -192,8 +197,12 @@ def __init__(self, db_path): super().__init__() self.db_session = db_path - def query_sequence_internal(self, seqid, start=None, end=None): - if start is not None and end is not None: + def query_sequence_internal(self, seqid, start=None, end=None, grouped_db=False,): + if grouped_db: + db_sequence = self.db_session.query(db.AnnotationGroup) \ + .filter(db.AnnotationGroup.id == seqid) \ + .one_or_none() + elif start is not None and end is not None: db_sequence = self.db_session.query(db.AnnotatedSequence) \ .filter(db.AnnotatedSequence.seqid == seqid) \ .filter((db.AnnotatedSequence.start == start) & (db.AnnotatedSequence.end == end)).one_or_none() @@ -229,7 +238,7 @@ def __init__(self, db_path): super().__init__() self.db = db_path - def query_sequence_internal(self, seqid, start=None, end=None): + def query_sequence_internal(self, seqid, start=None, end=None, grouped_db=False,): if start is not None and end is not None: seqs = [ seq diff --git a/gffquant/db/models/db.py b/gffquant/db/models/db.py index bcff37d6..04187cb2 100644 --- a/gffquant/db/models/db.py +++ b/gffquant/db/models/db.py @@ -8,6 +8,16 @@ from .meta import Base +class AnnotationGroup(Base): + __tablename__ = "annotation_group" + + id = Column(Integer, primary_key=True) + id16 = Column(String, index=True) + annotation_str = Column(String) + n_members = Column(Integer) + sha256 = Column(String) + + class AnnotationString(Base): __tablename__ = "annotationstring"