diff --git a/config/plugins/visualizations/ts_visjs/package.json b/config/plugins/visualizations/ts_visjs/package.json
index ada8e3d8b11..3d3d7e79f75 100644
--- a/config/plugins/visualizations/ts_visjs/package.json
+++ b/config/plugins/visualizations/ts_visjs/package.json
@@ -3,11 +3,9 @@
"version": "1.0.0",
"license": "MIT",
"dependencies": {
- "plotly.js": "^2.11.1",
- "pca-js": "^1.0.2",
- "d3": "^7.4.4"
+ "vis": "^4.21.0"
},
"scripts": {
- "build": "mkdir -p static/dist && cp node_modules/pca-js/pca.min.js node_modules/plotly.js/dist/plotly.min.js node_modules/d3/dist/d3.min.js static/dist"
+ "build": "mkdir -p static/dist && cp node_modules/vis/vis.min.js node_modules/vis/vis.min.css static/dist"
}
}
diff --git a/config/plugins/visualizations/ts_visjs/static/script.js b/config/plugins/visualizations/ts_visjs/static/script.js
new file mode 100644
index 00000000000..42bf5817531
--- /dev/null
+++ b/config/plugins/visualizations/ts_visjs/static/script.js
@@ -0,0 +1,113 @@
+var container = document.getElementById('mynetwork');
+
+// data filters
+hell_filter = document.getElementById('hell_node')
+loops_filter = document.getElementById('loop_edges')
+border_filter = document.getElementById('border_nodes')
+
+let noHell = false
+const nodesFilter = (node) => {
+ if (noHell) {
+ return (node.class != 'hell')
+ } else {
+ return true
+ }
+}
+
+var nodesView = new vis.DataView(nodes, { filter: nodesFilter })
+
+// remove hell
+hell_filter.addEventListener('change', (e) => {
+ if (hell_filter.checked){
+ noHell = false
+ } else {
+ noHell = true
+ }
+ nodesView.refresh()
+});
+
+data = {
+ nodes: nodesView,
+ edges: edges
+ };
+
+var network = new vis.Network(container, data, options);
+
+loops_filter.addEventListener('change', (e) => {
+ if (loops_filter.checked){
+ for (index = 0; index < self_loops.length; index++) {
+ edges.add(self_loops[index]);
+ }
+ } else {
+ for (index = 0; index < self_loops.length; index++) {
+ edges.remove({id: self_loops[index].id});
+ }
+ }
+});
+
+border_filter.addEventListener('change', (e) => {
+ if (border_filter.checked){
+ for (index = 0; index < border_nodes.length; index++) {
+ nodes.update({id: border_nodes[index].id, shape: "box"});
+ }
+ } else {
+ for (index = 0; index < border_nodes.length; index++) {
+ nodes.update({id: border_nodes[index].id, shape: "ellipse"});
+ }
+ }
+});
+
+var stabil = true;
+
+network.on("click", function (params) {
+ params.event = "[original event]";
+ var tmp = " ";
+
+
+ for (var i = 1; i <= nodes.length; i++) {
+ if (nodes.get(i).id == params.nodes) {
+ tmp = nodes.get(i).text;
+ };
+ };
+
+ if(params.nodes.length === 0 && params.edges.length > 0) {
+ for (var i = 1; i <= edges.length; i++) {
+ if (edges.get(i).id == params.edges) {
+ tmp = edges.get(i).text;
+ };
+ };
+ };
+
+ document.getElementById('rectangle').innerHTML = '
' + tmp + '
';
+});
+
+network.on("stabilized", function (params) {
+ if(stabil) {
+ network.fit();
+ stabil = false;
+ };
+});
+
+network.once("stabilizationIterationsDone", function() {
+ document.getElementById('text').innerHTML = '100%';
+ document.getElementById('bar').style.width = '496px';
+ document.getElementById('loadingBar').style.opacity = 0;
+ // really clean the dom element
+ setTimeout(function () {document.getElementById('loadingBar').style.display = 'none';}, 0);
+});
+
+clickedNode = nodes.get(fromNode);
+clickedNode.color = {
+ border: 'orange',
+ background: 'orange',
+ highlight: {
+ border: 'orange',
+ background: 'orange'
+ }
+ }
+ nodes.update(clickedNode);
+
+network.on("doubleClick", function (params) {
+ params.event = "[original event]";
+ network.focus(params.nodes);
+});
diff --git a/config/plugins/visualizations/ts_visjs/templates/ts_visjs.mako b/config/plugins/visualizations/ts_visjs/templates/ts_visjs.mako
index ae6be9d77b8..6893d2b17f5 100644
--- a/config/plugins/visualizations/ts_visjs/templates/ts_visjs.mako
+++ b/config/plugins/visualizations/ts_visjs/templates/ts_visjs.mako
@@ -7,13 +7,7 @@ from numpy import inf
<%
def to_counter(state, ordering):
- """
- Transforms given state to Counter using given ordering
-
- :param state: str representation of state
- :param ordering: enumeration of agents
- :return: Counter representing the state
- """
+ """Transforms given state to Counter using given ordering."""
state = eval(state)
if state[0] == inf:
return inf
@@ -21,36 +15,21 @@ def to_counter(state, ordering):
def node_to_string(node):
- """
- Creates string representation of Counter of agents.
-
- :param node: given Counter of agents.
- :return: string representation of Counter
- """
+ """Creates string representation of Counter of agents."""
if node == inf:
return "inf"
return "
".join([str(int(v)) + " " + str(k) for k, v in node.items()])
def side_to_string(side):
- """
- Another string representation of Counter, this time used as side in reaction
- :param side: given Counter
- :return: string representation of Counter
- """
+ """Another string representation of Counter, this time used as side in reaction."""
if side == inf:
return "inf"
return " + ".join([str(int(v)) + " " + str(k) for k, v in side.items()])
def create_sides(lhs, rhs):
- """
- From given substrates and products counters creates their mutual differences
-
- :param lhs: dict of substrates
- :param rhs: dict of products
- :return: two counters representing differences
- """
+ """From given substrates and products counters creates their mutual differences."""
if lhs == inf:
return inf, inf
if rhs == inf:
@@ -61,13 +40,7 @@ def create_sides(lhs, rhs):
def write_node(ID, label, node_class):
- """
- Creates string representation of a node
-
- :param ID: ID of given node
- :param label: enumeration of agents
- :return: string representation
- """
+ """Creates string representation of a node."""
if label == "inf":
node_class = "hell"
return "\t\t{{id: {0}, label: '{0}', class: '{2}', shape: 'ellipse', title: '{0}', text: '{1}'}},\n".format(
@@ -75,32 +48,19 @@ def write_node(ID, label, node_class):
def write_reaction(edge_id, left_index, right_index, substrates, products, rate, label):
- """
- Creates string representation of a reaction
-
- :param edge_id: ID of given reaction
- :param left_index: ID of FROM node
- :param right_index: ID of TO node
- :param substrates: enumeration of substrates
- :param products: enumeration of products
- :param rate: rate of the reaction (if any)
- :param label: used rule label
- :return: string representation
- """
+ """Creates string representation of a reaction."""
rate = " @ " + str(rate) if rate else ""
label = label + " ~ " if label else ""
return "\t\t{{id: {}, from: {}, to: {}, arrows: 'to', text: '{}{} => {}{}'}},\n".format(
edge_id, left_index, right_index, label, side_to_string(substrates), side_to_string(products), rate)
-def create_HTML_graph(): #data):
- output_file = firstpart
+def load_data():
+ output = dict()
data = ''.join(list(hda.datatype.dataprovider(hda, 'line', strip_lines=True, strip_newlines=True)))
data = json.loads(data)
- # data = json.load(data)
-
ordering = data['ordering']
nodes = {int(key): to_counter(data['nodes'][key], ordering) for key in data['nodes'].keys()}
@@ -118,6 +78,8 @@ def create_HTML_graph(): #data):
if products == inf and substrates != inf:
border_nodes.add(edge['s'])
+ output["nodes"] = ""
+
border_nodes_write = []
for id, state in nodes.items():
if id in border_nodes:
@@ -125,338 +87,176 @@ def create_HTML_graph(): #data):
border_nodes_write.append((id, node_to_string(state), node_class))
else:
node_class = "default"
- output_file += write_node(id, node_to_string(state), node_class)
+ output["nodes"] += write_node(id, node_to_string(state), node_class)
- output_file += mid_1
+ output["border_nodes"] = ""
for node in border_nodes_write:
- output_file += write_node(*node)
+ output["border_nodes"] += write_node(*node)
- output_file += mid_2
+ output["edges"] = ""
for edge in edges:
- output_file += write_reaction(*edge)
+ output["edges"] += write_reaction(*edge)
- output_file += mid_3
+ output["self_loops"] = ""
for edge in self_loops:
- output_file += write_reaction(*edge)
+ output["self_loops"] += write_reaction(*edge)
initial = data['initial']
iterations = (len(nodes)//100+1) * 100
step = iterations//100
- output_file += secondpart_1_1
- output_file += stabil_physics.format(iterations, step)
- output_file += secondpart_1_2
-
- output_file += "\tvar fromNode = " + str(int(initial)) + ";\n"
-
- output_file += secondpart_2_1
- output_file += stabil_bar.format(iterations, step)
- output_file += secondpart_2_2
- return output_file
+ output["step"] = step
+ output["iterations"] = iterations
+ output["fromNode"] = str(int(initial))
+ return output
-firstpart = \
-'''
+root = h.url_for("/static/")
+app_root = root + "plugins/visualizations/ts_visjs/static/"
+output = load_data()
+%>
+
+## ----------------------------------------------------------------------------
+
+
TS network visualisation
${h.javascript_link(app_root + "dist/vis.min.js")}
- # da sa to?
${h.stylesheet_link(app_root + "dist/vis.min.css")}
${h.stylesheet_link(app_root + "style.css")}
-
-
+
+
+ ${h.javascript_link(app_root + "script.js")}
+
+
+
+
-
+
-
+
-
-
-'''
-
-stabil_physics = \
-''' iterations: {},
- updateInterval: {}
-'''
-
-stabil_bar = \
-''' var iterations = {};
- var updateInterval = {};
-'''
-
-# for testing
-# filename = open('bigger_pMC.json', "r")
-# graph = create_HTML_graph(filename)
-
-graph = create_HTML_graph()
-%>
-
-${graph}