Spaces:
Running
Running
| <html lang="en"> | |
| <head> | |
| <meta charset="UTF-8"> | |
| <meta name="viewport" content="width=device-width, initial-scale=1.0"> | |
| <title>Interactive Knowledge Graph</title> | |
| <script src="https://cdn.tailwindcss.com"></script> | |
| <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.4.0/css/all.min.css"> | |
| <style> | |
| .node { | |
| transition: all 0.3s ease; | |
| cursor: pointer; | |
| } | |
| .node:hover { | |
| transform: scale(1.05); | |
| box-shadow: 0 10px 15px -3px rgba(0, 0, 0, 0.1), 0 4px 6px -2px rgba(0, 0, 0, 0.05); | |
| } | |
| .link { | |
| stroke: #94a3b8; | |
| stroke-width: 2px; | |
| } | |
| .graph-container { | |
| background: linear-gradient(135deg, #f8fafc 0%, #e2e8f0 100%); | |
| border-radius: 1rem; | |
| } | |
| .tooltip { | |
| position: absolute; | |
| padding: 0.5rem 1rem; | |
| background: white; | |
| border-radius: 0.5rem; | |
| box-shadow: 0 4px 6px -1px rgba(0, 0, 0, 0.1), 0 2px 4px -1px rgba(0, 0, 0, 0.06); | |
| pointer-events: none; | |
| opacity: 0; | |
| transition: opacity 0.2s; | |
| z-index: 10; | |
| } | |
| @keyframes pulse { | |
| 0% { transform: scale(1); } | |
| 50% { transform: scale(1.05); } | |
| 100% { transform: scale(1); } | |
| } | |
| .pulse { | |
| animation: pulse 2s infinite; | |
| } | |
| </style> | |
| </head> | |
| <body class="bg-gray-50 min-h-screen"> | |
| <div class="container mx-auto px-4 py-12"> | |
| <div class="text-center mb-12"> | |
| <h1 class="text-4xl font-bold text-gray-800 mb-4">Interactive Knowledge Graph</h1> | |
| <p class="text-xl text-gray-600 max-w-3xl mx-auto"> | |
| Visualize complex relationships between concepts in an interactive network diagram. | |
| </p> | |
| <div class="mt-6 flex justify-center space-x-4"> | |
| <button id="physicsBtn" class="px-4 py-2 bg-blue-600 text-white rounded-lg hover:bg-blue-700 transition"> | |
| <i class="fas fa-atom mr-2"></i>Toggle Physics | |
| </button> | |
| <button id="addNodeBtn" class="px-4 py-2 bg-green-600 text-white rounded-lg hover:bg-green-700 transition"> | |
| <i class="fas fa-plus mr-2"></i>Add Node | |
| </button> | |
| <button id="resetBtn" class="px-4 py-2 bg-red-600 text-white rounded-lg hover:bg-red-700 transition"> | |
| <i class="fas fa-redo mr-2"></i>Reset Graph | |
| </button> | |
| </div> | |
| </div> | |
| <div class="graph-container relative p-6 shadow-xl"> | |
| <div id="graph" class="w-full h-[600px]"></div> | |
| <div id="tooltip" class="tooltip"></div> | |
| </div> | |
| <div class="mt-12 grid grid-cols-1 md:grid-cols-3 gap-8"> | |
| <div class="bg-white p-6 rounded-xl shadow-md"> | |
| <div class="flex items-center mb-4"> | |
| <div class="w-10 h-10 rounded-full bg-blue-100 flex items-center justify-center mr-4"> | |
| <i class="fas fa-info-circle text-blue-600"></i> | |
| </div> | |
| <h3 class="text-xl font-semibold text-gray-800">What is a Knowledge Graph?</h3> | |
| </div> | |
| <p class="text-gray-600"> | |
| A knowledge graph is a network of interconnected entities and their relationships. | |
| It represents information in a way that's closer to how humans think about concepts. | |
| </p> | |
| </div> | |
| <div class="bg-white p-6 rounded-xl shadow-md"> | |
| <div class="flex items-center mb-4"> | |
| <div class="w-10 h-10 rounded-full bg-purple-100 flex items-center justify-center mr-4"> | |
| <i class="fas fa-project-diagram text-purple-600"></i> | |
| </div> | |
| <h3 class="text-xl font-semibold text-gray-800">Graph Features</h3> | |
| </div> | |
| <ul class="text-gray-600 space-y-2"> | |
| <li class="flex items-start"> | |
| <i class="fas fa-check-circle text-green-500 mt-1 mr-2"></i> | |
| <span>Interactive nodes and connections</span> | |
| </li> | |
| <li class="flex items-start"> | |
| <i class="fas fa-check-circle text-green-500 mt-1 mr-2"></i> | |
| <span>Physics-based simulation</span> | |
| </li> | |
| <li class="flex items-start"> | |
| <i class="fas fa-check-circle text-green-500 mt-1 mr-2"></i> | |
| <span>Dynamic tooltips</span> | |
| </li> | |
| </ul> | |
| </div> | |
| <div class="bg-white p-6 rounded-xl shadow-md"> | |
| <div class="flex items-center mb-4"> | |
| <div class="w-10 h-10 rounded-full bg-green-100 flex items-center justify-center mr-4"> | |
| <i class="fas fa-lightbulb text-green-600"></i> | |
| </div> | |
| <h3 class="text-xl font-semibold text-gray-800">Try It Out</h3> | |
| </div> | |
| <p class="text-gray-600 mb-4"> | |
| Click on nodes to see details. Drag nodes to rearrange the graph. Use the buttons above to control the visualization. | |
| </p> | |
| <div class="flex space-x-2"> | |
| <span class="px-3 py-1 bg-blue-100 text-blue-800 rounded-full text-sm">Interactive</span> | |
| <span class="px-3 py-1 bg-purple-100 text-purple-800 rounded-full text-sm">Dynamic</span> | |
| <span class="px-3 py-1 bg-green-100 text-green-800 rounded-full text-sm">Responsive</span> | |
| </div> | |
| </div> | |
| </div> | |
| </div> | |
| <script src="https://d3js.org/d3.v7.min.js"></script> | |
| <script> | |
| document.addEventListener('DOMContentLoaded', function() { | |
| // Sample knowledge graph data | |
| const graphData = { | |
| nodes: [ | |
| { id: 1, name: "Artificial Intelligence", type: "concept", description: "The simulation of human intelligence processes by machines.", color: "#3B82F6" }, | |
| { id: 2, name: "Machine Learning", type: "subfield", description: "A subset of AI that enables systems to learn from data.", color: "#10B981" }, | |
| { id: 3, name: "Neural Networks", type: "technique", description: "Computational models inspired by biological neural networks.", color: "#8B5CF6" }, | |
| { id: 4, name: "Deep Learning", type: "method", description: "ML technique using multi-layered neural networks.", color: "#EC4899" }, | |
| { id: 5, name: "Natural Language Processing", type: "application", description: "AI field focused on interactions between computers and human language.", color: "#F59E0B" }, | |
| { id: 6, name: "Computer Vision", type: "application", description: "Field of AI that enables computers to interpret visual data.", color: "#6366F1" }, | |
| { id: 7, name: "Reinforcement Learning", type: "method", description: "ML method where agents learn by taking actions in an environment.", color: "#EF4444" } | |
| ], | |
| links: [ | |
| { source: 1, target: 2, relation: "includes" }, | |
| { source: 2, target: 3, relation: "uses" }, | |
| { source: 3, target: 4, relation: "basis of" }, | |
| { source: 2, target: 5, relation: "applies to" }, | |
| { source: 2, target: 6, relation: "applies to" }, | |
| { source: 2, target: 7, relation: "includes" }, | |
| { source: 4, target: 5, relation: "enhances" }, | |
| { source: 4, target: 6, relation: "enhances" } | |
| ] | |
| }; | |
| // Set up the SVG container | |
| const width = document.getElementById('graph').clientWidth; | |
| const height = document.getElementById('graph').clientHeight; | |
| const svg = d3.select("#graph") | |
| .append("svg") | |
| .attr("width", width) | |
| .attr("height", height) | |
| .attr("viewBox", [0, 0, width, height]) | |
| .attr("style", "max-width: 100%; height: auto;"); | |
| // Set up the simulation | |
| const simulation = d3.forceSimulation(graphData.nodes) | |
| .force("link", d3.forceLink(graphData.links).id(d => d.id).distance(150)) | |
| .force("charge", d3.forceManyBody().strength(-500)) | |
| .force("center", d3.forceCenter(width / 2, height / 2)) | |
| .force("collision", d3.forceCollide().radius(60)); | |
| // Create the links | |
| const link = svg.append("g") | |
| .selectAll("line") | |
| .data(graphData.links) | |
| .join("line") | |
| .attr("class", "link") | |
| .attr("stroke-width", 2); | |
| // Add link labels | |
| const linkText = svg.append("g") | |
| .selectAll("text") | |
| .data(graphData.links) | |
| .join("text") | |
| .attr("font-size", 12) | |
| .attr("fill", "#64748b") | |
| .text(d => d.relation); | |
| // Create the nodes | |
| const node = svg.append("g") | |
| .selectAll("g") | |
| .data(graphData.nodes) | |
| .join("g") | |
| .attr("class", "node") | |
| .call(drag(simulation)); | |
| // Add circles to the nodes | |
| node.append("circle") | |
| .attr("r", 25) | |
| .attr("fill", d => d.color) | |
| .attr("stroke", "#fff") | |
| .attr("stroke-width", 2); | |
| // Add icons to the nodes based on type | |
| node.append("text") | |
| .attr("text-anchor", "middle") | |
| .attr("dy", ".35em") | |
| .attr("fill", "white") | |
| .attr("font-size", "12px") | |
| .html(d => { | |
| switch(d.type) { | |
| case "concept": return "π§ "; | |
| case "subfield": return "π"; | |
| case "technique": return "βοΈ"; | |
| case "method": return "π"; | |
| case "application": return "π»"; | |
| default: return "π"; | |
| } | |
| }); | |
| // Add node labels | |
| const labels = node.append("text") | |
| .attr("dy", 50) | |
| .attr("text-anchor", "middle") | |
| .attr("fill", "#1e293b") | |
| .attr("font-weight", "600") | |
| .text(d => d.name) | |
| .clone(true).lower() | |
| .attr("stroke", "white") | |
| .attr("stroke-width", 3); | |
| // Tooltip setup | |
| const tooltip = d3.select("#tooltip"); | |
| node.on("mouseover", function(event, d) { | |
| d3.select(this).select("circle").attr("r", 30); | |
| tooltip.transition() | |
| .duration(200) | |
| .style("opacity", 1); | |
| tooltip.html(` | |
| <h3 class="font-bold text-lg mb-1" style="color: ${d.color}">${d.name}</h3> | |
| <p class="text-sm text-gray-600 mb-1">Type: ${d.type}</p> | |
| <p class="text-sm text-gray-700">${d.description}</p> | |
| `) | |
| .style("left", (event.pageX + 10) + "px") | |
| .style("top", (event.pageY + 10) + "px"); | |
| }) | |
| .on("mouseout", function() { | |
| d3.select(this).select("circle").attr("r", 25); | |
| tooltip.transition() | |
| .duration(500) | |
| .style("opacity", 0); | |
| }); | |
| // Update positions on each tick | |
| simulation.on("tick", () => { | |
| link | |
| .attr("x1", d => d.source.x) | |
| .attr("y1", d => d.source.y) | |
| .attr("x2", d => d.target.x) | |
| .attr("y2", d => d.target.y); | |
| linkText | |
| .attr("x", d => (d.source.x + d.target.x) / 2) | |
| .attr("y", d => (d.source.y + d.target.y) / 2); | |
| node | |
| .attr("transform", d => `translate(${d.x},${d.y})`); | |
| }); | |
| // Drag behavior | |
| function drag(simulation) { | |
| function dragstarted(event, d) { | |
| if (!event.active) simulation.alphaTarget(0.3).restart(); | |
| d.fx = d.x; | |
| d.fy = d.y; | |
| } | |
| function dragged(event, d) { | |
| d.fx = event.x; | |
| d.fy = event.y; | |
| } | |
| function dragended(event, d) { | |
| if (!event.active) simulation.alphaTarget(0); | |
| d.fx = null; | |
| d.fy = null; | |
| } | |
| return d3.drag() | |
| .on("start", dragstarted) | |
| .on("drag", dragged) | |
| .on("end", dragended); | |
| } | |
| // Button interactions | |
| let physicsEnabled = true; | |
| document.getElementById('physicsBtn').addEventListener('click', function() { | |
| physicsEnabled = !physicsEnabled; | |
| if (physicsEnabled) { | |
| simulation.alphaTarget(0.3).restart(); | |
| this.innerHTML = '<i class="fas fa-atom mr-2"></i>Toggle Physics'; | |
| this.classList.remove('bg-gray-600'); | |
| this.classList.add('bg-blue-600'); | |
| } else { | |
| simulation.alphaTarget(0); | |
| this.innerHTML = '<i class="fas fa-pause mr-2"></i>Toggle Physics'; | |
| this.classList.remove('bg-blue-600'); | |
| this.classList.add('bg-gray-600'); | |
| } | |
| }); | |
| document.getElementById('resetBtn').addEventListener('click', function() { | |
| // Reset node positions | |
| graphData.nodes.forEach(node => { | |
| node.fx = null; | |
| node.fy = null; | |
| node.x = Math.random() * width; | |
| node.y = Math.random() * height; | |
| }); | |
| if (physicsEnabled) { | |
| simulation.alpha(1).restart(); | |
| } | |
| // Add pulse animation to all nodes temporarily | |
| node.select("circle").classList.add("pulse"); | |
| setTimeout(() => { | |
| node.select("circle").classList.remove("pulse"); | |
| }, 2000); | |
| }); | |
| document.getElementById('addNodeBtn').addEventListener('click', function() { | |
| const newNodeId = graphData.nodes.length + 1; | |
| const colors = ["#3B82F6", "#10B981", "#8B5CF6", "#EC4899", "#F59E0B", "#6366F1", "#EF4444"]; | |
| const types = ["concept", "subfield", "technique", "method", "application"]; | |
| const newNode = { | |
| id: newNodeId, | |
| name: `New Node ${newNodeId}`, | |
| type: types[Math.floor(Math.random() * types.length)], | |
| description: "This is a newly added node to the knowledge graph.", | |
| color: colors[Math.floor(Math.random() * colors.length)] | |
| }; | |
| // Add the new node | |
| graphData.nodes.push(newNode); | |
| // Add a random link to an existing node | |
| if (graphData.nodes.length > 1) { | |
| const randomExistingNode = graphData.nodes[Math.floor(Math.random() * (graphData.nodes.length - 1))]; | |
| const relations = ["related to", "connected with", "part of", "similar to", "derived from"]; | |
| graphData.links.push({ | |
| source: newNodeId, | |
| target: randomExistingNode.id, | |
| relation: relations[Math.floor(Math.random() * relations.length)] | |
| }); | |
| } | |
| // Update the simulation with new data | |
| updateGraph(); | |
| // Highlight the new node | |
| const newNodeElement = node.filter(d => d.id === newNodeId); | |
| newNodeElement.select("circle").classList.add("pulse"); | |
| setTimeout(() => { | |
| newNodeElement.select("circle").classList.remove("pulse"); | |
| }, 3000); | |
| }); | |
| function updateGraph() { | |
| // Update the simulation | |
| simulation.nodes(graphData.nodes); | |
| simulation.force("link").links(graphData.links); | |
| if (physicsEnabled) { | |
| simulation.alpha(1).restart(); | |
| } | |
| // Update the links | |
| link.data(graphData.links).join("line").attr("class", "link"); | |
| linkText.data(graphData.links).join("text").text(d => d.relation); | |
| // Update the nodes | |
| const newNode = node.data(graphData.nodes).join("g") | |
| .attr("class", "node") | |
| .call(drag(simulation)); | |
| newNode.select("circle").attr("fill", d => d.color); | |
| newNode.select("text").text(d => d.name); | |
| // Add icons to new nodes | |
| newNode.filter((d, i) => i >= graphData.nodes.length - 1) | |
| .append("text") | |
| .attr("text-anchor", "middle") | |
| .attr("dy", ".35em") | |
| .attr("fill", "white") | |
| .attr("font-size", "12px") | |
| .html(d => { | |
| switch(d.type) { | |
| case "concept": return "π§ "; | |
| case "subfield": return "π"; | |
| case "technique": return "βοΈ"; | |
| case "method": return "π"; | |
| case "application": return "π»"; | |
| default: return "π"; | |
| } | |
| }); | |
| // Add tooltip to new nodes | |
| newNode.on("mouseover", function(event, d) { | |
| d3.select(this).select("circle").attr("r", 30); | |
| tooltip.transition() | |
| .duration(200) | |
| .style("opacity", 1); | |
| tooltip.html(` | |
| <h3 class="font-bold text-lg mb-1" style="color: ${d.color}">${d.name}</h3> | |
| <p class="text-sm text-gray-600 mb-1">Type: ${d.type}</p> | |
| <p class="text-sm text-gray-700">${d.description}</p> | |
| `) | |
| .style("left", (event.pageX + 10) + "px") | |
| .style("top", (event.pageY + 10) + "px"); | |
| }) | |
| .on("mouseout", function() { | |
| d3.select(this).select("circle").attr("r", 25); | |
| tooltip.transition() | |
| .duration(500) | |
| .style("opacity", 0); | |
| }); | |
| } | |
| }); | |
| </script> | |
| <p style="border-radius: 8px; text-align: center; font-size: 12px; color: #fff; margin-top: 16px;position: fixed; left: 8px; bottom: 8px; z-index: 10; background: rgba(0, 0, 0, 0.8); padding: 4px 8px;">Made with <img src="https://enzostvs-deepsite.hf.space/logo.svg" alt="DeepSite Logo" style="width: 16px; height: 16px; vertical-align: middle;display:inline-block;margin-right:3px;filter:brightness(0) invert(1);"><a href="https://enzostvs-deepsite.hf.space" style="color: #fff;text-decoration: underline;" target="_blank" >DeepSite</a> - 𧬠<a href="https://enzostvs-deepsite.hf.space?remix=Arg1990/knowledge-graph-s1" style="color: #fff;text-decoration: underline;" target="_blank" >Remix</a></p></body> | |
| </html> |