From bc83eb7afeda49c3b50adeb69826c31824521050 Mon Sep 17 00:00:00 2001 From: Stepanova Valeriya Date: Sat, 19 Apr 2025 11:25:19 +0300 Subject: [PATCH 1/3] added qc_test logger and parsing --- addscript/fastq_read_write_file.py | 29 ----- addscript/{ => qc_tool}/fastq_qc_function.py | 16 ++- addscript/qc_tool/fastq_read_write_file.py | 28 ++++ addscript/qc_tool/test_qc_tool.py | 55 ++++++++ bioprogsv.py | 127 +++++++++++++++---- 5 files changed, 194 insertions(+), 61 deletions(-) delete mode 100644 addscript/fastq_read_write_file.py rename addscript/{ => qc_tool}/fastq_qc_function.py (64%) create mode 100644 addscript/qc_tool/fastq_read_write_file.py create mode 100644 addscript/qc_tool/test_qc_tool.py diff --git a/addscript/fastq_read_write_file.py b/addscript/fastq_read_write_file.py deleted file mode 100644 index 4124eb8..0000000 --- a/addscript/fastq_read_write_file.py +++ /dev/null @@ -1,29 +0,0 @@ -import os - - -def read_fastq(input_fastq): - base_directory = os.path.dirname(input_fastq) - filtered_directory = os.path.join(base_directory, 'filtered') - if not os.path.exists(filtered_directory): - os.makedirs(filtered_directory) - with open(input_fastq) as file: - keys = [] - values = [] - for line in file.readlines(): - line_new = line.strip() - if line_new.startswith('@SRX'): - keys.append(line_new) - elif not line_new.startswith('+'): - values.append(line_new) - input_fastq_data = {keys[i]: (values[2 * i], values[2 * i + 1]) - for i in range(len(keys))} - return input_fastq_data, filtered_directory - - -def write_fastq(output_fastq_data, output_fastq): - with open(output_fastq, 'w') as file: - for sequence_id, (sequence_fastq, quality_fastq) in output_fastq_data.items(): - file.write(sequence_id + '\n') - file.write(sequence_fastq + '\n') - file.write('+' + sequence_id[1:] + '\n') - file.write(quality_fastq + '\n') diff --git a/addscript/fastq_qc_function.py b/addscript/qc_tool/fastq_qc_function.py similarity index 64% rename from addscript/fastq_qc_function.py rename to addscript/qc_tool/fastq_qc_function.py index 1573ead..3d235df 100644 --- a/addscript/fastq_qc_function.py +++ b/addscript/qc_tool/fastq_qc_function.py @@ -25,10 +25,16 @@ def fast_qc(seqs): indicating the reliability of the sequence data. """ gc_len_q = {} - quality_scores = [] for sequence_name, (sequence, quality) in seqs.items(): - gc_count = (sequence.count('G') + sequence.count('C'))/len(sequence) * 100 - quality_scores = [ord(char) - 33 for char in quality] - average_quality = sum(quality_scores) / len(quality_scores) if quality_scores else 0 - gc_len_q[sequence_name] = (gc_count, len(sequence), average_quality) + if not sequence: # Проверка на пустую последовательность + gc_count = 0.0 + length = 0 + average_quality = 0.0 + else: + gc_count = (sequence.count('G') + sequence.count('C')) / len(sequence) * 100 + quality_scores = [ord(char) - 33 for char in quality] + average_quality = sum(quality_scores) / len(quality_scores) if quality_scores else 0 + length = len(sequence) + + gc_len_q[sequence_name] = (gc_count, length, average_quality) return gc_len_q diff --git a/addscript/qc_tool/fastq_read_write_file.py b/addscript/qc_tool/fastq_read_write_file.py new file mode 100644 index 0000000..aa1aad0 --- /dev/null +++ b/addscript/qc_tool/fastq_read_write_file.py @@ -0,0 +1,28 @@ +import os + +def read_fastq(input_fastq): + base_directory = os.path.dirname(input_fastq) + filtered_directory = os.path.join(base_directory, 'filtered') + os.makedirs(filtered_directory, exist_ok=True) + + input_fastq_data = {} + with open(input_fastq) as file: + while True: + header = file.readline().strip() + if not header: + break + sequence = file.readline().strip() + _ = file.readline().strip() # Пропускаем строку '+' + quality = file.readline().strip() + input_fastq_data[header] = (sequence, quality) + + return input_fastq_data, filtered_directory + + +def write_fastq(output_fastq_data, output_fastq): + with open(output_fastq, 'w') as file: + for sequence_id, (sequence, quality) in output_fastq_data.items(): + file.write(f"{sequence_id}\n") + file.write(f"{sequence}\n") + file.write(f"+{sequence_id[1:]}\n") + file.write(f"{quality}\n") \ No newline at end of file diff --git a/addscript/qc_tool/test_qc_tool.py b/addscript/qc_tool/test_qc_tool.py new file mode 100644 index 0000000..1522030 --- /dev/null +++ b/addscript/qc_tool/test_qc_tool.py @@ -0,0 +1,55 @@ +import unittest +import os +from qc_tool.fastq_read_write_file import read_fastq, write_fastq +from qc_tool.fastq_qc_function import fast_qc + +class TestFastQC(unittest.TestCase): + def test_gc_content(self): + seqs = {"seq1": ("AGCTGCTA", "IIIIIIII")} + result = fast_qc(seqs) + self.assertAlmostEqual(result["seq1"][0], 50.0) # GC content is 50% + + def test_sequence_length(self): + seqs = {"seq1": ("AGCTGCTA", "IIIIIIII")} + result = fast_qc(seqs) + self.assertEqual(result["seq1"][1], 8) # Length is 8 + + def test_average_quality(self): + seqs = {"seq1": ("AGCTGCTA", "IIIIIIII")} + result = fast_qc(seqs) + self.assertAlmostEqual(result["seq1"][2], 40.0) # Average quality is 40 + + def test_empty_sequence(self): + seqs = {"seq1": ("", "")} + result = fast_qc(seqs) + self.assertEqual(result["seq1"], (0.0, 0, 0.0)) # Empty sequence + + def test_read_fastq(self): + with open("test.fastq", "w") as f: + f.write("@seq1\nAGCTGCTA\n+\nIIIIIIII\n") + seqs, _ = read_fastq("test.fastq") + self.assertEqual(seqs, {"@seq1": ("AGCTGCTA", "IIIIIIII")}) + os.remove("test.fastq") + + def test_write_fastq(self): + data = {"@seq1": ("AGCTGCTA", "IIIIIIII")} + write_fastq(data, "output.fastq") + with open("output.fastq") as f: + content = f.read() + expected = "@seq1\nAGCTGCTA\n+seq1\nIIIIIIII\n" + self.assertEqual(content, expected) + os.remove("output.fastq") + + def test_invalid_file(self): + with self.assertRaises(FileNotFoundError): + read_fastq("nonexistent.fastq") + + def test_logging(self): + import logging + logger = logging.getLogger(__name__) + with self.assertLogs(logger, level='INFO') as log: + logger.info("Test log message") + self.assertIn("INFO:Test log message", log.output[0]) + +if __name__ == "__main__": + unittest.main() \ No newline at end of file diff --git a/bioprogsv.py b/bioprogsv.py index c704552..7133a88 100644 --- a/bioprogsv.py +++ b/bioprogsv.py @@ -4,9 +4,10 @@ complement, reverse_complement, is_none) -from addscript.fastq_qc_function import fast_qc -from addscript.fastq_read_write_file import read_fastq, write_fastq - +from addscript.qc_tool.fastq_qc_function import fast_qc +from addscript.qc_tool.fastq_read_write_file import read_fastq, write_fastq +import argparse +import logging def run_dna_rna_tools(*args): @@ -45,34 +46,106 @@ def run_dna_rna_tools(*args): def filter_fastq( input_fastq: str, output_fastq: str, - gc_bounds: tuple[int, int] = (0, 100), - length_bounds: tuple[int, int] = (0, 2**32), + gc_bounds: tuple[int, int] | int = (0, 100), + length_bounds: tuple[int, int] | int = (0, 2**32), quality_threshold: float = 0.0 ) -> str: """ + Filters FASTQ sequences based on GC content, length, and quality thresholds. + Parameters: - input_fastq (str): Path to the input FASTQ file. - output_fastq (str): filtered FASTQ file name. - gc_bounds (tuple of int or int): Bounds for GC content filtering; - if an int, used as an upper bound. - length_bounds (tuple of int or int): Bounds for sequence length filtering; - if an int, used as an upper bound. - quality_threshold (float): Minimum quality score required for sequences to be included. + - input_fastq (str): Path to the input FASTQ file. + - output_fastq (str): Path to the filtered FASTQ file. + - gc_bounds (tuple[int, int] | int): Bounds for GC content filtering. + If an integer is provided, it is treated as the upper bound. + - length_bounds (tuple[int, int] | int): Bounds for sequence length filtering. + If an integer is provided, it is treated as the upper bound. + - quality_threshold (float): Minimum average quality score required. Returns: - str: Path to the generated FASTQ file containing the filtered sequences. + - str: Path to the generated FASTQ file containing the filtered sequences. """ - if isinstance(gc_bounds, (int)): - gc_bounds = (0, gc_bounds) - if isinstance(length_bounds, (int)): - length_bounds = (0, length_bounds) - input_fastq_data, filtered_directory = read_fastq(input_fastq) - output_fastq = filtered_directory + '/' + output_fastq - data_param = fast_qc(input_fastq_data) - output_fastq_data = {} - for sequence_name, (gc, length, quality) in data_param.items(): - if (gc_bounds[0] <= gc <= gc_bounds[1]) and \ - (length_bounds[0] <= length <= length_bounds[1]) and \ - (quality >= float(quality_threshold)): - output_fastq_data[sequence_name] = input_fastq_data[sequence_name] - return write_fastq(output_fastq_data, output_fastq) + + gc_bounds = (0, gc_bounds) if isinstance(gc_bounds, int) else gc_bounds + length_bounds = (0, length_bounds) if isinstance(length_bounds, int) else length_bounds + input_fastq_data, _ = read_fastq(input_fastq) + qc_results = fast_qc(input_fastq_data) + filtered_data = { + seq_name: seq_data + for seq_name, seq_data in input_fastq_data.items() + if ( + gc_bounds[0] <= qc_results[seq_name][0] <= gc_bounds[1] and + length_bounds[0] <= qc_results[seq_name][1] <= length_bounds[1] and + qc_results[seq_name][2] >= quality_threshold + ) + } + + write_fastq(filtered_data, output_fastq) + return output_fastq + + +# Настройка парсера аргументов +def parse_args(): + parser = argparse.ArgumentParser(description="DNA/RNA tools and FASTQ filtering.") + subparsers = parser.add_subparsers(dest="command") + + # Парсер для DNA/RNA инструментов + dna_rna_parser = subparsers.add_parser("dna_rna_tools", help="Perform DNA/RNA transformations.") + dna_rna_parser.add_argument("--seqs", nargs="+", required=True, help="List of DNA/RNA sequences.") + dna_rna_parser.add_argument("--action", choices=["transcribe", "reverse", "complement", "reverse_complement"], + required=True, help="Action to perform.") + + # Парсер для фильтрации FASTQ + fastq_parser = subparsers.add_parser("filter_fastq", help="Filter FASTQ sequences.") + fastq_parser.add_argument("input_fastq", help="Path to the input FASTQ file.") + fastq_parser.add_argument("output_fastq", help="Path to the filtered FASTQ file.") + fastq_parser.add_argument("--gc_bounds", nargs=2, type=int, default=(0, 100), + help="GC content bounds (min max).") + fastq_parser.add_argument("--length_bounds", nargs=2, type=int, default=(0, 2**32), + help="Sequence length bounds (min max).") + fastq_parser.add_argument("--quality_threshold", type=float, default=0.0, + help="Minimum average quality score.") + + return parser.parse_args() + +# Настройка логгирования +def setup_logger(log_file): + logging.basicConfig( + filename=log_file, + level=logging.INFO, + format="%(asctime)s - %(levelname)s - %(message)s" + ) + return logging.getLogger(__name__) + +# Основная программа +def main(): + args = parse_args() + logger = setup_logger("tool.log") + + try: + if args.command == "dna_rna_tools": + logger.info("Running DNA/RNA tools...") + result = run_dna_rna_tools(args.seqs, args.action) + print(result) + + elif args.command == "filter_fastq": + logger.info("Filtering FASTQ file...") + output_path = filter_fastq( + args.input_fastq, + args.output_fastq, + gc_bounds=args.gc_bounds, + length_bounds=args.length_bounds, + quality_threshold=args.quality_threshold + ) + logger.info(f"Filtered FASTQ saved to {output_path}") + + else: + logger.error("Unknown command.") + raise ValueError("Unknown command.") + + except Exception as e: + logger.error(f"An error occurred: {e}") + raise + +if __name__ == "__main__": + main() From 92ab8c06ed9bc219e8984684c60438af4246d3ea Mon Sep 17 00:00:00 2001 From: Stepanova Valeriya Date: Sat, 19 Apr 2025 11:27:31 +0300 Subject: [PATCH 2/3] add req.txt --- requirements.txt | 0 1 file changed, 0 insertions(+), 0 deletions(-) create mode 100644 requirements.txt diff --git a/requirements.txt b/requirements.txt new file mode 100644 index 0000000..e69de29 From 517eef56d618ad1a5c72025153367998acdd0ae6 Mon Sep 17 00:00:00 2001 From: Stepanova Valeriya Date: Sat, 19 Apr 2025 11:32:32 +0300 Subject: [PATCH 3/3] readme was updated --- README.md | 215 ++++++++++++++++++++++++++++++------------------------ 1 file changed, 119 insertions(+), 96 deletions(-) diff --git a/README.md b/README.md index f993596..460b857 100644 --- a/README.md +++ b/README.md @@ -1,163 +1,186 @@ +# BioProg_SV -# BIOPROG_SV +**BioProg_SV** (Biological Program by Stepnova Valeriya) is a toolkit designed for performing basic DNA/RNA sequence analysis and filtering FASTQ data based on quality metrics. The toolset includes functions for sequence transformation, filtering, and analysis. +--- -**BioProg_SV** (Biological Programm by Stepnova Valeriya) is a toolkit designed to calculate basic DNA/RNA analysis and validate DNA quality from FastQC data. - -Authors: -**Stepanova Valeria - Bioinformatics institute 2024/2025** - +## Authors -**BioProg_SV** documentation is available on the GitHub [repo](https://github.com/Stepanovalera/BioProgSV).
+- **Stepanova Valeriya** + Bioinformatics Institute, 2024–2025 +Documentation is available in the GitHub repository: [Repository Link](https://github.com/your-repo-link). -## Content +--- +## Table of Contents -* [Instructions](#instructions) -* [Example input](#examples) -* [Contact](#contact) +1. [Instructions](#instructions) +2. [Function Descriptions](#function-descriptions) +3. [Usage Examples](#usage-examples) +4. [Contact](#contact) +--- ## Instructions -### Function Descriptions -This program contains main functions: -#### `filter_fastqc()` -This function processes FastQC output data to filter and validate DNA sequences based on quality metrics. It applies multiple quality criteria to determine which sequences from a given dictionary (seqs) pass the filtering steps. The filtering criteria include: +### Installing Dependencies -**Description:** -Filters sequences in a FASTQ file based on GC content, length, and quality threshold. +If the project uses third-party libraries, install them using the `requirements.txt` file: -**Parameters:** +```bash +pip install -r requirements.txt +``` -- `input_fastq` (str): Path to the input FASTQ file. - -- `output_fastq` (str): Name of output FASTQ file. - -- `gc_bounds` (tuple or int): GC content bounds for filtering. +If the file is empty, it means the project only uses Python's standard libraries. -- `length_bounds` (tuple or int): Length bounds for filtering. +### Running the Program -- `quality_threshold`(float): Minimum average quality score for filtering. +The program supports two main modes of operation: - *GC Content Bounds*: Only sequences within the specified percentage range are retained. The GC content influences sequence stability and should fall within acceptable bounds for specific analyses. Default paramenter: `gc_bounds = (0, 100)` Input can contain a single number, which will be interpreted as the upper bound. +1. **DNA/RNA Sequence Analysis**: + ```bash + python main.py dna_rna_tools --seqs "ATG" --action transcribe + ``` - *Length Bounds*: The function checks if sequence lengths are within the specified minimum and maximum values, ensuring that only sequences of appropriate length are included. Default paramenter: `length_bounds = (0, 2**32)` Input can contain a single number, which will be interpreted as the upper bound. +2. **FASTQ File Filtering**: + ```bash + python main.py filter_fastq input.fastq output.fastq --gc_bounds 50 60 --length_bounds 50 100 --quality_threshold 30 + ``` - *Quality Threshold*: Sequences must exceed a minimum quality score, ensuring that only high-quality data are used for downstream analyses. Default paramenter: `quality_threshold = 0` +--- -**Returns:** +## Function Descriptions -output FASTA file +### 1. `filter_fastq` +This function filters sequences from a FASTQ file based on specified quality criteria. +#### Parameters: +- `input_fastq` (str): Path to the input FASTQ file. +- `output_fastq` (str): Path to the output FASTQ file. +- `gc_bounds` (tuple or int): GC content bounds (default: `(0, 100)`). If a single number is provided, it is treated as the upper bound. +- `length_bounds` (tuple or int): Sequence length bounds (default: `(0, 2**32)`). If a single number is provided, it is treated as the upper bound. +- `quality_threshold` (float): Minimum average quality score required for sequences to be included (default: `0.0`). - in-build function `fast_qc` - The function calculates: +#### Returns: +- A filtered FASTQ file containing sequences that meet the specified criteria. +--- - - GC Content: Percentage of guanine (G) and cytosine (C) in the DNA sequence. +### 2. `fast_qc` +This function calculates quality metrics for DNA/RNA sequences. - - Sequence Length: The number of bases in the DNA sequence. +#### Metrics Calculated: +- **GC Content**: Percentage of guanine (G) and cytosine (C) in the sequence. +- **Sequence Length**: Number of bases in the sequence. +- **Average Quality Score**: Mean quality score derived from Phred quality scores. +#### Parameters: +- `seqs` (dict): A dictionary where keys are sequence names, and values are tuples containing the sequence (str) and its quality string (str). - - Average Quality Score: An average quality derived from Phred quality scores +#### Returns: +- A dictionary with sequence names as keys and tuples as values. Each tuple contains: + - GC content (float) + - Sequence length (int) + - Average quality score (float) +--- -#### `convert_multiline_fasta_to_oneline(input_fasta, output_fasta)` +### 3. `convert_multiline_fasta_to_oneline` -**Description:** -This function processes a FASTA file, converting sequences that are split over multiple lines into a single line format. Each sequence starts with a header line beginning with `>`. The function ensures that every sequence is represented as a single line in the output file. +Converts a multi-line FASTA file into a single-line format. -**Parameters:** -- `input_fasta` (str): The path to the input FASTA file, where sequences may be spread across multiple lines. -- `output_fasta` (str): The reformatted FASTA file name. +#### Parameters: +- `input_fasta` (str): Path to the input FASTA file. +- `output_fasta` (str): Path to the output FASTA file. -**Returns:** -- (str): output FASTA file where sequences are converted to a one-line format. +#### Returns: +- A FASTA file where each sequence is represented as a single line. --- -#### `parse_blast_output(input_blast, output_blast)` +### 4. `parse_blast_output` -**Description:** -This function parses the output of a BLAST search, extracting relevant sequence descriptions. It starts recording after encountering the 'Description' line and continues until it reaches the first empty line. The function then saves a truncated version of each description line, containing only the portion before the ellipsis (`...`). +Parses BLAST output files to extract relevant sequence descriptions. -**Parameters:** -- `input_blast` (str): The path to the input BLAST output file, which contains the results to be parsed. -- `output_blast` (str): The file name where the parsed BLAST output will be saved. +#### Parameters: +- `input_blast` (str): Path to the input BLAST output file. +- `output_blast` (str): Path to the output file for parsed results. -**Returns:** -- (str): The path to the output file containing the parsed BLAST results. +#### Returns: +- A file containing truncated descriptions of sequences. --- -#### `select_genes_from_gbk_to_fasta(input_gbk, output_fasta, genes, n_before=1, n_after=1)` +### 5. `select_genes_from_gbk_to_fasta` -**Description:** -This function extracts protein-coding sequences from a GenBank (GBK) file and writes neighboring genes' sequences to a FASTA file, excluding the target genes themselves. It identifies genes of interest and writes their adjacent genes' sequences, defined by `n_before` and `n_after`, to the output file. +Extracts neighboring gene sequences from a GenBank (GBK) file. -**Parameters:** -- `input_gbk` (str): The path to the input GenBank file, containing the sequence data to be processed. -- `output_fasta` (str): FASTA file name where selected genes' sequences will be saved. -- `genes` (any): A list of target gene names adjacent to which the sequences will be extracted. -- `n_before` (int, optional): The number of genes before each target gene to include in the output. Defaults to 1. -- `n_after` (int, optional): The number of genes after each target gene to include in the output. Defaults to 1. +#### Parameters: +- `input_gbk` (str): Path to the input GenBank file. +- `output_fasta` (str): Path to the output FASTA file. +- `genes` (list): List of target gene names. +- `n_before` (int, optional): Number of genes before the target gene to include (default: `1`). +- `n_after` (int, optional): Number of genes after the target gene to include (default: `1`). -**Returns:** -- (str): the output FASTA file containing sequences of neighboring genes. +#### Returns: +- A FASTA file containing sequences of neighboring genes. +--- +### 6. `run_dna_rna_tools` -#### `run_dna_rna_tools() ` +Performs various DNA/RNA operations, including transcription, reverse complementation, and more. -This function perform multiple DNA/RNA operations, providing a streamlined interface to process sequences efficiently.The function is case-insensitive. +#### Supported Actions: +- `transcribe`: Converts DNA to RNA. +- `reverse`: Reverses a sequence. +- `complement`: Generates the complement of a DNA sequence. +- `reverse_complement`: Generates the reverse complement of a DNA sequence. - `is_none()` - Checks if the given sequence is empty or None. This utility function ensures that subsequent operations are performed only on valid sequences, preventing errors in data processing. - - `is_DNA()` - Validates whether the provided sequence is a DNA sequence, checking for the presence of valid DNA nucleotides (A, T, C, G). - - `is_RNA()` - Determines if the sequence is an RNA sequence by verifying the presence of valid RNA nucleotides (A, U, C, G). +#### Parameters: +- `seqs` (list): List of DNA/RNA sequences. +- `action` (str): Action to perform (e.g., `"transcribe"`, `"reverse"`). - `reverse()` - Reverses a given nucleotide sequence. - +#### Returns: +- A single sequence (if one input) or a list of processed sequences. - `reverse_complement()` - Generates the reverse complement of a DNA sequence. - +--- - `transcribe()` - Converts a DNA sequence into an RNA sequence by replacing thymine with uracil. - - - `complement()` - Produces the complement of a DNA strand by replacing each nucleotide with its complementary base. - +## Usage Examples -Each sequence is processed, and results are collected into a list. If there is only one sequence to process, the function directly returns the single result; otherwise, it returns a `list()`. +### Example 1: DNA/RNA Tools -## Examples +```python +# Transcribe DNA to RNA +run_dna_rna_tools(["ATG"], "transcribe") # Output: ["AUG"] -For `run_dna_rna_tools()`: +# Reverse a sequence +run_dna_rna_tools(["AGT"], "reverse") # Output: ["TGA"] +# Generate reverse complement +run_dna_rna_tools(["GTGT"], "reverse_complement") # Output: ["ACAC"] +``` -~~~ - run_dna_rna_tools("ATG", "transcribe") == "AUG" - run_dna_rna_tools("AGt", "ATTCC" "reverse") == "AGu" - run_dna_rna_tools("GTGT", "TGU" "complement") == "AGu" -~~~ +### Example 2: FASTQ Filtering -For `bioprogsv()`: +```python +# Filter sequences based on length +filter_fastq("input.fastq", "output.fastq", length_bounds=(50, 100)) +# Filter sequences based on GC content and quality +filter_fastq("input.fastq", "output.fastq", gc_bounds=(50, 60), quality_threshold=30) +``` -~~~ -EXAMPLE_FASTQ = { - # 'name' : ('sequence', 'quality') - '@SRX079801': ('ACAGCAACATAAACATGATGGGATGGCGTAAGCCCCCGAGATATCAGTTTACCCAGGATAAGAGATTAAATTATGAGCAACATTATTAA', 'FGGGFGGGFGGGFGDFGCEBB@CCDFDDFFFFBFFGFGEFDFFFF;D@DD>C@DDGGGDFGDGG?GFGFEGFGGEF@FDGGGFGFBGGD'), - '@SRX079802': ('ATTAGCGAGGAGGAGTGCTGAGAAGATGTCGCCTACGCCGTTGAAATTCCCTTCAATCAGGGGGTACTGGAGGATACGAGTTTGTGTG', 'BFFFFFFFB@B@A<@D>BDDACDDDEBEDEFFFBFFFEFFDFFF=CC@DDFD8FFFFFFF8/+.2,@7<<:?B/:<><-><@.A*C>D'), - '@SRX079803': ('GAACGACAGCAGCTCCTGCATAACCGCGTCCTTCTTCTTTAGCGTTGTGCAAAGCATGTTTTGTATTACGGGCATCTCGAGCGAATC', 'DFFFEGDGGGGFGGEDCCDCEFFFFCCCCCB>CEBFGFBGGG?DE=:6@=>AD?D8DCEE:>EEABE5D@5:DDCA;EEE-DCD')} +--- - filter_fastq(EXAMPLE_FASTQ, length_bounds=1) - filter_fastq(EXAMPLE_FASTQ, gc_bounds = (55, 90), quality_threshold=10) -~~~ ## Contact -Also, you can send your feedback to [ukrainskaya49@gmail.com](mailto:ukrainskaya49@gmail.com). +For questions, feedback, or suggestions, please contact: + +- Email: ukrainskaya49@gmail.com + +--- +