Virtual properties
Table of Contents
1. Virtual properties in the Detail tab
Virtual properties in visualization can be created or modified in the Detail tab. Virtual properties are small javascript functions (called formulas) that can be used to create properties based on values stored in an element or in the elements in its neighborhood. This formula has to return a single value (string or number) which represents the value of this virtual property for the particular element.
1.1. Create or unhide virtual property (1)
With this menu, you can create a new virtual property that will be created on every element (nodes, relationships, or merged relationships). With this menu, you can also hide and unhide hidden virtual properties.
1.2. Edit, hide or delete virtual property (2)
With this menu, you can
edit virtual property (change title or formula) or
hide virtual property (it will be not shown in the Virtual properties list but you can unhide it anytime) or
delete virtual property (it will no longer be available and you can't restore it)
2. Creating a virtual property
Virtual property is created for every element in a group. Group is formed by nodes, relationships, merged relationships, and direction merged relationships. So when you create a virtual property on the Detail tab of a node, this property is added to every node in the visualization.
When creating a virtual property:
define a title for property (mandatory)
define formula (mandatory). Only valid formulas can be created - you can test your formula with the Test formula button. You can write your own formula or you can insert one of the built-in formula templates and change it to suit your purpose.
2.1. Context of a virtual property
Every group of elements has a different context when creating a virtual property. Context is a set of variables available in the formula by default. The formula, that is entered in the modal window is evaluated using this syntax:
function (context_var_1, context_var_2, ...){
...your formula...
}
2.1.1. Node's virtual property context
Virtual property on a node can use these variables in the virtual property's code:
node: an object with node's data. When you want to use a particular DB property of this node in the formula, use syntax node.data.name_of_property.
nodes: an array of node objects connected to the node for which the virtual property is being calculated.
edges: array of objects with data of node's relationships (all relationships in node's neighborhood). When you want to use a particular DB property of the first relationship in the formula, use edges[0].data.name_of_property.
numOfHiddenRelationships: number of all node's relationships stored in DB (incoming or outgoing) minus the number of node's relationships already in visualization
2.1.2. Relationship's virtual property context
Virtual property on a relationship can use these variables in the virtual property's code:
edge: an object with relationship's data. When you want to use a particular DB property of a relationship in the formula, use edge.data.name_of_property.
source: relationship's source (start) node. When you want to use a particular DB property of the source (start) node in the formula, use source.data.name_of_property.
target: relationship's target (end) node. When you want to use a particular DB property of the target (end) node in the formula, use target.data.name_of_property.
2.1.3. Merged relationship's virtual property context
Virtual property on a merged relationship can use these variables in the virtual property's code:
edges: array of objects with data of relationships that are merged to a particular merged relationship. When you want to use a particular DB property of the first relationship in the formula, use edges[0].data.name_of_property.
source: relationship's source (start) node. When you want to use a particular DB property of the source (start) node in the formula, use source.data.name_of_property.
target: relationship's target (end) node. When you want to use a particular DB property of the target (end) node in the formula, use target.data.name_of_property.
2.1.4. Direction merged relationship's virtual property context
Virtual property on a direction merged relationship can use these variables in the virtual property's code:
edges: array of objects with data of relationships that are merged to a particular merged relationship. When you want to use a particular DB property of the first relationship in the formula, use edges[0].data.name_of_property.
source: relationship's source (start) node. When you want to use a particular DB property of the source (start) node in the formula, use source.data.name_of_property.
target: relationship's target (end) node. When you want to use a particular DB property of the target (end) node in the formula, use target.data.name_of_property.
2.2. Data structures of graph elements
Every graph element in the virtual property context is represented by a JS object that contains
System properties - calculated by Graphlytic of by the rendering library (Cytoscape.js). The full list of System properties is in the table below.
Database properties - properties loaded from the graph database
System properties:
Property | Values | Description |
---|---|---|
group | "nodes", "edges" | Cytoscape.js group property. |
position | Object | Cytoscape.js position object. Contains "x" and "y" position values. This property exists only for nodes. When the position is updated the virtual property is not recalculated. |
data | Object | Cytoscape.js data object. |
data.id | String | Cytoscape.js element ID. |
data.source | String | Cytoscape.js relationship's source node ID. Exists only for relationships. |
data.target | String | Cytoscape.js relationship's target node ID. Exists only for relationships. |
data._dbId | String | Element ID in the graph database. Exists only for nodes and unmerged relationships. |
data._gl_group | "nodes", "edges", "mergedEdges", "dirMergedEdges" | Graphlytic group of the elements. |
data._dbLabels | Array | An array of node's labels (strings) in the graph database. Exists only for nodes. |
data._dbRelType | String | Relationship type from the graph database. Exists only for relationships. |
data._created | Number (epoch ms) | Created by Graphlytic when the element is created using the UI or import features of Graphlytic. |
data._updated | Number (epoch ms) | Created/updated by Graphlytic every time when the element is updated using the UI or import features of Graphlytic. |
data._numOfHiddenRelationships | Number | System property calculated by Graphlytic representing the number of not rendered relationships (_numOfHiddenRelationships = _numOfRelations - <number of rendered relationships>). Exists only for nodes. |
data._numOfRelatedNodes | Number | The number of node's related nodes in the graph database. Exists only for nodes. |
data._numOfRelations | Number | The number of node relationships (incoming and outgoing) in the graph database. Exists only for nodes. |
2.2.1. Example data structure of a node
An example data structure of a node:
{
"group"
:
"nodes"
,
"data"
:{
"id"
:
"0"
,
"_dbId"
:
"0"
,
"_gl_group"
:
"nodes"
,
"_dbLabels"
:[
"node_label_1"
,
"node_label_2"
],
"_created"
:
1607958614713
,
"_updated"
:
1615797599879
"_numOfHiddenRelationships"
:
0
,
"_numOfRelatedNodes"
:
9
,
"_numOfRelations"
:
9
,
<prop_1>: <value_1>,
...
<prop_n>: <value_n>
},
"position"
:{
"x"
:-
11.266923121409485
,
"y"
:-
39.89026192275111
}
}
2.2.2. Example data structure of a relationship
An example data structure of a relationship:
{
"group"
:
"edges"
,
"data"
:{
"id"
:
"edge0"
,
"source"
:
"0"
,
"target"
:
"6"
,
"_dbId"
:
"0"
,
"_gl_group"
:
"edges"
,
"_dbRelType"
:
"FREE"
,
"_created"
:
1608450451999
,
"_updated"
:
1608477685120
,
<prop_1>: <value_1>,
...
<prop_n>: <value_n>
}
}
2.2.3. Example data structure of a direction merged relationship
An example data structure of a direction merged relationship:
{
"group"
:
"edges"
,
"data"
:{
"id"
:
"dme_0_2"
,
"source"
:
"0"
,
"target"
:
"2"
,
"_gl_group"
:
"dirMergedEdges"
,
"<prop_1>"
:
"<value_1>"
,
...
"<prop_n>"
:
"<value_n>"
}
}
2.2.4. Example data structure of a merged relationship
An example data structure of a merged relationship:
{
"group"
:
"edges"
,
"data"
:{
"id"
:
"me_0_2"
,
"source"
:
"0"
,
"target"
:
"2"
,
"_gl_group"
:
"mergedEdges"
,
"<prop_1>"
:
"<value_1>"
,
...
"<prop_n>"
:
"<value_n>"
}
}
3. Graph API
For more advanced cases there’s a Graph API available in the virtual property’s context. This API can be used to traverse the graph and access graph elements by their IDs. This gives great flexibility but can be more performance demanding.
3.1. Method “Model.getNodeById(nodeId)”
Returns node from the Model based on its ID value.
Example:
let someNode = Model.getNodeById(nodeId);
3.2. Method “Model.getEdgeById(edgeId)”
Returns edge (relationship) from the Model based on its ID value.
Example:
let someEdge = Model.getEdgeById(edgeId);
3.3. Method “Model.getNodeNeighbors(nodeId, direction)”
Returns nodes from the Model that are connected to a specific node identified by its node ID value.
A direction can be specified to get only outgoing, incoming, or both types of nodes. Available values for direction are:
“IN” - returns only nodes with relationships ending in the nodeId node.
“OUT” - returns only nodes with relationships starting in the nodeId node.
“BOTH” or undefined - returns all neighboring nodes of the nodeId node.
Example:
let neighbors = Model.getNodeNeighbors(nodeId,
"BOTH"
);
3.4. Method “Model.getNodeRelationships(nodeId, direction)”
Returns relationships from the Model that are connected to a specific node identified by its node ID value.
A direction can be specified to get only outgoing, incoming, or both types of relationships. Available values for direction are:
“IN” - returns only relationships that end in the nodeId node.
“OUT” - returns only relationships that start in the nodeId node.
“BOTH” or undefined - returns all relationships connected to the nodeId node.
Example:
let neighbors = Model.getNodeRelationships(nodeId,
"BOTH"
);
4. Examples
4.1. Title by node labels
If you want to, for instance, use different property values as titles of nodes for different node labels, you can create a virtual property on nodes (example below) and then use this virtual property as the node title to show the values in the visualization.
for
(
var
i = 0; i < node.data._dbLabels.length; i++){
var
label = node.data._dbLabels[i];
switch
(label){
case
"Person"
:
return
node.data.name;
break
;
case
"Company"
:
return
node.data.title;
break
;
case
"Address"
:
return
node.data.street +
", "
+ node.data.city;
break
;
default
:
return
node.data.uuid;
}
}
4.2. Average of property values
This formula can be used to calculate an average value of some property stored on the relationships of a node. This virtual property can be then used for styling the nodes in the visualization, e.g. size or color can be linearly mapped to numerical intervals.
if
(edges == undefined || edges.length == 0){
return
0;}
var
sum = 0;
var
count = 0;
for
(
var
i = 0; i < edges.length; i++){
var
edge = edges[i];
var
value = parseFloat(edge.data.property);
if
(!isNaN(value)){
sum += value;
count++;
}
}
var
avg = sum/count;
return
avg;