Commit e78cdff6 authored by Lukas Pravda's avatar Lukas Pravda
Browse files

add more documentation and comments

parent f701abb1
Pipeline #176763 passed with stages
in 46 seconds
namespace Config { namespace Config {
export const nodeSize: number = 30; export const nodeSize: number = 30;
export const interactionClickEvent: string = 'PDB.interactions.click'; export const interactionClickEvent: string = "PDB.interactions.click";
export const interactionMouseoverEvent: string = 'PDB.interactions.mouseover'; export const interactionMouseoverEvent: string = "PDB.interactions.mouseover";
export const interactionMouseoutEvent: string = 'PDB.interactions.mouseout' export const interactionMouseoutEvent: string = "PDB.interactions.mouseout"
export const interactionShowLabelEvent: string = 'PDB.interactions.showLabel'; export const interactionShowLabelEvent: string = "PDB.interactions.showLabel";
export const interactionHideLabelEvent: string = 'PDB.interactions.hideLabel'; export const interactionHideLabelEvent: string = "PDB.interactions.hideLabel";
export const molstarClickEvent: string = 'PDB.molstar.click'; export const molstarClickEvent: string = "PDB.molstar.click";
export const molstarMouseoverEvent: string = 'PDB.molstar.mouseover'; export const molstarMouseoverEvent: string = "PDB.molstar.mouseover";
export const molstarMouseoutEvent: string = 'PDB.molstar.mouseout'; export const molstarMouseoutEvent: string = "PDB.molstar.mouseout";
export const aaTypes = new Map<string, Array<string>>([ export const aaTypes = new Map<string, Array<string>>([
['hydrophobic', new Array<string>('A', 'I', 'L', 'M', 'F', 'W', 'V')], ["hydrophobic", new Array<string>("A", "I", "L", "M", "F", "W", "V")],
['positive', Array<string>('K', 'R', 'O')], ["positive", Array<string>("K", "R", "O")],
['negative', Array<string>('E', 'D')], ["negative", Array<string>("E", "D")],
['polar', Array<string>('N', 'Q', 'S', 'T')], ["polar", Array<string>("N", "Q", "S", "T")],
['cystein', Array<string>('C', 'U')], ["cystein", Array<string>("C", "U")],
['glycine', Array<string>('G')], ["glycine", Array<string>("G")],
['proline', Array<string>('P')], ["proline", Array<string>("P")],
['aromatic', Array<string>('H', 'Y')] ["aromatic", Array<string>("H", "Y")]
]); ]);
export const aaAbreviations = new Map<string, string>([ export const aaAbreviations = new Map<string, string>([
['ALA', 'A'], ["ALA", "A"],
['ARG', 'R'], ["ARG", "R"],
['ASN', 'N'], ["ASN", "N"],
['ASP', 'D'], ["ASP", "D"],
['CYS', 'C'], ["CYS", "C"],
['GLU', 'E'], ["GLU", "E"],
['GLN', 'Q'], ["GLN", "Q"],
['GLY', 'G'], ["GLY", "G"],
['HIS', 'H'], ["HIS", "H"],
['ILE', 'I'], ["ILE", "I"],
['LEU', 'L'], ["LEU", "L"],
['LYS', 'K'], ["LYS", "K"],
['MET', 'M'], ["MET", "M"],
['PHE', 'F'], ["PHE", "F"],
['PRO', 'P'], ["PRO", "P"],
['SER', 'S'], ["SER", "S"],
['THR', 'T'], ["THR", "T"],
['TRP', 'W'], ["TRP", "W"],
['TYR', 'Y'], ["TYR", "Y"],
['VAL', 'V'] ["VAL", "V"]
]); ]);
export const backboneAtoms: Array<string> = ['N', 'CA', 'C', 'O']; export const backboneAtoms: Array<string> = ["N", "CA", "C", "O"];
// Mapping of interaction classes and interactions comming from arpeggio
export const interactionsClasses = new Map<string, Array<string>>([ export const interactionsClasses = new Map<string, Array<string>>([
["covalent", new Array<string>("covalent")], ["covalent", new Array<string>("covalent")],
["electrostatic", new Array<string>("ionic", "hbond", "weak_hbond", "polar", "weak_polar", "xbond", "carbonyl")], ["electrostatic", new Array<string>("ionic", "hbond", "weak_hbond", "polar", "weak_polar", "xbond", "carbonyl")],
['amide', new Array<string>("AMIDEAMIDE", "AMIDERING")], ["amide", new Array<string>("AMIDEAMIDE", "AMIDERING")],
["vdw", new Array<string>("vdw")], ["vdw", new Array<string>("vdw")],
["hydrophobic", new Array<string>("hydrophobic")], ["hydrophobic", new Array<string>("hydrophobic")],
["aromatic", new Array<string>("aromatic", "FF", "OF", "EE", "FT", "OT", "ET", "FE", "OE", "EF")], ["aromatic", new Array<string>("aromatic", "FF", "OF", "EE", "FT", "OT", "ET", "FE", "OE", "EF")],
...@@ -59,6 +60,13 @@ namespace Config { ...@@ -59,6 +60,13 @@ namespace Config {
["clashes", new Array<string>("clash", "vdw_clash")] ["clashes", new Array<string>("clash", "vdw_clash")]
]); ]);
/**
* Configuration of the UI menu (e.g. the hamburger visible in top
* right component's corner)
*
* @export
* @class UIParameters
*/
export class UIParameters { export class UIParameters {
reinitialize: boolean; reinitialize: boolean;
zoom: boolean; zoom: boolean;
......
...@@ -58,7 +58,7 @@ class Depiction { ...@@ -58,7 +58,7 @@ class Depiction {
/** /**
* Returns an initial position of Residue node bound to a list of * Returns an initial position of a Residue node bound to a list of
* atom. * atom.
* *
* Present implementation sorts all the partners based on the atom * Present implementation sorts all the partners based on the atom
...@@ -74,12 +74,15 @@ class Depiction { ...@@ -74,12 +74,15 @@ class Depiction {
if (this.atoms.length === 1) { if (this.atoms.length === 1) {
return new Vector2D(this.atoms[0].position.x, this.atoms[0].position.y); return new Vector2D(this.atoms[0].position.x, this.atoms[0].position.y);
} }
// ideally we want to find an atom which is part just a single bond to get nice initial position. // ideally we want to find an atom which is part of just
// If there is no such atom any will do // a single bond to get nice initial position.
// If there is no such atom any would do.
let atoms = this.atoms.filter(x => atomNames.includes(x.name)).sort((x, y) => x.connectivity - y.connectivity); let atoms = this.atoms
let thisAtom = atoms[0]; .filter(x => atomNames.includes(x.name))
.sort((x, y) => x.connectivity - y.connectivity);
let thisAtom = atoms[0];
let bond = this.bonds.find(x => x.containsAtom(thisAtom)); let bond = this.bonds.find(x => x.containsAtom(thisAtom));
let otherAtom = bond.getOtherAtom(thisAtom); let otherAtom = bond.getOtherAtom(thisAtom);
...@@ -90,6 +93,13 @@ class Depiction { ...@@ -90,6 +93,13 @@ class Depiction {
return new Vector2D(x, y); return new Vector2D(x, y);
} }
/**
* Draw ligand depiction to the canvas using D3.js. Any previous
* ligands are discarded.
*
* @param {boolean} [atomNames=false] Whether or not atom names should be drawn.
* @memberof Depiction
*/
public draw(atomNames: boolean = false) { public draw(atomNames: boolean = false) {
this.structure.selectAll("*").remove(); this.structure.selectAll("*").remove();
...@@ -99,6 +109,15 @@ class Depiction { ...@@ -99,6 +109,15 @@ class Depiction {
else this.appendLabels(); else this.appendLabels();
} }
/**
* Highlight substructure of a depiction formed by a list of atoms.
* Any former highlights are discarded.
*
* @param {Array<string>} atoms List of atoms to be displayed
* @param {string} [color=undefined] highlight collor
* @returns
* @memberof Depiction
*/
public highlightSubgraph(atoms: Array<string>, color: string = undefined) { public highlightSubgraph(atoms: Array<string>, color: string = undefined) {
if (!this.atoms || !atoms) return; if (!this.atoms || !atoms) return;
...@@ -126,6 +145,15 @@ class Depiction { ...@@ -126,6 +145,15 @@ class Depiction {
.attr('style', `fill:none;fill-rule:evenodd;stroke:${color};stroke-width:22px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1`) .attr('style', `fill:none;fill-rule:evenodd;stroke:${color};stroke-width:22px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1`)
} }
/**
* Add code so that the component can draw contour levels. Shape of
* data is driven by the requirements of the D3.js code.
*
* TODO
*
* @param {*} data to be decided
* @memberof Depiction
*/
public addContour(data: any) { public addContour(data: any) {
this.contour.selectAll('*').remove(); this.contour.selectAll('*').remove();
......
...@@ -537,6 +537,12 @@ class Visualization { ...@@ -537,6 +537,12 @@ class Visualization {
return 'blank.svg'; return 'blank.svg';
} }
/**
* Remove fixed positions of nodes, after they have been manipulated with.
*
* @private
* @memberof Visualization
*/
private nullNodesPositions() { private nullNodesPositions() {
this.presentBindingSite.interactionNodes.forEach((x: Model.InteractionNode) => { this.presentBindingSite.interactionNodes.forEach((x: Model.InteractionNode) => {
if (!x.static) { if (!x.static) {
...@@ -547,7 +553,7 @@ class Visualization { ...@@ -547,7 +553,7 @@ class Visualization {
} }
// #region fire events // #region fire events For component interoperability with other components
private fireExternalLinkEvent(link: Model.Link, eventName: string) { private fireExternalLinkEvent(link: Model.Link, eventName: string) {
let atomsSource = []; let atomsSource = [];
...@@ -643,6 +649,15 @@ class Visualization { ...@@ -643,6 +649,15 @@ class Visualization {
/**
* Add labels to the InteractionNodes e.g.
*
* ALA
* 42
* @private
* @param {*} selection
* @memberof Visualization
*/
private addNodeLabels(selection: any) { private addNodeLabels(selection: any) {
selection selection
.append('text') .append('text')
...@@ -662,7 +677,8 @@ class Visualization { ...@@ -662,7 +677,8 @@ class Visualization {
//#endregion //#endregion
/** /**
* Initialize scene after user selected a part of bound molecule. * Initialize scene after user selected a a ligand that is a part of
* bound molecule.
* *
* @private * @private
* @param {Model.InteractionNode} n Interaction node user clicked to * @param {Model.InteractionNode} n Interaction node user clicked to
...@@ -707,10 +723,14 @@ class Visualization { ...@@ -707,10 +723,14 @@ class Visualization {
/** /**
* Setup ligand scene for display of ligand and interactions. * Setup display of interactions for a ligand
* This includes: setup of links, nodes, simulation and subscribing to relevant events. * This includes:
* setup of links
* nodes
* simulation
* subscribing to relevant events.
* *
* Depiction is expected to be downloaded already. * Depiction is expected to be downloaded already!
* *
* @private * @private
* @memberof Visualization * @memberof Visualization
...@@ -783,7 +803,12 @@ class Visualization { ...@@ -783,7 +803,12 @@ class Visualization {
/** /**
* Setup display of interactions for bound molecule. * Setup display of interactions for bound molecule.
* * This includes: setup of links, nodes, simulation and subscribing to relevant events. * This includes:
* setup of links
* nodes
* simulation
* subscribing to relevant events.
*
* No depiction is required for this step. * No depiction is required for this step.
* *
* @private * @private
...@@ -881,6 +906,15 @@ class Visualization { ...@@ -881,6 +906,15 @@ class Visualization {
} }
/**
* Dim all the nodes but the selected one.
*
* @private
* @param {Model.InteractionNode} x
* @param {number} i
* @param {*} g
* @memberof Visualization
*/
private nodeDim(x: Model.InteractionNode, i: number, g: any) { private nodeDim(x: Model.InteractionNode, i: number, g: any) {
if (!x.static) x.scale = 1.0; if (!x.static) x.scale = 1.0;
...@@ -906,6 +940,15 @@ class Visualization { ...@@ -906,6 +940,15 @@ class Visualization {
.attr('opacity', 0.4); .attr('opacity', 0.4);
} }
/**
* Dim all the links but the selected one.
*
* @private
* @param {Model.Link} x
* @param {number} i
* @param {*} g
* @memberof Visualization
*/
private linkDim(x: Model.Link, i: number, g: any) { private linkDim(x: Model.Link, i: number, g: any) {
let parent = d3.select(g[i]).node().parentNode; let parent = d3.select(g[i]).node().parentNode;
d3.select(parent).classed('pdb-lig-env-svg-bond-highlighted', false); d3.select(parent).classed('pdb-lig-env-svg-bond-highlighted', false);
......
...@@ -28,6 +28,13 @@ namespace Model { ...@@ -28,6 +28,13 @@ namespace Model {
Internal Internal
} }
/**
* Utility to translate arpeggio interaction to component's
* interactions
*
* @export
* @class InteractionTypeUtil
*/
export class InteractionTypeUtil { export class InteractionTypeUtil {
public static parse(value: string) { public static parse(value: string) {
if (value === 'atom_atom') return InteractionType.AtomAtom; if (value === 'atom_atom') return InteractionType.AtomAtom;
...@@ -112,6 +119,17 @@ namespace Model { ...@@ -112,6 +119,17 @@ namespace Model {
} }
} }
/**
* Interaction node in the simulation. This is the colorful node
* that is being shown on the canvas and a transparent node per one
* heavy atom in ligand (for proper layout of the binding site).
*
* Implements D3 interface.
*
* @export
* @class InteractionNode
* @implements {d3.SimulationNodeDatum}
*/
export class InteractionNode implements d3.SimulationNodeDatum { export class InteractionNode implements d3.SimulationNodeDatum {
id: string; id: string;
residue: Residue; residue: Residue;
...@@ -154,12 +172,12 @@ namespace Model { ...@@ -154,12 +172,12 @@ namespace Model {
let chainStr = splitted[0]; let chainStr = splitted[0];
let symString = ""; let symString = "";
if (splitted.length > 1) { if (splitted.length > 1) {
symString = splitted[1] !== "1"? `[${splitted[1]}]` : ""; symString = splitted[1] !== "1"? `[${splitted[1]}]` : "";
} }
let str = `${r.chemCompId} | ${chainStr}${symString} | ${r.authorResidueNumber}${r.authorInsertionCode}`; let str = `${r.chemCompId} | ${chainStr}${symString} | ${r.authorResidueNumber}${r.authorInsertionCode}`;
return str; return str;
} }
...@@ -168,6 +186,15 @@ namespace Model { ...@@ -168,6 +186,15 @@ namespace Model {
} }
} }
/**
* Visual representation of the interaction between two residues or
* a residue and an atom. Percise color/type of the interaction is
* subsequently controlled by the pdb-ligand-env-svg.css file.
*
* @export
* @abstract
* @class Link
*/
export abstract class Link { export abstract class Link {
public source: InteractionNode; public source: InteractionNode;
public target: InteractionNode; public target: InteractionNode;
...@@ -195,7 +222,7 @@ namespace Model { ...@@ -195,7 +222,7 @@ namespace Model {
return (this.target.residue.equals(n) || this.source.residue.equals(n)); return (this.target.residue.equals(n) || this.source.residue.equals(n));
} }
public getOtherNode(node: InteractionNode) { public getOtherNode(node: InteractionNode) {
return this.source.equals(node) ? this.target : this.source; return this.source.equals(node) ? this.target : this.source;
} }
...@@ -204,6 +231,15 @@ namespace Model { ...@@ -204,6 +231,15 @@ namespace Model {
abstract toTooltip(): string; abstract toTooltip(): string;
} }
/**
* Implementation of the Link for the BoundMolecule view
* e.g. bm1 of 3d12
*
* @export
* @class ResidueResidueLink
* @extends {Link}
*/
export class ResidueResidueLink extends Link { export class ResidueResidueLink extends Link {
target: InteractionNode; target: InteractionNode;
source: InteractionNode source: InteractionNode
...@@ -263,6 +299,13 @@ namespace Model { ...@@ -263,6 +299,13 @@ namespace Model {
} }
/**
* Implementation of the link for the Ligand view e.g REA of 1cbs
*
* @export
* @class LigandResidueLink
* @extends {Link}
*/
export class LigandResidueLink extends Link { export class LigandResidueLink extends Link {
interaction: Array<Interaction>; interaction: Array<Interaction>;
...@@ -335,10 +378,12 @@ namespace Model { ...@@ -335,10 +378,12 @@ namespace Model {
} }
/** /**
* DataObject representing the entire binding site with the bound * DataObject representing the entire binding site with the bound
* molecule and all its interactions. * molecule and all its interactions.
*
* @export
* @class BindingSite
*/ */
export class BindingSite { export class BindingSite {
pdbId: string; pdbId: string;
...@@ -358,11 +403,19 @@ namespace Model { ...@@ -358,11 +403,19 @@ namespace Model {
} }
/**
* Initialize BindingSite from BoundMolecule API call
*
* @param {string} pdbId
* @param {*} data
* @returns {BindingSite}
* @memberof BindingSite
*/
public fromBoundMolecule(pdbId: string, data: any): BindingSite { public fromBoundMolecule(pdbId: string, data: any): BindingSite {
this.pdbId = pdbId; this.pdbId = pdbId;
this.bmId = data.bm_id; this.bmId = data.bm_id;
this.tmpResidueSet = new ObjectSet<Residue>(); this.tmpResidueSet = new ObjectSet<Residue>(); // custom objects need to be unique
this.tmpNodesSet = new ObjectSet<InteractionNode>(); this.tmpNodesSet = new ObjectSet<InteractionNode>();
data.composition.ligands.forEach(x => this.tmpResidueSet.tryAdd(new Residue(x, true))); data.composition.ligands.forEach(x => this.tmpResidueSet.tryAdd(new Residue(x, true)));
...@@ -394,6 +447,15 @@ namespace Model { ...@@ -394,6 +447,15 @@ namespace Model {
} }
/**
* Process API response interaction partner (BoundMolecule view).
* Create a new instance if not observed alread.
*
* @private
* @param {*} r
* @returns {InteractionNode} Interaction node to that partner
* @memberof BindingSite
*/
private processResidueInteractionPartner(r: any): InteractionNode { private processResidueInteractionPartner(r: any): InteractionNode {
let residue = new Residue(r, false); let residue = new Residue(r, false);
residue = this.tmpResidueSet.tryAdd(residue); residue = this.tmpResidueSet.tryAdd(residue);
...@@ -404,6 +466,17 @@ namespace Model { ...@@ -404,6 +466,17 @@ namespace Model {
} }
/**
* Process API response interaction partner (Ligand view).
*
*
* @private
* @param {Residue} r
* @param {Depiction} d
* @param {string[]} atom_names
* @returns {InteractionNode} Interaction node to that partner
* @memberof BindingSite
*/
private processLigandInteractionPartner(r: Residue, d: Depiction, atom_names: string[]): InteractionNode { private processLigandInteractionPartner(r: Residue, d: Depiction, atom_names: string[]): InteractionNode {
let scale = 0.0; let scale = 0.0;
if (r.isLigand) scale = atom_names.length > 1 ? 0.5 : 0.0 if (r.isLigand) scale = atom_names.length > 1 ? 0.5 : 0.0
...@@ -438,7 +511,7 @@ namespace Model { ...@@ -438,7 +511,7 @@ namespace Model {
if (bgnNode.residue.equals(endNode.residue)) { if (bgnNode.residue.equals(endNode.residue)) {
this.tmpNodesSet.delete(endNode); this.tmpNodesSet.delete(endNode);
return; // we do not want to show 'self interactions'