Spaces:
Running
Running
""" | |
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 """ | |
<style> | |
.widget-dropdown > select { | |
font-size: 16px; | |
font-weight: normal; | |
background-color: #f0f0f0; | |
border-radius: 5px; | |
padding: 5px; | |
} | |
.widget-label { | |
font-size: 18px; | |
font-weight: bold; | |
} | |
.custom-container { | |
display: flex; | |
flex-direction: column; | |
align-items: flex-start; | |
} | |
.widget-dropdown option[value^="\u200b"] { | |
font-family: sans-serif; | |
font-weight: bold; | |
font-size: 18px; | |
padding: 510px; | |
} | |
.widget-dropdown option[value*="Selected Organisms"], | |
.widget-dropdown option[value*="All Organisms"] { | |
text-align: center; | |
font-family: Arial, sans-serif; | |
font-weight: bold; | |
font-size: 20px; | |
color: #6900A1; | |
background-color: #00D8A1; | |
} | |
</style> | |
""" | |
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( | |
'<b style="font-size:20px;">Select Organism:</b>' | |
'<div style="height:10px;"></div>' | |
) | |
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 = """ | |
<style> | |
.widget-textarea > textarea { | |
font-size: 12px; | |
font-family: Arial, sans-serif; | |
font-weight: normal; | |
background-color: #f0f0f0; | |
border-radius: 5px; | |
padding: 10px; | |
} | |
.widget-label { | |
font-size: 18px; | |
font-weight: bold; | |
} | |
.custom-container { | |
display: flex; | |
flex-direction: column; | |
align-items: flex-start; | |
} | |
</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( | |
'<b style="font-size:20px;">Enter Protein Sequence:</b>' | |
'<div style="height:18px;"></div>' | |
) | |
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() | |