Spaces:
Running
Running
#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) |