In this tutorial, we demonstrate how to build an advanced yet accessible Bioinformatics AI Agent using Biopython and popular Python libraries, designed to run seamlessly in Google Colab. By combining sequence retrieval, molecular analysis, visualization, multiple sequence alignment, phylogenetic tree construction, and motif searches into a single streamlined class, the tutorial provides a hands-on approach to explore the full spectrum of biological sequence analysis. Users can start with built-in sample sequences such as the SARS-CoV-2 Spike protein, Human Insulin precursor, and E. coli 16S rRNA, or fetch custom sequences directly from NCBI. With built-in visualization tools powered by Plotly and Matplotlib, researchers and students alike can quickly perform comprehensive DNA and protein analyses without needing prior setup beyond a Colab notebook. Check out the FULL CODES here.
!pip install biopython pandas numpy matplotlib seaborn plotly requests beautifulsoup4 scipy scikit-learn networkx !apt-get update !apt-get install -y clustalw import os import requests import pandas as pd import numpy as np import matplotlib.pyplot as plt import seaborn as sns import plotly.express as px import plotly.graph_objects as go from plotly.subplots import make_subplots from Bio import SeqIO, Entrez, Align, Phylo from Bio.Seq import Seq from Bio.SeqRecord import SeqRecord from Bio.SeqUtils import gc_fraction, molecular_weight from Bio.SeqUtils.ProtParam import ProteinAnalysis from Bio.Blast import NCBIWWW, NCBIXML from Bio.Phylo.TreeConstruction import DistanceCalculator, DistanceTreeConstructor import warnings warnings.filterwarnings('ignore') Entrez.email = "[email protected]"
We begin by installing essential bioinformatics and data science libraries, along with ClustalW for sequence alignment. We then import Biopython modules, visualization tools, and supporting packages, while setting up Entrez with our email to fetch sequences from NCBI. This ensures our Colab environment is fully prepared for advanced sequence analysis. Check out the FULL CODES here.
class BioPythonAIAgent: def __init__(self, email="[email protected]"): self.email = email Entrez.email = email self.sequences = {} self.analysis_results = {} self.alignments = {} self.trees = {} def fetch_sequence_from_ncbi(self, accession_id, db="nucleotide", rettype="fasta"): try: handle = Entrez.efetch(db=db, id=accession_id, rettype=rettype, retmode="text") record = SeqIO.read(handle, "fasta") handle.close() self.sequences[accession_id] = record return record except Exception as e: print(f"Error fetching sequence: {str(e)}") return None def create_sample_sequences(self): covid_spike = "MFVFLVLLPLVSSQCVNLTTRTQLPPAYTNSFTRGVYYPDKVFRSSVLHSTQDLFLPFFSNVTWFHAIHVSGTNGTKRFDNPVLPFNDGVYFASTEKSNIIRGWIFGTTLDSKTQSLLIVNNATNVVIKVCEFQFCNDPFLGVYYHKNNKSWMESEFRVYSSANNCTFEYVSQPFLMDLEGKQGNFKNLREFVFKNIDGYFKIYSKHTPINLVRDLPQGFSALEPLVDLPIGINITRFQTLLALHRSYLTPGDSSSGWTAGAAAYYVGYLQPRTFLLKYNENGTITDAVDCALDPLSETKCTLKSFTVEKGIYQTSNFRVQPTESIVRFPNITNLCPFGEVFNATRFASVYAWNRKRISNCVADYSVLYNSASFSTFKCYGVSPTKLNDLCFTNVYADSFVIRGDEVRQIAPGQTGKIADYNYKLPDDFTGCVIAWNSNNLDSKVGGNYNYLYRLFRKSNLKPFERDISTEIYQAGSTPCNGVEGFNCYFPLQSYGFQPTNGVGYQPYRVVVLSFELLHAPATVCGPKKSTNLVKNKCVNFNFNGLTGTGVLTESNKKFLPFQQFGRDIADTTDAVRDPQTLEILDITPCSFGGVSVITPGTNTSNQVAVLYQDVNCTEVPVAIHADQLTPTWRVYSTGSNVFQTRAGCLIGAEHVNNSYECDIPIGAGICASYQTQTNSPRRARSVASQSIIAYTMSLGAENSVAYSNNSIAIPTNFTISVTTEILPVSMTKTSVDCTMYICGDSTECSNLLLQYGSFCTQLNRALTGIAVEQDKNTQEVFAQVKQIYKTPPIKDFGGFNFSQILPDPSKPSKRSFIEDLLFNKVTLADAGFIKQYGDCLGDIAARDLICAQKFNGLTVLPPLLTDEMIAQYTSALLAGTITSGWTFGAGAALQIPFAMQMAYRFNGIGVTQNVLYENQKLIANQFNSAIGKIQDSLSSTASALGKLQDVVNQNAQALNTLVKQLSSNFGAISSVLNDILSRLDKVEAEVQIDRLITGRLQSLQTYVTQQLIRAAEIRASANLAATKMSECVLGQSKRVDFCGKGYHLMSFPQSAPHGVVFLHVTYVPAQEKNFTTAPAICHDGKAHFPREGVFVSNGTHWFVTQRNFYEPQIITTDNTFVSGNCDVVIGIVNNTVYDPLQPELDSFKEELDKYFKNHTSPDVDLGDISGINASVVNIQKEIDRLNEVAKNLNESLIDLQELGKYEQYIKWPWYIWLGFIAGLIAIVMVTIMLCCMTSCCSCLKGCCSCGSCCKFDEDDSEPVLKGVKLHYT" human_insulin = "MALWMRLLPLLALLALWGPDPAAAFVNQHLCGSHLVEALYLVCGERGFFYTPKTRREAEDLQVGQVELGGGPGAGSLQPLALEGSLQKRGIVEQCCTSICSLYQLENYCN" e_coli_16s = "AAATTGAAGAGTTTGATCATGGCTCAGATTGAACGCTGGCGGCAGGCCTAACACATGCAAGTCGAACGGTAACAGGAAGCAGCTTGCTGCTTTGCTGACGAGTGGCGGACGGGTGAGTAATGTCTGGGAAACTGCCTGATGGAGGGGGATAACTACTGGAAACGGTAGCTAATACCGCATAATGTCGCAAGACCAAAGAGGGGGACCTTCGGGCCTCTTGCCATCGGATGTGCCCAGATGGGATTAGCTAGTAGGTGGGGTAACGGCTCACCTAGGCGACGATCCCTAGCTGGTCTGAGAGGATGACCAGCCACACTGGAACTGAGACACGGTCCAGACTCCTACGGGAGGCAGCAGTGGGGAATATTGCACAATGGGCGCAAGCCTGATGCAGCCATGCCGCGTGTATGAAGAAGGCCTTCGGGTTGTAAAGTACTTTCAGCGGGGAGGAAGGCGTTAAGGTTAATAACCTTGGCGATTGACGTTACCCGCAGAAGAAGCACCGGCTAACTCCGTGCCAGCAGCCGCGGTAATACGGAGGGTGCAAGCGTTAATCGGAATTACTGGGCGTAAAGCGCACGCAGGCGGTCTGTCAAGTCGGATGTGAAATCCCCGGGCTCAACCTGGGAACTGCATCTGATACTGGCAAGCTTGAGTCTCGTAGAGGGGGGTAGAATTCCAGGTGTAGCGGTGAAATGCGTAGAGATCTGGAGGAATACCGGTGGCGAAGGCGGCCCCCTGGACAAAGACTGACGCTCAGGTGCGAAAGCGTGGGGAGCAAACA" sample_sequences = [ ("COVID_Spike", covid_spike, "SARS-CoV-2 Spike Protein"), ("Human_Insulin", human_insulin, "Human Insulin Precursor"), ("E_coli_16S", e_coli_16s, "E. coli 16S rRNA") ] for seq_id, seq_str, desc in sample_sequences: record = SeqRecord(Seq(seq_str), id=seq_id, description=desc) self.sequences[seq_id] = record return sample_sequences def analyze_sequence(self, sequence_id=None, sequence=None): if sequence_id and sequence_id in self.sequences: seq_record = self.sequences[sequence_id] seq = seq_record.seq description = seq_record.description elif sequence: seq = Seq(sequence) description = "Custom sequence" else: return None analysis = { 'length': len(seq), 'composition': {} } for base in ['A', 'T', 'G', 'C']: analysis['composition'][base] = seq.count(base) if 'A' in analysis['composition'] and 'T' in analysis['composition']: analysis['gc_content'] = round(gc_fraction(seq) * 100, 2) try: analysis['molecular_weight'] = round(molecular_weight(seq, seq_type='DNA'), 2) except: analysis['molecular_weight'] = len(seq) * 650 try: if len(seq) % 3 == 0: protein = seq.translate() analysis['translation'] = str(protein) analysis['stop_codons'] = protein.count('*') if '*' not in str(protein)[:-1]: prot_analysis = ProteinAnalysis(str(protein)[:-1]) analysis['protein_mw'] = round(prot_analysis.molecular_weight(), 2) analysis['isoelectric_point'] = round(prot_analysis.isoelectric_point(), 2) analysis['protein_composition'] = prot_analysis.get_amino_acids_percent() except: pass key = sequence_id if sequence_id else "custom" self.analysis_results[key] = analysis return analysis def visualize_composition(self, sequence_id): if sequence_id not in self.analysis_results: return analysis = self.analysis_results[sequence_id] fig = make_subplots( rows=2, cols=2, specs=[[{"type": "pie"}, {"type": "bar"}], [{"colspan": 2}, None]], subplot_titles=("Nucleotide Composition", "Base Count", "Sequence Properties") ) labels = list(analysis['composition'].keys()) values = list(analysis['composition'].values()) fig.add_trace( go.Pie(labels=labels, values=values, name="Composition"), row=1, col=1 ) fig.add_trace( go.Bar(x=labels, y=values, name="Count", marker_color=['red', 'blue', 'green', 'orange']), row=1, col=2 ) properties = ['Length', 'GC%', 'MW (kDa)'] prop_values = [ analysis['length'], analysis.get('gc_content', 0), analysis.get('molecular_weight', 0) / 1000 ] fig.add_trace( go.Scatter(x=properties, y=prop_values, mode='markers+lines', marker=dict(size=10, color='purple'), name="Properties"), row=2, col=1 ) fig.update_layout( title=f"Comprehensive Analysis: {sequence_id}", showlegend=False, height=600 ) fig.show() def perform_multiple_sequence_alignment(self, sequence_ids): if len(sequence_ids) < 2: return None sequences = [] for seq_id in sequence_ids: if seq_id in self.sequences: sequences.append(self.sequences[seq_id]) if len(sequences) < 2: return None from Bio.Align import PairwiseAligner aligner = PairwiseAligner() aligner.match_score = 2 aligner.mismatch_score = -1 aligner.open_gap_score = -2 aligner.extend_gap_score = -0.5 alignments = [] for i in range(len(sequences)): for j in range(i+1, len(sequences)): alignment = aligner.align(sequences[i].seq, sequences[j].seq)[0] alignments.append(alignment) return alignments def create_phylogenetic_tree(self, alignment_key=None, sequences=None): if alignment_key and alignment_key in self.alignments: alignment = self.alignments[alignment_key] elif sequences: records = [] for i, seq in enumerate(sequences): record = SeqRecord(Seq(seq), id=f"seq_{i}") records.append(record) SeqIO.write(records, "temp.fasta", "fasta") try: clustalw_cline = ClustalwCommandline("clustalw2", infile="temp.fasta") stdout, stderr = clustalw_cline() alignment = AlignIO.read("temp.aln", "clustal") os.remove("temp.fasta") os.remove("temp.aln") os.remove("temp.dnd") except: return None else: return None calculator = DistanceCalculator('identity') dm = calculator.get_distance(alignment) constructor = DistanceTreeConstructor() tree = constructor.upgma(dm) tree_key = f"tree_{len(self.trees)}" self.trees[tree_key] = tree return tree def visualize_tree(self, tree): fig, ax = plt.subplots(figsize=(10, 6)) Phylo.draw(tree, axes=ax) plt.title("Phylogenetic Tree") plt.tight_layout() plt.show() def protein_structure_analysis(self, sequence_id): if sequence_id not in self.sequences: return None seq = self.sequences[sequence_id].seq try: if len(seq) % 3 == 0: protein = seq.translate() if '*' not in str(protein)[:-1]: prot_analysis = ProteinAnalysis(str(protein)[:-1]) structure_analysis = { 'molecular_weight': prot_analysis.molecular_weight(), 'isoelectric_point': prot_analysis.isoelectric_point(), 'amino_acid_percent': prot_analysis.get_amino_acids_percent(), 'secondary_structure': prot_analysis.secondary_structure_fraction(), 'flexibility': prot_analysis.flexibility(), 'gravy': prot_analysis.gravy() } return structure_analysis except: pass return None def comparative_analysis(self, sequence_ids): results = [] for seq_id in sequence_ids: if seq_id in self.analysis_results: analysis = self.analysis_results[seq_id].copy() analysis['sequence_id'] = seq_id results.append(analysis) df = pd.DataFrame(results) if len(df) > 1: fig = make_subplots( rows=2, cols=2, subplot_titles=("Length Comparison", "GC Content", "Molecular Weight", "Composition Heatmap") ) fig.add_trace( go.Bar(x=df['sequence_id'], y=df['length'], name="Length"), row=1, col=1 ) if 'gc_content' in df.columns: fig.add_trace( go.Scatter(x=df['sequence_id'], y=df['gc_content'], mode='markers+lines', name="GC%"), row=1, col=2 ) if 'molecular_weight' in df.columns: fig.add_trace( go.Bar(x=df['sequence_id'], y=df['molecular_weight'], name="MW"), row=2, col=1 ) fig.update_layout(title="Comparative Sequence Analysis", height=600) fig.show() return df def codon_usage_analysis(self, sequence_id): if sequence_id not in self.sequences: return None seq = self.sequences[sequence_id].seq if len(seq) % 3 != 0: return None codons = {} for i in range(0, len(seq) - 2, 3): codon = str(seq[i:i+3]) codons[codon] = codons.get(codon, 0) + 1 codon_df = pd.DataFrame(list(codons.items()), columns=['Codon', 'Count']) codon_df = codon_df.sort_values('Count', ascending=False) fig = px.bar(codon_df.head(20), x='Codon', y='Count', title=f"Top 20 Codon Usage - {sequence_id}") fig.show() return codon_df def motif_search(self, sequence_id, motif_pattern): if sequence_id not in self.sequences: return [] seq = str(self.sequences[sequence_id].seq) positions = [] for i in range(len(seq) - len(motif_pattern) + 1): if seq[i:i+len(motif_pattern)] == motif_pattern: positions.append(i) return positions def gc_content_window(self, sequence_id, window_size=100): if sequence_id not in self.sequences: return None seq = self.sequences[sequence_id].seq gc_values = [] positions = [] for i in range(0, len(seq) - window_size + 1, window_size//4): window = seq[i:i+window_size] gc_values.append(gc_fraction(window) * 100) positions.append(i + window_size//2) fig = go.Figure() fig.add_trace(go.Scatter(x=positions, y=gc_values, mode='lines+markers', name=f'GC Content (window={window_size})')) fig.update_layout( title=f"GC Content Sliding Window Analysis - {sequence_id}", xaxis_title="Position", yaxis_title="GC Content (%)" ) fig.show() return positions, gc_values def run_comprehensive_analysis(self, sequence_ids): results = {} for seq_id in sequence_ids: if seq_id in self.sequences: analysis = self.analyze_sequence(seq_id) self.visualize_composition(seq_id) gc_analysis = self.gc_content_window(seq_id) codon_analysis = self.codon_usage_analysis(seq_id) results[seq_id] = { 'basic_analysis': analysis, 'gc_window': gc_analysis, 'codon_usage': codon_analysis } if len(sequence_ids) > 1: comparative_df = self.comparative_analysis(sequence_ids) results['comparative'] = comparative_df return results
We define a BioPython AIAgent that allows us to fetch or create sequences, run core analyses (composition, GC%, translation, and protein properties), and visualize results interactively. We also perform pairwise alignments, build phylogenetic trees, scan motifs, profile codon usage, analyze GC with sliding windows, and compare multiple sequences—then bundle everything into one comprehensive pipeline. Check out the FULL CODES here.
agent = BioPythonAIAgent() sample_seqs = agent.create_sample_sequences() for seq_id, _, _ in sample_seqs: agent.analyze_sequence(seq_id) results = agent.run_comprehensive_analysis(['COVID_Spike', 'Human_Insulin', 'E_coli_16S']) print("BioPython AI Agent Tutorial Complete!") print("Available sequences:", list(agent.sequences.keys())) print("Available methods:", [method for method in dir(agent) if not method.startswith('_')])
We instantiate the BioPythonAIAgent, generate sample sequences (COVID Spike, Human Insulin, and E. coli 16S), and run a full analysis pipeline. The outputs confirm that our agent successfully performs nucleotide, codon, and GC-content analyses while also preparing comparative visualizations. Finally, we print the list of available sequences and supported methods, indicating that the agent’s full analytical capabilities are now ready for use. Check out the FULL CODES here.
agent.visualize_composition('COVID_Spike') agent.gc_content_window('E_coli_16S', window_size=50) agent.codon_usage_analysis('COVID_Spike') comparative_df = agent.comparative_analysis(['COVID_Spike', 'Human_Insulin', 'E_coli_16S']) print(comparative_df) motif_positions = agent.motif_search('COVID_Spike', 'ATG') print(f"ATG start codons found at positions: {motif_positions}") tree = agent.create_phylogenetic_tree(sequences=[ str(agent.sequences['COVID_Spike'].seq[:300]), str(agent.sequences['Human_Insulin'].seq[:300]), str(agent.sequences['E_coli_16S'].seq[:300]) ]) if tree: agent.visualize_tree(tree)
We visualize nucleotide composition, scan E. coli 16S GC% in sliding windows, and profile codon usage for the COVID Spike sequence. We then compare sequences side-by-side, search for the “ATG” motif, and build/plot a quick phylogenetic tree from the first 300 nt of each sequence.
In conclusion, we have a fully functional BioPython AI Agent capable of handling multiple layers of sequence analysis, from basic nucleotide composition to codon usage profiling, GC-content sliding windows, motif searches, and even comparative analyses across species. The integration of visualization and phylogenetic tree construction provides both intuitive and in-depth insights into genetic data. Whether for academic projects, bioinformatics education, or research prototyping, this Colab-friendly workflow showcases how open-source tools like Biopython can be harnessed with modern AI-inspired pipelines to simplify and accelerate biological data exploration.
Check out the FULL CODES here. Feel free to check out our GitHub Page for Tutorials, Codes and Notebooks. Also, feel free to follow us on Twitter and don’t forget to join our 100k+ ML SubReddit and Subscribe to our Newsletter.
Asif Razzaq
Asif Razzaq is the CEO of Marktechpost Media Inc.. As a visionary entrepreneur and engineer, Asif is committed to harnessing the potential of Artificial Intelligence for social good. His most recent endeavor is the launch of an Artificial Intelligence Media Platform, Marktechpost, which stands out for its in-depth coverage of machine learning and deep learning news that is both technically sound and easily understandable by a wide audience. The platform boasts of over 2 million monthly views, illustrating its popularity among audiences.