Files
semantica/libs/semantica/visualization/semantic_network_visualizer.py
T
KaifAhmad1 d585214992 feat: Add comprehensive visualization module for semantic models, ontologies, and knowledge graphs
- Add KGVisualizer for knowledge graph network, community, and centrality visualizations
- Add OntologyVisualizer for class hierarchy, property graphs, and semantic model visualization
- Add EmbeddingVisualizer for 2D/3D projections, similarity heatmaps, and clustering
- Add SemanticNetworkVisualizer for semantic network graph visualizations
- Add QualityVisualizer for quality metrics dashboards and issue tracking
- Add AnalyticsVisualizer for centrality rankings, community structures, and connectivity analysis
- Add TemporalVisualizer for timeline, animation, and temporal pattern visualizations
- Add visualization utilities (layout algorithms, color schemes, export formats)
- Enhanced support for semantic models, ontologies, and semantic networks with multiple input formats
- Auto-extraction of classes and properties from semantic networks
- Update pyproject.toml with optional viz dependencies (pyvis, graphviz, umap-learn)
- Add comprehensive visualization examples to README
- Clean imports without try-except complexity for core dependencies
2025-11-05 21:27:36 +05:30

264 lines
10 KiB
Python

"""
Semantic Network Visualizer
This module provides visualization capabilities for semantic networks.
"""
from typing import Any, Dict, List, Optional, Union
from pathlib import Path
import plotly.graph_objects as go
import plotly.express as px
from ..utils.logging import get_logger
from ..utils.exceptions import ProcessingError
from .utils.layout_algorithms import ForceDirectedLayout
from .utils.color_schemes import ColorPalette, ColorScheme
from .utils.export_formats import export_plotly_figure
class SemanticNetworkVisualizer:
"""
Semantic network visualizer.
Provides visualization methods for semantic networks.
"""
def __init__(self, **config):
"""Initialize semantic network visualizer."""
self.logger = get_logger("semantic_network_visualizer")
self.config = config
color_scheme_name = config.get("color_scheme", "default")
try:
self.color_scheme = ColorScheme[color_scheme_name.upper()]
except (KeyError, AttributeError):
self.color_scheme = ColorScheme.DEFAULT
def visualize_network(
self,
semantic_network: Any,
output: str = "interactive",
file_path: Optional[Union[str, Path]] = None,
**options
) -> Optional[Any]:
"""
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, dict, or semantic model
output: Output type
file_path: Output file path
**options: Additional options
Returns:
Visualization figure or None
"""
self.logger.info("Visualizing semantic network")
# Extract nodes and edges from 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": getattr(node, "id", ""),
"label": getattr(node, "label", ""),
"type": getattr(node, "type", "entity"),
"metadata": getattr(node, "metadata", {}) or {},
"properties": getattr(node, "properties", {}) or {}
})
for edge in semantic_network.edges:
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 dictionary format
elif isinstance(semantic_network, dict):
# 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
graph = {"entities": nodes, "relationships": edges}
kg_viz = KGVisualizer(**self.config)
return kg_viz.visualize_network(graph, output, file_path, **options)
def visualize_node_types(
self,
semantic_network: Any,
output: str = "interactive",
file_path: Optional[Union[str, Path]] = None,
**options
) -> Optional[Any]:
"""
Visualize node type distribution.
Args:
semantic_network: SemanticNetwork object
output: Output type
file_path: Output file path
**options: Additional options
Returns:
Visualization figure or None
"""
self.logger.info("Visualizing semantic network node types")
# Extract nodes
nodes = []
if hasattr(semantic_network, "nodes"):
nodes = semantic_network.nodes
elif isinstance(semantic_network, dict):
nodes = semantic_network.get("nodes", [])
# Count node types
type_counts = {}
for node in nodes:
node_type = node.type if hasattr(node, "type") else node.get("type", "Unknown")
type_counts[node_type] = type_counts.get(node_type, 0) + 1
fig = px.bar(
x=list(type_counts.keys()),
y=list(type_counts.values()),
labels={"x": "Node Type", "y": "Count"},
title="Semantic Network Node Type Distribution"
)
if output == "interactive":
return fig
elif file_path:
export_plotly_figure(fig, file_path, format=output if output != "interactive" else "html")
return None
def visualize_edge_types(
self,
semantic_network: Any,
output: str = "interactive",
file_path: Optional[Union[str, Path]] = None,
**options
) -> Optional[Any]:
"""
Visualize edge type distribution.
Args:
semantic_network: SemanticNetwork object
output: Output type
file_path: Output file path
**options: Additional options
Returns:
Visualization figure or None
"""
self.logger.info("Visualizing semantic network edge types")
# Extract edges
edges = []
if hasattr(semantic_network, "edges"):
edges = semantic_network.edges
elif isinstance(semantic_network, dict):
edges = semantic_network.get("edges", [])
# Count edge types
type_counts = {}
for edge in edges:
edge_type = edge.label if hasattr(edge, "label") else edge.get("label", "Unknown")
type_counts[edge_type] = type_counts.get(edge_type, 0) + 1
fig = px.bar(
x=list(type_counts.keys()),
y=list(type_counts.values()),
labels={"x": "Edge Type", "y": "Count"},
title="Semantic Network Edge Type Distribution"
)
if output == "interactive":
return fig
elif file_path:
export_plotly_figure(fig, file_path, format=output if output != "interactive" else "html")
return None