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 clustalwimport osimport requestsimport pandas as pdimport numpy as npimport matplotlib.pyplot as pltimport seaborn as snsimport plotly.express as pximport plotly.graph_objects as gofrom plotly.subplots import make_subplotsfrom Bio import SeqIO, Entrez, Align, Phylofrom Bio.Seq import Seqfrom Bio.SeqRecord import SeqRecordfrom Bio.SeqUtils import gc_fraction, molecular_weightfrom Bio.SeqUtils.ProtParam import ProteinAnalysisfrom Bio.Blast import NCBIWWW, NCBIXMLfrom Bio.Phylo.TreeConstruction import DistanceCalculator, DistanceTreeConstructorimport warningswarnings.filterwarnings('ignore')Entrez.email = "your_email@example.com"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="your_email@example.com"): 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 resultsWe 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.
The post How to Create a Bioinformatics AI Agent Using Biopython for DNA and Protein Analysis appeared first on MarkTechPost.
