added basic controls
This commit is contained in:
parent
0b7f3f2be5
commit
a9b70d61a8
6
:w
Normal file
6
:w
Normal file
@ -0,0 +1,6 @@
|
||||
#mynetwork {
|
||||
height: 500px;
|
||||
width: 500px;
|
||||
background-color: white;
|
||||
border: 4px black;
|
||||
}
|
||||
@ -1,5 +1,6 @@
|
||||
#mynetwork {
|
||||
height: 500px;
|
||||
width: 500px;
|
||||
background-color: black;
|
||||
background-color: white;
|
||||
border: 3px solid black;
|
||||
}
|
||||
|
||||
@ -1,34 +1,13 @@
|
||||
// create an array with nodes
|
||||
//var nodes = new vis.DataSet([
|
||||
//{ id: 1, label: "Node 1" },
|
||||
//{ id: 2, label: "Node 2" },
|
||||
//{ id: 3, label: "Node 3" },
|
||||
//{ id: 4, label: "Node 4" },
|
||||
//{ id: 5, label: "Node 5" }
|
||||
//]);
|
||||
//
|
||||
//// create an array with edges
|
||||
//var edges = new vis.DataSet([
|
||||
//{ from: 1, to: 3 },
|
||||
//{ from: 1, to: 2 },
|
||||
//{ from: 2, to: 4 },
|
||||
//{ from: 2, to: 5 },
|
||||
//{ from: 3, to: 3 }
|
||||
//]);
|
||||
|
||||
// create a network
|
||||
//var container = document.getElementById("mynetwork");
|
||||
//var data = {
|
||||
//nodes: nodes,
|
||||
//edges: edges
|
||||
//};
|
||||
//var options = {
|
||||
//height: '100%',
|
||||
//width: '100%',
|
||||
//};
|
||||
//var network = new vis.Network(container, data, options);
|
||||
var network;
|
||||
var simulationData;
|
||||
animationPlaying = false;
|
||||
currentAnimationStep = 0;
|
||||
var animationInterval;
|
||||
var animationLen = 10;
|
||||
const stepSlider = document.querySelector('#stepRange');
|
||||
const stepField = document.querySelector('#stepField');
|
||||
const animationDurationSlider = document.querySelector('#animationDurationRange');
|
||||
const animationDurationField = document.querySelector('#animationDurationField');
|
||||
function createGraphFromDot(dotString){
|
||||
var parsedData = vis.parseDOTNetwork(dotString);
|
||||
// create a network
|
||||
@ -42,6 +21,10 @@ function createGraphFromDot(dotString){
|
||||
width: '100%',
|
||||
autoResize: true,
|
||||
nodes:{
|
||||
shape: 'dot',
|
||||
size: 40,
|
||||
borderWidth: 0,
|
||||
chosen: false,
|
||||
font:{
|
||||
size:0
|
||||
},
|
||||
@ -50,18 +33,18 @@ function createGraphFromDot(dotString){
|
||||
randomSeed: undefined,
|
||||
improvedLayout:true,
|
||||
clusterThreshold: 150,
|
||||
//hierarchical: {
|
||||
//enabled:false,
|
||||
//levelSeparation: 150,
|
||||
//nodeSpacing: 100,
|
||||
//treeSpacing: 200,
|
||||
//blockShifting: true,
|
||||
//edgeMinimization: true,
|
||||
//parentCentralization: true,
|
||||
//direction: 'UD', // UD, DU, LR, RL
|
||||
//sortMethod: 'hubsize', // hubsize, directed
|
||||
//shakeTowards: 'leaves' // roots, leaves
|
||||
//}
|
||||
hierarchical: {
|
||||
enabled:false,
|
||||
levelSeparation: 150,
|
||||
nodeSpacing: 100,
|
||||
treeSpacing: 200,
|
||||
blockShifting: true,
|
||||
edgeMinimization: true,
|
||||
parentCentralization: true,
|
||||
direction: 'UD', // UD, DU, LR, RL
|
||||
sortMethod: 'hubsize', // hubsize, directed
|
||||
shakeTowards: 'leaves' // roots, leaves
|
||||
}
|
||||
},
|
||||
};
|
||||
network = new vis.Network(container, data, options);
|
||||
@ -74,14 +57,6 @@ function createGraphFromDot(dotString){
|
||||
//}
|
||||
//});
|
||||
//});
|
||||
|
||||
//console.log(network.selectNodes([0]));
|
||||
n = network.body.nodes[0];
|
||||
n.setOptions({
|
||||
color:{
|
||||
background: "#ffffff",
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
function visualizeOneStep(step){
|
||||
@ -102,6 +77,7 @@ function visualizeOneStep(step){
|
||||
});
|
||||
}
|
||||
}
|
||||
network.redraw();
|
||||
}
|
||||
|
||||
|
||||
@ -110,7 +86,9 @@ function getSimulation(){
|
||||
.then(response => response.json())
|
||||
.then(response =>{
|
||||
simulationData = response;
|
||||
stepSlider.max = simulationData.steps - 1;
|
||||
createGraphFromDot(simulationData.dotGraph);
|
||||
visualizeOneStep(simulationData.states[0]);
|
||||
//kelvin to celsius
|
||||
//let temp = Math.ceil(response.main.temp - 273.15);
|
||||
//document.getElementById("weather").innerHTML = temp + "ºC";
|
||||
@ -118,4 +96,56 @@ function getSimulation(){
|
||||
});
|
||||
}
|
||||
|
||||
function playAnimation(){
|
||||
if(!animationPlaying){
|
||||
currentAnimationStep = 0;
|
||||
//Play the animation
|
||||
animationInterval = setInterval(function(){
|
||||
//This is the animation routine
|
||||
if(currentAnimationStep == simulationData.steps){
|
||||
//At the end of animation
|
||||
clearInterval(animationInterval);
|
||||
animationPlaying = false;
|
||||
return;
|
||||
}
|
||||
visualizeOneStep(simulationData.states[currentAnimationStep]);
|
||||
currentAnimationStep ++;
|
||||
stepSlider.value = currentAnimationStep;
|
||||
stepField.value = currentAnimationStep;
|
||||
}, animationLen * 1000 / simulationData.steps);
|
||||
|
||||
}else{
|
||||
//stop the animation
|
||||
clearInterval(animationInterval);
|
||||
currentAnimationStep = 0;
|
||||
}
|
||||
//switch boolean
|
||||
animationPlaying = !animationPlaying;
|
||||
}
|
||||
|
||||
stepField.value = 0;
|
||||
stepSlider.min = 0;
|
||||
stepSlider.max = 0;
|
||||
stepSlider.addEventListener('input', function(){
|
||||
stepField.value = stepSlider.value;
|
||||
visualizeOneStep(simulationData.states[stepSlider.value]);
|
||||
//console.log(stepSlider.value);
|
||||
});
|
||||
stepField.addEventListener('input', function(){
|
||||
stepSlider.value = stepField.value;
|
||||
visualizeOneStep(simulationData.states[stepField.value]);
|
||||
//console.log(stepSlider.value);
|
||||
});
|
||||
|
||||
animationDurationField.value = 10;
|
||||
animationDurationSlider.value = 10;
|
||||
animationDurationSlider.addEventListener('input', function(){
|
||||
animationLen = animationDurationSlider.value;
|
||||
animationDurationField.value = animationLen;
|
||||
});
|
||||
animationDurationField.addEventListener('input', function(){
|
||||
animationLen = animationDurationField.value;
|
||||
animationDurationSlider.value = animationLen;
|
||||
});
|
||||
|
||||
getSimulation()
|
||||
|
||||
@ -34,12 +34,13 @@ def gen_sis(G, steps = 1000, inf_rate=1.0, rec_rate=2.0, noise=0.1, statesList =
|
||||
jump_time = np.random.exponential(rates)
|
||||
change_n = np.argmin(jump_time)
|
||||
states[change_n] = S if states[change_n] == I else I
|
||||
statesList.append(states)
|
||||
statesList.append(states.copy())
|
||||
return states
|
||||
|
||||
statesList = []
|
||||
steps = 1000 + random.choice(range(1000))
|
||||
G_grid10x10 = nx.grid_2d_graph(10,10)
|
||||
# G_grid10x10 = nx.grid_2d_graph(10,10)
|
||||
G_grid10x10 = nx.newman_watts_strogatz_graph(120, 4, 0.15, seed=42)
|
||||
G = clean_shuffle_graph(G_grid10x10)
|
||||
TS_data = gen_sis(G, steps=steps,statesList=statesList)
|
||||
# print(G.number_of_nodes())
|
||||
|
||||
@ -12,7 +12,12 @@
|
||||
<script src="{{ asset('js/main.js') }}"></script>
|
||||
{% endblock %}
|
||||
{% block body %}
|
||||
|
||||
<h1>Hello {{ controller_name }}! ✅</h1>
|
||||
<div id="mynetwork"></div>
|
||||
<label for="step">Choose a step</label>
|
||||
<input type="range" id="stepRange" name="step">
|
||||
<input type="number" id="stepField" for="step" min=0></output>
|
||||
<label for="animationDuration">Choose animation duration</label>
|
||||
<input type="range" id="animationDurationRange" name="animationDuration" min=10 max=30>
|
||||
<input type="number" id="animationDurationField" for="animationDuration" min=10 max=30></output>
|
||||
<button id="playAnimation" onclick="playAnimation()">Run</button>
|
||||
<div id="mynetwork"></div>
|
||||
{% endblock %}
|
||||
|
||||
68
ä
Normal file
68
ä
Normal file
@ -0,0 +1,68 @@
|
||||
import math, random, os, time, sys, io
|
||||
import json
|
||||
import numpy as np
|
||||
import networkx as nx
|
||||
import scipy
|
||||
import time
|
||||
from networkx.drawing.nx_pydot import write_dot
|
||||
|
||||
def clean_shuffle_graph(G):
|
||||
random_seed_state = int(random.random()*100000) # quick hack to go back to random afterwards
|
||||
random.seed(42)
|
||||
node_mapping = dict(zip(sorted(G.nodes()), sorted(G.nodes(), key=lambda _: random.random()))) # maybe sorted not really deterministic
|
||||
G = nx.relabel_nodes(G, node_mapping)
|
||||
G = nx.convert_node_labels_to_integers(G)
|
||||
if not nx.is_connected(G):
|
||||
print('Graph is not connected, try a differnt one.')
|
||||
assert(nx.is_connected(G))
|
||||
random.seed(random_seed_state)
|
||||
return G
|
||||
|
||||
def gen_sis(G, steps = 1000, inf_rate=1.0, rec_rate=2.0, noise=0.1, statesList = None):
|
||||
S = [1., 0.]
|
||||
I = [0., 1.]
|
||||
states = [random.choice([S, I]) for i in range(G.number_of_nodes())]
|
||||
for _ in range(steps):
|
||||
rates = np.zeros(G.number_of_nodes())
|
||||
for n in range(G.number_of_nodes()):
|
||||
rates[n] = noise
|
||||
if states[n] == I:
|
||||
rates[n] += rec_rate
|
||||
if states[n] == S:
|
||||
rates[n] += inf_rate * len([n_j for n_j in G.neighbors(n) if states[n_j] == I])
|
||||
rates[n] = 1.0/rates[n] # numpy uses mean as rate param
|
||||
jump_time = np.random.exponential(rates)
|
||||
change_n = np.argmin(jump_time)
|
||||
states[change_n] = S if states[change_n] == I else I
|
||||
statesList.append(states.copy())
|
||||
return states
|
||||
|
||||
statesList = []
|
||||
steps = 1000 + random.choice(range(1000))
|
||||
G_grid10x10 = nx.grid_2d_graph(10,10)
|
||||
G = clean_shuffle_graph(G_grid10x10)
|
||||
TS_data = gen_sis(G, steps=steps,statesList=statesList)
|
||||
# print(G.number_of_nodes())
|
||||
# f = open("graph.dot", "rw")
|
||||
# nx.drawing.nx_pydot.write_dot(G,f)
|
||||
# f.write("\n")
|
||||
# f.close()
|
||||
# Writing the json file to stdout
|
||||
# f = StringIO("")
|
||||
dotGraph = ""
|
||||
|
||||
#Write dot file to string
|
||||
with io.StringIO() as f:
|
||||
write_dot(G, f)
|
||||
f.seek(0)
|
||||
dotGraph = f.read()
|
||||
|
||||
output = {
|
||||
"name" : "testGraph",
|
||||
"dotGraph" : dotGraph,
|
||||
"steps" : steps,
|
||||
"states" : statesList,
|
||||
}
|
||||
|
||||
jsonOutput = json.dumps(output)
|
||||
print(jsonOutput)
|
||||
Loading…
x
Reference in New Issue
Block a user