mirror of
https://github.com/gsi-upm/soil
synced 2024-11-23 03:32:28 +00:00
Map added
This commit is contained in:
parent
da1ce1ea30
commit
819c371292
@ -1,6 +1,6 @@
|
|||||||
name: TerroristNetworkModel_sim
|
name: TerroristNetworkModel_sim
|
||||||
load_module: TerroristNetworkModel
|
load_module: TerroristNetworkModel
|
||||||
max_time: 100
|
max_time: 150
|
||||||
num_trials: 1
|
num_trials: 1
|
||||||
network_params:
|
network_params:
|
||||||
generator: random_geometric_graph
|
generator: random_geometric_graph
|
||||||
@ -30,7 +30,7 @@ environment_params:
|
|||||||
# TerroristSpreadModel
|
# TerroristSpreadModel
|
||||||
information_spread_intensity: 0.7
|
information_spread_intensity: 0.7
|
||||||
terrorist_additional_influence: 0.035
|
terrorist_additional_influence: 0.035
|
||||||
max_vulnerability: 0.5
|
max_vulnerability: 0.6
|
||||||
prob_interaction: 0.5
|
prob_interaction: 0.5
|
||||||
|
|
||||||
# TrainingAreaModel and HavenModel
|
# TrainingAreaModel and HavenModel
|
||||||
@ -38,7 +38,7 @@ environment_params:
|
|||||||
haven_influence: 0.20
|
haven_influence: 0.20
|
||||||
|
|
||||||
# TerroristNetworkModel
|
# TerroristNetworkModel
|
||||||
vision_range: 0.50
|
vision_range: 0.30
|
||||||
sphere_influence: 2
|
sphere_influence: 2
|
||||||
weight_social_distance: 0.035
|
weight_social_distance: 0.035
|
||||||
weight_link_distance: 0.035
|
weight_link_distance: 0.035
|
||||||
@ -49,10 +49,12 @@ visualization_params:
|
|||||||
shapes:
|
shapes:
|
||||||
TrainingAreaModel: target
|
TrainingAreaModel: target
|
||||||
HavenModel: home
|
HavenModel: home
|
||||||
|
TerroristNetworkModel: person
|
||||||
colors:
|
colors:
|
||||||
- attr_id: 0
|
- attr_id: 0
|
||||||
color: green
|
color: '#40de40'
|
||||||
- attr_id: 1
|
- attr_id: 1
|
||||||
color: red
|
color: red
|
||||||
- attr_id: 2
|
- attr_id: 2
|
||||||
color: '#c16a6a'
|
color: '#c16a6a'
|
||||||
|
background_image: 'map.png'
|
||||||
|
2
run.py
2
run.py
@ -14,7 +14,7 @@ if __name__ == "__main__":
|
|||||||
|
|
||||||
parser = argparse.ArgumentParser(description='Visualization of a Graph Model')
|
parser = argparse.ArgumentParser(description='Visualization of a Graph Model')
|
||||||
|
|
||||||
parser.add_argument('--name', '-n', nargs=1, default='SOIL Model', help='name of the simulation')
|
parser.add_argument('--name', '-n', nargs=1, default='SOIL', help='name of the simulation')
|
||||||
parser.add_argument('--dump', '-d', help='dumping results in folder output', action='store_true')
|
parser.add_argument('--dump', '-d', help='dumping results in folder output', action='store_true')
|
||||||
parser.add_argument('--verbose', '-v', help='verbose mode', action='store_true')
|
parser.add_argument('--verbose', '-v', help='verbose mode', action='store_true')
|
||||||
args = parser.parse_args()
|
args = parser.parse_args()
|
||||||
|
12
server.py
12
server.py
@ -94,10 +94,11 @@ class SocketHandler(tornado.websocket.WebSocketHandler):
|
|||||||
|
|
||||||
settings = []
|
settings = []
|
||||||
for key in self.config['environment_params']:
|
for key in self.config['environment_params']:
|
||||||
if type(self.config['environment_params'][key]) == float:
|
if type(self.config['environment_params'][key]) == float or type(self.config['environment_params'][key]) == int:
|
||||||
setting_type = 'number'
|
if self.config['environment_params'][key] <= 1:
|
||||||
elif type(self.config['environment_params'][key]) == int:
|
setting_type = 'number'
|
||||||
setting_type = 'number'
|
else:
|
||||||
|
setting_type = 'great_number'
|
||||||
elif type(self.config['environment_params'][key]) == bool:
|
elif type(self.config['environment_params'][key]) == bool:
|
||||||
setting_type = 'boolean'
|
setting_type = 'boolean'
|
||||||
else:
|
else:
|
||||||
@ -122,7 +123,6 @@ class SocketHandler(tornado.websocket.WebSocketHandler):
|
|||||||
elif msg['type'] == 'run_simulation':
|
elif msg['type'] == 'run_simulation':
|
||||||
if self.application.verbose:
|
if self.application.verbose:
|
||||||
logger.info('Running new simulation for {name}'.format(name=self.config['name']))
|
logger.info('Running new simulation for {name}'.format(name=self.config['name']))
|
||||||
print(msg['data'])
|
|
||||||
self.send_log('INFO.soil', 'Running new simulation for {name}'.format(name=self.config['name']))
|
self.send_log('INFO.soil', 'Running new simulation for {name}'.format(name=self.config['name']))
|
||||||
self.config['environment_params'] = msg['data']
|
self.config['environment_params'] = msg['data']
|
||||||
self.run_simulation()
|
self.run_simulation()
|
||||||
@ -209,7 +209,7 @@ class ModularServer(tornado.web.Application):
|
|||||||
settings = {'debug': True,
|
settings = {'debug': True,
|
||||||
'template_path': os.path.dirname(__file__) + '/templates'}
|
'template_path': os.path.dirname(__file__) + '/templates'}
|
||||||
|
|
||||||
def __init__(self, model, visualization_element, name='SOIL Model', verbose=True,
|
def __init__(self, model, visualization_element, name='SOIL', verbose=True,
|
||||||
*args, **kwargs):
|
*args, **kwargs):
|
||||||
|
|
||||||
self.verbose = verbose
|
self.verbose = verbose
|
||||||
|
@ -33,6 +33,25 @@ html, body {
|
|||||||
cursor: pointer;
|
cursor: pointer;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.wrapper-heading {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: row;
|
||||||
|
padding: 0 !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
.soil_logo {
|
||||||
|
padding: 0 !important;
|
||||||
|
border-left: none !important;
|
||||||
|
border-right: none !important;
|
||||||
|
display: flex;
|
||||||
|
justify-content: flex-end;
|
||||||
|
background-color: rgb(88, 88, 88);
|
||||||
|
}
|
||||||
|
|
||||||
|
.soil_logo > img {
|
||||||
|
max-height: 100%;
|
||||||
|
}
|
||||||
|
|
||||||
.node {
|
.node {
|
||||||
stroke: #fff;
|
stroke: #fff;
|
||||||
stroke-width: 1.5px;
|
stroke-width: 1.5px;
|
||||||
@ -292,7 +311,7 @@ table#link-distance .max {
|
|||||||
|
|
||||||
/* Console */
|
/* Console */
|
||||||
|
|
||||||
#update, .console {
|
#update, .console, .soil_logo {
|
||||||
padding: 10px 15px;
|
padding: 10px 15px;
|
||||||
height: 135px;
|
height: 135px;
|
||||||
border: 1px solid #585858;
|
border: 1px solid #585858;
|
||||||
@ -317,6 +336,7 @@ table#link-distance .max {
|
|||||||
overflow: auto;
|
overflow: auto;
|
||||||
border-top-left-radius: 5px;
|
border-top-left-radius: 5px;
|
||||||
border-bottom-left-radius: 5px;
|
border-bottom-left-radius: 5px;
|
||||||
|
width: 100%;
|
||||||
}
|
}
|
||||||
|
|
||||||
.console::-webkit-scrollbar {
|
.console::-webkit-scrollbar {
|
||||||
|
BIN
templates/img/background/map.png
Normal file
BIN
templates/img/background/map.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 1.1 MiB |
BIN
templates/img/logo_soil.png
Normal file
BIN
templates/img/logo_soil.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 101 KiB |
@ -74,7 +74,7 @@
|
|||||||
);
|
);
|
||||||
|
|
||||||
if ( file['type'] !== "application/x-yaml" ) {
|
if ( file['type'] !== "application/x-yaml" ) {
|
||||||
console.log('File format not supported. Sorry for the inconvenience.');
|
console.error('File format not supported. Sorry for the inconvenience.');
|
||||||
_socket.error('File format not supported. Sorry for the inconvenience.');
|
_socket.error('File format not supported. Sorry for the inconvenience.');
|
||||||
return;
|
return;
|
||||||
} else {
|
} else {
|
||||||
@ -142,13 +142,21 @@
|
|||||||
|
|
||||||
<div class="container-fluid fixed">
|
<div class="container-fluid fixed">
|
||||||
|
|
||||||
<!-- CONSOLE -->
|
<div class="col-sm-9 wrapper-heading">
|
||||||
<div class="col-sm-9 console">
|
<!-- CONSOLE -->
|
||||||
Please, upload a YAML file that defines all the parameters of a simulation. <br/>
|
<div class="console">
|
||||||
If you don't know how to write the file, please visit this page:<br/>
|
Please, upload a YAML file that defines all the parameters of a simulation. <br/>
|
||||||
http://soilsim.readthedocs.io/en/latest/quickstart.html<br/>
|
If you don't know how to write the file, please visit this page:<br/>
|
||||||
|
http://soilsim.readthedocs.io/en/latest/quickstart.html<br/>
|
||||||
|
</div>
|
||||||
|
<!-- //CONSOLE -->
|
||||||
|
|
||||||
|
<!-- SOIL Logo -->
|
||||||
|
<div class="soil_logo" >
|
||||||
|
<img src="img/logo_soil.png" />
|
||||||
|
</div>
|
||||||
|
<!-- //SOIL Logo -->
|
||||||
</div>
|
</div>
|
||||||
<!-- //CONSOLE -->
|
|
||||||
|
|
||||||
<div id="update" class="col-sm-3">
|
<div id="update" class="col-sm-3">
|
||||||
<!-- Load File -->
|
<!-- Load File -->
|
||||||
@ -210,7 +218,7 @@
|
|||||||
<div class="container-fluid">
|
<div class="container-fluid">
|
||||||
|
|
||||||
<div id="graph_container">
|
<div id="graph_container">
|
||||||
<svg id="graph" class="col-sm-9"></svg>
|
<svg id="graph" class="col-sm-9" xmlns="http://www.w3.org/2000/svg"></svg>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div id="configuration" class="col-sm-3">
|
<div id="configuration" class="col-sm-3">
|
||||||
|
@ -26,12 +26,12 @@ ws.onmessage = function(message) {
|
|||||||
self.GraphVisualization.import(convertJSON(msg['data']), function() {
|
self.GraphVisualization.import(convertJSON(msg['data']), function() {
|
||||||
reset_configuration();
|
reset_configuration();
|
||||||
set_configuration();
|
set_configuration();
|
||||||
$('#home_menu').click(function() {
|
// $('#home_menu').click(function() {
|
||||||
setTimeout(function() {
|
// setTimeout(function() {
|
||||||
reset_timeline();
|
// reset_timeline();
|
||||||
set_timeline(msg['data']);
|
// set_timeline(msg['data']);
|
||||||
}, 1000);
|
// }, 1000);
|
||||||
});
|
// });
|
||||||
reset_timeline();
|
reset_timeline();
|
||||||
set_timeline(msg['data']);
|
set_timeline(msg['data']);
|
||||||
$('#load').hide();
|
$('#load').hide();
|
||||||
@ -52,7 +52,7 @@ ws.onmessage = function(message) {
|
|||||||
break;
|
break;
|
||||||
|
|
||||||
case 'error':
|
case 'error':
|
||||||
console.log(msg['error']);
|
console.error(msg['error']);
|
||||||
_socket.error(msg['error']);
|
_socket.error(msg['error']);
|
||||||
$('#load').removeClass('loader');
|
$('#load').removeClass('loader');
|
||||||
break;
|
break;
|
||||||
@ -65,10 +65,18 @@ ws.onmessage = function(message) {
|
|||||||
case 'visualization_params':
|
case 'visualization_params':
|
||||||
console.log(msg['data']);
|
console.log(msg['data']);
|
||||||
self.GraphVisualization.set_params(msg['data']['shape_property'], msg['data']['shapes'], msg['data']['colors']);
|
self.GraphVisualization.set_params(msg['data']['shape_property'], msg['data']['shapes'], msg['data']['colors']);
|
||||||
|
|
||||||
|
if ( msg['data']['background_image'] ) {
|
||||||
|
// $('svg#graph').css('background-image', 'linear-gradient(to bottom, rgba(0,0,0,0.4) 0%,rgba(0,0,0,0.4) 100%), url(img/background/' + msg['data']['background_image'])
|
||||||
|
// .css('background-size', '130%').css('background-position', '5% 30%').css('background-repeat', 'no-repeat');
|
||||||
|
$('<style>').text('svg line.link { stroke: white !important; stroke-width: 1.5px !important; }').appendTo($('html > head'));
|
||||||
|
$('<style>').text('svg circle.node { stroke-width: 2.5px !important; }').appendTo($('html > head'));
|
||||||
|
self.GraphVisualization.set_background('img/background/' + msg['data']['background_image']);
|
||||||
|
}
|
||||||
break;
|
break;
|
||||||
|
|
||||||
default:
|
default:
|
||||||
console.log('Unexpected message!')
|
console.warn('Unexpected message!')
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
@ -111,8 +119,8 @@ var reset_trials = function() {
|
|||||||
var convertJSON = function(json) {
|
var convertJSON = function(json) {
|
||||||
// For NetworkX Geometric Graphs get positions
|
// For NetworkX Geometric Graphs get positions
|
||||||
json.nodes.forEach(function(node) {
|
json.nodes.forEach(function(node) {
|
||||||
var scx = d3.scale.linear().domain([0, 1]).range([0, height]);
|
var scx = d3.scale.linear().domain([0, 1]).range([0, width]);
|
||||||
var scy = d3.scale.linear().domain([0, 1]).range([height, 0]);
|
var scy = d3.scale.linear().domain([0, 1]).range([width, 0]);
|
||||||
if ( node.pos ) {
|
if ( node.pos ) {
|
||||||
node.scx = scx(node.pos[0]);
|
node.scx = scx(node.pos[0]);
|
||||||
node.scy = scy(node.pos[1]);
|
node.scy = scy(node.pos[1]);
|
||||||
@ -227,7 +235,14 @@ var set_timeline = function(graph) {
|
|||||||
// Draw graph for the first time
|
// Draw graph for the first time
|
||||||
self.GraphVisualization.update_graph($('.config-item #properties').val(), maxUnix, function() {
|
self.GraphVisualization.update_graph($('.config-item #properties').val(), maxUnix, function() {
|
||||||
update_statistics_table();
|
update_statistics_table();
|
||||||
|
$('svg #root > image').attr('height', d3.select('#root').node().getBBox().height)
|
||||||
setTimeout(function() {
|
setTimeout(function() {
|
||||||
|
if ( $('svg #root > image').length !== 0 ) {
|
||||||
|
$('svg #root > image').attr('height', d3.select('#root').node().getBBox().height * 1.2);
|
||||||
|
var dx = d3.select('#graph-wrapper').node().getBBox().width - d3.select('svg #root > image').node().getBBox().width;
|
||||||
|
var dy = d3.select('#graph-wrapper').node().getBBox().height - d3.select('svg #root > image').node().getBBox().height;
|
||||||
|
$('svg #root > image').attr('transform', 'translate(' + (dx / 2) + ',' + (dy / 2) + ')');
|
||||||
|
}
|
||||||
self.GraphVisualization.fit();
|
self.GraphVisualization.fit();
|
||||||
}, 100);
|
}, 100);
|
||||||
});
|
});
|
||||||
@ -397,7 +412,11 @@ var run_simulation = function() {
|
|||||||
case 'checkbox':
|
case 'checkbox':
|
||||||
environment_variables[this.id] = ($(this).is(':checked')) ? true : false;
|
environment_variables[this.id] = ($(this).is(':checked')) ? true : false;
|
||||||
break;
|
break;
|
||||||
|
case 'number':
|
||||||
|
environment_variables[this.id] = Number(this.value);
|
||||||
|
break;
|
||||||
default:
|
default:
|
||||||
|
console.warn(this.id + ' not defined when running simulation!');
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -64,6 +64,13 @@ var initGUI = function(model_params) {
|
|||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
|
var addNumberInput = function(name, value) {
|
||||||
|
var wrapper = $('<div>').attr('class', 'col-sm-6').height('110px');
|
||||||
|
var label = $('<div>').width('100%').text(name).css('text-align', 'center').css('font-weight', 'bolder').appendTo(wrapper);
|
||||||
|
var input = $('<input>').attr('id', name).attr('type', 'number').attr('class', 'form-control').attr('value', value).attr('min', 0).css('margin-top', '18px').appendTo(wrapper);
|
||||||
|
$('#wrapper-settings').append(wrapper);
|
||||||
|
}
|
||||||
|
|
||||||
var addTextBox = function(param, obj) {
|
var addTextBox = function(param, obj) {
|
||||||
var well = $('<div class="well">' + obj.value + '</div>')[0];
|
var well = $('<div class="well">' + obj.value + '</div>')[0];
|
||||||
sidebar.append(well);
|
sidebar.append(well);
|
||||||
@ -81,8 +88,11 @@ var initGUI = function(model_params) {
|
|||||||
case 'number':
|
case 'number':
|
||||||
addSliderInput(model_params[option]['label'], model_params[option]['value']);
|
addSliderInput(model_params[option]['label'], model_params[option]['value']);
|
||||||
break;
|
break;
|
||||||
|
case 'great_number':
|
||||||
|
addNumberInput(model_params[option]['label'], model_params[option]['value']);
|
||||||
|
break;
|
||||||
default:
|
default:
|
||||||
console.log(model_params[option]['label'] + ' not defined!');
|
console.warn(model_params[option]['label'] + ' not defined!');
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -14,6 +14,7 @@
|
|||||||
// Private constants
|
// Private constants
|
||||||
var focus_opacity = 0.1,
|
var focus_opacity = 0.1,
|
||||||
radius = 8,
|
radius = 8,
|
||||||
|
shape_size = 16,
|
||||||
required_node = ['id', 'index', 'label', 'px', 'py', 'spells', 'weight', 'x', 'y', 'pos', 'scx', 'scy'];
|
required_node = ['id', 'index', 'label', 'px', 'py', 'spells', 'weight', 'x', 'y', 'pos', 'scx', 'scy'];
|
||||||
|
|
||||||
// Private variables
|
// Private variables
|
||||||
@ -29,8 +30,10 @@
|
|||||||
zoom, // Zoom
|
zoom, // Zoom
|
||||||
|
|
||||||
groot, // Append sections to svg to have nodes and edges separately
|
groot, // Append sections to svg to have nodes and edges separately
|
||||||
|
graph_wrapper,
|
||||||
glinks,
|
glinks,
|
||||||
gnodes,
|
gnodes,
|
||||||
|
background_image,
|
||||||
data_node, // Actual node data for the graph
|
data_node, // Actual node data for the graph
|
||||||
data_link, // Actual link data for the graph
|
data_link, // Actual link data for the graph
|
||||||
|
|
||||||
@ -38,7 +41,8 @@
|
|||||||
node, // Circles for the nodes
|
node, // Circles for the nodes
|
||||||
shape_property, // Property to whom the shape will be applied
|
shape_property, // Property to whom the shape will be applied
|
||||||
shapes, // Dictionary of shapes for nodes
|
shapes, // Dictionary of shapes for nodes
|
||||||
colors; // Dictionary of colors for nodes
|
colors, // Dictionary of colors for nodes
|
||||||
|
background; // Background of the graph
|
||||||
|
|
||||||
Number.prototype.between = function(min, max) {
|
Number.prototype.between = function(min, max) {
|
||||||
var min = (min || min === 0) ? min : Math.max(),
|
var min = (min || min === 0) ? min : Math.max(),
|
||||||
@ -221,9 +225,18 @@
|
|||||||
.size([width, height]);
|
.size([width, height]);
|
||||||
|
|
||||||
// Append sections to svg to have nodes and edges separately
|
// Append sections to svg to have nodes and edges separately
|
||||||
groot = svg.append('g') .attr('id', 'root');
|
groot = svg.append('g').attr('id', 'root');
|
||||||
glinks = groot.append('g') .attr('id', 'links');
|
|
||||||
gnodes = groot.append('g') .attr('id', 'nodes');
|
// Set background
|
||||||
|
if ( background !== undefined ) {
|
||||||
|
background_image = groot.append('image').attr('href', background).style('opacity', '0.8');
|
||||||
|
graph_wrapper = groot.append('g') .attr('id', 'graph-wrapper');
|
||||||
|
glinks = graph_wrapper.append('g') .attr('id', 'links');
|
||||||
|
gnodes = graph_wrapper.append('g') .attr('id', 'nodes');
|
||||||
|
} else {
|
||||||
|
glinks = groot.append('g') .attr('id', 'links');
|
||||||
|
gnodes = groot.append('g') .attr('id', 'nodes');
|
||||||
|
}
|
||||||
|
|
||||||
// Add patterns for shapes
|
// Add patterns for shapes
|
||||||
var defs = [];
|
var defs = [];
|
||||||
@ -245,8 +258,8 @@
|
|||||||
.attr('href', function(d) {
|
.attr('href', function(d) {
|
||||||
return window.location.protocol + '//' + window.location.host + '/img/svg/' + d + '.svg';
|
return window.location.protocol + '//' + window.location.host + '/img/svg/' + d + '.svg';
|
||||||
})
|
})
|
||||||
.attr('width', 16)
|
.attr('width', shape_size)
|
||||||
.attr('height', 16);
|
.attr('height', shape_size);
|
||||||
|
|
||||||
// Zoom
|
// Zoom
|
||||||
zoom = d3.behavior
|
zoom = d3.behavior
|
||||||
@ -447,10 +460,25 @@
|
|||||||
radius = r(distance);
|
radius = r(distance);
|
||||||
node.attr('r', radius);
|
node.attr('r', radius);
|
||||||
|
|
||||||
|
var s = d3.scale.linear().domain([30, 1000]).range([16, 48]);
|
||||||
|
if ( shapes instanceof Object && shape_property ) {
|
||||||
|
svg.selectAll('pattern image').attr('width', s(distance)).attr('height', s(distance));
|
||||||
|
}
|
||||||
|
|
||||||
if (callback) { callback(radius); }
|
if (callback) { callback(radius); }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Set background image.
|
||||||
|
* A function that set a background image.
|
||||||
|
*
|
||||||
|
* @param {object} image Path to image.
|
||||||
|
*/
|
||||||
|
function set_background(image) {
|
||||||
|
background = image;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Set property and instant of time.
|
* Set property and instant of time.
|
||||||
* A function that draws the graph depends on the property and instant of time selected.
|
* A function that draws the graph depends on the property and instant of time selected.
|
||||||
@ -623,6 +651,7 @@
|
|||||||
update_graph: update_graph,
|
update_graph: update_graph,
|
||||||
set_params: set_params,
|
set_params: set_params,
|
||||||
set_link_distance: set_link_distance,
|
set_link_distance: set_link_distance,
|
||||||
|
set_background: set_background,
|
||||||
fit: zoom_to_fit,
|
fit: zoom_to_fit,
|
||||||
reset: reset,
|
reset: reset,
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user