""" File: CodonJupyter.py --------------------- Includes Jupyter-specific functions for displaying interactive widgets. """ from typing import Dict, List, Tuple import ipywidgets as widgets from IPython.display import HTML, display from CodonTransformer.CodonUtils import ( COMMON_ORGANISMS, ID2ORGANISM, ORGANISM2ID, DNASequencePrediction, ) class UserContainer: """ A container class to store user inputs for organism and protein sequence. Attributes: organism (int): The selected organism id. protein (str): The input protein sequence. """ def __init__(self) -> None: self.organism: int = -1 self.protein: str = "" def create_styled_options( organisms: list, organism2id: Dict[str, int], is_fine_tuned: bool = False ) -> list: """ Create styled options for the dropdown widget. Args: organisms (list): List of organism names. organism2id (Dict[str, int]): Dictionary mapping organism names to their IDs. is_fine_tuned (bool): Whether these are fine-tuned organisms. Returns: list: Styled options for the dropdown widget. """ styled_options = [] for organism in organisms: organism_id = organism2id[organism] if is_fine_tuned: if organism_id < 10: styled_options.append(f"\u200b{organism_id:>6}. {organism}") elif organism_id < 100: styled_options.append(f"\u200b{organism_id:>5}. {organism}") else: styled_options.append(f"\u200b{organism_id:>4}. {organism}") else: if organism_id < 10: styled_options.append(f"{organism_id:>6}. {organism}") elif organism_id < 100: styled_options.append(f"{organism_id:>5}. {organism}") else: styled_options.append(f"{organism_id:>4}. {organism}") return styled_options def create_dropdown_options(organism2id: Dict[str, int]) -> list: """ Create the full list of dropdown options, including section headers. Args: organism2id (Dict[str, int]): Dictionary mapping organism names to their IDs. Returns: list: Full list of dropdown options. """ fine_tuned_organisms = sorted( [org for org in organism2id.keys() if org in COMMON_ORGANISMS] ) all_organisms = sorted(organism2id.keys()) fine_tuned_options = create_styled_options( fine_tuned_organisms, organism2id, is_fine_tuned=True ) all_organisms_options = create_styled_options( all_organisms, organism2id, is_fine_tuned=False ) return ( [""] + ["Selected Organisms"] + fine_tuned_options + [""] + ["All Organisms"] + all_organisms_options ) def create_organism_dropdown(container: UserContainer) -> widgets.Dropdown: """ Create and configure the organism dropdown widget. Args: container (UserContainer): Container to store the selected organism. Returns: widgets.Dropdown: Configured dropdown widget. """ dropdown = widgets.Dropdown( options=create_dropdown_options(ORGANISM2ID), description="", layout=widgets.Layout(width="40%", margin="0 0 10px 0"), style={"description_width": "initial"}, ) def show_organism(change: Dict[str, str]) -> None: """ Update the container with the selected organism and print to terminal. Args: change (Dict[str, str]): Information about the change in dropdown value. """ dropdown_choice = change["new"] if dropdown_choice and dropdown_choice not in [ "Selected Organisms", "All Organisms", ]: organism = "".join(filter(str.isdigit, dropdown_choice)) organism_id = ID2ORGANISM[int(organism)] container.organism = organism_id else: container.organism = None dropdown.observe(show_organism, names="value") return dropdown def get_dropdown_style() -> str: """ Return the custom CSS style for the dropdown widget. Returns: str: CSS style string. """ return """ """ def display_organism_dropdown(container: UserContainer) -> None: """ Display the organism dropdown widget and apply custom styles. Args: container (UserContainer): Container to store the selected organism. """ dropdown = create_organism_dropdown(container) header = widgets.HTML( 'Select Organism:' '
' ) container_widget = widgets.VBox( [header, dropdown], layout=widgets.Layout(padding="12px 0 12px 25px"), ) display(container_widget) display(HTML(get_dropdown_style())) def display_protein_input(container: UserContainer) -> None: """ Display a widget for entering a protein sequence and save it to the container. Args: container (UserContainer): A container to store the entered protein sequence. """ protein_input = widgets.Textarea( value="", placeholder="Enter here...", description="", layout=widgets.Layout(width="100%", height="100px", margin="0 0 10px 0"), style={"description_width": "initial"}, ) # Custom CSS for the input widget input_style = """ """ # Function to save the input protein sequence to the container def save_protein(change: Dict[str, str]) -> None: """ Save the input protein sequence to the container. Args: change (Dict[str, str]): A dictionary containing information about the change in textarea value. """ container.protein = ( change["new"] .upper() .strip() .replace("\n", "") .replace(" ", "") .replace("\t", "") ) # Attach the function to the input widget protein_input.observe(save_protein, names="value") # Display the input widget header = widgets.HTML( 'Enter Protein Sequence:' '' ) container_widget = widgets.VBox( [header, protein_input], layout=widgets.Layout(padding="12px 12px 0 25px") ) display(container_widget) display(widgets.HTML(input_style)) def format_model_output(output: DNASequencePrediction) -> str: """ Format DNA sequence prediction output in an appealing and easy-to-read manner. This function takes the prediction output and formats it into a structured string with clear section headers and separators. Args: output (DNASequencePrediction): Object containing the prediction output. Expected attributes: - organism (str): The organism name. - protein (str): The input protein sequence. - processed_input (str): The processed input sequence. - predicted_dna (str): The predicted DNA sequence. Returns: str: A formatted string containing the organized output. """ def format_section(title: str, content: str) -> str: """Helper function to format individual sections.""" separator = "-" * 29 title_line = f"| {title.center(25)} |" return f"{separator}\n{title_line}\n{separator}\n{content}\n\n" sections: List[Tuple[str, str]] = [ ("Organism", output.organism), ("Input Protein", output.protein), ("Processed Input", output.processed_input), ("Predicted DNA", output.predicted_dna), ] formatted_output = "" for title, content in sections: formatted_output += format_section(title, content) # Remove the last newline to avoid extra space at the end return formatted_output.rstrip()