summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorNathan Fargo <32229490+ntfargo@users.noreply.github.com>2024-06-16 12:37:07 +0200
committerNathan Fargo <32229490+ntfargo@users.noreply.github.com>2024-06-16 12:37:07 +0200
commit89e4462af83daf4f4f03ad39a9310d7951384dad (patch)
tree9f71f61e669a9c2c235e05b9958020d2cede8246
parent62e1e48b30bf07889a8c313291415ab90036f72e (diff)
Minor changes.
-rw-r--r--SequenceViewer/app/routes.py85
-rw-r--r--SequenceViewer/app/sequence_tools.py78
-rw-r--r--SequenceViewer/app/static/genview.css10
-rw-r--r--SequenceViewer/app/templates/view.html99
-rw-r--r--SequenceViewer/example.fasta4
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 &copy; 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