Skip to main content

Develop with FastTrack

NetworkGraph

The NetworkGraph widget displays relationships between entities. The relationships are displayed as nodes connected by lines. A configuration allows users to filter the nodes displayed in the graph. 

 

NetworkGraph MarkLogic setup

The NetworkGraph widget displays graphs showing relationships from MarkLogic result sets. For example, the result sets from the /v1/search and /v1/graphs/sparql endpoints from the MarkLogic REST API can be graphed using the widget.

In order to display triples from /v1/search results, the content must be extracted and included in the search results. This can be done by using the extract-document-data property in the query options in the application. For more information, see Include document extracts in search results.

Note

To use the /v1/graphs/sparql endpoint to execute SPARQL queries on triples and display the SPARQL results as a graph, the database triples index must be turned on.

Graph data model

To configure the NetworkGraph widget, an object with key/value pairs is provided that represents nodes and links in the graph. Each node and link have a unique key with a value object that determines how they appear in the graph. Link objects have id1 and id2 properties that use node keys as their values. The node keys determine the source and destination of each link.

In this example, the NetworkGraph widget configuration object has three nodes and three links. The configuration object is passed into NetworkGraph using the items prop. Additional configuration values are passed into the widget using the settings prop. The options object turns on navigation buttons (navigation: true) and sets the canvas background to white (backgroundColor: 'white').

For more information, see the third-party documentation included with FastTrack.

import { NetworkGraph } from "ml-fasttrack";
  
function App() {
  
  const items = {
    node1: {
      label: [{ text: 'My Node 1' }]
    },
    node2: {
      label: [{ text: 'My Node 2' }]
    },
    node3: {
      label: [{ text: 'My Node 3' }]
    },
    link1: {
      id1: 'node1',
      id2: 'node2'
    },
    link2: {
      id1: 'node1',
      id2: 'node3'
    },
    link3: {
      id1: 'node3',
      id2: 'node1',
    }
  };
 
  const settings = {
    options: {
      navigation: true,
      backgroundColor: 'white',
    }
  };
  
  return (
    <div>
      <NetworkGraph
        items={items}
        settings={{
          options: {
            backgroundColor: "white",
            navigation: true,
          }
        }}
      />;
    </div>
  );
}
  
export default App;

Note

The example displays nodes and graphs in NetworkGraph by defining them directly in an items object. The example does not transform data from MarkLogic into an object.

The next sections describe how to transform MarkLogic data and display it in a graph. The configuration displays the NetworkGraph example rendering.

NetworkGraph example rendering

In this example, one link goes from My Node 1 to My Node 2, another goes from My Node 1 to My Node 3, and a third goes from My Node 3 to My Node 1. Labels are added to the nodes as part of the node configuration.

An example rendering of the NetworkGraph widget.

There are many other configuration options for the nodes, links, and graph canvas.

For more information, see the third-party documentation included with FastTrack.

Graph search results with entityConfig

Relationship data from embedded triples in /v1/search results can be displayed as a graph. This is accomplished using the data and entityConfig props. The data prop is set to the /v1/search response. The entityConfig prop maps responses to the graph. This strategy assumes that:

  • Documents in the search results represent entity instances that will be represented as nodes in the graph. Node URIs are used as node keys.

  • Document URIs can be derived from the relationship triples embedded in the documents. If the data is modeled differently, refer to Graph results with transforms to transform relationship data.

In this example, the subject, predicate, and object are graphed from each embedded triple in a /v1/search response. The search response looks like this:

{
    "snippet-format": "snippet",
    "total": 3,
    "start": 1,
    "page-length": 10,
    "results": [
        {
            "index": 1,
            "uri": "/person/1001.json",
            "path": "fn:doc(\"/person/1001.json\")",
            "extracted": {
                "kind": "array",
                "content": [
                    {
                        "envelope": {
                            "entityType": "person",
                            "id": 1001,
                            "firstName": "Nerta",
                            "lastName": "Hallwood",
                            "address": {
                                "state": "Texas",
                                "country": "United States"
                            },                          
                            "relations": [
                                {
                                    "triple": {
                                        "subject": "http://example.org/person/1001.json",
                                        "predicate": "http://xmlns.com/foaf/0.1/knows/",
                                        "object": "http://example.org/person/1002.json"
                                    }
                                },
                                {
                                    "triple": {
                                        "subject": "http://example.org/person/1001.json",
                                        "predicate": "http://xmlns.com/foaf/0.1/knows/",
                                        "object": "http://example.org/person/1003.json"
                                    }
                                }
                            ]
                        }
                    }
                ]
            }
        },
        // more results
    ],
    "qtext": "person",
}

Each search result includes a document extract with semantic triples. The subject and object values in the triples include the URIs of the entities they relate to. Each search result also includes the entityType for the entity instance. In this example, entityType is set to person.

The NetworkGraph widget can be configured to display entity instances as nodes in the graph. Links represent the triple relationships.

NetworkGraph example configuration

A React application with the NetworkGraph widget and entityConfig and data props looks like this:

import { useContext } from "react";
import "./App.css";
import { MarkLogicContext, SearchBox, NetworkGraph } from "ml-fasttrack";
  
function App() {
  
  const context = useContext(MarkLogicContext);
  
  const handleSearch = (params) => {
    context.setQtext(params?.q);
  }
 
  const entityConfig = {
    entityTypeConfig: {
      "path": "extracted.content[0].envelope.entityType"
    },
    entities: [
      {
        entityType: "person",
        triples: {
          path: "extracted.content[0].envelope.relations",
          subject: {
            path: "triple.subject",
            regex: /\/\w+\/[^/]+$/
          },
          predicate: {
            path: "triple.predicate"
          },
          object: {
            path: "triple.object",
            regex: /\/\w+\/[^/]+$/
          }
        },
        items: {
          label: [
            {
              text: { path: "extracted.content[0].envelope.firstName" }
            }
          ]
        },
        nodeRelations: {
          relationLabelRgx: /(\w+)$/
        }
      }
    ]
  }
  
  return (
    <div className="App">
      <div>
        <SearchBox onSearch={handleSearch}/>
      </div>
      <div>
          <NetworkGraph
            data={context?.searchResponse}
            entityConfig={entityConfig}
          />
      </div>
    </div>
  );
}
  
export default App;

 

Code explanation

Notes on the NetworkGraph example configuration:

  • To make the MarkLogic search response available to the NetworkGraph widget, the data prop is assigned the searchResponse value from the application context.

  • The entityConfig prop accepts a configuration object that tells the widget how to build the data model for the underlying graph from the response data.

  • The path values in the configuration object map the data in the search response payload to the graph data model.

  • Regex props can be used to select parts of the triple values to use in the graph. This example uses the regex values to extract the URIs from the subject and object values. For more details about the configuration props, see NetworkGraph API

NetworkGraph example rendering

The NetworkGraph example configuration generates this graph:

An example graph.

Node labels are defined in the firstName property from each entity instance and are configured with the entities[].items property. The link label is extracted from the predicate value in each triple using the regex in the nodeRelations property.

Graph results with transforms

Data from SPARQL results and other types of payloads can be transformed into the data model expected by the graph widget. Then, the data can be passed to the NetworkGraph widget as an items prop.

This example shows a React application using a SPARQL query and the transformation strategy:

import { useContext, useEffect } from "react";
import "./App.css";
import { MarkLogicContext, NetworkGraph } from "ml-fasttrack";
  
function App() {
  
  const context = useContext(MarkLogicContext);
 
  const sparqlQuery = `    
    SELECT (str(?subName) as ?s) ?p (str(?objName) as ?o) (str(?subState) as ?sState) (str(?objState) as ?oState)    
    WHERE {
      ?subject ?predicate ?object .
      ?subject <http://xmlns.com/foaf/0.1/knows> ?object .
      ?subject <http://example.org/firstName> ?subName .
      ?object <http://example.org/firstName> ?objName .      
      ?subject <http://example.org/state> ?subState .
      ?object <http://example.org/state> ?objState .
      BIND (SUBSTR(?predicate,27,5) AS ?p)    
    }
  `
 
  const sparqlToItems = (sparqlResponse) => {
    if (!sparqlResponse) return;
    let items = {};
    sparqlResponse.results.bindings.forEach(r => {
      const { s, p, o } = r
      // create subject node
      if (s && s?.value) {
          items[s.value] = {
            label: [{ text: s?.value }],
          }
      }
      // create object node
      if (o && o?.value) {
          items[o.value] = {
            label: [{ text: o?.value }],
          }
      }
      // create predicate link
      if (s && s?.value && o && o?.value) {
        items[s.value + '-' + o.value] = {
          id1: s.value,
          id2: o.value,
          label: { text: p?.value },
        }
      }
    })
    return items;
  }
 
  useEffect(() => {
    context.getSparql(sparqlQuery);
  }, []);
 
  return (
    <div className="App">
      <div>
          <NetworkGraph
            items={sparqlToItems(context.sparqlResponse)}
            onSelectNode={(event) => console.log(event)}
          />
      </div>
    </div>
  );
}
  
export default App;
Code explanation

In Graph results with transforms:

  • The SPARQL query is used on the /v1/graphs/sparql endpoint using the getSparql method from the application context. The query is defined in the sparqlQuery variable.

  • The query is executed on load using a useEffect hook and the getSparql method from the application context.

  • The SPARQL result is stored in context.sparqlResponse by the application context.

  • To transform the MarkLogic SPARQL response into the data model expected by the graph widget, a sparqlToItems function is used. It is a custom function that accesses the bindings in a SPARQL response to build nodes and links. 

  • The onSelectNode prop is passed a callback to handle node selection events.

Graph results with transforms example rendering

The code in Graph results with transforms generates this graph. Clicking a node in the graph logs the click event to the console.

An example rendering of the NetworkGraph.

Styling nodes and links

Styles can be applied to nodes and links in the graph by adding properties. The examples in this section illustrate how to:

  • change the color and size of nodes.

  • change the color and width of links.

  • turn on link arrows.

If the entityConfig strategy is used for mapping, additional properties can be added to the entityConfig object under the entities[].items and entities[].nodeRelations properties:

const entityConfig = {
    entityTypeConfig: {
      "path": "extracted.content[0].envelope.entityType"
    },
    entities: [
      {
        entityType: "person",
        triples: {
          path: "extracted.content[0].envelope.relations",
          subject: {
            path: "triple.subject",
            regex: /\/\w+\/[^/]+$/
          },
          predicate: {
            path: "triple.predicate"
          },
          object: {
            path: "triple.object",
            regex: /\/\w+\/[^/]+$/
          }
        },
        items: {
          color: "red",
          size: 2,
          label: [
            {
              text: { path: "extracted.content[0].envelope.firstName" }
            }
          ]
        },
        nodeRelations: {
          relationLabelRgx: /(\w+)$/,
          link: {
            width: 10,
            color: "orange",
            end1: { arrow: false },
            end2: { arrow: true }
          }
        }
      }
    ]
  }

If a transformation function is used for mapping, the style properties can be set for each subject, predicate, and object in the function:

const sparqlToItems = (sparqlResponse) => {
  if (!sparqlResponse) return;
  let items = {};
  sparqlResponse.results.bindings.forEach(r => {
    const { s, p, o } = r
    if (s && s?.value) {
        items[s.value] = {
          label: [{ text: s?.value }],
          color: "red",
          size: 2
        }
    }
 
    if (o && o?.value) {
        items[o.value] = {
          label: [{ text: o?.value }],
          color: "red",
          size: 2
        }
    }
 
    if (s && s?.value && o && o?.value) {
      items[s.value + '-' + o.value] = {
        id1: s.value,
        id2: o.value,
        label: { text: p?.value },
        width: 3,
        color: "orange",
        end1: { arrow: false },
        end2: { arrow: true }
      }
    }
 
  })
  return items;
}

Styling the nodes and links using the additional properties displays this graph:

Graphic showing styled nodes and links.

For more information, see the third-party documentation included with FastTrack.

Filter nodes

Nodes in the graph can be filtered. To filter nodes, include properties for the filter in each node's configuration. If the entityConfig strategy is used to show search results as a graph, include a filters object with key/value pairs. The key/values pairs should specify the path to the result property. This example includes the state address in each node configuration with the key stateVal:

const entityConfig = {
    entityTypeConfig: {
      "path": "extracted.content[0].envelope.entityType"
    },
    entities: [
      {
        entityType: "person",
        triples: {
          path: "extracted.content[0].envelope.relations",
          subject: {
            path: "triple.subject",
            regex: /\/\w+\/[^/]+$/
          },
          predicate: {
            path: "triple.predicate"
          },
          object: {
            path: "triple.object.value",
            regex: /\/\w+\/[^/]+$/
          }
        },      
        filters: {
          stateVal: { path: 'extracted.content[0].envelope.address.state' },
        },        
        nodeRelations: {
          relationLabelRgx: /(\w+)$/
        }
      }
    ]
  }

Custom transformation functions can include filter properties in each node configuration. In this example SPARQL query, state values for the subjects and objects are included as the sState and oState bindings. These bindings can then be accessed in order to put the state values in the subject and object node configurations:

const sparqlToItems = (sparqlResponse) => {
    if (!sparqlResponse) return;
    let items = {};
    sparqlResponse.results.bindings.forEach(r => {
      const { s, p, o, sState, oState } = r
      if (s && s?.value) {
          items[s.value] = {
            label: [{ text: s?.value }],
            stateVal: sState.value
          }
      }
 
      if (o && o?.value) {
          items[o.value] = {
            label: [{ text: o?.value }],
            stateVal: oState.value          
          }
      }
   
      if (s && s?.value && o && o?.value) {
        items[s.value + '-' + o.value] = {
          id1: s.value,
          id2: o.value,
          label: { text: p?.value },
        }
      }
   
    })
    return items;
  }

Once the filter values are present in the node configuration objects, a filter list can be configured in the NetworkGraph widget with a filterConfig prop:

<NetworkGraph
  data={context?.searchResponse}
  entityConfig={graphConfig}
  filterConfig={[
    {
      label: 'State',
      path: 'stateVal'
    }
  ]}
/>
Code explanation

In the Filter nodes example:

  • Each object in the filterConfig array defines a filter list. This example defines a single filter list for the state property.

  • The label value specifies the list title.

  • The path value references the property in the node object. This path value can be the key from the filter's configuration object (in this case, stateVal) or a dot-notated path from the key if the value in the node object is an object.

Filter nodes example rendering

Adding a filter list to the NetworkGraph using the example code in Filter nodes displays:

Example rendering of filtering nodes.

Users can click the check boxes to limit the nodes displayed.

NetworkGraph API

Prop 

Type 

Description 

items

object

Items to display in the graph. Each node and relation are defined with a property and object value.

For more information, see the third-party documentation included with FastTrack.

Note

Nodes and links can be defined in the graph directly using the items prop.

data

object

Search results payload to display in the graph. This works in conjunction with the entityConfig prop.

dataConfig

object

Optional JSONPath for indicating the results in the data prop.

entityConfig

object

Entity-specific configuration settings for the subject, predicate, and object values, labels, and styles in the graph.

For more information, see the third-party documentation included with FastTrack.

showMap

boolean

Show the map in the canvas with Leaflet. Requires a coordinates object.

For more information, see the third-party documentation included with FastTrack.

settings

Record<string, any>

Configuration props passed in for the graph, including canvas options, event handlers, and other properties (such as adding a reference to manage adjustments in the view).

For more information, see the third-party documentation included with FastTrack.

height

string

Height of the widget canvas as a CSS height value. Default is "400px".

width

string

Width of the widget canvas as a CSS width value. Default is "100%"

relationsLevel

number

Relations level for filtering.

selectedElement

string

ID of the selected element.

filterConfig

{ id: string; label: string; path: string; }[]

Configuration settings for the graph filter.

fontFamilies

string[]

Array of font families. Example name: "Font Awesome 5 Free".

nodeConfig

object

Default settings for a node when it is not defined in entityConfig.

relationConfig

object

Default settings for a relation link when it is not defined in entityConfig.

itemsTooltipConfig

object

Configuration object that maps and formats a tooltip for a node when not defined in entityConfig.

onSelectNode

((node: any) => void)

Callback function triggered when a node is clicked.

onDoubleClickNode

((node: any) => void)

Callback function triggered when a node is double-clicked.

entityConfig API

Property 

Type 

Description 

entityTypeConfig

object

Entity type configuration object.

entityTypeConfig.path

string

Path to the entity type in the search result. The path is specified using JSONPath .

entities[]

object[]

Array of graph configuration objects for each entity.

entities[].entityType

string

Entity type of the configuration object.

entities[].triples

object

Triples configuration object.

entities[].triples.path

string

Path to the array of triples. The path is specified using JSONPath.

entities[].triples.subject

object

Triple subject configuration object.

entities[].triples.subject.path

string

Path to the subject value relative to the triples path. The path is specified using JSONPath.

entities[].triples.subject.regex

regex

Optional regex with which to select a part of the subject value.

entities[].triples.predicate

object

Triple predicate configuration object.

entities[].triples.predicate.path

string

Path to the predicate value relative to the triples path. The path is specified using JSONPath.

entities[].triples.object

object

Triple object configuration object.

entities[].triples.object.path

string

Path to the object value relative to the triples path. The path is specified using JSONPath.

entities[].triples.object.regex

regex

Optional regex with which to select a part of the object value.

entities[].items

object

Styles and formatting applied to the nodes.

For more information, see the third-party documentation included with FastTrack.

entities[].nodeRelations.relationLabelRgx

string

Optional regex with which to select a part of the predicate value as a link label.

entities[].nodeRelations.link

object

Styles and formatting applied to the links.

For more information, see the third-party documentation included with FastTrack.

entities[].tooltipConfig

object

Configuration object that maps and formats a tooltip for a node.

entities[].filters

object

Configuration object that defines extra values to include in the node objects. The values are used for filtering.