mirror of
https://github.com/semantica-agi/semantica.git
synced 2026-09-13 04:04:09 +00:00
- 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
264 lines
10 KiB
Python
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
|
|
|