File size: 4,460 Bytes
bf20385
9d23b87
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
3a4201f
 
9d23b87
 
 
 
 
bf20385
9d23b87
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
#Developed by ruslanmv.com
import gradio as gr
import matplotlib.pyplot as plt
import networkx as nx
from owlready2 import *
import difflib
import tempfile
import os
def plot_ontology(search_term, owl_file):
    """
    Loads an ontology OWL file, builds a graph of its classes and subclass relationships,
    performs fuzzy matching to find nodes similar to the search term, and returns a plot
    highlighting the matching nodes (and their immediate neighbors) in pink.

    Args:
        search_term (str): The search term used for fuzzy matching on node names.
        owl_file (file): An uploaded ontology file in OWL format.

    Returns:
        A tuple with:
            - The file path of the saved plot image.
            - A text message with search result details.
    """
    if owl_file is None:
        return None, "Please upload an ontology OWL file."

    # Load the ontology from the provided file.
    try:
        # Append temporary directory to the ontology search path.
        onto_path.append(tempfile.gettempdir())
        # Load the ontology using its file URI.
        onto = get_ontology("file://"+owl_file.name).load()
    except Exception as e:
        return None, f"Error loading ontology: {e}"

    # Build a directed graph: nodes represent ontology classes and edges represent subclass relationships.
    G = nx.DiGraph()
    for cls in onto.classes():
        G.add_node(cls.name, iri=cls.iri)
        for parent in cls.is_a:
            if isinstance(parent, ThingClass):
                G.add_edge(parent.name, cls.name)

    # Define a helper function for fuzzy searching nodes.
    def fuzzy_search(query, cutoff=0.6):
        query = query.lower()
        lower_to_orig = {node.lower(): node for node in G.nodes}
        lower_nodes = list(lower_to_orig.keys())
        matches = difflib.get_close_matches(query, lower_nodes, cutoff=cutoff)
        return [lower_to_orig[m] for m in matches]

    search_results = fuzzy_search(search_term)
    if not search_results:
        result_message = f"No matches found for '{search_term}'."
    else:
        result_message = f"Found nodes: {', '.join(search_results)}"

    # Determine which nodes to highlight: matched nodes plus their immediate neighbors (parents and children).
    highlight_nodes = set()
    for node in search_results:
        highlight_nodes.add(node)
        highlight_nodes.update(G.predecessors(node))
        highlight_nodes.update(G.successors(node))

    # Create the graph layout and plot.
    pos = nx.spring_layout(G, k=0.5, iterations=50)
    plt.figure(figsize=(12, 8))
    node_colors = ['pink' if node in highlight_nodes else 'lightblue' for node in G.nodes]
    nx.draw(G, pos, with_labels=True, node_size=1500, node_color=node_colors, font_size=10, arrows=True)
    plt.title("Ontology Graph with Highlighted Related Nodes\n" + result_message)

    # Save the plot to a temporary file and close the plot.
    tmpfile = tempfile.NamedTemporaryFile(suffix='.png', delete=False)
    plt.savefig(tmpfile.name, format="png")
    plt.close()

    return tmpfile.name, result_message

# Load default file and search term
default_owl_path = "genai.owl"
default_search_term = "LoRa"
with open(default_owl_path, "rb") as f:
    default_owl_bytes = f.read()

# Create a temporary file to store the default OWL content
temp_owl_file = tempfile.NamedTemporaryFile(delete=False, suffix=".owl")
temp_owl_file.write(default_owl_bytes)
temp_owl_file.close()

# Define the Gradio interface.
iface = gr.Interface(
    fn=plot_ontology,
    inputs=[
        gr.Textbox(lines=1, label="Search Term", placeholder="Enter a search term (e.g., LoRa)", value=default_search_term),
        gr.File(label="Upload Ontology OWL File", value=temp_owl_file.name)
    ],
    outputs=[
        gr.Image(type="filepath", label="Ontology Graph"),
        gr.Textbox(label="Search Result Details")
    ],
    title="Ontology Explorer",
    description="Upload an ontology OWL file and enter a search term to visualize the ontology graph. "
                "Nodes matching the search term and their immediate neighbors (parents and children) are highlighted in pink."
                "Reference of the Ontology Loaded: [GENAI](https://bioportal.bioontology.org/ontologies/GENAI)",
    examples=[
        ["LoRa", "genai.owl"],
        ["LLM", "genai.owl"],
        ["RLHF", "genai.owl"]
    ],
    cache_examples=True
)

if __name__ == "__main__":
    iface.launch(share=True)