Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
125 commits
Select commit Hold shift + click to select a range
ac1a6a7
working on single exon bug
cafelton Mar 9, 2026
525983e
Merge branch 'transcriptome-polish' of github.com:diekhans/flair into…
cafelton Mar 9, 2026
8aa497d
modify how intermediate files are made
cafelton Mar 10, 2026
69af4d5
fix bugs in single exon transcript handling and filtering
cafelton Mar 10, 2026
318aca8
add script to compare output to expected by junction chain
cafelton Mar 10, 2026
ae5ef72
return SeqRange to previous and instead redefine Exon with name
cafelton Mar 10, 2026
332b318
remove no intron errors from intronsupport
cafelton Mar 13, 2026
fa45848
transcriptome: add read filtering option and remove unnecesary logging
cafelton Mar 13, 2026
0b16bcb
spliceevents: improve initial read filtering and AFE, also implement …
cafelton Mar 13, 2026
ee4f2ea
actually adding intron support removing no intron errors - prev commi…
cafelton Mar 13, 2026
1e7956f
update flair fusion - better genomic gene ID, better initial fusion f…
cafelton Mar 13, 2026
286cca9
transcriptome: stop trying to assemble if no reads in region
cafelton Mar 17, 2026
a7bac17
edit output reads file name
cafelton Mar 17, 2026
ebfa343
fusion: improved alignment to synthetic, filtering of close fusions, …
cafelton Mar 17, 2026
fac1a21
update fusion tests
cafelton Mar 17, 2026
57a8c8f
Merge branch 'transcriptome-polish' of github.com:diekhans/flair into…
cafelton Mar 18, 2026
747a78c
update data structures in transcriptome
cafelton Mar 19, 2026
cb18bdc
comment out more unused code
cafelton Mar 19, 2026
417fd42
clean up classes in transcriptome
cafelton Mar 19, 2026
30f7608
fusion: allow modifying of req dist to TSS in args
cafelton Mar 19, 2026
a721582
Merge branch 'dev' of github.com:BrooksLabUCSC/flair into dev
cafelton Mar 19, 2026
9548d89
transcriptome updates (breaks some tests) - move gene ID earlier, use…
cafelton Mar 20, 2026
21b75b2
improve early gene id (esp single exon), add quantification of partia…
cafelton Mar 20, 2026
6d7ce83
fix bug for no firtpass found
cafelton Mar 20, 2026
630540c
fusion: remove transcriptomic_chimeras, better output supporting read…
cafelton Mar 20, 2026
476d6dc
reverse complement functions standardized to the one in isoform_data
cafelton Mar 20, 2026
b70bb2d
remove bug for removing , in bed parsing in old code
cafelton Mar 20, 2026
588d8c0
remove bed_to_sequence, bedtools instead
cafelton Mar 21, 2026
c5fd2c8
consolidate code for processing bedtools get_fasta output
cafelton Mar 21, 2026
ab8bbff
fix bug with sjc vs se_support in transcriptome
cafelton Mar 21, 2026
4d6ca2f
fusion: improve initial getting of chimeric reads
cafelton Mar 21, 2026
1952669
planning for updated stranding
cafelton Mar 24, 2026
2ea6dc7
Merge branch 'dev' of github.com:BrooksLabUCSC/flair into dev
cafelton Mar 24, 2026
856384e
transcriptome: fix novel gene detection bug
cafelton Mar 25, 2026
fb02ce1
use recurisve make in top level so a failure is report at the end of …
diekhans Mar 30, 2026
bd04c0d
add more fusion files, fix close genes on negative strand fusion filt…
cafelton Mar 30, 2026
ce6aadf
Merge branch 'dev' of github.com:BrooksLabUCSC/flair into dev
cafelton Mar 30, 2026
b0f85b0
make combine options more intuitive
cafelton Mar 30, 2026
7244c4c
stranding notes, also fixed bug in single exon gene identification (b…
cafelton Mar 30, 2026
8bdd8c5
fix SE gene detection bug, add polyA and intprim detection to indiv. …
cafelton Apr 2, 2026
62d8873
added polyA strand correction for single exon reads
cafelton Apr 2, 2026
51f9c01
transcriptome: fix novel gene detection bug
cafelton Mar 25, 2026
60ff229
add more fusion files, fix close genes on negative strand fusion filt…
cafelton Mar 30, 2026
fb25fc2
make combine options more intuitive
cafelton Mar 30, 2026
30517df
stranding notes, also fixed bug in single exon gene identification (b…
cafelton Mar 30, 2026
56e6d4c
fix SE gene detection bug, add polyA and intprim detection to indiv. …
cafelton Apr 2, 2026
3cf87d7
added polyA strand correction for single exon reads
cafelton Apr 2, 2026
d857b5e
test is noew the default target
diekhans Mar 30, 2026
874dac0
claude add doc
diekhans Mar 30, 2026
ec0e847
fixed flake8 errors after merge
diekhans Apr 4, 2026
838c14e
added github workflow to fix flake8 errors
diekhans Apr 4, 2026
0a9a1e3
flake8 fixes
diekhans Apr 4, 2026
2c3ec04
added FIXME to use samtools for filtering
diekhans Apr 4, 2026
844322c
work with Claude on fixing flake8 errors
diekhans Apr 4, 2026
ebf6940
major flake8 cleanup
diekhans Apr 5, 2026
a8a21dc
test of github lint workflow
diekhans Apr 5, 2026
38575b0
Revert "test of github lint workflow"
diekhans Apr 5, 2026
18f0eec
update args in count_sam_transcripts
cafelton Apr 6, 2026
2c7769d
Merge branch 'transcriptome-polish' of github.com:diekhans/flair into…
cafelton Apr 6, 2026
90df3b2
fix flake8 in count_sam_transcripts
cafelton Apr 6, 2026
2213192
moved flake8 ignores from file global to code
diekhans Apr 6, 2026
76bd9d1
Merge branch 'transcriptome-polish' of github.com:diekhans/flair into…
cafelton Apr 7, 2026
9532210
add more fusion files, fix close genes on negative strand fusion filt…
cafelton Mar 30, 2026
6cc74ed
make combine options more intuitive
cafelton Mar 30, 2026
5796698
stranding notes, also fixed bug in single exon gene identification (b…
cafelton Mar 30, 2026
948c6e5
fix SE gene detection bug, add polyA and intprim detection to indiv. …
cafelton Apr 2, 2026
b649e0c
update args in count_sam_transcripts
cafelton Apr 6, 2026
16d037e
fix flake8 in count_sam_transcripts
cafelton Apr 6, 2026
0356bc7
set strand based on gene when matching transcriptome
diekhans Apr 9, 2026
c9b5e92
resolved merge issues
diekhans Apr 9, 2026
8718f49
merge some merge mistakes
diekhans Apr 9, 2026
65a931d
added back check for no support loaded
diekhans Apr 9, 2026
8283a35
refine clipping processing to be more readable
cafelton Apr 10, 2026
57b9076
Merge branch 'transcriptome-polish' of github.com:diekhans/flair into…
cafelton Apr 10, 2026
0edc350
add fix for gtf files with underscore in gene ID
cafelton Apr 10, 2026
f7a5868
fix flake8 in gtf_io
cafelton Apr 10, 2026
0db4c68
restore isoform_data update that was seemingly lost in merge
cafelton Apr 10, 2026
f4627c0
remove uncessary re-creation of a BED during junction correction
diekhans Apr 11, 2026
fa5147a
added strand assignment from splice junctions or poly(A)
diekhans Apr 12, 2026
f85720d
handle ploy(T) in cDNA was well
diekhans Apr 12, 2026
bed2f40
added gene class to contain isoforms
diekhans Apr 12, 2026
0ebd100
switch all GTF I/O' to use library
diekhans Apr 12, 2026
aefd346
moved from adhoc BED parsing to using library
diekhans Apr 12, 2026
777fd9b
replace filter_transcriptome_chim.py with samtools filter
diekhans Apr 12, 2026
ddaf98e
log reads being dropped
diekhans Apr 12, 2026
13a1f51
fixmes
diekhans Apr 13, 2026
6821275
moved AnnotData to a module and switched splice events to use it
diekhans Apr 13, 2026
b579aa8
Merge branch 'transcriptome-polish' of github.com:diekhans/flair into…
cafelton Apr 13, 2026
fb774b6
improved junction correct setup for spliceevents
diekhans Apr 13, 2026
d00f64d
replace all manual parsing and formating of BEDs with library calls
diekhans Apr 13, 2026
46bb015
don't allow minimap2 to multiple number of threads used
diekhans Apr 14, 2026
991f118
Merge branch 'transcriptome-polish' of github.com:diekhans/flair into…
cafelton Apr 14, 2026
f6ad722
bed parsing in spliceevents
cafelton Apr 14, 2026
eeec310
add definition of old direct-RNA
diekhans Apr 15, 2026
a4bc5b2
cleanup up of count_sam_transcripts
diekhans Apr 19, 2026
19cf057
mior optimzation of cigar parsin
diekhans Apr 20, 2026
685db79
fixed potential multiprocessing issues with error handling
diekhans Apr 22, 2026
8bd91d0
moved filter_correct_group_reads to a common module
diekhans Apr 23, 2026
49dab7a
duplicate code between transcriptome and spliceevents combined
diekhans Apr 23, 2026
28ed6c9
switch from IntervalTree to ruranges_py to speed up intron support
diekhans Apr 24, 2026
49a1497
wrap execution of count_sam_transcripts in a function to abstract cal…
diekhans Apr 28, 2026
42fd113
Merge branch 'transcriptome-polish' of github.com:diekhans/flair into…
cafelton May 6, 2026
31e1886
count_sam_transcripts edited to address #623
cafelton May 6, 2026
9cc36c0
update predictProd to work with additional columns in bed file
cafelton May 11, 2026
73e84ae
implement new IDs and extra columns in bed in transcriptome, predictP…
cafelton May 12, 2026
d605451
clean up code and improve gtf conversion for bed with cds
cafelton May 12, 2026
62b68f2
fix flake8
cafelton May 12, 2026
6941e6e
change gene ID handling to use hashes, clean up final IDs
cafelton May 14, 2026
ebccc88
update count_sam_transcripts to better account for multiple transcrip…
cafelton May 15, 2026
6def584
test and further improve count_sam_transcripts
cafelton May 15, 2026
88d6823
incorporate productivity prediction into transcriptome (required slig…
cafelton May 18, 2026
e6f5767
add back in trust_ends, add test for it
cafelton May 18, 2026
432a651
fix bug with NGO transcript thickStart/End
cafelton May 18, 2026
8a43085
added FlairBed class
diekhans May 19, 2026
ab4bb9c
fix bug with NGO transcript thickStart/End
cafelton May 18, 2026
a0aff01
add tests and missing filed for FlairBed
diekhans May 19, 2026
fb3aea7
flake8 problem
diekhans May 19, 2026
3c1cf27
Merge pull request #1 from diekhans/colette-dev
cafelton May 19, 2026
c952363
fixed problems with some diffsplice_fishers_exact, and other auxiliar…
diekhans May 19, 2026
e55705d
integrate FlairBed class into transcriptome, predictProductivity, and…
cafelton May 19, 2026
ad9760c
Merge branch 'dev' of github.com:BrooksLabUCSC/flair into dev
cafelton May 19, 2026
912158a
fixed predictProductivity temp file name collision
diekhans May 20, 2026
3f61174
minor change to flair_bed encoding
diekhans May 20, 2026
20e2578
Merge branch 'colette-dev' into transcriptome-polish
diekhans May 20, 2026
385dd23
restore correct behavior of checking poly(A) as htslib has already or…
diekhans Jun 5, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
22 changes: 7 additions & 15 deletions .flake8
Original file line number Diff line number Diff line change
@@ -1,19 +1,11 @@
[flake8]
# E722: do not use bare except; maybe fix later
# E302: expected 2 blank lines
# E741: ambiguous variable name
# F523: .format unused named arguments
# F524: .format missing named arguments
# W503: line break before binary operator (PEP 8 preferred style)
# W504: line break after binary operator
ignore = E302,E741,F523,F524,W503,W504
max-complexity = 10
max-line-length = 256

per-file-ignores =
# imported but unused
src/flair/count_sam_transcripts.py: E502
# fixing W504 causes E502
src/flair/filter_collapsed_isoforms.py,src/flair/collapse_isoforms_precise.py,src/flair/call_diffsplice_events.py: W504
# openblas setting must be in middle of import section
deFLAIR.py,es_as_inc_excl_to_counts.py,flair.py,runDE.py,runDS.py,runDU.py,samJuncs.py: E402
src/flair/ssPrep.py: F401
# hard to fix in-loop variable definitions (maybe later)
src/flair/identify_gene_isoform.py: F821
# FIXME: make these less complex
src/flair/flair_transcriptome.py: C901
src/flair/filter_transcriptome_align.py: C901
exclude = .claude.bak,src/flair/pycbio
12 changes: 12 additions & 0 deletions .github/workflows/lint.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
name: Lint
on: [push, pull_request]
jobs:
flake8:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: actions/setup-python@v5
with:
python-version: '3.x'
- run: pip install flake8
- run: make flake8
3 changes: 3 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,9 @@
# Major user-visible changes

## [v3.x.xx]
* General
* fixed problems with some diffsplice_fishers_exact, and other
auxiliary console script installs
* Incompatibles
* Removed flair correct and collapse modules, the functionality is replaced
by flair transcriptome.
Expand Down
6 changes: 5 additions & 1 deletion Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,11 @@ include ${root}/defs.mk
# make test-installed
#

# get files to include in flake8
PYPROGS = $(shell file -F $$'\t' test/bin/* | awk '/Python script/{print $$1}')

FLAKE8_CHECK = src/flair/*.py test/*.py ${PYPROGS}

default:

doc:
Expand All @@ -34,7 +39,6 @@ test-base-installed:
# see .flake8 for configuration
# due to to gradual cleanup of code, flake8.mk is the list of files to check
##
include flake8.mk
lint: flake8
pycbio-lint: pycbio-flake8

Expand Down
3 changes: 2 additions & 1 deletion docs/source/modules.rst
Original file line number Diff line number Diff line change
Expand Up @@ -70,7 +70,8 @@ Optional arguments
--stringent [HIGHLY RECOMMENDED] specify if all supporting reads need to be full-length
(spanning 25 bp of the first and last exons)
--check_splice [HIGHLY RECOMMENDED] enforce coverage of 4 out of 6 bp around each splice site
and no insertions greater than 3 bp at the splice site DON'T USE WITH DATA WITH HIGH ERROR RATES (old direct-RNA)
and no insertions greater than 3 bp at the splice site. DON'T USE WITH DATA WITH ERROR RATES of 5% or more, such
as older direct-RNA (anything before using the RNA-specific flow-cell with the Dorado basecaller).
-w --end_window
window size for comparing TSS/TES (100)
--noaligntoannot related to old annotation_reliant, now specify if you don't want an initial alignment
Expand Down
24 changes: 0 additions & 24 deletions flake8.mk

This file was deleted.

4 changes: 1 addition & 3 deletions pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -18,13 +18,12 @@ dependencies = [
"pysam (>=0.23.0,<0.24.0)",
"pipettor (>=1.1.0,<2.0.0)",
"ncls (>=0.0.70,<0.1.0)",
"intervaltree (>=3.0,<4.0)",
"ruranges (>=0.1.4,<0.2.0)",
"setuptools (>=80.2.0,<81.0.0)",
"mappy (>=2.28,<3.0)",
"numpy (>=2.2,<3.0)",
"scipy (>=1.15.1,<2.0.0)",
"matplotlib (>=3.10.0,<4.0.0)",
"intervaltree (>=3.2.1,<4.0.0)",
]

[project.optional-dependencies]
Expand All @@ -46,7 +45,6 @@ repository = "https://github.com/BrooksLabUCSC/flair/"
flair = "flair.flair_cli:main"
junctions_from_sam = "flair.junctions_from_sam:main"
mark_intron_retention = "flair.mark_intron_retention:main"
mark_productivity = "flair.mark_productivity:main"
normalize_counts_matrix = "flair.normalize_counts_matrix:main"
plot_isoform_usage = "flair.plot_isoform_usage:main"
predictProductivity = "flair.predictProductivity:main"
Expand Down
7 changes: 5 additions & 2 deletions src/flair/annotate_aaseq_with_uniprot.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,8 @@
def parse_args():
parser = argparse.ArgumentParser(description='''for annotating FLAIR aaseq predictions with UniProt names''')
parser.add_argument('-i', '--input_aaseq', required=True, help='protein sequence fasta file - sequence names should be aaseqID_geneID')
parser.add_argument('-r', '--reference_seq', required=True, help='reference protein sequence fasta file - sequence names should be db|refID|geneName_organism, ex: >sp|Q8NH21|OR4F5_HUMAN. This script will extract the refID. this can be fasta or fasta.gz')
parser.add_argument('-r', '--reference_seq', required=True,
help='reference protein sequence fasta file - sequence names should be db|refID|geneName_organism, ex: >sp|Q8NH21|OR4F5_HUMAN. This script will extract the refID. this can be fasta or fasta.gz')
parser.add_argument('-o', '--output', required=True, help='output name - should be a fasta file')
args = parser.parse_args()
return args
Expand Down Expand Up @@ -44,10 +45,12 @@ def annotate_input(input_aaseq, ref_seq_to_name, output_name):
out.write('>' + info + '\n' + seq + '\n')
out.close()


def main():
args = parse_args()
ref_seq_to_name = process_reference(args.reference_seq)
annotate_input(args.input_aaseq, ref_seq_to_name, args.output)


if __name__ == '__main__':
main()
main()
2 changes: 1 addition & 1 deletion src/flair/annotate_group_vcf_vars.py
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,7 @@ def main():
out = open(args.output, 'w')
for chrom, region in vcfvars:
annotate_vars_in_region(vcfvars[(chrom, region)], chrom, region, out)


if __name__ == "__main__":
main()
139 changes: 139 additions & 0 deletions src/flair/annotation_data.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,139 @@
"""External gene annotation data loaded from GTF.

Provides indexed lookups for junction-to-gene mapping, gene strand,
transcript exon structure, and single-exon gene tracking. Used by
flair_transcriptome and flair_spliceevents for read correction, gene
assignment, and isoform filtering.
"""

from flair.isoform_data import Exon, exons_to_juncs


class AnnotData(object):
def __init__(self):
# map of (transcript_id, gene_id) -> tuple of Exon
self.transcript_to_exons = {}

# list of (transcript_id, gene_id, strand)
self.transcripts = []

# map of junction chain tuple -> (transcript_id, gene_id)
self.juncchain_to_transcript = {}

# map of Junc -> set of (transcript_id, gene_id)
self.junc_to_gene = {}

# single-exon annotations by strand: {'+': [], '-': []}
# each entry is Exon(start, end, gene_id), sorted for binary search
# FIXME: rename once it is figured out how this works in get_single_exon_gene_overlaps
self.all_annot_SE = {'+': [], '-': []}

# map of strand -> gene_id -> set of Exon
# FIXME: why is strand needed here
self.spliced_exons = {'+': {}, '-': {}}

# map of gene_id -> set of Junc
self.gene_to_annot_juncs = {}

# map of gene_id -> strand
self.gene_to_strand = {}

# map of gene_id -> tuple of sorted exon coordinate tuples
# union of all exons across all transcripts in the gene
self.gene_to_exons = {}

# map of junction chain tuple -> gene_id
self.sjc_to_gene = {}

# map of "transcript_id_gene_id" -> junction chain tuple
# key format matches BED name field from gtf_to_bed --include_gene
self.transcript_to_sjc = {}

# map of Junc -> gene_id (single value, last gene seen wins)
# used by spliceevents for simple junction-to-gene lookup
self.junc_to_gene_id = {}

self.gene_to_cds_starts = {}

self.transcript_to_nmd_except = {}

self.start_codon_count = 0


def annot_data_from_gtf(gtf_data, region):
"""Build AnnotData for a region from a pre-partitioned GtfData object."""
annots = AnnotData()
if gtf_data is None:
return annots
region_map = {region: annots}
for trans in gtf_data.transcripts:
if len(trans.exons) > 0:
_process_transcript(annots, region, region_map, trans)
# finalize gene_to_exons as sorted tuples
for gene_id in annots.gene_to_exons:
annots.gene_to_exons[gene_id] = tuple(sorted(annots.gene_to_exons[gene_id]))
return annots

def _process_transcript(annots, region, region_map, trans):
trans.gene_id = trans.gene_id.replace('_', '-')
exons = [Exon(exon.start, exon.end) for exon in trans.exons]
sorted_exons = sorted(exons)
t_start = sorted_exons[0].start
t_end = sorted_exons[-1].end
_save_transcript_annot(trans.transcript_id, trans.gene_id, region,
region_map, t_start, t_end, trans.strand, sorted_exons,
trans.attrs['tag'], trans.start_codon)

def _save_cds_starts(gene_id, start_codon, strand, annots):
if gene_id not in annots.gene_to_cds_starts:
annots.gene_to_cds_starts[gene_id] = set()
if start_codon is not None:
annots.start_codon_count += 1
if strand == '+':
annots.gene_to_cds_starts[gene_id].add(start_codon.start)
else:
annots.gene_to_cds_starts[gene_id].add(start_codon.end)

def _save_spliced_transcript_info(gene_id, t_exons, juncs, transcript_id, strand, annots):
if gene_id not in annots.spliced_exons[strand]:
annots.spliced_exons[strand][gene_id] = set()
annots.spliced_exons[strand][gene_id].update(set(t_exons))
annots.juncchain_to_transcript[tuple(juncs)] = (transcript_id, gene_id)
annots.sjc_to_gene[tuple(juncs)] = gene_id
annots.transcript_to_sjc[f"{transcript_id}_{gene_id}"] = tuple(juncs)
if gene_id not in annots.gene_to_annot_juncs:
annots.gene_to_annot_juncs[gene_id] = set()
for j in juncs:
if j not in annots.junc_to_gene:
annots.junc_to_gene[j] = set()
annots.junc_to_gene[j].add((transcript_id, gene_id))
annots.junc_to_gene_id[j] = gene_id
annots.gene_to_annot_juncs[gene_id].add(j)

def _save_transcript_annot(transcript_id, gene_id, region, region_map, t_start, t_end,
strand, t_exons, transcript_tags, start_codon):
# region is a SeqRegion object
annots = region_map[region]

_save_cds_starts(gene_id, start_codon, strand, annots)
annots.transcript_to_nmd_except[transcript_id] = False
if 'NMD_exception' in transcript_tags:
annots.transcript_to_nmd_except[transcript_id] = True

annots.transcript_to_exons[(transcript_id, gene_id)] = tuple(t_exons)
juncs = exons_to_juncs(t_exons)
annots.transcripts.append((transcript_id, gene_id, strand))
if gene_id not in annots.gene_to_strand:
annots.gene_to_strand[gene_id] = strand
# accumulate exons per gene (as coordinate tuples for spliceevents compatibility)
exon_coords = set((e.start, e.end) for e in t_exons)
if gene_id not in annots.gene_to_exons:
annots.gene_to_exons[gene_id] = exon_coords
else:
annots.gene_to_exons[gene_id].update(exon_coords)
if len(juncs) == 0:
annots.all_annot_SE[strand].append(Exon(t_start, t_end, gene_id))
else:
_save_spliced_transcript_info(gene_id, t_exons, juncs, transcript_id, strand, annots)
for strand in ['+', '-']:
annots.all_annot_SE[strand] = sorted(annots.all_annot_SE[strand]) # FIXME: make set? Colette note: needs to be sorted for binary search later
Loading