@matdata/yasgui-graph-plugin
v1.6.2
Published
YASGUI plugin for visualizing SPARQL CONSTRUCT and DESCRIBE query results as interactive graphs
Maintainers
Readme
YASGUI Graph Plugin
A YASGUI plugin for visualizing SPARQL CONSTRUCT and DESCRIBE query results as interactive graphs with nodes (subjects/objects) and edges (predicates).
✨ Features
- 🔷 Interactive Graph Visualization: Automatic force-directed layout with smooth physics-based positioning
- 🎨 Smart Color Coding:
- 🔵 Light Blue (#97C2FC) = URIs
- 🟢 Light Green (#a6c8a6ff) = Literals
- ⚪ Light Grey (#c5c5c5ff) = Blank nodes
- 🟠 Orange (#e15b13ff) = rdf:type objects (classes)
- 🖼️ Node Icons & Images: Render images or emoji/icons on nodes via
schema:image/schema:iconproperties (see Node icons and images) - � Compact Mode: Hide literal and class nodes; show rdf:type and datatype properties in enhanced tooltips instead
- 🔍 Navigation: Mouse wheel zoom, drag to pan, "Zoom to Fit" button
- ✋ Drag & Drop: Reorganize nodes by dragging them to new positions (nodes stay pinned after manual drag)
- � Node Expansion: Double-click any URI node to fetch and merge related triples via DESCRIBE queries (see Expand Nodes with Double Click)
- �💬 Rich Tooltips: Modern HTML tooltips with node type, value, namespace, and datatype information
- 🌓 Theme Support: Automatic light/dark mode detection and dynamic color switching
- ⚡ Performance: Handles up to 1,000 nodes with <2s render time
- ♿ Accessible: WCAG AA color contrast, keyboard navigation support
📦 Installation
NPM
npm install @matdata/yasgui-graph-pluginimport Yasgui from '@matdata/yasgui';
import GraphPlugin from '@matdata/yasgui-graph-plugin';
Yasgui.Yasr.registerPlugin('Graph', GraphPlugin);
const yasgui = new Yasgui(document.getElementById('yasgui'));CDN (UMD)
<!-- YASGUI -->
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/@matdata/yasgui/build/yasgui.min.css">
<script src="https://cdn.jsdelivr.net/npm/@matdata/yasgui/build/yasgui.min.js"></script>
<!-- Graph Plugin -->
<script src="https://cdn.jsdelivr.net/npm/@matdata/yasgui-graph-plugin/dist/yasgui-graph-plugin.min.js"></script>
<script>
// Plugin auto-registers as 'graph'
const yasgui = new Yasgui(document.getElementById('yasgui'));
</script>🚀 Quick Start
See the complete working example in demo/index.html.
Basic Usage
const yasgui = new Yasgui(document.getElementById('yasgui'), {
requestConfig: {
endpoint: 'https://dbpedia.org/sparql'
}
});Sample Queries
CONSTRUCT Query:
PREFIX ex: <http://example.org/>
PREFIX rdf: <http://www.w3.org/1999/02/22-rdf-syntax-ns#>
CONSTRUCT {
ex:Alice rdf:type ex:Person .
ex:Alice ex:knows ex:Bob .
ex:Alice ex:name "Alice" .
ex:Bob rdf:type ex:Person .
ex:Bob ex:name "Bob" .
}
WHERE {}DESCRIBE Query:
PREFIX ex: <http://example.org/>
# Returns all triples about the specified resources
DESCRIBE ex:Alice ex:BobAfter running the query, click the "Graph" tab to see the visualization.
🎮 User Guide
Navigation
- Zoom: Mouse wheel (scroll up = zoom in, scroll down = zoom out)
- Pan: Click and drag the background
- Fit to View: Click the "Zoom to Fit" button to center the entire graph
Interaction
- Drag Nodes: Click and drag any node to reposition it (nodes are automatically pinned in place after dragging)
- Expand Nodes: 🆕 Double-click any blue URI node to fetch and merge additional RDF triples for that resource (see Node Expansion below)
- Tooltips: Hover over nodes/edges to see rich HTML tooltips with type, value, namespace, and datatype information
Understanding Colors
| Color | Meaning | Example |
|-------|---------|---------||
| 🔵 Light Blue (#97C2FC) | URI nodes | ex:Person, ex:Alice |
| 🟢 Light Green (#a6c8a6ff) | Literal values | "Alice", "30"^^xsd:integer |
| ⚪ Light Grey (#c5c5c5ff) | Blank nodes | _:b1, _:addr1 |
| 🟠 Orange (#e15b13ff) | rdf:type objects (classes) | ex:Person in ex:Alice rdf:type ex:Person |
⚙️ Configuration
The plugin ships with sensible defaults and stores every change in localStorage so settings survive page reloads.
Settings panel
Click the ⚙ Settings button (top-right of the graph) to open the settings panel.
| Setting | Values | Default | Description |
|---------|--------|---------|-------------|
| Compact mode | on / off | off | Hide literal and class nodes; show rdf:type and datatype properties in tooltips instead |
| Arrow style | Curved / Straight | Curved | Toggle between smooth curved edges and straight lines between nodes |
| Predicate display | Label / Icon / Hidden | Icon | Show the full prefixed URI on edges, a compact symbol/icon, or nothing |
| Show literals | on / off | on | Include or exclude literal value nodes (strings, numbers, dates, …) |
| Show classes | on / off | on | Include or exclude nodes that are objects of rdf:type triples (class nodes) |
| Show blank nodes | on / off | on | Include or exclude blank nodes (_:b0, _:b1, …) |
| Show node labels | on / off | on | Render the prefixed URI / literal text inside each node |
| Enable physics | on / off | on | Keep the force-directed layout simulation running so nodes keep adjusting |
| Node size | Small / Medium / Large | Medium | Set the radius of all nodes |
Predicate icons
When Predicate display is set to Icon, each edge displays a compact symbol instead of the full label. Symbols are defined for the 20+ most common predicates:
| Predicate | Symbol |
|-----------|--------|
| rdf:type | a |
| rdfs:label | lbl |
| rdfs:comment | cmt |
| rdfs:subClassOf | ⊂ |
| rdfs:subPropertyOf | ⊆ |
| rdfs:domain | dom |
| rdfs:range | rng |
| rdfs:seeAlso | see |
| rdfs:isDefinedBy | idb |
| owl:sameAs | ≡ |
| owl:equivalentClass | ≅ |
| owl:inverseOf | ⇄ |
| owl:disjointWith | ≠ |
| skos:prefLabel | ★ |
| skos:altLabel | ☆ |
| skos:definition | def |
| skos:broader | ↑ |
| skos:narrower | ↓ |
| skos:related | ↔ |
| skos:note | note |
| skos:exactMatch | ≡ |
| skos:closeMatch | ≈ |
| dcterms:title | ttl |
| dcterms:description | dsc |
| dcterms:created | crt |
| dcterms:modified | mod |
| dcterms:creator | by |
| dcterms:subject | sbj |
| foaf:name | nm |
| foaf:knows | ⟷ |
| foaf:member | mbr |
| schema:name | nm |
| schema:description | dsc |
For predicates not in the table the full prefixed label is used as a fallback.
🖼️ Node icons and images
Any URI node can display an image or an icon instead of (or in addition to) the default coloured dot by attaching schema:image or schema:icon as a property directly in the SPARQL result.
| Property | Object | Effect |
|----------|--------|--------|
| schema:image (https://schema.org/image) | URL literal or URI | Node is rendered as a circular image |
| schema:icon (https://schema.org/icon) | emoji / short string | The string is used as the node's label |
schema:icon takes priority over schema:image. The corresponding schema:icon/schema:image triples are not rendered as separate nodes or edges, but their values are shown in the node tooltip. Similarly, any rdfs:label triple is consumed to determine the node's displayed label and is never drawn as an edge, even when predicate display is enabled.
Example – inline image on a resource
CONSTRUCT {
ex:alice schema:image <https://example.com/alice.png> .
ex:alice ex:knows ex:bob .
}
WHERE {}ex:alice will be drawn as a circular photograph.
Example – icon/emoji on a class
CONSTRUCT {
ex:alice rdf:type ex:Person .
ex:Person schema:icon "👤" .
}
WHERE {}ex:alice remains a normal dot node in regular mode.
In compact mode the class node (ex:Person) is hidden and Alice's node inherits the 👤 emoji as its label.
Compact mode visual inheritance
When compact mode is enabled, class nodes are hidden and the plugin resolves the image/icon to show on the resource node using the following priority:
schema:image/schema:icondirectly on the resource (highest priority)schema:image/schema:iconon the rdf:type classschema:image/schema:iconon a rdfs:subClassOf superclass (one hop)
Programmatic configuration
You can also pass initial settings when extending the class:
class CustomGraphPlugin extends GraphPlugin {
constructor(yasr) {
super(yasr);
// Override defaults
this.settings.edgeStyle = 'straight';
this.settings.predicateDisplay = 'label';
this.settings.nodeSize = 'large';
}
}
Yasgui.Yasr.registerPlugin('customGraph', CustomGraphPlugin);� Expand Nodes with Double Click
The graph plugin supports interactive node expansion via double-clicking. This allows you to progressively explore RDF graphs by fetching additional triples for any URI node without redrawing the entire graph.
How It Works
- Double-click a blue URI node in the graph
- The node's border turns orange and thickens (loading state)
- A
DESCRIBE <uri>query is sent to the SPARQL endpoint - New triples are merged into the existing graph
- Node's border returns to normal width with thicker border (3px) to indicate expansion
- Graph layout and zoom level are preserved
Visual Feedback
| State | Border | Meaning | |-------|--------|---------| | Default | 2px | Node has not been expanded | | Loading | 4px, orange | DESCRIBE query in progress | | Expanded | 3px, normal color | Successfully expanded |
Supported Node Types
| Node Type | Can Expand? | Reason | |-----------|-------|----| | 🔵 URI nodes | ✅ Yes | DESCRIBE works on URIs | | 🟢 Literals | ❌ No | Cannot run DESCRIBE on literal values | | ⚪ Blank nodes | ❌ No | Blank nodes have no resolvable identity |
Example: Exploring a Knowledge Graph
Initial Query:
PREFIX ex: <http://example.org/>
PREFIX foaf: <http://xmlns.com/foaf/0.1/>
CONSTRUCT {
ex:alice foaf:knows ex:bob .
ex:alice foaf:name "Alice" .
ex:bob foaf:name "Bob" .
}
WHERE {}Initial Graph: 3 nodes (Alice, "Alice", Bob, "Bob"), 2 edges
User Action: Double-click the ex:bob node
What Happens:
- System executes:
DESCRIBE <http://example.org/bob> - Endpoint returns all triples about Bob (from your SPARQL endpoint)
- New nodes and edges appear in the graph
- Graph layout shifts smoothly to accommodate new nodes
ex:bobnode gets a thicker border
Result: You can now see Bob's relationships, properties, and connections without losing your current view
Requirements
The node expansion feature requires:
- SPARQL 1.1 DESCRIBE support: Your endpoint must support DESCRIBE queries
- Query execution callback: YASR must provide
yasr.executeQuery()for background queries - RDF response format: Endpoint must return results in RDF (JSON-LD, Turtle, N-Triples, etc.)
Limitations & Behavior
- Only new triples are added (existing triples are skipped if already in graph)
- Expansion is one-level deep - only triples directly about the URI are added
- For very large result sets (1000+ triples from DESCRIBE), performance may be affected
- Blank nodes returned by DESCRIBE may not connect properly if disconnected from existing nodes
Troubleshooting Expansion
"Nothing happens when I double-click"
- Ensure the node is blue (URI node, not literal or blank node)
- Check browser console for warnings about
yasr.executeQuery - Verify your SPARQL endpoint supports DESCRIBE queries
"Graph becomes slow after many expansions"
- Disable physics simulation in Settings panel for faster UI response
- Consider limiting query results with WHERE clause constraints
- Each expansion adds more triples to the visualization
"New nodes don't appear where I expect"
- The force-directed layout will position new nodes to minimize overlaps
- Disable Physics in Settings to lock positions if desired
- Manually drag new nodes to preferred positions
Demo
See demo/expand.html for a working example with mock DESCRIBE responses and detailed logging.
�🔧 Development
Build
npm install
npm run buildOutput:
dist/yasgui-graph-plugin.esm.js(ES Module for bundlers)dist/yasgui-graph-plugin.cjs.js(CommonJS for Node.js)dist/yasgui-graph-plugin.min.js(IIFE for browsers/unpkg)dist/index.d.ts(TypeScript declarations)
Local Testing
- Build the plugin:
npm run build - Open
demo/index.htmlin a browser (or runnpm run dev) - Try the sample queries in different tabs
Code Quality
npm test # Run Jest unit tests
npm run lint # ESLint check
npm run format # Prettier format📚 Documentation
- Quickstart Guide - Installation, usage, troubleshooting
- Node Expansion Feature - Complete guide to double-click expansion (FR-001 through FR-009)
- Data Model - Entity definitions and relationships
- Contracts - API specifications for YASR plugin and vis-network integration
- Specification - Complete feature specification
- [Constitution](./. specify/memory/constitution.md) - Project governance and principles
🧪 Browser Compatibility
Tested on latest 2 versions of:
- ✅ Chrome
- ✅ Firefox
- ✅ Safari
- ✅ Edge
Requires ES2018+ support and Canvas API.
🤝 Contributing
Contributions welcome! Please follow the project constitution (.specify/memory/constitution.md) for governance principles:
- Plugin-First Architecture - No YASGUI core modifications
- Visualization Quality - Performance (<2s for 1k nodes), accessibility (WCAG AA)
- Configuration Flexibility - Sensible defaults, but customizable
- Browser Compatibility - ES2018+, latest 2 browser versions
- Documentation - Keep docs updated with changes
📄 License
🙏 Acknowledgments
- Built with vis-network for graph rendering
- Integrates with YASGUI SPARQL editor
- Follows the yasgui-geo plugin pattern
📊 Project Status
Current Version: 0.1.0 (MVP)
Implemented Features (v0.1.0):
- ✅ Basic graph visualization (US1) - CONSTRUCT/DESCRIBE results as interactive graphs
- ✅ Navigation controls (US2) - Zoom, pan, "Fit to View" button
- ✅ Color-coded nodes - URIs, literals, blank nodes, rdf:type objects
- ✅ Prefix abbreviation - Display prefixed URIs instead of full URLs
- ✅ Blank node support - Handle anonymous RDF nodes
- ✅ Drag & repositioning - Manually adjust node positions
- ✅ Rich tooltips - Hover for detailed node/edge information
- ✅ Theme support - Light/dark mode detection and switching
- ✅ Settings panel - Configurable display options with localStorage persistence
- ✅ Node icons & images - Display images via schema:image property
- ✅ Compact mode - Hide literals and classes for cleaner visualization
- ✅ Double-click expansion (US5) - Fetch and merge related triples via DESCRIBE queries (see Expand Nodes with Double Click)
🐛 Troubleshooting
Plugin tab not showing
- Verify plugin is registered correctly
- Check browser console for errors
- Ensure you're running a CONSTRUCT or DESCRIBE query
Empty visualization
- Ensure query type is CONSTRUCT or DESCRIBE
- Confirm query returns triples (check "Table" or "Response" tab)
- Verify results have RDF structure
Performance issues
- Limit results to <1000 nodes for best performance
- Disable physics after initial layout
- Consider using LIMIT clause in SPARQL query
For more help, see Quickstart Guide - Troubleshooting.
🛠️ Development
Setup
git clone https://github.com/yourusername/yasgui-graph-plugin.git
cd yasgui-graph-plugin
npm installDev Workflow (Live Reload)
The project supports live development - edit source files and see changes immediately without rebuilding:
Start a local dev server (any HTTP server will work):
# Using Python python -m http.server 8000 # Using Node.js (http-server) npx http-server -p 8000 # Using VS Code Live Server extension # Right-click demo/index.html → "Open with Live Server"Open demo in browser:
http://localhost:8000/demo/index.htmlEdit source files (e.g.,
src/colorUtils.js):export function getNodeColor(node) { // Change colors here if (node.isBlankNode) return '#FF00FF'; // Magenta // ... }Refresh browser - changes appear immediately! ⚡
The demo automatically loads ES modules directly from src/ in development mode, so no rebuild is needed.
Production Build
Build all distribution formats:
npm run buildOutputs:
dist/yasgui-graph-plugin.esm.js- ES Module format (bundled with vis-network)dist/yasgui-graph-plugin.cjs.js- CommonJS format (bundled with vis-network)dist/yasgui-graph-plugin.min.js- IIFE browser bundle (bundled with vis-network)dist/index.d.ts- TypeScript type declarations
Testing
npm test # Run all tests
npm run lint # Check code style
npm run format # Auto-fix formatting