Introduction

This document provides a set of guidelines for developers on how to properly render Reactome pathway diagrams. Pathway Diagrams represent pathways as a series of connected molecular events, known in Reactome as ‘reactions’, which can be considered as steps in the pathway. For a more detailed guide about diagrams refer to our user guide.

Currently, there are two projects that follow these guidelines:

Regulation of Apoptosis diagramRegulation of Apoptosis diagram

Diagram layout and graph files

All the class diagrams can be found as UML in xmi (Umbrello) format. Download

The layout information of every diagram is stored in a JSON file, named after its stable identifier, i.e. R-HSA-12345.json . This file contains all the information regarding what to draw and how to draw it, including coordinates and sizes. In addition to the layout file, Reactome provides another JSON file per diagram containing a small graph view of the diagram content, i.e. R-HSA-12345.graph.json. We discuss this diagram graph file in more detail further on.

The general structure of a diagram layout file:

{
    "dbId":169911,
    "stableId":"R-HSA-169911",
    "displayName":"Diagram of Regulation of Apoptosis",
    "disease":false,
    "minX":61,
    "maxX":1126,
    "minY":202,
    "maxY":656,
    "nodes":[],
    "edges":[],
    "compartments":[],
    "notes":[],
    "links":[],
    "shadows":[]
}

To get a more detailed description of the diagram layout, expand the following tree:

 

Diagram objects

Diagram layout is made up of six types of elements:

  • Compartments
  • Nodes
  • Edges
  • Links
  • Notes
  • Shadows

These elements follow this hierarchy.

Hierarchy of diagram layout objects

Compartments

Compartment

Compartments are rendered in the background and represent where reactions happen. They are rendered as rounded rectangles using NodeCommon.prop. Compartments might have an additional layer when surrounded by a membrane, which must be specified using NodeCommon.innerProp. Text (DiagramObject.displayName) is displayed in one line, using NodeCommon.textPosition. Color is taken from the diagram profile sheet (Profile.compartment). Compartments cannot be rendered on top of any other node.

Nodes

Nodes represent the participants of reactions, i.e. inputs, outputs, catalysts, regulators and other pathways. The type of each node is coded into renderableClass. The renderable class can be one of Chemical, ChemicalDrug, Complex, Entity, EntitySet, Gene, ProcessNode, EncapsulatedNode, Protein and RNA.

Nodes are laid in 2 layers, background and foreground. The background is rendered using a different shape for each class with dimensions defined in NodeCommon.prop. Some nodes may have a foreground (ProcessNode, EncapsulatedNode and EntitySet). The foreground shape and colour are class specific. The text is centred to the node with a padding of 5 points to the NodeCommon.prop. In case it is too large, then it is wrapped in several lines and, if needed, the size of the font is reduced. When a foreground is present, the text is padded to foreground limits.

ClassBackgroundForegroundExample
Chemical ellipse   Chemical
ChemicalDrug ellipse   Chemical drug
Complex edged rectangle (octagon)   Complex
Entity rectangle   Entity
EntitySet rounded rectangle rounded rectangle (padding = 4) EntitySet
* Gene recatangle with 2 rounded corners   Gene
ProcessNode rectangle rectangle (padding = 10) ProcessNode
EncapsulatedNode hexagon hexagon (padding = 10) EncapsulatedNode
Protein rounded rectangle   Protein with attachment
RNA bone   RNA

*Genes are made up using a different approach. They have 2 shapes, a rectangle with 2 rounded corners (y=NodeCommon.prop.y + 25) and a triangle. The rectangle is filled but not stroked. Both shapes are joint using 3 perpendicular lines.

shape = SemiRoundedRectangle(prop.x, prop.y + 25, prop.width. prop.height)
arrow = Path()
arrow.moveTo(prop.maxX,     prop.getY + 8)
arrow.lineTo(prop.maxX,     prop.getY - 8)
arrow.lineTo(prop.maxX + 8, prop.getY)
arrow.closePath()
path = Path()
path.moveTo(prop.x,        prop.y + 25)
path.lineTo(prop.maxX,     prop.y + 25)
path.moveTo(prop.maxX - 4, prop.y + 25)
path.lineTo(prop.maxX - 4, prop.y)
path.lineTo(prop.maxX,     prop.y)  # already closed
fill(shape, arrow)
stroke(path, arrow)

RNA shape looks after a bone :

x1 = rna.x + 16
x2 = rna.maxX - 16
y1 = rna.y + 8
y2 = rna.maxY - 8
path = Path()
path.moveTo(x1, y1)
path.lineTo(x2, y1)
path.quadTo(rna.maxX, rna.y,    rna.maxX, rna.centerY)
path.quadTo(rna.maxX, rna.maxY, x2,       y2)
path.lineTo(x1, y2)
path.quadTo(rna.x,    rna.maxY, rna.x,    rna.centerY)
path.quadTo(rna.x,    rna.y,    x1,       y1)
fill(path)
stroke(path)

Some nodes contain attachments, such as post-translational modifications (PTMs) . Attachments are styled after their owner. The border of nodes is rendered after the background and foreground shapes, except for genes, which have a custom border shape. When a node has NodeCommon.needDashedBorder then the border must be dashed.

Drugs use the same shape as chemicals, but with different colors. They also have a small reactangle (14x7) in the bottom right corner with the text Rx (recipe, latin word for prescription).

Edges

Edges represent reactions in the diagram. They are layout as lines with shapes. They can have 2 shapes: a reaction shape, to indicate the type of reaction, and an end shape. Both can be omitted. Lines are taken from EdgeCommon.segments. Shape is created using several properties inside EdgeCommon.

Reaction typeshape.typeshape.emptyshape.textExample
Association circle fill   Association
Dissociation double circle empty   Dissociation
Omitted process box empty \\ Omitted
Transition box empty   Transition
Uncertain box empty ? Uncertain
All (end shape) arrow fill   End shape

 

Shapes are specified in the Shape element inside Edge.reactionType and Edge.endShape.

Shape.type Shape
ARROW triangle with points: a, b, c
BOX rectangle from a (top left) to b (bottom right)
CIRCLE circle with center c and radius r
STOP line from a to b
DOUBLE CIRCLE 2 circles with center c and radii r and r1

 

When Shape.s is present, the value of Shape.s is written in the centre of the shape. When Shape.emtpy is true, the Shape is filled with Profile.reaction.fill color (usually white), otherwise, it is filled with Profile.reaction.stroke (usually black).

Connectors

As each reaction can have several participants, a connector is created in the participant with Connector.EdgeId = DiagramObject.Id . Connectors are styled after the reaction they belong. Connectors have segments and 2 shapes: end shape and stoichiometry shape. Stoichiometries are always empty boxes with the stoichiometry value as text only if stoichiometry value is greater than 1.

endShape.typeShapeEmptyExample
Inhibitor line fill Inhibitor
Catalyst circle empty Catalyst
Output arrow fill Output
Activator arrow empty Activator
Input no shape    

Links

Links are used for linking elements which are related, normally subpathways or distant nodes.

Notes

Notes are just texts. The text is displayed in one line beginning at NodeCommon.textPosition. Color is taken from Profile.note.text.

Shadows

Shadows are used when there are several subpathways in the same diagram. In particular, these coloured rectangles highlight the specific diagram reactions belonging to each subpathway, allowing further zooming in to the areas of interest within a given pathway diagram. Rendering them is optional, but it is recommended that they are drawn on top of every element, as rectangles, using Shadow.points and Shadow.color for text and filling. It is also adviced to use transparency for the filling so that all subpathway participants are visible. The text contains the name of the subpathway and should be rendered using a bigger font size. 

Text

The default font for texts is Arial black with size 9. For shadows, font size is 24.

Colouring

Element colors are taken from a JSON stylesheet. Currently, we have 2 styles: standard and modern.

To get a more detailed description of the diagram colour profile, expand the following tree:

  • DiagramProfile
    • stoichiometry : DiagramProfileNode
      • stroke : String
      • lineWidth : String
      • fadeOutFill : String
      • fadeOutStroke : String
      • lighterFill : String
      • lighterStroke : String
      • text : String
      • fadeOutText : String
      • lighterText : String
      • fill : String
    • entity : DiagramProfileNode
      • stroke : String
      • lineWidth : String
      • fadeOutFill : String
      • fadeOutStroke : String
      • lighterFill : String
      • lighterStroke : String
      • text : String
      • fadeOutText : String
      • lighterText : String
      • fill : String
    • complex : DiagramProfileNode
      • stroke : String
      • lineWidth : String
      • fadeOutFill : String
      • fadeOutStroke : String
      • lighterFill : String
      • lighterStroke : String
      • text : String
      • fadeOutText : String
      • lighterText : String
      • fill : String
    • note : DiagramProfileNode
      • stroke : String
      • lineWidth : String
      • fadeOutFill : String
      • fadeOutStroke : String
      • lighterFill : String
      • lighterStroke : String
      • text : String
      • fadeOutText : String
      • lighterText : String
      • fill : String
    • interactor : DiagramProfileNode
      • stroke : String
      • lineWidth : String
      • fadeOutFill : String
      • fadeOutStroke : String
      • lighterFill : String
      • lighterStroke : String
      • text : String
      • fadeOutText : String
      • lighterText : String
      • fill : String
    • attachment : DiagramProfileNode
      • stroke : String
      • lineWidth : String
      • fadeOutFill : String
      • fadeOutStroke : String
      • lighterFill : String
      • lighterStroke : String
      • text : String
      • fadeOutText : String
      • lighterText : String
      • fill : String
    • flowline : DiagramProfileNode
      • stroke : String
      • lineWidth : String
      • fadeOutFill : String
      • fadeOutStroke : String
      • lighterFill : String
      • lighterStroke : String
      • text : String
      • fadeOutText : String
      • lighterText : String
      • fill : String
    • gene : DiagramProfileNode
      • stroke : String
      • lineWidth : String
      • fadeOutFill : String
      • fadeOutStroke : String
      • lighterFill : String
      • lighterStroke : String
      • text : String
      • fadeOutText : String
      • lighterText : String
      • fill : String
    • processnode : DiagramProfileNode
      • stroke : String
      • lineWidth : String
      • fadeOutFill : String
      • fadeOutStroke : String
      • lighterFill : String
      • lighterStroke : String
      • text : String
      • fadeOutText : String
      • lighterText : String
      • fill : String
    • encapsulatednode : DiagramProfileNode
      • stroke : String
      • lineWidth : String
      • fadeOutFill : String
      • fadeOutStroke : String
      • lighterFill : String
      • lighterStroke : String
      • text : String
      • fadeOutText : String
      • lighterText : String
      • fill : String
    • protein : DiagramProfileNode
      • stroke : String
      • lineWidth : String
      • fadeOutFill : String
      • fadeOutStroke : String
      • lighterFill : String
      • lighterStroke : String
      • text : String
      • fadeOutText : String
      • lighterText : String
      • fill : String
    • link : DiagramProfileNode
      • stroke : String
      • lineWidth : String
      • fadeOutFill : String
      • fadeOutStroke : String
      • lighterFill : String
      • lighterStroke : String
      • text : String
      • fadeOutText : String
      • lighterText : String
      • fill : String
    • otherentity : DiagramProfileNode
      • stroke : String
      • lineWidth : String
      • fadeOutFill : String
      • fadeOutStroke : String
      • lighterFill : String
      • lighterStroke : String
      • text : String
      • fadeOutText : String
      • lighterText : String
      • fill : String
    • chemical : DiagramProfileNode
      • stroke : String
      • lineWidth : String
      • fadeOutFill : String
      • fadeOutStroke : String
      • lighterFill : String
      • lighterStroke : String
      • text : String
      • fadeOutText : String
      • lighterText : String
      • fill : String
    • chemicaldrug : DiagramProfileNode
      • stroke : String
      • lineWidth : String
      • fadeOutFill : String
      • fadeOutStroke : String
      • lighterFill : String
      • lighterStroke : String
      • text : String
      • fadeOutText : String
      • lighterText : String
      • fill : String
    • entityset : DiagramProfileNode
      • stroke : String
      • lineWidth : String
      • fadeOutFill : String
      • fadeOutStroke : String
      • lighterFill : String
      • lighterStroke : String
      • text : String
      • fadeOutText : String
      • lighterText : String
      • fill : String
    • compartment : DiagramProfileNode
      • stroke : String
      • lineWidth : String
      • fadeOutFill : String
      • fadeOutStroke : String
      • lighterFill : String
      • lighterStroke : String
      • text : String
      • fadeOutText : String
      • lighterText : String
      • fill : String
    • reaction : DiagramProfileNode
      • stroke : String
      • lineWidth : String
      • fadeOutFill : String
      • fadeOutStroke : String
      • lighterFill : String
      • lighterStroke : String
      • text : String
      • fadeOutText : String
      • lighterText : String
      • fill : String
    • rna : DiagramProfileNode
      • stroke : String
      • lineWidth : String
      • fadeOutFill : String
      • fadeOutStroke : String
      • lighterFill : String
      • lighterStroke : String
      • text : String
      • fadeOutText : String
      • lighterText : String
      • fill : String
    • thumbnail : DiagramProfileThumbnail
      • hovering : String
      • highlight : String
      • selection : String
      • edge : String
      • node : String
    • name : String
    • properties : DiagramProfileProperties
      • hovering : String
      • highlight : String
      • selection : String
      • halo : String
      • flag : String
      • trigger : String
      • button : String
      • text : String
      • disease : String

 

The DiagramProfileNode defines 3 colors per each node: fill, stroke and text . If an object is fadeout ( DiagramObject.isFadeOut), then we must choose fadeOutFill, fadeOutStroke and fadeOutText. If an analysis is being run, then we use lighterFill, lighterStroke and lighterText. And by default fill, stroke and text.

There is 1 exception: reactions and stoichiometries’ texts; text color is ignored and stroke is used instead. When DiagramObject.isDisease is true, the color of node border, edge border, edge text and segments is changed to Profile.properties.disease (usually red).

Decorators

Some elements can be decorated in the diagram. This information is not in the diagram and has to be inserted from the outside. Reactome supports 2 types of decoration: selection and flagging.

When a node is selected, the border is changed in 2 ways: the color is changed to Profile.properties.selection and the width is increased. The node, the reactions in which it participates and the nodes that participate in these reactions are haloed. Haloing is made by drawing the border behind the node with a larger width and with Profile.properties.halo color.

When a reaction is selected, its segments, texts and borders change color to Profile.properties.selection and segments increase its width. The reaction and its participants are haloed.

When a node is flagged, the border is drawn in the background with a larger width using Profile.properties.flag. At this moment, edges are not being flagged.

Node layers
Representation of layers for a node. From bottom to top: flag, halo, background, analysis, foreground, border and text.

 

Edge layers
Edge layers. From bottom to top: halo, segments, filling, border and text.

Analysis

When an analysis is overlaid, we must modify the color of elements to lighter. Then, those nodes hit by the analysis must render a new layer between the background and the foreground. At first, we must calculate how much a node is hit by the analysis. We can do it by using the graph JSON file and the analysis results (or the analysis token). We must traverse the graph from each node through its children (EntityNode.children) .

C1 has 1/2 children hit. S1 has 3/4 leaves hit. P1, P3 and P4 have 1/1 leaves hit.
C1 has 1/2 children hit. S1 has 3/4 leaves hit. P1, P3 and P4 have 1/1 leaves hit.

 

To get a more detailed description of the diagram graph, expand the following tree:

  • Graph
    • nodes : EntityNode[]
      • identifier : String
      • parents : Long[]
      • children : Long[]
      • geneNames : String[]
      • diagramIds : Long[]
      • [GraphNode] schemaClass : String
      • [GraphNode] dbId : Long
      • [GraphNode] stId : String
      • [GraphNode] speciesID : Long
      • [GraphNode] displayName : String
    • edges : EventNode[]
      • catalysts : Long[]
      • inhibitors : Long[]
      • activators : Long[]
      • inputs : Long[]
      • outputs : Long[]
      • diagramIds : Long[]
      • preceding : Long[]
      • following : Long[]
      • requirements : Long[]
      • [GraphNode] schemaClass : String
      • [GraphNode] dbId : Long
      • [GraphNode] stId : String
      • [GraphNode] speciesID : Long
      • [GraphNode] displayName : String
    • dbId : Long
    • stId : String
    • subpathways : SubpathwayNode[]
      • dbId : Long
      • stId : String
      • events : Long[]
      • displayName : String

 

ProcessNodes percentages are taken from the SubpathwaySummary: entity.found / entity.total. For the analysis, there is another stylesheet. We draw enrichment using the AnalysisSheet.enrichment.gradient.max color. There are 3 analysis stylesheets: Standard, Copper Plus and Strosobar

To get a more detailed description of the analysis colour profile, expand the following tree:

 

If the analysis is an expression analysis, we must take the individual expression values from the leaves. We can show only 1 column at a time. If we want to show them all we must create an animation (play button in the pathway browser and GIFs in the diagram exporter). Once we have the expression values for an element, we divide it into regions and use AnalysisSheet.expression.gradient to calculate the color of each region, using AnalysisResult.expression.max and AnalysisResult.expression.min as limit values. Leaves are sorted using the identifier from the analysis (FoundEntity.id).

Example of diagram with analysis enrichment
Subsection of a diagram with an analysis overlaid
Expression
Example of a diagram with an expression analysis

Elements order

From bottom to top, elements must be rendered in the following order:

  1. Compartments
  2. Fade out reactions
  3. Fade out nodes
  4. Flags
  5. Halos
  6. Reactions
  7. Nodes
  8. Notes
  9. Shadows

More Information

To learn more about our pathway diagrams and the techniques we use to render them efficiently please go through our relevant publications:

  1. Reactome diagram viewer: data structures and strategies to boost performance
  2. Reactome enhanced pathway visualization