diff options
author | Nathan Fargo <32229490+ntfargo@users.noreply.github.com> | 2024-06-16 12:37:07 +0200 |
---|---|---|
committer | Nathan Fargo <32229490+ntfargo@users.noreply.github.com> | 2024-06-16 12:37:07 +0200 |
commit | 89e4462af83daf4f4f03ad39a9310d7951384dad (patch) | |
tree | 9f71f61e669a9c2c235e05b9958020d2cede8246 | |
parent | 62e1e48b30bf07889a8c313291415ab90036f72e (diff) |
Minor changes.
-rw-r--r-- | SequenceViewer/app/routes.py | 85 | ||||
-rw-r--r-- | SequenceViewer/app/sequence_tools.py | 78 | ||||
-rw-r--r-- | SequenceViewer/app/static/genview.css | 10 | ||||
-rw-r--r-- | SequenceViewer/app/templates/view.html | 99 | ||||
-rw-r--r-- | SequenceViewer/example.fasta | 4 |
5 files changed, 139 insertions, 137 deletions
diff --git a/SequenceViewer/app/routes.py b/SequenceViewer/app/routes.py index 2ee9c46..9e9bad7 100644 --- a/SequenceViewer/app/routes.py +++ b/SequenceViewer/app/routes.py @@ -3,7 +3,7 @@ from Bio import SeqIO from GenoFusion.Utils import get_sequence_properties import os from app import app -from .sequence_tools import translate_sequence, find_enzyme_sites +from .sequence_tools import translate_sequence, find_enzyme_sites, get_color_for_enzyme, enzyme_groups @app.route('/') def index(): @@ -29,66 +29,51 @@ def view_file(filename): sequences = [] with open(filepath, "r") as handle: - if file_type in ['fasta', 'fa']: - for record in SeqIO.parse(handle, "fasta"): - sequence_str = str(record.seq) - highlighted_sequence, enzyme_sites = find_enzyme_sites(sequence_str, selected_group='All Commercial') - sequence_properties = get_sequence_properties(sequence_str) - amino_acid_sequence = translate_sequence(sequence_str) - sequences.append({ - "id": record.id, - "sequence": sequence_str, - "highlighted_sequence": highlighted_sequence, - "amino_acid_sequence": amino_acid_sequence, - "features": enzyme_sites, - "properties": sequence_properties - }) - elif file_type in ['fastq']: - for record in SeqIO.parse(handle, "fastq"): - sequence_str = str(record.seq) - highlighted_sequence, enzyme_sites = find_enzyme_sites(sequence_str, selected_group='All Commercial') - sequence_properties = get_sequence_properties(sequence_str) - amino_acid_sequence = translate_sequence(sequence_str) - sequences.append({ - "id": record.id, - "highlighted_sequence": highlighted_sequence, - "amino_acid_sequence": amino_acid_sequence, - "features": enzyme_sites, - "properties": sequence_properties - }) - elif file_type in ['gb', 'genbank']: - for record in SeqIO.parse(handle, "genbank"): - sequence_str = str(record.seq) - highlighted_sequence, enzyme_sites = find_enzyme_sites(sequence_str, selected_group='All Commercial') - features = [f"{feature.type}: {feature.location}" for feature in record.features] - features.extend([f"{enzyme} site at {start}-{end}" for enzyme, start, end in enzyme_sites]) - sequence_properties = get_sequence_properties(sequence_str) - amino_acid_sequence = translate_sequence(sequence_str) - sequences.append({ - "id": record.id, - "highlighted_sequence": highlighted_sequence, - "amino_acid_sequence": amino_acid_sequence, - "features": features, - "properties": sequence_properties - }) + for record in SeqIO.parse(handle, file_type): + sequence_str = str(record.seq) + highlighted_sequence, enzyme_sites = find_enzyme_sites(sequence_str, selected_group='All Commercial') + sequence_properties = get_sequence_properties(sequence_str) + amino_acid_sequence = translate_sequence(sequence_str) + sequences.append({ + "id": record.id, + "sequence": sequence_str, + "highlighted_sequence": highlighted_sequence, + "amino_acid_sequence": amino_acid_sequence, + "features": enzyme_sites, + "properties": sequence_properties + }) - selected_enzyme_type = request.args.get('enzyme_type', 'All Commercial') + selected_enzyme_type = request.args.get('enzyme_type', '6+ Cutters') filtered_sequences = [] for sequence in sequences: filtered_features = [] - for feature in sequence['features']: - if selected_enzyme_type == 'All Commercial' or selected_enzyme_type in feature[0]: - filtered_features.append(feature) + enzyme_objects = [] + for enzyme_info in sequence['features']: + enzyme = enzyme_info[0] + start = enzyme_info[1] + end = enzyme_info[2] + color = get_color_for_enzyme(enzyme.__name__) + if selected_enzyme_type == 'Fermentas' or selected_enzyme_type in enzyme_groups or selected_enzyme_type in enzyme.__class__.__name__: + filtered_features.append((enzyme, start, end, color)) + enzyme_objects.append({ + "name": enzyme.__name__, + "rseq": enzyme.site, + "fcut": 0, + "rcut": len(enzyme.site), + "color": color + }) sequence['features'] = filtered_features + sequence['enzyme_objects'] = enzyme_objects filtered_sequences.append(sequence) sequences_data = [{ 'id': sequence['id'], 'description': '', - 'sequence': sequence['highlighted_sequence'], + 'sequence': sequence.get('sequence', ''), 'amino_acid_sequence': sequence['amino_acid_sequence'], - 'features': sequence['features'] + 'features': sequence['features'], + 'enzyme_objects': sequence['enzyme_objects'] } for sequence in filtered_sequences] - return render_template('view.html', sequences=sequences_data, filename=filename)
\ No newline at end of file + return render_template('view.html', sequences=sequences_data, filename=filename) diff --git a/SequenceViewer/app/sequence_tools.py b/SequenceViewer/app/sequence_tools.py index 6239f0b..5fb2db5 100644 --- a/SequenceViewer/app/sequence_tools.py +++ b/SequenceViewer/app/sequence_tools.py @@ -1,22 +1,29 @@ +import random from Bio.Seq import Seq -from Bio.Restriction import AllEnzymes, CommOnly, RestrictionBatch +from Bio.Restriction import AllEnzymes, CommOnly -# Manually define enzymes for groups that cannot be filtered programmatically -NEB_enzymes = ['EcoRI', 'BamHI', 'HindIII'] # Example list, expand as needed -Fermentas_enzymes = ['BglII', 'EcoRV', 'HindIII'] # Example list, expand as needed +# Define groups of enzymes +NEB_enzymes = ['EcoRI', 'BamHI', 'HindIII'] +Fermentas_enzymes = ['BglII', 'EcoRV', 'HindIII'] +# Functions to categorize enzymes def is_unique(enzyme): + """Check if an enzyme recognizes a unique sequence in a 10kb sequence of 'A's.""" return len(enzyme.search(Seq("A" * 10000))) == 1 def is_double_cutter(enzyme): + """Check if an enzyme recognizes exactly two sites in a 10kb sequence of 'A's.""" return len(enzyme.search(Seq("A" * 10000))) == 2 def is_type_iis(enzyme): + """Check if an enzyme is a Type IIS enzyme.""" return enzyme.elucidate().startswith("^") or enzyme.elucidate().endswith("^") def is_nicking(enzyme): + """Check if an enzyme is a nicking endonuclease.""" return "Nicking" in enzyme.__class__.__name__ - + +# Group enzymes based on properties enzyme_groups = { "All Commercial": CommOnly, "Nonredundant Commercial": CommOnly, # This should be updated with a proper list if available @@ -31,7 +38,22 @@ enzyme_groups = { "Nicking Endonucleases": [enzyme for enzyme in AllEnzymes if is_nicking(enzyme)] } +# Define colors for enzyme highlighting +colors = [ + "red", "green", "blue", "yellow", "orange", "purple", "cyan", "magenta", "lime", "pink", + "teal", "lavender", "brown", "beige", "maroon", "mint", "olive", "coral", "navy", "grey" +] + +enzyme_colors = {} + +def get_color_for_enzyme(enzyme_name): + """Assign a random color to each enzyme for highlighting.""" + if enzyme_name not in enzyme_colors: + enzyme_colors[enzyme_name] = random.choice(colors) + return enzyme_colors[enzyme_name] + def get_enzyme_sites(sequence, enzymes): + """Find enzyme recognition sites in a given DNA sequence.""" enzyme_sites = [] for enzyme in enzymes: for site in enzyme.search(sequence): @@ -40,35 +62,51 @@ def get_enzyme_sites(sequence, enzymes): return enzyme_sites def translate_sequence(nucleotide_sequence): + """Translate a nucleotide sequence into a protein sequence.""" sequence = Seq(nucleotide_sequence) return str(sequence.translate()) def find_enzyme_sites(sequence_str, selected_group): + """Highlight enzyme recognition sites in a DNA sequence.""" if selected_group in enzyme_groups: enzymes = enzyme_groups[selected_group] else: - enzymes = AllEnzymes # Fallback to AllEnzymes if group not found - - restriction_batch = RestrictionBatch(enzymes) - - enzyme_sites = [] - for enzyme in restriction_batch: - seq_obj = Seq(sequence_str) - - sites = enzyme.search(seq_obj) - for site in sites: - enzyme_sites.append((enzyme, site, site + len(enzyme.site))) - - enzyme_sites.sort(key=lambda x: x[1]) + enzymes = AllEnzymes # Default to all enzymes if group not found + enzyme_sites = get_enzyme_sites(Seq(sequence_str), enzymes) highlighted_sequence = "" last_end = 0 for enzyme, start, end in enzyme_sites: highlighted_sequence += sequence_str[last_end:start] - highlighted_sequence += f'<span class="enzyme" data-enzyme="{enzyme}">{sequence_str[start:end]}</span>' + highlighted_sequence += f'<span class="enzyme" data-enzyme="{enzyme}" style="background-color:{get_color_for_enzyme(enzyme.__name__)}">{sequence_str[start:end]}</span>' last_end = end highlighted_sequence += sequence_str[last_end:] - return highlighted_sequence, enzyme_sites
\ No newline at end of file + return highlighted_sequence, enzyme_sites + +def get_sequence_properties(sequence_str): + """Calculate basic properties of a DNA sequence.""" + sequence = Seq(sequence_str) + gc_content = (sequence.count("G") + sequence.count("C")) / len(sequence) * 100 + return { + "length": len(sequence), + "gc_content": gc_content + } + +# Example usage: +sequence = "ATGCGTACG" +selected_group = "Fermentas" + +highlighted_sequence, enzyme_sites = find_enzyme_sites(sequence, selected_group) +sequence_properties = get_sequence_properties(sequence) + +print("Highlighted Sequence:") +print(highlighted_sequence) +print("\nEnzyme Sites:") +for enzyme, start, end in enzyme_sites: + print(f"{enzyme.__name__} cuts at position {start}-{end}") + +print("\nSequence Properties:") +print(sequence_properties) diff --git a/SequenceViewer/app/static/genview.css b/SequenceViewer/app/static/genview.css index ea31ff1..5c73952 100644 --- a/SequenceViewer/app/static/genview.css +++ b/SequenceViewer/app/static/genview.css @@ -193,15 +193,7 @@ hr { margin: 0 auto; padding: 0 15px; box-sizing: border-box; -} - -.view { - display: flex; - flex-direction: column; - align-items: center; - justify-content: center; - height: 100vh; /* Optional: This will make the container take up the full height of the viewport */ -} +} .enzyme { background-color: transparent; diff --git a/SequenceViewer/app/templates/view.html b/SequenceViewer/app/templates/view.html index ea1f638..6173d55 100644 --- a/SequenceViewer/app/templates/view.html +++ b/SequenceViewer/app/templates/view.html @@ -5,68 +5,57 @@ <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>View Sequences - {{ filename }}</title> <link rel="stylesheet" href="{{ url_for('static', filename='genview.css') }}"> + <script src="https://unpkg.com/seqviz"></script> + <style> + .enzyme { + color: black; + border: 1px solid red; + padding: 2px; + } + </style> </head> <body> - <div class="container view"> + <div class="container"> <h1>Viewing Sequences from {{ filename }}</h1> <a href="{{ url_for('index') }}">View Another File</a> <hr> - <div> - <button onclick="filterEnzymes('All Commercial')">All Commercial</button> + {% for record in sequences %} + <div class="sequence-container"> + <div style="overflow: hidden;" id="seqviz-{{ record.id }}"></div> + <script> + window.seqviz.Viewer("seqviz-{{ record.id }}", { + name: "{{ record.id }}", + seq: "{{ record.sequence|safe }}", + style: { height: "65vh", width: "65vw", color: "white" }, + bpColors: { A: "white", T: "white", G: "white", C: "white" }, + highlights: [ + {% for enzyme, start, end, color in record.features %} + { start: {{ start }}, end: {{ end }}, color: "{{ color }}" }, + {% endfor %} + ], + enzymes: [ + {% for enzyme in record.enzyme_objects %} + { + name: "{{ enzyme.name }}", + rseq: "{{ enzyme.rseq }}", + fcut: {{ enzyme.fcut }}, + rcut: {{ enzyme.rcut }}, + color: "{{ enzyme.color }}" + }, + {% endfor %} + ], + viewer: "both_flip" + }).render(); + </script> + <hr> </div> - <hr> - <ul> - {% for record in sequences %} - <li id="{{ record.id }}"> - <strong>ID: {{ record.id }}</strong><br> - <pre>{{ record.sequence|safe }}</pre> - <h3>Amino Acid Sequence</h3> - <pre>{{ record.amino_acid_sequence }}</pre> - <div class="details" id="details-{{ record.id }}"> - <h3>Features</h3> - <button class="close-details">Close</button> - <ul> - {% for feature in record.features %} - <li> - <a href="#{{ record.id }}"> - {{ feature[0] }} at position {{ feature[1] }}-{{ feature[2] }} - </a> - </li> - {% endfor %} - </ul> - </div> - </li> {% endfor %} </div> - <script> - document.querySelectorAll('.enzyme').forEach(function(el) { - el.addEventListener('click', function() { - const id = this.closest('li').id; - const details = document.getElementById('details-' + id); - if (details.style.display === 'none' || details.style.display === '') { - details.style.display = 'block'; - } else { - details.style.display = 'none'; - } - }); - }); - - document.querySelectorAll('.close-details').forEach(function(el) { - el.addEventListener('click', function() { - this.parentElement.style.display = 'none'; - }); - }); - - function highlightFeature(id, start, end) { - const sequence = document.querySelector('#' + id + ' pre'); - const text = sequence.textContent; - const before = text.slice(0, start); - const feature = text.slice(start, end); - const after = text.slice(end); - - sequence.innerHTML = `${before}<span class="highlight">${feature}</span>${after}`; - window.location.hash = id; - } - </script> + <footer> + <center> + <img src="{{ url_for('static', filename='img/LFX-genofusionv.png') }}" alt="Logo" width="100px"> + <p>2024 © Linear Fox, Sequences Viewer (open source under Apache License)</p> + </center> + </footer> </body> </html> diff --git a/SequenceViewer/example.fasta b/SequenceViewer/example.fasta index c01aa78..3c76530 100644 --- a/SequenceViewer/example.fasta +++ b/SequenceViewer/example.fasta @@ -1,4 +1,2 @@ >Sequence_1 -GGATCCGCGGCCGCAAGCTTGAATTCCGCGGCCGCAAGCTTGAATTCCGCGGCCGCAAGCTTGAATTCCGCGGCCGCAAGCTTGAATTC ->Sequence_2 -AGCTTGCGGCCGCGGATCCAGCTTGAATTCGCGGCCGCGGATCCAGCTTGAATTCGCGGCCGCGGATCCAGCTTGAATTCGCGGCCGC
\ No newline at end of file +CGCATAGTGAGAGTTACATGTTCGTTGGGCTCTTCCGACACGAACCTCAG
\ No newline at end of file |