Skip to content
Snippets Groups Projects

viz-layout


Description

The viz-layout is a hierarchical layout to draw metabolic pathways. To use the layout, a network with nodes and directed links is required. User can provide an object describing the network style. If defined in the network style, height and width of nodes can be taken into account. The layout change the position of nodes, and can add some classes for nodes and links.

The layout is designed to be applied on directed bipartite graphs, where metabolite nodes are only connected to reaction nodes. Reactions can be reversible, but for each reversible reaction, all links must be declared for one direction. To reverse the direction of a reaction, the source and target of the links are swapped. Additionally, metabolite nodes can be marked as side compounds, with common examples being water and ATP. A step of the layout can duplicate them and place them after the other nodes.

The y-axis is inverted compared to the usual Cartesian convention (where smaller y values are lower on the graph). It was designed for systems like SVG where smaller y values are positioned at the top of the screen. Therefore, the initial reactants, placed at the start of the reaction sequence, will have smaller y values, positioning them at the top of the diagram. The products of the reaction will have larger y values, placing them lower.

The layout doesn’t work for large graphs. The exact size limit is currently unknown, but it will be determined as development progresses.

Table of Contents


Getting started

Create a typescript project

  1. Initialize a new project

    First, create a new directory for your project and initialize it with npm:

    mkdir my-project
    cd my-project
    npm init -y
  2. Install TypeScript

    You'll need to install TypeScript as a development dependency in your project:

    npm install --save-dev typescript
  3. Set up the TypeScript configuration

    TypeScript requires a tsconfig.json file (at the root of the project) to specify how your TypeScript code should be compiled. You can generate a default configuration file by running:

    npx tsc --init
  4. Create your source files

    Inside your project, create a src directory and a index.ts file for your TypeScript code:

    mkdir src
    touch src/index.ts

Install via npm

The viz-layout package is currently only available on the MetaboHUB forge. To install it, you need to configure an .npmrc file (at the root of the project) to specify the retrieval path.

@metabohub:registry=https://forgemia.inra.fr/api/v4/packages/npm/

Then you can install the package:

npm install @metabohub/viz-layout

Typescript configuration

Once the installation step is completed, you need to declare the module. To do this, add the following line in the env.d.ts file (at the root of the project):

declare module "@metabohub/viz-layout";

Usage

// Imports
import type { UserParameters, Network , Node, Link, GraphStyleProperties, NodeStyle} from "@metabohub/viz-layout";
import { layoutOnNetwork, getDefaultParam, PathType } from "@metabohub/viz-layout";

// Creation of network
const nodes : {[key:string]:Node} = {
	MetaboliteA: {
		id: 'MetaboliteA',
		x: 50,
		y: 50,
        classes: ["metabolite"],
        metadata :{
            isSideCompound : false
        }
	},
	Reaction1: {
		id: 'Reaction1',
		x: 100,
		y: 100,
        classes: ["reaction"],
        metadata : {
            isReversible : true
        }
	},
  MetaboliteB: {
		id: 'MetaboliteB',
		x: 100,
		y: 150,
        classes: ["metabolite"],
        metadata : {
            isSideCompound : false
        }
	}
}
const links : Link[] = [
	{
		source: nodes.MetaboliteA,
		target: nodes.Reaction1,
		id: 'MetaboliteA->Reaction1'
	},
  {
		source: nodes.Reaction1,
		target: nodes.MetaboliteB,
		id: 'Reaction1->MetaboliteB'
	}
]
const network:Network = { id: 'network', nodes: nodes, links: links };


// Creation of network styles
const nodeStyle :  {[key:string]:NodeStyle} = {
            metabolite: {
                height: 50,
                width: 50
            },
            reaction: {
                height: 25,
                width: 25
            }
        };
const networkStyle :GraphStyleProperties ={ nodeStyles: nodeStyle };

// Choosing parameters
//      get default parameters and modify some of them
const parameters:UserParameters=getDefaultParam();
parameters.doCycle = false;
parameters.pathType = PathType.ALL_LONGEST;
//      estimate parameters of spacing depending on network and network style (not necessary)
const defaultSpacing= getDefaultSpacingAttributesPixel(network,styleNetwork,2);
parameters.spacePixelHorizontal=defaultSpacing.spacePixelHorizontal;
parameters.spacePixelVertical=defaultSpacing.spacePixelVertical;

// Application of layout
const newNetwork = await layoutOnNetwork(network, networkStyle, parameters);

Another example of a more complex network can be found in the public folder. It includes variables for the nodes, the links, network, and a svg of the drawing with default parameters.


Types

Types for network

Network
Attribut Type Description
id string Network's id
nodes {[key: string] Node} Object that contains nodes
links Array<Link> List that contains links
Node
Attribut Type Description
id string Node's id
x number X node's position
y number Y node's position
classes Array<string> Node's classes to manage style
metadata {[key: string]: string | number | {[key: string]: string | number} | Array<string> | boolean} Node's metadata

To have a bipartite metabolic network, the classes of a node can contain at least either metabolite or reaction.

Metadata can contains those elements :

Key Type Description
isSideCompound boolean Node is declared as a side compound
duplicate boolean Node is declared as a duplicated node
isReversible boolean Node is declared as a reversible

If isSideCompound or duplicate is not set, the step to handle side compounds will not perform any actions, as no nodes are marked as side compounds or duplicated node. A duplicate class will be added to side compound nodes that are duplicated. If isReversible is not set, and the reaction node does not have a reaction class, the step to handle reversible reactions will not perform any actions, as no reactions are marked as reversible.

Link
Attribut Type Description
id string Link's id
source Node Source node of the link
target Node Target node of the link
classes Array Link's classes
Both the source and target must be references to nodes that are present in the network (see usage for details)!

In order to have a bipartite graph, links should associate a metabolite node with a reaction node. A class reversible will be added by the layout for links associated with a reversible reaction if the step to manage reversible reaction is done.

Types for style

GraphStyleProperties

Attribut Type Description
nodeStyles { [key: string]: NodeStyle } Object that contains nodes classes name associated to their style

The keys of nodeStyles must match the node classes to correctly associate styles with the corresponding nodes.

NodeStyle

Attribut Type Description
height number Node's height (in pixels)
width number Node's width (in pixels)

If not defined for a node, the default value used is 25 pixels.

Types for parameters

UserParameters

To initialize the parameters, use the getDefaultParam() function from the package, it return a type UserParameters. You can then modify the desired parameters as needed (see usage). Refer to the Step of the layout section for a better understanding of certain parameters.

Parameter Type Default Description
spacePixelHorizontal number 100 Minimum horizontal spacing (in pixels) for hierarchical layout
spacePixelVertical number 100 Minimum vertical spacing (in pixels) for hierarchical layout
doDuplicateSideCompounds boolean true Whether to duplicate side compounds
doPutAsideSideCompounds boolean true Whether to remove (temporarily) side compounds
doInsertionSideCompounds boolean true Whether to reinsert side compounds
doMainChain boolean true Whether to find and clusterize main chain
pathType PathType ALL_LONGEST Defines the path type for the main chain step: LONGEST, ALL_LONGEST, or ALL.
merge boolean true Whether to merge path with common nodes
doCycle boolean true Whether to process directed cycles
shiftCoord boolean false Whether to get top left corner coordinates of nodes (if false, center of nodes is returned)

getDefaultParam

Get default parameters for the layout.

getDefaultParam()

Output

Return default parameters.

Type Description
UserParameters default user parameters

getDefaultSpacingAttributesPixel

Estimate minimal spacing parameters (spacePixelHorizontal, spacePixelVertical) depending on the size of nodes in the network.

getDefaultSpacingAttributesPixel(network:Network,styleNetwork?:GraphStyleProperties,factor?:number)

Input
Arguments Type default Description Optional
network Network - Network object that contains nodes and links of the network No
networkStyle GraphStyleProperties undefined Network style object that contains classes and style associated with nodes Yes
factor number 3 A factor to increase the minimal spacing yes

The network style input is not mandatory but the function isn't usefull if not provided as all nodes will be considered of size 25 pixels.

Output

Return an object with spacing parameters.

Key Type Description
spacePixelHorizontal number Mean of width of all nodes in the network multiply by the factor
spacePixelVertical number Mean of height of all nodes in the network multiply by the factor

layoutOnNetwork

Apply the layout on a network.

layoutOnNetwork(network, networkStyle?, parameters?) is a asynchronous function.

Input
Arguments Type default Description Optional
network Network - Network object that contains nodes and links of the network No
networkStyle GraphStyleProperties { } Network style object that contains classes and style associated with nodes Yes
parameters Parameters undefined Parameters of the layout Yes

If parameters is undefined, default parameters defined above are used (see (defaultParameters)) and the values for spacePixelHorizontal and spacePixelVertical are estimated with getDefaultSpacingAttributesPixel.

Output
Type Description
Promise<Network> network with modified node positions, and some added classes

Step of the layout

Base Layout

The base layout used in the algorithm is a Sugiyama layout. It is implemented by the viz.js library (https://github.com/mdaines/viz-js), a JS wrapper of the dot layout of GraphViz (https://graphviz.org/documentation/). The separation between nodes in the dot layout is define with spacePixelVertical (graphviz attribut ranksep) and by spacePixelHorizontal (graphviz attribut nodesep).

E. R. GANSNER, E. KOUTSOFIOS, S. C. NORTH et K.-P. VO, “A technique for drawing directed graphs”, IEEE Transactions on Software Engineering, t. 19, no 3, p. 214-230, 1993.

Management of side compounds

Nodes declared as side compounds are duplicated if doDuplicateSideCompounds = true. It will add a duplicate attribut and class on those nodes. If side compounds nodes are already duplicated and doDuplicateSideCompounds = false, they need to be declared as duplicated nodes (see type node).

If doPutAsideSideCompounds = true, duplicated nodes are temporarily removed from the network object. They will be reinserted based on the locations of other nodes during the layout process if doInsertionSideCompounds = true.

If side compounds are temporarily removed and then reinserted without being duplicated, there is currently no method to reintegrate them and that can create an error in the algorithm.

Management of reversible reaction

For this step to take effect, reaction nodes representing a reversible reaction must have the class reaction in their classes and metadata.isReversible = true.

In this step, a direction is choosen to each reversible reaction not yet determined. The method promotes the continuity of the reaction sequence in the drawing. Links corresponding to these reactions are assigned the class reversible.

Management of directed cycles

The step is done if doCycle = true.

Directed cycles with more than three nodes are identified and arranged in a circle as much as possible. When multiple directed cycles share common nodes, not all nodes may be positioned in a circle; those nodes will be placed using a force layout (utilizing the D3 library: https://d3js.org/).

It is important to note that not all cycles may be detected. A timer is implemented to limit the duration of the cycle search, ensuring the process does not take too long. As a result, the outcomes are not deterministic, and the set of cycles found may vary between runs.

For the cycle search, the algorithm considers both directions of reversible reactions, enabling the identification of different directed cycles. The direction of a reversible reaction that allows for cycle formation is retained. This selection is made prior to the direction choice in the reversible reaction management step.

Management of main chains

The step is done if doMainChain = true.

Some nodes representing the "main chain" are grouped into a cluster subgraph in the viz.js library (Sugiyama layout), which may enhance or negatively impact the resulting drawing. You can test the effect of this step by enabling or disabling it.

Main chains are defined as merges of paths in the network. Start nodes are determined by the algorithm, after which the network is converted into a Directed Acyclic Graph (DAG) with no directed cycles. The longest path(s) is identified from each start nodes. If multiple paths share common nodes, they can be merged (merge = true), with each merged path representing a main chain. If merge = false and paths have common nodes, only the longest of them is defined as a main chain.

Several versions of the path search are implemented : - LONGEST : when longest paths are searched from a start node, if several are found, only one will be keeped - ALL_LONGEST : when longest paths are searched from a start node, all the longest are keeped - ALL : when longest paths are searched from a start node, all paths between start node and terminal node of longest paths are keeped

ALL_LONGEST is the default version, to change it you need to change the parameter pathType with the defined type PathType (ex : parameters.pathType = PathType.ALL).

Shifting coordinates

If shiftCoord = true, the node's coordinates represent its top-left corner; otherwise, they represent the node's center (default). When shifting the coordinates, the adjustment is made so that positioning the node by its top-left corner keeps it centered in its original location. Specifically, the coordinates are shifted by half the node's height and width. To define a node's height and width, refer to type for style. This is useful when rendering networks in SVG format.