gravis JSON Graph Format (gJGF)¶
Introduction¶
The package
gravis
uses a custom data format called gravis JSON Graph Format or short gJGF
to define a single graph with optional annotations or to define a collection of such graphs.
It is a text format that is human-readable and based on
JSON
as well as
JSON Graph Format (JGF).
Files that contain data in this format should end with the extension .gjgf.
The following specification defines gJGF version 0.1 by extending JGF with custom metadata properties. These properties are recognized by gravis and they are translated into visual elements and their appearance in graph visualizations. For example, node shapes, sizes and colors can be influenced among many other options.
Motivation¶
JSON was chosen because it is a well-supported text format in Python and JavaScript, but also in many other programming languages. This means that it is easy to decode
JSON stringsintolanguage objectsor encodelanguage objectsintoJSON stringswith built-in functionality. For these purposes Python offers a json module that can be imported, while JavaScript provides a built-in JSON object available in its global scope. In contrast, other text formats not based on JSON would have required to write custom decoder and encoder functions (or parser and generator functions) in both languages, which can be a tedious and error-prone task.JSON Graph Format (JGF) was chosen because it is open to defining custom metadata, which is suitable for introducing specific graph annotations as required by this package. Beyond that, building on a well-defined existing format seemed more reasonable than inventing yet another completely custom one.
Specification¶
Part 1: Data types specified by JSON¶
JSON is specified in two compatible standards (RFC 8259, ECMA-404) that aim to define the same formal language with a JSON grammar written in two different formalisms (ABNF, EBNF). Here is a short summary of the main ingredients of the JSON language:
A
valuecan be anobject,array,number,stringor one of the literal namestrue,false, ornull.An
objectstructure is represented as a pair of curly brackets surrounding zero or more name/value pairs.An
arraystructure is represented as a pair of square brackets surrounding zero or more values.A
numberis a sequence of decimal digits with no leading zero.A
stringis a sequence of Unicode code points wrapped with quotation marks.
These structures are defined in more detail in the official standards. In the following text, they will be referred to with their name prefixed by JSON. They have corresponding data types in Python and JavaScript:
Part 2: Graph structure specified by JGF¶
JSON Graph Format (JGF) is a specification for representing graph structures in JSON. The package gravis adheres to JGF Version 2 (precisely: commit ce5ed40 on February 1, 2021). Its ingredients are summarized in the following. Note that some elements are ignored by gravis, which is indicated below and means that they do not appear as elements in a graph visualization by default:
A
JGFstructure is aJSON object, which can contain a single name/value pair from the following two options:Name
Value
Meaning
“graph”
graphstructure (see below)A single graph
“graphs”
graphsstructure (see below)A collection of graphs
A
graphsstructure is aJSON array, which can contain zero or moregraphstructures (see below).A
graphstructure is aJSON object, which can contain following name/value pairs:Name
Value
Meaning
Status
“id”
JSON stringAn identifier for the graph
optional
“type”
JSON stringA classification for the graph
ignored
“label”
JSON stringA text label for the graph
optional
“directed”
JSON falseorJSON true(default)Undirected or directed graph
optional
“nodes”
nodesstructure (see below)Nodes of the graph
optional
“edges”
edgesstructure (see below)Edges of the graph
optional
“hyperedges”
JSON arrayHyperedges of a hypergraph
ignored
“metadata”
graph metadata(see part 3)Custom graph annotations defined by gJGF
optional
A
nodesstructure is aJSON object, which represents the nodes or vertices of a graph. It can contain zero or more name/value pairs of following form:Name
Value
Meaning
Status
node idwhich is aJSON stringnodestructure (see below)A node of the graph
optional
Note that a
node id(and therefore a node) is necessarily unique, because it appears as name in aJSON object. This allows edges to unambigously refer to a certain node as source or target by its uniquenode id.An
edgesstructure is aJSON array, which represents the edges or links of a graph. It can contain zero or more values, where each value is anedgestructure (see below).Note that an edge may not be unique, because it can repeatedly appear as entry in a
JSON array. This allows to define multiedges and thereby multigraphs.A
nodestructure is aJSON object, which represents a single node. It can contain following name/value pairs:Name
Value
Meaning
Status
“label”
JSON stringA text label for the node
optional
“metadata”
node metadata(see part 3)Custom node annotations defined by gJGF
optional
An
edgestructure is aJSON object, which represents a single edge. It can contain following name/value pairs, some of which are required:Name
Value
Meaning
Status
“source”
JSON stringSource node, needs to be a
node idcontained innodesrequired
“target”
JSON stringTarget node, needs to be a
node idcontained innodesrequired
“relation”
JSON stringInteraction between source and target
ignored
“label”
JSON stringA text label for the edge
optional
“directed”
JSON trueorJSON falseWhether the edge is directed or undirected
ignored
“metadata”
edge metadata(see part 3)Custom edge annotations defined by gJGF
optional
Note that “label” is missing in JGF Version 2, but was there in previous states and is still present in an example, therefore it was included here.
Caution
This package detects if an edge has a source or target that is not a node id. Such an edge is ignored as if it were not part of the given data. A message is written to the web console in the browser, which can be inspected by developers but will not be visible to regular users.
Part 3: Graph annotation specified by gJGF¶
JGF contains a graph structure, a node structure and an
edge structure. Each of them is a JSON object, where one of the allowed
name/value pairs is “metadata”/JSON object. In the following, these objects
associated to the “metadata” name will be referred to as graph metadata,
node metadata and edge metadata. They allow to add custom graph, node and
edge annotations, which can modify the appearance of the graph, its nodes and its
edges when visualized. gJGF specifies which annotations are recognized by gravis.
All values are defined as JSON string or JSON number as described below,
but for greater flexibility gravis also accepts JSON string for numerical values
and auto-converts them to numbers.
A
graph metadatastructure is aJSON objectand can contain following name/value pairs:Name
Value
Meaning
“arrow_color”
JSON stringColor of arrows in directed graphs
“arrow_size”
JSON numberSize of arrows in directed graphs
“background_color”
JSON stringBackground color of graph drawing area
“node_color”
JSON stringFill color of nodes
“node_opacity”
JSON numberOpacity of nodes
“node_size”
JSON numberSize of nodes (both height and width)
“node_shape”
JSON stringShape of nodes: “circle”, “rectangle” or “hexagon”
“node_border_color”
JSON stringLine color of node border
“node_border_size”
JSON numberLine width of node border
“node_label_color”
JSON stringText color of node labels
“node_label_size”
JSON numberText size of node labels
“node_hover”
JSON stringHTML text shown in a pop-up tooltip when hovering over a node
“node_click”
JSON stringHTML text shown in details area when clicking on a node
“node_image”
JSON stringImage shown inside nodes: a URL pointing to an image or a data URL
“node_x”
JSON numberx position to fix each node at, can be released in UI
“node_y”
JSON numbery position to fix each node at, can be released in UI
“node_z”
JSON numberz position to fix each node at, can be released in UI, ignored in 2D
“edge_color”
JSON stringLine color of edges
“edge_opacity”
JSON numberOpacity of edges
“edge_size”
JSON numberLine width of edges
“edge_label_color”
JSON stringText color of edge labels
“edge_label_size”
JSON numberText size of edge labels
“edge_hover”
JSON stringHTML text shown in a pop-up tooltip when hovering over an edge
“edge_click”
JSON stringHTML text shown in details area when clicking on an edge
A
node metadatastructure is aJSON objectand can contain following name/value pairs:Name
Value
Meaning
“color”
JSON stringFill color of the node
“opacity”
JSON numberOpacity of the node
“size”
JSON numberSize of the node
“shape”
JSON stringShape of the node: “circle”, “rectangle” or “hexagon”
“border_color”
JSON stringLine color of node border
“border_size”
JSON numberLine width of node border
“label_color”
JSON stringText color of node label
“label_size”
JSON numberText size of node label
“hover”
JSON stringHTML text shown in a pop-up tooltip when hovering over the node
“click”
JSON stringHTML text shown in details area when clicking on the node
“image”
JSON stringImage shown inside the node: a URL pointing to an image or a data URL
“x”
JSON numberx position to fix the node at, can be released in UI
“y”
JSON numbery position to fix the node at, can be released in UI
“z”
JSON numberz position to fix the node at, can be released in UI, ignored in 2D
An
edge metadatastructure is aJSON objectand can contain following name/value pairs:Name
Value
Meaning
“color”
JSON stringLine color of the edge
“opacity”
JSON numberOpacity of the edge
“size”
JSON numberLine width of the edge
“label_color”
JSON stringText color of edge label
“label_size”
JSON numberText size of edge label
“hover”
JSON stringHTML text shown in a pop-up tooltip when hovering over the edge
“click”
JSON stringHTML text shown in details area when clicking on the edge
Examples¶
A minimal graph as JSON text in gJGF:
{
  "graph": {
    "directed": false,
    "nodes": {
      "1": {},
      "2": {},
      "3": {}
    },
    "edges": [
      {"source": 1, "target": 2},
      {"source": 2, "target": 3}
    ]
  }
}
The same graph as Python dict adhering to gJGF:
data = {
  'graph': {
    'directed': False,
    'nodes': {
      1: {},
      2: {},
      3: {},
    },
    'edges': [
      {'source': 1, 'target': 2},
      {'source': 2, 'target': 3},
    ]
  }
}
Further gJGF examples can be found in a Jupyter notebook
Auto-conversion of external graph objects to gJGF¶
This package supports six popular Python graph libraries which are listed below.
More specifically, the plotting functions of this package accept the different
graph objects of these libraries directly as input.
Internally the plotting functions first convert the graph objects
into gJGF and then proceed as if gJGF data was provided by the user.
The responsible conversion functions are located in the
gravis.convert module and
can also be accessed by the user, e.g. to inspect the resulting
gJGF object and check whether everything is converted as expected.
There are also two convenience functions that make conversions easier:
Single graph from any supported library:
gravis.convert.any_to_gjgfList of multiple graphs from supported libraries:
gravis.convert.multiple_to_gjgf