Skip to content

Commit

Permalink
Merge 3e52f4b into b240ce3
Browse files Browse the repository at this point in the history
  • Loading branch information
dany-fu committed Feb 9, 2019
2 parents b240ce3 + 3e52f4b commit 42d671e
Show file tree
Hide file tree
Showing 12 changed files with 413 additions and 339 deletions.
2 changes: 1 addition & 1 deletion demos/server.js
Original file line number Diff line number Diff line change
Expand Up @@ -45,7 +45,7 @@ app.post('/postSpecs', function(req,res) {

let data;
try {
data = constellation(designName, langText, categories, numDesigns, maxCycles);
data = constellation.constellationGOLDBAR(designName, langText, categories, numDesigns, maxCycles);
res.status(200).send(data);
} catch (error) {
console.log(error);
Expand Down
65 changes: 34 additions & 31 deletions demos/static/js/client.js
Original file line number Diff line number Diff line change
Expand Up @@ -67,13 +67,13 @@ function generateGraph(stateGraph) {
let text;
let node = stateGraph[nodeId];

if (node.type === graph.ROOT) {
if (node.type === ROOT) {
text = 'Root';
} else if (node.type === graph.EPSILON) {
} else if (node.type === EPSILON) {
text = 'Epsilon'
} else if (node.type === graph.ACCEPT) {
} else if (node.type === ACCEPT) {
text = 'Accept';
} else if (node.type === graph.ATOM) {
} else if (node.type === ATOM) {
text = node.text;
}
nodes.push({id: nodeId, type: node.type, text, operator: node.operator});
Expand Down Expand Up @@ -146,14 +146,14 @@ function drawNodes(nodes) {
.style('font-family', 'Montserrat');

// Add circles
circlePointer = nodePointer.filter(function (d) { return d.type !== graph.ATOM; })
circlePointer = nodePointer.filter(function (d) { return d.type !== ATOM; })
.append('circle')
.attr('fill', function(d) {
if (d.type === graph.ROOT) {
if (d.type === ROOT) {
return 'rgb(33,168,174)';
} else if (d.type === graph.ACCEPT) {
} else if (d.type === ACCEPT) {
return 'rgb(133,151,41)';
} else if (d.type === graph.EPSILON) {
} else if (d.type === EPSILON) {
return 'rgb(253,183,152)';
} else if (d.type === INTERMEDIATE) {
return 'rgb(253,183,152)';
Expand All @@ -171,37 +171,37 @@ function drawNodes(nodes) {
});

// Add images
imagePointer = nodePointer.filter(function(d) { return d.type === graph.ATOM; })
imagePointer = nodePointer.filter(function(d) { return d.type === ATOM; })
.append('g')
.attr('transform', 'translate(-15 , -30)')
.append('svg:image')
.attr('xlink:href', function(d) {
switch (d.text) {
case 'ribosomeBindingSite':
case 'promoter':
case 'terminator':
// KEEP IN ALPHABETICAL ORDER
case 'aptamer':
case 'assemblyScar':
case 'bluntRestrictionSite':
case 'cds':
case 'restriction_enzyme_assembly_scar':
case 'restriction_enzyme_recognition_site':
case 'protein_stability_element':
case 'blunt_end_restriction_enzyme_cleavage_site':
case 'ribonuclease_site':
case 'restriction_enzyme_five_prime_single_strand_overhang':
case 'ribosome_entry_site':
case 'five_prime_sticky_end_restriction_enzyme_cleavage_site':
case 'RNA_stability_element':
case 'ribozyme':
case 'dnaStabilityElement':
case 'engineeredRegion':
case 'fivePrimeOverhang':
case 'fivePrimeStickyRestrictionSite':
case 'insulator':
case 'signature':
case 'nonCodingRna':
case 'operator':
case 'origin_of_replication':
case 'restriction_enzyme_three_prime_single_strand_overhang':
case 'primer_binding_site':
case 'three_prime_sticky_end_restriction_enzyme_cleavage_site':
case 'protease_site':
case 'originOfReplication':
case 'originOfTrasnfer':
case 'polyA':
case 'promoter':
case 'proteaseSite':
case 'proteinStabilityElement':
case 'ribosomeBindingSite':
case 'ribozyme':
case 'signature':
case 'terminator':
return './sbol/' + d.text + '.svg';
default:
return './sbol/' + 'user_defined.svg';
return './sbol/' + 'noGlyphAssigned.svg';
}
})
.attr('width', IMAGESIZE);
Expand Down Expand Up @@ -388,8 +388,11 @@ $(document).ready(function() {
'designName': designName,
'sbolDocs[]': JSON.stringify(sbolDocs)})
.fail((response) => {
alert(response.responseText);
});
alert(response.responseText);
})
.done(() => {
alert('Design successfully stored in Knox')
});
});


Expand Down
18 changes: 10 additions & 8 deletions lib/constellation.js
Original file line number Diff line number Diff line change
@@ -1,10 +1,10 @@
/*global graph:true designEnumeration:true imparse:true*/

if (typeof(window) === 'undefined') {
graph = require('./graph');
designEnumeration = require('./designEnumeration');
design = require('./designEnumeration');
imparse = require('imparse');
sbol = require('./sbol');
graphGOLDBAR = require('./graphGOLDBAR');
}

const GRAMMAR_DEF = [{'Seq':[{'Then':[['Exp'],'.',['Seq']]},{'Then':[['Exp'],'then',['Seq']]},{'':[['Exp']]}]},{'Exp':[{'Or':[['Term'],'or',['Exp']]},{'And':[['Term'],'and',['Exp']]},{'':[['Term']]}]},{'Term':[{'OneOrMore':['one-or-more',['Term']]},{'ZeroOrMore':['zero-or-more',['Term']]},{'ZeroOrMoreSBOL':['zero-or-more-sbol',['Term']]},{'':['{',['Seq'],'}']},{'':['(',['Seq'],')']},{'Atom':[{'RegExp':'([A-Za-z0-9]|-|_)+'}]}]}];
Expand All @@ -21,7 +21,7 @@ const GRAMMAR_DEF = [{'Seq':[{'Then':[['Exp'],'.',['Seq']]},{'Then':[['Exp'],'th
* @param maxCycles Maximum depth of cycles
* @returns {{stateGraph, designs: *, paths}}
*/
const constellation = function (designName, langText, categories, numDesigns, maxCycles = 1) {
function constellationGOLDBAR(designName, langText, categories, numDesigns, maxCycles = 1) {
if (isNaN(numDesigns)) {
throw new Error('Invalid number of designs');
}
Expand Down Expand Up @@ -52,9 +52,9 @@ const constellation = function (designName, langText, categories, numDesigns, ma
throw new Error('Parsing error!')
}

gra = graph(parsed, maxCycles);
graSBOL = graph(parsedSBOL, maxCycles).stateGraph;
designs = designEnumeration(gra.paths, categories, numDesigns);
gra = graphGOLDBAR(parsed, maxCycles);
graSBOL = graphGOLDBAR(parsedSBOL, maxCycles).stateGraph;
designs = design.enumerateDesigns(gra.paths, categories, numDesigns);

try {
designName = String(designName).replace(/ /g, '_');
Expand All @@ -64,7 +64,7 @@ const constellation = function (designName, langText, categories, numDesigns, ma
}

return {stateGraph: gra.stateGraph, designs: designs, paths: gra.paths, sbols: [sbolDoc]}; //todo
};
}

/**
* Sanitises specification input and parses GOLDBAR
Expand All @@ -83,5 +83,7 @@ function parseCategories(categories) {
}

if (typeof window === 'undefined') {
module.exports = constellation;
module.exports = {
constellationGOLDBAR,
};
}
8 changes: 4 additions & 4 deletions lib/designEnumeration.js
Original file line number Diff line number Diff line change
Expand Up @@ -133,9 +133,9 @@ function addDesigns(designs, collection) {
return collection;
}

const designEnumeration = enumerateDesigns;
designEnumeration.getCartesianProduct = getCartesianProduct;

if (typeof window === 'undefined') {
module.exports = designEnumeration;
module.exports = {
enumerateDesigns,
getCartesianProduct
};
}
94 changes: 22 additions & 72 deletions lib/graph.js
Original file line number Diff line number Diff line change
Expand Up @@ -15,66 +15,8 @@ const THEN = 'Then';
const ONE_MORE = "OneOrMore";
const ZERO_MORE = "ZeroOrMore";
const ZERO_SBOL = 'ZeroOrMoreSBOL';
const ONE = 'one';

/* * * * * * * * * * * */
/* GRAPH GENERATION */
/* * * * * * * * * * * */

/**
* Generates graph based on parsed GOLDBAR object
* @param parsedObject Parsed GOLDBAR object
* @returns {{stateGraph: Object, paths: Array}}
*/
const graph = function (parsedObject, maxCycles) {
if (maxCycles > 10) {
throw new Error('Cycle depth is too high');
}

const stateGraph = {}; // Stores currently generated edges
const boundaryStack = []; // Stores connected nodes in an object. Leaf nodes are stored in object.leaves

// Generate graph
populateGraph(parsedObject, stateGraph, boundaryStack);
addAcceptNodes(stateGraph, boundaryStack);

// Get root of whole graph
const root = generateRootNode(stateGraph, boundaryStack);

// Generate all paths
const paths = enumeratePaths(root, stateGraph, maxCycles);

return {stateGraph, paths};
};

/**
* Receives object from parsed GOLDBAR specification and recursively builds a graph
* @param parsed The parsed GOLDBAR object
* @param stateGraph Current graph
* @param boundaryStack Boundary stack
*/
function populateGraph(parsed, stateGraph, boundaryStack) {
// Handle if input is an atom
if (parsed.Atom) {
handleAtom(parsed.Atom, stateGraph, boundaryStack);
return;
}

// Handle if input is an or
if (Array.isArray(parsed)) {
for (let i = 0; i < parsed.length; i++) {
populateGraph(parsed[i], stateGraph, boundaryStack);
}
return;
}

// Handle if input contains other or nested operations
if (Object.keys(parsed).length > 0) {
for (let operation in parsed) {
populateGraph(parsed[operation], stateGraph, boundaryStack);
handleOp(operation, stateGraph, boundaryStack);
}
}
}

/* * * * * * * * * * */
/* NODE HANDLING */
Expand Down Expand Up @@ -134,6 +76,10 @@ function addToBoundaryStack(head, leaves, boundaryStack) {
* @param boundaryStack Boundary stack
*/
function handleOp(op, stateGraph, boundaryStack) {

if(op === 'one'){
return;
}
// Parent must always be added to the graph
const parentId = uuidv4();
stateGraph[parentId] = {id: parentId, text: EPSILON, type: EPSILON, edges:[], operator: []};
Expand Down Expand Up @@ -509,20 +455,24 @@ function getEpsilonParents(stateGraph) {
return epsilonMap;
}

// Ensure constants are accessible externally.
graph.EPSILON = EPSILON;
graph.ATOM = ATOM;
graph.ACCEPT = ACCEPT;
graph.ROOT = ROOT;

graph.OR = OR;
graph.THEN = THEN;
graph.ONE_MORE = ONE_MORE;
graph.ZERO_MORE = ZERO_MORE;
graph.ZERO_SBOL = ZERO_SBOL;

if (typeof window === 'undefined') {
module.exports = graph;
module.exports = {
enumeratePaths,
generateRootNode,
addAcceptNodes,
handleOp,
handleAtom,
EPSILON,
ATOM,
ACCEPT,
ROOT,
OR,
THEN,
ONE_MORE,
ZERO_MORE,
ZERO_SBOL,
ONE
};
}

/* * * * * * * * * * */
Expand Down
63 changes: 63 additions & 0 deletions lib/graphGOLDBAR.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,63 @@
if (typeof window === 'undefined') {
graph = require('./graph');
}

/**
* Generates graph based on parsed GOLDBAR object
* @param parsedObject Parsed GOLDBAR object
* @returns {{stateGraph: Object, paths: Array}}
*/
function createGraphFromGOLDBAR(parsedObject, maxCycles) {
if (maxCycles > 10) {
throw new Error('Cycle depth is too high');
}

const stateGraph = {}; // Stores currently generated edges
const boundaryStack = []; // Stores connected nodes in an object. Leaf nodes are stored in object.leaves

// Generate graph
populateGraph(parsedObject, stateGraph, boundaryStack);
graph.addAcceptNodes(stateGraph, boundaryStack);

// Get root of whole graph
const root = graph.generateRootNode(stateGraph, boundaryStack);

// Generate all paths
const paths = graph.enumeratePaths(root, stateGraph, maxCycles);

return {stateGraph, paths};
}

/**
* Receives object from parsed GOLDBAR specification and recursively builds a graph
* @param parsed The parsed GOLDBAR object
* @param stateGraph Current graph
* @param boundaryStack Boundary stack
*/
function populateGraph(parsed, stateGraph, boundaryStack) {
// Handle if input is an atom
if (parsed.Atom) {
graph.handleAtom(parsed.Atom, stateGraph, boundaryStack);
return;
}

// Handle if input is an or
if (Array.isArray(parsed)) {
for (let i = 0; i < parsed.length; i++) {
populateGraph(parsed[i], stateGraph, boundaryStack);
}
return;
}

// Handle if input contains other or nested operations
if (Object.keys(parsed).length > 0) {
for (let operation in parsed) {
populateGraph(parsed[operation], stateGraph, boundaryStack);
graph.handleOp(operation, stateGraph, boundaryStack);
}
}
}

if (typeof window === 'undefined') {
module.exports = createGraphFromGOLDBAR;
}
Loading

0 comments on commit 42d671e

Please sign in to comment.