Data Model: SPARQL CONSTRUCT Graph Visualization

December 6, 2025 · View on GitHub

Feature: 001-construct-graph-viz
Date: 2025-12-05
Purpose: Define core data structures and their relationships

Entity Definitions

GraphNode

Represents a unique subject or object from RDF triples in the visualization.

Attributes:

  • id (Number): Unique numeric identifier for vis-network (auto-incremented)
  • uri (String | null): Full URI for URI nodes, null for literals
  • label (String): Display text (prefixed URI or literal value, truncated if needed)
  • color (String): Hex color code - #a6c8a6ff (light green, literals), #e15b13ff (orange, rdf:type objects), #97C2FC (light blue, other URIs), #c5c5c5ff (light grey, blank nodes)
  • type (Enum): 'uri' or 'literal'
  • fullValue (String): Un-truncated value for tooltip display

Relationships:

  • Connected to other GraphNodes via GraphEdges (many-to-many through edges)
  • Multiple edges can connect same pair of nodes (different predicates)

Lifecycle:

  • Created during triple parsing
  • Deduplicated by URI/literal value (Map-based construction)
  • Persists in vis-network DataSet until new query results arrive

Example:

{
  id: 1,
  uri: 'http://example.org/Person',
  label: 'ex:Person',
  color: '#e15b13ff', // Orange if object of rdf:type
  type: 'uri',
  fullValue: 'http://example.org/Person'
}

{
  id: 2,
  uri: null,
  label: 'John',
  color: '#a6c8a6ff', // Light green for literals
  type: 'literal',
  fullValue: '"John"^^xsd:string'
}

GraphEdge

Represents an RDF predicate connecting two nodes.

Attributes:

  • id (String): Optional unique identifier (can be auto-generated by vis-network)
  • from (Number): Source node ID (subject)
  • to (Number): Target node ID (object)
  • label (String): Predicate label (prefixed form, truncated if needed)
  • predicate (String): Full predicate URI
  • arrows (String): Arrow direction ('to' for directed edges)

Relationships:

  • Links exactly one source GraphNode (from) to one target GraphNode (to)
  • One-to-one with RDF predicate (after deduplication)

Lifecycle:

  • Created for each unique triple (subject-predicate-object combination)
  • Duplicate triples deduplicated (same from/to/predicate = single edge)
  • Automatically repositions when connected nodes are dragged

Example:

{
  id: 'edge_1_2',
  from: 1,
  to: 2,
  label: 'ex:name',
  predicate: 'http://example.org/name',
  arrows: 'to'
}

RDFTriple (Intermediate)

Raw triple data extracted from SPARQL CONSTRUCT results. Transformed into GraphNodes and GraphEdges.

Attributes:

  • subject (String): Subject URI
  • predicate (String): Predicate URI
  • object (Object): Object with properties:
    • value (String): URI or literal value
    • type (String): 'uri' or 'literal'
    • datatype (String | undefined): Datatype URI for literals (e.g., http://www.w3.org/2001/XMLSchema#string)

Lifecycle:

  • Parsed from YASR results (bindings or JSON-LD format)
  • Exists transiently during transformation
  • Not persisted after graph data created

Example:

{
  subject: 'http://example.org/Person',
  predicate: 'http://example.org/name',
  object: {
    value: 'John',
    type: 'literal',
    datatype: 'http://www.w3.org/2001/XMLSchema#string'
  }
}

PrefixMap

Mapping of namespace prefixes to URIs for label abbreviation.

Attributes:

  • Key (String): Prefix abbreviation (e.g., 'ex', 'rdf', 'xsd')
  • Value (String): Full namespace URI (e.g., 'http://example.org/')

Lifecycle:

  • Extracted from YASR query metadata or result prefixes
  • Merged with common default prefixes (rdf, rdfs, xsd, owl)
  • Used during node/edge label generation
  • Persists for duration of visualization

Example:

{
  'rdf': 'http://www.w3.org/1999/02/22-rdf-syntax-ns#',
  'rdfs': 'http://www.w3.org/2000/01/rdf-schema#',
  'xsd': 'http://www.w3.org/2001/XMLSchema#',
  'ex': 'http://example.org/'
}

NetworkOptions

Configuration object passed to vis-network instance.

Attributes:

  • physics (Object): Physics engine settings (force-directed layout)
    • enabled (Boolean): Physics simulation on/off
    • stabilization (Object): Initial layout stabilization config
      • iterations (Number): Max iterations (200 default)
  • interaction (Object): User interaction settings
    • dragNodes (Boolean): Enable node dragging
    • zoomView (Boolean): Enable zoom via mouse wheel
    • dragView (Boolean): Enable pan via drag
    • hover (Boolean): Enable hover events for tooltips
  • layout (Object): Layout algorithm settings
    • improvedLayout (Boolean): Use improved force-directed layout
  • autoResize (Boolean): Auto-detect container size changes
  • width (String): Canvas width ('100%')
  • height (String): Canvas height ('100%')

Lifecycle:

  • Defined once during plugin initialization
  • Can be updated via network.setOptions() (e.g., disable physics after stabilization)

Example:

{
  physics: {
    enabled: true,
    stabilization: {iterations: 200}
  },
  interaction: {
    dragNodes: true,
    zoomView: true,
    dragView: true,
    hover: true
  },
  layout: {improvedLayout: true},
  autoResize: true,
  width: '100%',
  height: '100%'
}

Data Flow

SPARQL CONSTRUCT Results (YASR)

   Parse to RDFTriples[]

   Extract PrefixMap

   Transform to {nodes: GraphNode[], edges: GraphEdge[]}

   Create vis-network DataSets

   Render Network instance

   User Interactions → Update DataSets → Re-render

State Management

Plugin State

  • this.yasr: Reference to YASR instance (access to results, resultsEl)
  • this.network: vis-network Network instance (null until first draw)
  • this.container: DOM element containing visualization
  • this.prefixes: Current PrefixMap
  • this.nodesDataSet: vis-network DataSet for nodes
  • this.edgesDataSet: vis-network DataSet for edges

Lifecycle

  1. Plugin Creation: Constructor called, state initialized
  2. Results Arrival: canHandleResults() checks format
  3. First Render: draw() creates container, Network instance, parses triples, renders
  4. Subsequent Renders: Clear DataSets, parse new results, update visualization
  5. Interactions: vis-network handles internally, state preserved
  6. Tab Switch: Container hidden/shown by YASR, Network instance persists

Validation Rules

GraphNode

  • id must be unique within visualization
  • color must be valid hex code (#RRGGBB)
  • type must be 'uri' or 'literal'
  • label should not exceed 50 characters (truncate with ellipsis)

GraphEdge

  • from and to must reference existing node IDs
  • predicate must be valid URI
  • No duplicate edges (same from + to + predicate)

RDFTriple

  • subject must be valid URI
  • predicate must be valid URI
  • object.type must be 'uri' or 'literal'
  • object.datatype required for literals (can be inferred as xsd:string if missing)

Edge Cases Handling

  • Empty triples array: No nodes or edges → Empty state message
  • Self-referencing triple: from === to → vis-network renders loop edge
  • Disconnected components: Multiple unconnected subgraphs → All rendered with auto-spacing
  • Very long labels: Truncate to 50 chars, preserve full value in fullValue attribute
  • Missing prefixes: Fall back to URI truncation with ellipsis
  • Duplicate triples: Deduplicate during edge creation (Set/Map-based tracking)
  • No datatype on literal: Default to xsd:string