Merge pull request #17 from Hawksight-AI/visualization

Visualization
This commit is contained in:
Mohd Kaif
2025-11-05 21:31:04 +05:30
committed by GitHub
3 changed files with 318 additions and 38 deletions
+32 -2
View File
@@ -908,11 +908,19 @@ kg_viz.visualize_relationship_matrix(graph, output="html", file_path="relationsh
#### Ontology Visualization
```python
from semantica.visualization import OntologyVisualizer
from semantica.ontology import OntologyGenerator
# Initialize ontology visualizer
onto_viz = OntologyVisualizer(color_scheme="default")
# Visualize class hierarchy
# Option 1: Visualize from ontology generator result
ontology_generator = OntologyGenerator()
semantic_model = ontology_generator.generate_ontology(data)
# Visualize semantic model (handles both ontology and semantic network)
onto_viz.visualize_semantic_model(semantic_model, output="html", file_path="semantic_model.html")
# Option 2: Visualize class hierarchy directly
ontology = {
"classes": classes,
"properties": properties
@@ -921,6 +929,15 @@ ontology = {
# Hierarchy tree visualization
onto_viz.visualize_hierarchy(ontology, output="html", file_path="ontology_hierarchy.html")
# Option 3: Visualize from semantic network (auto-extracts classes)
from semantica.semantic_extract import SemanticNetworkExtractor
extractor = SemanticNetworkExtractor()
semantic_network = extractor.extract_network(text)
# Can visualize directly - will extract classes automatically
onto_viz.visualize_hierarchy({"semantic_network": semantic_network},
output="html", file_path="ontology_from_network.html")
# Property graph visualization
onto_viz.visualize_properties(ontology, output="html", file_path="ontology_properties.html")
@@ -988,7 +1005,7 @@ from semantica.visualization import SemanticNetworkVisualizer
# Initialize semantic network visualizer
sem_net_viz = SemanticNetworkVisualizer()
# Visualize semantic network
# Option 1: Visualize SemanticNetwork dataclass object
from semantica.semantic_extract import SemanticNetworkExtractor
extractor = SemanticNetworkExtractor()
semantic_network = extractor.extract_network(text)
@@ -996,6 +1013,19 @@ semantic_network = extractor.extract_network(text)
# Network graph
sem_net_viz.visualize_network(semantic_network, output="html", file_path="semantic_network.html")
# Option 2: Visualize from dictionary format
semantic_network_dict = {
"nodes": [{"id": "n1", "label": "Node 1", "type": "Entity"}],
"edges": [{"source": "n1", "target": "n2", "label": "relatedTo"}]
}
sem_net_viz.visualize_network(semantic_network_dict, output="html", file_path="semantic_network.html")
# Option 3: Visualize from semantic model (ontology generator result)
from semantica.ontology import OntologyGenerator
generator = OntologyGenerator()
semantic_model = generator.generate_ontology(data)
sem_net_viz.visualize_network(semantic_model.semantic_network, output="html", file_path="semantic_model_network.html")
# Node type distribution
sem_net_viz.visualize_node_types(semantic_network, output="html", file_path="node_types.html")
@@ -68,7 +68,8 @@ class OntologyVisualizer:
Visualize class hierarchy as tree.
Args:
ontology: Ontology dictionary with classes
ontology: Ontology dictionary with classes, or SemanticNetwork object,
or ontology generator result
output: Output type ("interactive", "html", "png", "svg", "dot")
file_path: Output file path
**options: Additional options
@@ -78,10 +79,24 @@ class OntologyVisualizer:
"""
self.logger.info("Visualizing ontology class hierarchy")
classes = ontology.get("classes", [])
# Handle different input formats
if hasattr(ontology, "classes"):
# OntologyGenerator result object
classes = ontology.classes if hasattr(ontology, "classes") else []
elif isinstance(ontology, dict):
classes = ontology.get("classes", ontology.get("class_definitions", []))
else:
classes = []
# If no classes, try to extract from semantic network
if not classes and isinstance(ontology, dict):
# Check if it's a semantic model or semantic network
semantic_network = ontology.get("semantic_network", ontology.get("network"))
if semantic_network:
classes = self._extract_classes_from_semantic_network(semantic_network)
if not classes:
raise ProcessingError("No classes found in ontology")
raise ProcessingError("No classes found in ontology. Please provide classes or a semantic network.")
# If output is dot and graphviz is available, use it
if output == "dot" and graphviz is not None and file_path:
@@ -103,7 +118,7 @@ class OntologyVisualizer:
Visualize property graph showing properties and their domains/ranges.
Args:
ontology: Ontology dictionary
ontology: Ontology dictionary, SemanticNetwork, or ontology generator result
output: Output type
file_path: Output file path
**options: Additional options
@@ -113,8 +128,22 @@ class OntologyVisualizer:
"""
self.logger.info("Visualizing ontology properties")
properties = ontology.get("properties", [])
classes = ontology.get("classes", [])
# Handle different input formats
if hasattr(ontology, "properties"):
properties = ontology.properties if hasattr(ontology, "properties") else []
classes = ontology.classes if hasattr(ontology, "classes") else []
elif isinstance(ontology, dict):
properties = ontology.get("properties", ontology.get("property_definitions", []))
classes = ontology.get("classes", ontology.get("class_definitions", []))
else:
properties = []
classes = []
# If no properties, try to extract from semantic network
if not properties and isinstance(ontology, dict):
semantic_network = ontology.get("semantic_network", ontology.get("network"))
if semantic_network:
properties = self._extract_properties_from_semantic_network(semantic_network)
if not properties:
raise ProcessingError("No properties found in ontology")
@@ -350,17 +379,129 @@ class OntologyVisualizer:
def _calculate_class_depth(self, cls: Dict[str, Any], all_classes: List[Dict[str, Any]]) -> int:
"""Calculate depth of class in hierarchy."""
parent = cls.get("parent") or cls.get("subClassOf")
parent = cls.get("parent") or cls.get("subClassOf") or cls.get("superClassOf")
if not parent:
return 1
# Find parent class
for p_cls in all_classes:
if (p_cls.get("name") or p_cls.get("uri", "")) == parent:
cls_name = p_cls.get("name") or p_cls.get("uri") or p_cls.get("label", "")
if cls_name == parent:
return 1 + self._calculate_class_depth(p_cls, all_classes)
return 1
def _extract_classes_from_semantic_network(self, semantic_network: Any) -> List[Dict[str, Any]]:
"""Extract class definitions from semantic network."""
classes = []
# Handle SemanticNetwork dataclass
if hasattr(semantic_network, "nodes"):
# Group nodes by type to form classes
type_groups = {}
for node in semantic_network.nodes:
node_type = node.type if hasattr(node, "type") else "Unknown"
if node_type not in type_groups:
type_groups[node_type] = []
type_groups[node_type].append(node)
# Create class definitions
for node_type, nodes in type_groups.items():
classes.append({
"name": node_type,
"label": node_type,
"uri": f"#{node_type}",
"instances": len(nodes),
"properties": list(set(
prop for node in nodes
for prop in (node.properties.keys() if hasattr(node, "properties") else [])
))
})
# Handle dictionary format
elif isinstance(semantic_network, dict):
nodes = semantic_network.get("nodes", [])
type_groups = {}
for node in nodes:
node_type = node.get("type") if isinstance(node, dict) else (
node.type if hasattr(node, "type") else "Unknown"
)
if node_type not in type_groups:
type_groups[node_type] = []
type_groups[node_type].append(node)
for node_type, nodes in type_groups.items():
classes.append({
"name": node_type,
"label": node_type,
"uri": f"#{node_type}",
"instances": len(nodes)
})
return classes
def visualize_semantic_model(
self,
semantic_model: Any,
output: str = "interactive",
file_path: Optional[Union[str, Path]] = None,
**options
) -> Optional[Any]:
"""
Visualize semantic model from ontology generator.
This method extracts and visualizes both the ontology structure
and the underlying semantic network that generated it.
Args:
semantic_model: Semantic model from OntologyGenerator or semantic network
output: Output type
file_path: Output file path
**options: Additional options
Returns:
Visualization figure or None
"""
self.logger.info("Visualizing semantic model")
# Handle OntologyGenerator result
if hasattr(semantic_model, "semantic_network"):
# Visualize the semantic network
from .semantic_network_visualizer import SemanticNetworkVisualizer
sem_net_viz = SemanticNetworkVisualizer(**self.config)
return sem_net_viz.visualize_network(
semantic_model.semantic_network,
output=output,
file_path=file_path,
**options
)
# Handle dictionary format with semantic_network
elif isinstance(semantic_model, dict):
if "semantic_network" in semantic_model:
from .semantic_network_visualizer import SemanticNetworkVisualizer
sem_net_viz = SemanticNetworkVisualizer(**self.config)
return sem_net_viz.visualize_network(
semantic_model["semantic_network"],
output=output,
file_path=file_path,
**options
)
# Otherwise treat as ontology
else:
return self.visualize_structure(semantic_model, output, file_path, **options)
# Handle direct semantic network
else:
from .semantic_network_visualizer import SemanticNetworkVisualizer
sem_net_viz = SemanticNetworkVisualizer(**self.config)
return sem_net_viz.visualize_network(
semantic_model,
output=output,
file_path=file_path,
**options
)
def _visualize_hierarchy_plotly(
self,
hierarchy: Dict[str, List[str]],
@@ -522,6 +663,46 @@ class OntologyVisualizer:
kg_viz = KGVisualizer(**self.config)
return kg_viz._visualize_network_plotly(nodes, edges, output, file_path, **options)
def _extract_properties_from_semantic_network(self, semantic_network: Any) -> List[Dict[str, Any]]:
"""Extract property definitions from semantic network."""
properties = []
# Handle SemanticNetwork dataclass
if hasattr(semantic_network, "edges"):
# Extract unique edge labels as properties
property_types = set()
for edge in semantic_network.edges:
edge_label = edge.label if hasattr(edge, "label") else ""
if edge_label and edge_label not in property_types:
property_types.add(edge_label)
properties.append({
"name": edge_label,
"label": edge_label,
"uri": f"#{edge_label}",
"domain": "Thing", # Default domain
"range": "Thing" # Default range
})
# Handle dictionary format
elif isinstance(semantic_network, dict):
edges = semantic_network.get("edges", semantic_network.get("relationships", []))
property_types = set()
for edge in edges:
edge_label = edge.get("label") if isinstance(edge, dict) else (
edge.label if hasattr(edge, "label") else ""
)
if edge_label and edge_label not in property_types:
property_types.add(edge_label)
properties.append({
"name": edge_label,
"label": edge_label,
"uri": f"#{edge_label}",
"domain": edge.get("domain", "Thing") if isinstance(edge, dict) else "Thing",
"range": edge.get("range", "Thing") if isinstance(edge, dict) else "Thing"
})
return properties
def _visualize_structure_plotly(
self,
nodes: List[Dict[str, Any]],
@@ -44,8 +44,14 @@ class SemanticNetworkVisualizer:
"""
Visualize semantic network.
Supports multiple input formats:
- SemanticNetwork dataclass object
- Dictionary with 'nodes' and 'edges' keys
- Semantic model from ontology generator
- Entities and relationships lists
Args:
semantic_network: SemanticNetwork object
semantic_network: SemanticNetwork object, dict, or semantic model
output: Output type
file_path: Output file path
**options: Additional options
@@ -57,40 +63,103 @@ class SemanticNetworkVisualizer:
# Extract nodes and edges from semantic network
nodes = []
if hasattr(semantic_network, "nodes"):
edges = []
# Handle SemanticNetwork dataclass
if hasattr(semantic_network, "nodes") and hasattr(semantic_network, "edges"):
for node in semantic_network.nodes:
nodes.append({
"id": node.id,
"label": node.label,
"type": node.type,
"metadata": node.metadata
"id": getattr(node, "id", ""),
"label": getattr(node, "label", ""),
"type": getattr(node, "type", "entity"),
"metadata": getattr(node, "metadata", {}) or {},
"properties": getattr(node, "properties", {}) or {}
})
elif isinstance(semantic_network, dict):
for node in semantic_network.get("nodes", []):
nodes.append({
"id": node.get("id", ""),
"label": node.get("label", ""),
"type": node.get("type", ""),
"metadata": node.get("metadata", {})
})
edges = []
if hasattr(semantic_network, "edges"):
for edge in semantic_network.edges:
edges.append({
"source": edge.source,
"target": edge.target,
"label": edge.label,
"metadata": edge.metadata
"source": getattr(edge, "source", ""),
"target": getattr(edge, "target", ""),
"label": getattr(edge, "label", ""),
"type": getattr(edge, "label", ""),
"metadata": getattr(edge, "metadata", {}) or {},
"properties": getattr(edge, "properties", {}) or {}
})
# Handle dictionary format
elif isinstance(semantic_network, dict):
for edge in semantic_network.get("edges", []):
edges.append({
"source": edge.get("source", ""),
"target": edge.get("target", ""),
"label": edge.get("label", ""),
"metadata": edge.get("metadata", {})
})
# Check if it's a semantic model from ontology generator
if "semantic_network" in semantic_network:
semantic_network = semantic_network["semantic_network"]
# Extract nodes
network_nodes = semantic_network.get("nodes", [])
for node in network_nodes:
if isinstance(node, dict):
nodes.append({
"id": node.get("id", node.get("uri", "")),
"label": node.get("label", node.get("name", "")),
"type": node.get("type", node.get("class", "entity")),
"metadata": node.get("metadata", {}),
"properties": node.get("properties", {})
})
elif hasattr(node, "id"):
nodes.append({
"id": getattr(node, "id", ""),
"label": getattr(node, "label", ""),
"type": getattr(node, "type", "entity"),
"metadata": getattr(node, "metadata", {}) or {},
"properties": getattr(node, "properties", {}) or {}
})
# Extract edges
network_edges = semantic_network.get("edges", semantic_network.get("relationships", []))
for edge in network_edges:
if isinstance(edge, dict):
edges.append({
"source": edge.get("source", edge.get("subject", "")),
"target": edge.get("target", edge.get("object", "")),
"label": edge.get("label", edge.get("predicate", edge.get("type", ""))),
"type": edge.get("type", edge.get("predicate", "")),
"metadata": edge.get("metadata", {}),
"properties": edge.get("properties", {})
})
elif hasattr(edge, "source"):
edges.append({
"source": getattr(edge, "source", ""),
"target": getattr(edge, "target", ""),
"label": getattr(edge, "label", ""),
"type": getattr(edge, "label", ""),
"metadata": getattr(edge, "metadata", {}) or {},
"properties": getattr(edge, "properties", {}) or {}
})
# Handle entities/relationships format (for semantic models)
elif isinstance(semantic_network, (list, tuple)):
# Assume it's a list of entities/relationships
for item in semantic_network:
if isinstance(item, dict):
if "source" in item or "subject" in item:
edges.append({
"source": item.get("source", item.get("subject", "")),
"target": item.get("target", item.get("object", "")),
"label": item.get("label", item.get("predicate", item.get("type", ""))),
"type": item.get("type", ""),
"metadata": item.get("metadata", {})
})
else:
nodes.append({
"id": item.get("id", item.get("uri", "")),
"label": item.get("label", item.get("name", "")),
"type": item.get("type", "entity"),
"metadata": item.get("metadata", {})
})
if not nodes and not edges:
raise ProcessingError(
"Could not extract nodes and edges from semantic network. "
"Please provide a SemanticNetwork object, dict with 'nodes'/'edges', or semantic model."
)
# Use KG visualizer for network visualization
from .kg_visualizer import KGVisualizer