From 33344606630306563fe304e97d84144d733aa945 Mon Sep 17 00:00:00 2001 From: KaifAhmad1 Date: Wed, 5 Nov 2025 18:35:21 +0530 Subject: [PATCH 1/2] Update Readme --- libs/README.md | 60 ++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 60 insertions(+) diff --git a/libs/README.md b/libs/README.md index 85cc16e8..80155111 100644 --- a/libs/README.md +++ b/libs/README.md @@ -32,6 +32,15 @@ - **Provenance Tracking**: Track data sources and processing history - **Quality Assurance**: Comprehensive data quality validation and monitoring +### Visualization & Analytics +- **Interactive Visualizations**: Plotly-based interactive charts and graphs +- **Knowledge Graph Networks**: Network visualizations with community and centrality coloring +- **Ontology Hierarchies**: Class hierarchy trees and property graphs +- **Embedding Projections**: 2D/3D projections with UMAP, t-SNE, and PCA +- **Quality Dashboards**: Comprehensive quality metrics and issue tracking +- **Analytics Visualizations**: Centrality rankings, community structures, connectivity analysis +- **Temporal Views**: Timeline and evolution visualizations + ## 📦 Installation ### Basic Installation @@ -54,6 +63,13 @@ pip install semantica[cloud] pip install semantica[monitoring] ``` +### With Visualization (Optional) +```bash +pip install semantica[viz] +``` + +Note: Visualization dependencies (plotly, matplotlib, seaborn) are included by default. The `viz` extra includes optional dependencies like `umap-learn` and `graphviz` for advanced features. + ### Development Installation ```bash git clone https://github.com/semantica-dev/semantica.git @@ -87,6 +103,16 @@ statistics = result["statistics"] print(f"Processed {statistics['sources_processed']} documents") print(f"Success rate: {statistics['success_rate']:.2%}") + +# Visualize the knowledge graph +from semantica.visualization import KGVisualizer + +kg_viz = KGVisualizer(layout="force", color_scheme="vibrant") +fig = kg_viz.visualize_network(knowledge_graph, output="interactive") +fig.show() # Display interactive visualization + +# Or save to HTML file +kg_viz.visualize_network(knowledge_graph, output="html", file_path="knowledge_graph.html") ``` ### 2. Web Content Processing @@ -837,6 +863,8 @@ print(f"Total relationships: {len(graph.relationships)}") ### 9. Visualization Examples +The Semantica visualization module provides comprehensive visualization capabilities for all knowledge artifacts. All visualizers support both interactive (Plotly) and static export formats (HTML, PNG, SVG, PDF). + #### Knowledge Graph Visualization ```python from semantica.visualization import KGVisualizer @@ -1111,6 +1139,38 @@ temporal_viz.visualize_metrics_evolution(metrics_history, timestamps, output="html", file_path="metrics_evolution.html") ``` +#### Quick Visualization Example + +```python +from semantica import Semantica +from semantica.visualization import KGVisualizer, EmbeddingVisualizer +import numpy as np + +# Initialize framework and build knowledge graph +semantica = Semantica() +semantica.initialize() +result = semantica.build_knowledge_base(["document.pdf"], graph=True, embeddings=True) + +# Visualize knowledge graph +kg_viz = KGVisualizer(layout="force", color_scheme="vibrant") +kg_viz.visualize_network( + result["knowledge_graph"], + output="html", + file_path="kg_visualization.html" +) + +# Visualize embeddings +if "embeddings" in result: + emb_viz = EmbeddingVisualizer() + embeddings_array = np.array([e["embedding"] for e in result["embeddings"]]) + emb_viz.visualize_2d_projection( + embeddings_array, + method="umap", + output="html", + file_path="embeddings_2d.html" + ) +``` + ## 🔧 Configuration ### Basic Configuration From d585214992a8b24b1443bc3336c080acfcd4cffd Mon Sep 17 00:00:00 2001 From: KaifAhmad1 Date: Wed, 5 Nov 2025 21:27:36 +0530 Subject: [PATCH 2/2] 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 --- libs/README.md | 34 ++- .../visualization/ontology_visualizer.py | 197 +++++++++++++++++- .../semantic_network_visualizer.py | 125 ++++++++--- 3 files changed, 318 insertions(+), 38 deletions(-) diff --git a/libs/README.md b/libs/README.md index 80155111..cf05a8c4 100644 --- a/libs/README.md +++ b/libs/README.md @@ -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") diff --git a/libs/semantica/visualization/ontology_visualizer.py b/libs/semantica/visualization/ontology_visualizer.py index 591a06e8..fde1f913 100644 --- a/libs/semantica/visualization/ontology_visualizer.py +++ b/libs/semantica/visualization/ontology_visualizer.py @@ -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]], diff --git a/libs/semantica/visualization/semantic_network_visualizer.py b/libs/semantica/visualization/semantic_network_visualizer.py index 084c456b..d46ec3e9 100644 --- a/libs/semantica/visualization/semantic_network_visualizer.py +++ b/libs/semantica/visualization/semantic_network_visualizer.py @@ -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