CoolFace
Apppublic

farshidk/codon-optimizer

sourceHugging Facemitupdated 7mo agoView on Hugging Face
1likes
app.py160 linesDownload Raw Back to root
1import os2import gradio as gr3import pandas as pd4# from optimizer import optimization5from c_wobble import do_c_wobble, change_codon, aminoacid_percentage, gc_content, c_content6 7BASE_DIR = os.path.dirname(__file__)8SUMMARY_PATH = os.path.join(BASE_DIR, "region_sweep_summary.csv")9 10AA_ORDER = list("ACDEFGHIKLMNPQRSTVWY*")11AA_ALLOWED = set(AA_ORDER)12 13RESTRICTION_SITES = {14    "EcoRI": "GAATTC",15    "BamHI": "GGATCC",16    "HindIII": "AAGCTT",17    "XhoI": "CTCGAG",18    "XbaI": "TCTAGA",19    "SpeI": "ACTAGT",20    "NheI": "GCTAGC",21    "XmaI": "CCCGGG",22    "NotI": "GCGGCCGC",23    "PstI": "CTGCAG",24    "KpnI": "GGTACC",25    "SalI": "GTCGAC",26}27 28def _clean_aa_seq(raw: str) -> str:29    s = (raw or "").upper()30    return "".join(ch for ch in s if ch in AA_ALLOWED)31 32def aa_percent_to_onecol_df(aa_percent: dict, digits: int = 0) -> pd.DataFrame:33    rows = []34    order = AA_ORDER if set(aa_percent).issubset(set(AA_ORDER)) else sorted(aa_percent)35    for aa in order:36        mix = aa_percent.get(aa, {})37        if not mix:38            rows.append([aa, "—"])39            continue40        parts = sorted(mix.items(), key=lambda kv: (-kv[1], kv[0]))41        cell = " - ".join(f"{cod} ({val*100:.{digits}f}%)" for cod, val in parts)42        rows.append([aa, cell])43    return pd.DataFrame(rows, columns=["AA", "Codon percentage"])44 45def run(aa_seq: str, selected_enzymes):46    cleaned = _clean_aa_seq(aa_seq)47 48    if not cleaned:49        raise gr.Error("Input contains no valid amino-acid characters.")50 51    # Step 1: initial sequence52    designed_nt, aa_percent, gc_percent, c_percent, _ = do_c_wobble(53        summary_path=None,54        aa_seq=cleaned,55    )56 57    changed_positions = set()58    bold_intervals = []59 60    # Step 2: modify selected restriction sites61    if selected_enzymes:62        for enzyme in selected_enzymes:63            site = RESTRICTION_SITES[enzyme]64            designed_nt, changed_pos, site_intervals = change_codon(designed_nt, site)65            changed_positions.update(changed_pos)66            bold_intervals.extend(site_intervals)67 68    # Step 3: build HTML69    html = []70 71    for i, nt in enumerate(designed_nt):72    73        char_html = nt74    75        # red for modified nucleotides76        if i in changed_positions:77            char_html = f"<span style='color:red;'>{nt}</span>"78    79        # bold for restriction-site region80        in_bold = any(start <= i < end for start, end in bold_intervals)81        if in_bold:82            char_html = f"<b>{char_html}</b>"83    84        html.append(char_html)85    86        # add space every codon87        if (i + 1) % 3 == 0:88            html.append(" ")89 90    final_html = (91    "<div style='"92    "font-family:monospace;"93    "white-space:pre-wrap;"94    "word-break:break-word;"95    "font-size:14px;"96    "line-height:1.4;"97    "border:1px solid #ccc;"98    "border-radius:6px;"99    "padding:10px;"100    "max-height:250px;"101    "overflow:auto;"102    "background-color:#fafafa;"103    "'>"104    + "".join(html) +105    "</div>"106    )107 108    # Step 4: recalculate tables109    codon_list = [designed_nt[i:i+3] for i in range(0, len(designed_nt), 3)]110    aa_percent_dict, _counts = aminoacid_percentage(codon_list)111    aa_table = aa_percent_to_onecol_df(aa_percent_dict, digits=0)112    gc_percent = gc_content([designed_nt])113    c_percent = c_content([designed_nt])114 115    return final_html, aa_table, gc_percent, c_percent116 117 118# ---- Gradio Interface ----119iface = gr.Interface(120    fn=run,121    inputs=[122    gr.Textbox(123        label="Amino Acid Sequence",124        lines=5,125        placeholder="e.g. MKKLLPTAA..."126    ),127    gr.CheckboxGroup(128    choices=list(RESTRICTION_SITES.keys()),129    label="Remove Restriction Sites",130    info=(131        "Selected restriction enzyme recognition sites will be removed from the optimized nucleotide sequence. "132        "The algorithm starts modifying codons from the most left codon within the detected site, "133        "using wobble-priority substitutions (C > G > A > T) while preserving the amino acid sequence. "134        "In the output sequence, the region corresponding to the detected restriction site is shown in bold black, "135        "and any nucleotide modified to break the site is highlighted in red."136    )137    )138    ],139    140    outputs=[141        gr.HTML(label="Nucleotide Sequence"),142        gr.Dataframe(label="Codon Usage Percent (per AA)", wrap=True),143        gr.Dataframe(label="GC Content (%)", wrap=True),144        gr.Dataframe(label="C Content (%)", wrap=True),   # <-- NEW BOX145    ],146    title="Codon Optimizer",147    description=(148        # "**Optimized Codons** → sequence is optimized based on the best motifs in different regions, "149        # "balancing codon usage, wobble, and motif constraints.\n\n"150        "**C wobbling** → amino acids are encoded using codons that prefer C at the wobble position "151        "(C > G > A/T). For serine (S) the priority is TCC, for proline (P) the priority is CCC. "152        "If more than four Cs occur in a row, codons with G at the wobble position are chosen to break the run."153    ),154    flagging_mode="never",155)156 157if __name__ == "__main__":158    iface.launch()159 160