File app.rb changed (mode: 100644) (index f68e488..cd6b8e3) |
1 |
1 |
require 'rubygems'
|
require 'rubygems'
|
2 |
2 |
require 'sinatra'
|
require 'sinatra'
|
3 |
|
require 'redis'
|
|
4 |
|
require 'json'
|
|
5 |
|
require 'will_paginate'
|
|
6 |
|
require 'will_paginate/array'
|
|
7 |
|
require './node'
|
|
8 |
3 |
|
|
9 |
|
# bind to publicly accessable IP
|
|
10 |
|
set :bind, '0.0.0.0'
|
|
11 |
|
|
|
12 |
|
rdb = Redis.new
|
|
13 |
|
#CSS class names for alert levels from "ok" to "bad"
|
|
14 |
|
|
|
15 |
|
#HTML color codes from green to red in 0x11-steps
|
|
16 |
|
COLORS = ['#FF0000','#FF1100','#FF2200','#FF3300','#FF4400',
|
|
17 |
|
'#FF5500','#FF6600','#FF7700','#FF8800','#FF9900',
|
|
18 |
|
'#FFAA00','#FFBB00','#FFCC00','#FFDD00','#FFEE00',
|
|
19 |
|
'#FFFF00','#EEFF00','#DDFF00','#CCFF00','#BBFF00',
|
|
20 |
|
'#AAFF00','#99FF00','#88FF00','#77FF00','#66FF00',
|
|
21 |
|
'#55FF00','#44FF00','#33FF00','#22FF00','#11FF00',
|
|
22 |
|
'#00FF00'].reverse
|
|
23 |
|
|
|
24 |
|
# max number of nodes for display in metric listings
|
|
25 |
|
MAX_LIST = 20
|
|
26 |
|
|
|
27 |
|
# max number of neighbors for graphical representation with d3.js
|
|
28 |
|
MAX_GRAPH_NEIGHBORS = 300
|
|
29 |
|
|
|
30 |
|
|
|
31 |
|
# INDEX / ROOT PATH
|
|
32 |
|
get '/' do
|
|
33 |
|
rdb = Redis.new
|
|
34 |
|
@title = 'CoRiA'
|
|
35 |
|
erb :index
|
|
36 |
|
end
|
|
37 |
|
|
|
38 |
|
# NODE DETAILS
|
|
39 |
|
get '/node/:asn' do
|
|
40 |
|
rdb = Redis.new
|
|
41 |
|
@asn = params[:asn]
|
|
42 |
|
return status 404 unless Node.all_nodes.include?(@asn)
|
|
43 |
|
@title = 'Node Details'
|
|
44 |
|
@node = Node.get(params[:asn])
|
|
45 |
|
erb :node_details
|
|
46 |
|
end
|
|
47 |
|
|
|
48 |
|
# NODE SEARCH
|
|
49 |
|
post('/node') do
|
|
50 |
|
if Node.all_nodes.include?(params[:node_id].to_s)
|
|
51 |
|
redirect '/node/'+params[:node_id]
|
|
52 |
|
else
|
|
53 |
|
redirect '/'
|
|
54 |
|
end
|
|
55 |
|
end
|
|
56 |
|
|
|
57 |
|
|
|
58 |
|
# METRIC DETAILS
|
|
59 |
|
get '/metric/:metric/' do
|
|
60 |
|
@metric = params[:metric]
|
|
61 |
|
|
|
62 |
|
if Node.metric_names.keys.include?(@metric)
|
|
63 |
|
redis_key = @metric+'_normalized'
|
|
64 |
|
elsif Node.score_names.keys.include?(@metric)
|
|
65 |
|
redis_key = @metric
|
|
66 |
|
else
|
|
67 |
|
return status 404
|
|
68 |
|
end
|
|
|
4 |
|
require './config'
|
|
5 |
|
require './storage'
|
69 |
6 |
|
|
70 |
|
@metric_name = Node.metric_names[@metric] || Node.score_names[@metric]
|
|
71 |
|
|
|
72 |
|
@title = @metric_name+' Ranking'
|
|
73 |
|
|
|
74 |
|
rdb = Redis.new
|
|
75 |
|
@nodes = rdb.zrevrange(redis_key, 0, -1, {withscores: true}).paginate(:page => params[:page])
|
|
76 |
|
|
|
77 |
|
erb :metric_details
|
|
78 |
|
|
|
79 |
|
end
|
|
80 |
|
|
|
81 |
|
get '/nodes' do
|
|
82 |
|
content_type :json
|
|
83 |
|
return Node.all_nodes.to_json
|
|
84 |
|
end
|
|
85 |
|
|
|
86 |
|
|
|
87 |
|
#NODE NEIGHBORHOOD AJAX ENDPOINT FOR DISPLAY VIA d3.js
|
|
88 |
|
#color notes by unified risk score value
|
|
89 |
|
get '/node/neighbors/:id' do
|
|
90 |
|
content_type :json
|
|
91 |
|
|
|
92 |
|
@node = Node.get(params[:id])
|
|
93 |
|
|
|
94 |
|
#build response
|
|
95 |
|
response = {}
|
|
96 |
|
|
|
97 |
|
response[:nodes] = []
|
|
98 |
|
response[:links] = []
|
|
99 |
|
|
|
100 |
|
response[:nodes] << {:name => @node.data[:id], :size_multiplier => @node.data[:degree_normalized], :color => COLORS[(@node.data[:unified_risk_score]*COLORS.length).ceil]}
|
|
101 |
|
|
|
102 |
|
limited_neighbors = @node.data[:neighbors][0..MAX_GRAPH_NEIGHBORS]
|
|
103 |
|
i = 1
|
|
104 |
|
limited_neighbors.each do |node_id|
|
|
105 |
|
neighbor = Node.get(node_id)
|
|
106 |
|
color = COLORS[(neighbor.data[:unified_risk_score]*COLORS.length).ceil]
|
|
107 |
|
size_multiplier = neighbor.data[:degree_normalized]
|
|
108 |
|
|
|
109 |
|
response[:nodes] << {:name => neighbor.data[:id], :size_multiplier => size_multiplier, :color => color}
|
|
110 |
|
response[:links] << {:source => 0, :target => i}
|
|
111 |
|
i += 1
|
|
112 |
|
end
|
|
113 |
|
|
|
114 |
|
return response.to_json
|
|
115 |
|
end
|
|
|
7 |
|
# bind to all accessable interfaces
|
|
8 |
|
set :bind, '0.0.0.0'
|
116 |
9 |
|
|
117 |
|
get '/metric/:metric/histogram.json' do
|
|
118 |
|
content_type :json
|
|
119 |
10 |
|
|
120 |
|
metric = params[:metric]
|
|
|
11 |
|
require './index'
|
121 |
12 |
|
|
122 |
|
if Node.metric_names.keys.include?(metric)
|
|
123 |
|
redis_key = metric+'_normalized'
|
|
124 |
|
elsif Node.score_names.keys.include?(metric)
|
|
125 |
|
redis_key = metric
|
|
126 |
|
else
|
|
127 |
|
return status 404
|
|
128 |
|
end
|
|
|
13 |
|
require './node_routes'
|
129 |
14 |
|
|
130 |
|
values = rdb.zrevrange(redis_key, 0, -1, {withscores: true}).map{|score| score[1]}
|
|
|
15 |
|
require './metric_routes'
|
131 |
16 |
|
|
132 |
|
return values.to_json
|
|
|
17 |
|
require './score_routes'
|
133 |
18 |
|
|
134 |
|
end |
|
|
19 |
|
require './statistics_routes' |
File config.rb added (mode: 100644) (index 0000000..dca71f9) |
|
1 |
|
require 'redis'
|
|
2 |
|
require 'ostruct'
|
|
3 |
|
|
|
4 |
|
|
|
5 |
|
CONFIG = OpenStruct.new
|
|
6 |
|
|
|
7 |
|
CONFIG.node_index_key = 'all_nodes'
|
|
8 |
|
CONFIG.metric_index_key = 'all_metrics'
|
|
9 |
|
CONFIG.score_index_key = 'all_scores'
|
|
10 |
|
|
|
11 |
|
CONFIG.node_neighbors_prefix = 'node_neighbors:'
|
|
12 |
|
CONFIG.node_prefix = 'node_metrics:'
|
|
13 |
|
CONFIG.metric_prefix = 'metric:'
|
|
14 |
|
CONFIG.score_prefix = 'score:'
|
|
15 |
|
CONFIG.statistics_prefix = 'statistics:'
|
|
16 |
|
|
|
17 |
|
CONFIG.normalization_suffix = '_normalized'
|
|
18 |
|
|
|
19 |
|
CONFIG.statistical_indicators = { 'min' => "Minimum",
|
|
20 |
|
'max' => "Maximum",
|
|
21 |
|
'average' => "Average Value" ,
|
|
22 |
|
'median' => "Mean Value",
|
|
23 |
|
'standard_deviation' => "Standard Deviation"}
|
|
24 |
|
|
|
25 |
|
CONFIG.redis = Redis.new
|
|
26 |
|
|
|
27 |
|
#automatic retrieval and naive naming of available metrics from Redis
|
|
28 |
|
CONFIG.metric_names = CONFIG.redis.smembers(CONFIG.metric_index_key).inject({}) do |h,metric|
|
|
29 |
|
h[metric] = metric.split('_').map(&:capitalize).join(' ')
|
|
30 |
|
h
|
|
31 |
|
end
|
|
32 |
|
|
|
33 |
|
|
|
34 |
|
#CONFIG.metric_names = {
|
|
35 |
|
# 'clustering_coefficient' => "Clustering Coefficient",
|
|
36 |
|
# 'corrected_clustering_coefficient' => "Clustering Coefficient (Corrected)",
|
|
37 |
|
# 'degree' => "Node Degree",
|
|
38 |
|
# 'average_neighbor_degree' => "Average Neighbor Degree",
|
|
39 |
|
# 'corrected_average_neighbor_degree' => "Average Neighbor Degree (Corrected)",
|
|
40 |
|
# 'iterated_average_neighbor_degree' => "Iterated Average Neighbor Degree",
|
|
41 |
|
# 'corrected_iterated_average_neighbor_degree' => "Iterated Average Neighbor Degree (Corrected)",
|
|
42 |
|
# 'betweenness_centrality' => "Betweenness Centrality",
|
|
43 |
|
# 'eccentricity' => "Eccentricity",
|
|
44 |
|
# 'average_shortest_path_length' => "Average Shortest Path Length"
|
|
45 |
|
#}
|
|
46 |
|
|
|
47 |
|
|
|
48 |
|
#automatic retrieval and naive naming of available scores from Redis
|
|
49 |
|
CONFIG.score_names = CONFIG.redis.smembers(CONFIG.score_index_key).inject({}) do |h,score|
|
|
50 |
|
h[score] = score.split('_').map(&:capitalize).join(' ')
|
|
51 |
|
h
|
|
52 |
|
end
|
|
53 |
|
|
|
54 |
|
|
|
55 |
|
# scores have to be readable in redis
|
|
56 |
|
#CONFIG.score_names = {
|
|
57 |
|
# 'unified_risk_score' => "Unified Risk Score (URS)",
|
|
58 |
|
# 'advanced_unified_risk_score' => "Advanced URS"
|
|
59 |
|
#}
|
|
60 |
|
|
|
61 |
|
|
|
62 |
|
# css classes for status indication ordered from "good" to "bad"
|
|
63 |
|
CONFIG.color_classes = ['success','info', 'warning', 'danger']
|
|
64 |
|
|
|
65 |
|
#HTML color codes from green to red in 0x11-steps
|
|
66 |
|
CONFIG.color_codes = ['#FF0000','#FF1100','#FF2200','#FF3300','#FF4400',
|
|
67 |
|
'#FF5500','#FF6600','#FF7700','#FF8800','#FF9900',
|
|
68 |
|
'#FFAA00','#FFBB00','#FFCC00','#FFDD00','#FFEE00',
|
|
69 |
|
'#FFFF00','#EEFF00','#DDFF00','#CCFF00','#BBFF00',
|
|
70 |
|
'#AAFF00','#99FF00','#88FF00','#77FF00','#66FF00',
|
|
71 |
|
'#55FF00','#44FF00','#33FF00','#22FF00','#11FF00',
|
|
72 |
|
'#00FF00'].reverse
|
|
73 |
|
|
|
74 |
|
#can be metric or score
|
|
75 |
|
CONFIG.node_coloring_field = 'unified_risk_score'
|
|
76 |
|
|
|
77 |
|
# max number of neighbors for graphical representation with d3.js
|
|
78 |
|
CONFIG.max_graph_neighbors = 150
|
|
79 |
|
CONFIG.nodes_per_page = 25
|
File node.rb deleted (index 33505d4..0000000) |
1 |
|
class Node
|
|
2 |
|
@@redis = Redis.new
|
|
3 |
|
|
|
4 |
|
COLOR_TYPES = ['success','info', 'warning', 'danger']
|
|
5 |
|
|
|
6 |
|
attr_reader :data, :neighbors, :asn
|
|
7 |
|
|
|
8 |
|
# metrics have to be readable from redis as well as their respective *_normalized values
|
|
9 |
|
@@metric_names = {
|
|
10 |
|
'clustering_coefficient' => "Clustering Coefficient",
|
|
11 |
|
'corrected_clustering_coefficient' => "Clustering Coefficient (Corrected)",
|
|
12 |
|
'degree' => "Node Degree",
|
|
13 |
|
'average_neighbor_degree' => "Average Neighbor Degree",
|
|
14 |
|
'corrected_average_neighbor_degree' => "Average Neighbor Degree (Corrected)",
|
|
15 |
|
'iterated_average_neighbor_degree' => "Iterated Average Neighbor Degree",
|
|
16 |
|
'corrected_iterated_average_neighbor_degree' => "Iterated Average Neighbor Degree (Corrected)",
|
|
17 |
|
'betweenness_centrality' => "Betweenness Centrality",
|
|
18 |
|
'eccentricity' => "Eccentricity",
|
|
19 |
|
'average_shortest_path_length' => "Average Shortest Path Length"
|
|
20 |
|
}
|
|
21 |
|
|
|
22 |
|
# scores have to be readable in redis
|
|
23 |
|
@@score_names = {
|
|
24 |
|
'unified_risk_score' => "Unified Risk Score (URS)",
|
|
25 |
|
'advanced_unified_risk_score' => "Advanced URS"
|
|
26 |
|
}
|
|
27 |
|
|
|
28 |
|
|
|
29 |
|
# class methods for control flow
|
|
30 |
|
def self.all_nodes
|
|
31 |
|
@@all_nodes = @@redis.smembers("all_nodes") unless defined? @@all_nodes
|
|
32 |
|
return @@all_nodes
|
|
33 |
|
end
|
|
34 |
|
|
|
35 |
|
def self.metric_names
|
|
36 |
|
@@metric_names
|
|
37 |
|
end
|
|
38 |
|
|
|
39 |
|
def self.score_names
|
|
40 |
|
@@score_names
|
|
41 |
|
end
|
|
42 |
|
|
|
43 |
|
|
|
44 |
|
# find node by id
|
|
45 |
|
def self.get(id)
|
|
46 |
|
params = {}
|
|
47 |
|
params[:id] = id
|
|
48 |
|
|
|
49 |
|
#get all available values for the node from redis and store in variable
|
|
50 |
|
@@redis.hgetall('node_metrics:'+id.to_s).each do |metric, value|
|
|
51 |
|
params[metric.to_sym] = value.to_f
|
|
52 |
|
end
|
|
53 |
|
|
|
54 |
|
# fetch neighbors of node
|
|
55 |
|
params[:neighbors] = @@redis.smembers('node_neighbors:'+params[:id])
|
|
56 |
|
|
|
57 |
|
#instantiate new node with obtained params from redis
|
|
58 |
|
node = Node.new(params)
|
|
59 |
|
return node
|
|
60 |
|
end
|
|
61 |
|
|
|
62 |
|
def initialize(params)
|
|
63 |
|
@data = params
|
|
64 |
|
end
|
|
65 |
|
|
|
66 |
|
#helper to get an HTML colorcode for a percentage value parameter
|
|
67 |
|
def self.color_type_by_value(value)
|
|
68 |
|
if value > 1
|
|
69 |
|
return COLOR_TYPES[-1]
|
|
70 |
|
end
|
|
71 |
|
|
|
72 |
|
if value == 0
|
|
73 |
|
return COLOR_TYPES[0]
|
|
74 |
|
end
|
|
75 |
|
|
|
76 |
|
index = ((value-0.001)*COLOR_TYPES.length).floor.to_i
|
|
77 |
|
return COLOR_TYPES[index]
|
|
78 |
|
end
|
|
79 |
|
|
|
80 |
|
# instance helper to get HTML colorcode for a specific metric value of a node
|
|
81 |
|
def color_type(metric)
|
|
82 |
|
value = self.data[metric.to_sym].to_f
|
|
83 |
|
return Node.color_type_by_value(value)
|
|
84 |
|
end
|
|
85 |
|
|
|
86 |
|
end |
|
File node_routes.rb added (mode: 100644) (index 0000000..e1a9fec) |
|
1 |
|
#node_routes.rb
|
|
2 |
|
|
|
3 |
|
# NODE DETAILS
|
|
4 |
|
|
|
5 |
|
# NODE SEARCH
|
|
6 |
|
post('/node') do
|
|
7 |
|
node_id = params[:node_id]
|
|
8 |
|
if Storage.all_nodes.include?(node_id)
|
|
9 |
|
redirect '/node/'+node_id
|
|
10 |
|
else
|
|
11 |
|
redirect '/'
|
|
12 |
|
end
|
|
13 |
|
end
|
|
14 |
|
|
|
15 |
|
get '/node/:id/' do
|
|
16 |
|
id = params[:id]
|
|
17 |
|
return status 404 unless Storage.all_nodes.include?(id)
|
|
18 |
|
|
|
19 |
|
@title = 'Node Details'
|
|
20 |
|
@node = Storage.get_node(id)
|
|
21 |
|
erb :node_details
|
|
22 |
|
end
|
|
23 |
|
|
|
24 |
|
#NODE NEIGHBORHOOD AJAX ENDPOINT FOR DISPLAY VIA d3.js
|
|
25 |
|
#color notes by unified risk score value
|
|
26 |
|
get '/node/:id/neighbors.json' do
|
|
27 |
|
content_type :json
|
|
28 |
|
|
|
29 |
|
id = params[:id].to_s
|
|
30 |
|
|
|
31 |
|
node = Storage.get_node(id)
|
|
32 |
|
|
|
33 |
|
#build response for d3.js utilization
|
|
34 |
|
response = {}
|
|
35 |
|
response[:nodes] = []
|
|
36 |
|
response[:links] = []
|
|
37 |
|
|
|
38 |
|
color_code = node.scores.fetch(CONFIG.node_coloring_field,{}).fetch(:color_code, nil) || node.metrics.fetch(CONFIG.node_coloring_field,{}).fetch(:color_code, nil)
|
|
39 |
|
|
|
40 |
|
response[:nodes] << {:name => node.id, :color_code => color_code}
|
|
41 |
|
|
|
42 |
|
neighbors = node.neighbors[0..CONFIG.max_graph_neighbors]
|
|
43 |
|
|
|
44 |
|
neighbors.each_with_index do |node_id, i|
|
|
45 |
|
neighbor = Storage.get_node(node_id)
|
|
46 |
|
color_code = neighbor.scores.fetch(CONFIG.node_coloring_field,{}).fetch(:color_code, nil) || neighbor.metrics.fetch(CONFIG.node_coloring_field,{}).fetch(:color_code, nil)
|
|
47 |
|
|
|
48 |
|
response[:nodes] << {:name => neighbor.id, :color_code => color_code}
|
|
49 |
|
response[:links] << {:source => 0, :target => i+1}
|
|
50 |
|
end
|
|
51 |
|
|
|
52 |
|
return response.to_json
|
|
53 |
|
end |
File public/js/graph.js changed (mode: 100644) (index 54baf9d..0efd5a3) |
1 |
1 |
$(function() {
|
$(function() {
|
2 |
2 |
|
|
3 |
|
var width = 800,
|
|
4 |
|
height = 800
|
|
|
3 |
|
var width = 720,
|
|
4 |
|
height = 720
|
5 |
5 |
|
|
6 |
6 |
var svg = d3.select("#graph").append("svg").attr("width", width).attr("height", height)
|
var svg = d3.select("#graph").append("svg").attr("width", width).attr("height", height)
|
7 |
7 |
|
|
8 |
8 |
var fisheye = d3.fisheye.circular()
|
var fisheye = d3.fisheye.circular()
|
9 |
9 |
.radius(120);
|
.radius(120);
|
10 |
10 |
|
|
11 |
|
d3.json("/node/neighbors/"+node_id, function(error, json) {
|
|
|
11 |
|
d3.json("/node/"+node_id+"/neighbors.json", function(error, json) {
|
12 |
12 |
if (error) return console.warn(error);
|
if (error) return console.warn(error);
|
13 |
13 |
|
|
14 |
14 |
var n = json.nodes.length;
|
var n = json.nodes.length;
|
|
... |
... |
$(function() { |
51 |
51 |
.attr("cy", function(d) { return d.y; })
|
.attr("cy", function(d) { return d.y; })
|
52 |
52 |
.attr("r", 4)
|
.attr("r", 4)
|
53 |
53 |
.attr("fill", "#2a9fd6")
|
.attr("fill", "#2a9fd6")
|
54 |
|
.attr("stroke", function(d) {return d.color;})
|
|
|
54 |
|
.attr("stroke", function(d) {return d.color_code;})
|
55 |
55 |
.attr("stroke-width",3);
|
.attr("stroke-width",3);
|
56 |
56 |
|
|
57 |
57 |
node.append("text")
|
node.append("text")
|
File storage.rb added (mode: 100644) (index 0000000..5939518) |
|
1 |
|
require 'ostruct'
|
|
2 |
|
require 'redis'
|
|
3 |
|
require 'json'
|
|
4 |
|
require 'will_paginate'
|
|
5 |
|
require 'will_paginate/array'
|
|
6 |
|
|
|
7 |
|
require './color_helper'
|
|
8 |
|
|
|
9 |
|
|
|
10 |
|
|
|
11 |
|
module Storage
|
|
12 |
|
@@rdb = Redis.new
|
|
13 |
|
|
|
14 |
|
|
|
15 |
|
def self.all_nodes
|
|
16 |
|
@@all_nodes = JSON.parse(@@rdb.smembers(CONFIG.node_index_key)[0]) unless defined? @@all_nodes
|
|
17 |
|
return @@all_nodes.map{|id| id.to_s}
|
|
18 |
|
end
|
|
19 |
|
|
|
20 |
|
def self.metric_names
|
|
21 |
|
@@metric_names = JSON.parse(@@rdb.smembers(CONFIG.metric_index_key)[0]) unless defined? @@metric_names
|
|
22 |
|
return @@metric_names
|
|
23 |
|
end
|
|
24 |
|
|
|
25 |
|
def self.score_names
|
|
26 |
|
@@score_names = JSON.parse(@@rdb.smembers(CONFIG.score_index_key)[0]) unless defined? @@score_names
|
|
27 |
|
return @@score_names
|
|
28 |
|
end
|
|
29 |
|
|
|
30 |
|
|
|
31 |
|
|
|
32 |
|
def self.get_node(nodeid)
|
|
33 |
|
node = OpenStruct.new
|
|
34 |
|
node.id = nodeid
|
|
35 |
|
node.metrics = {}
|
|
36 |
|
node.scores = {}
|
|
37 |
|
|
|
38 |
|
#get raw data from redis
|
|
39 |
|
all_values = @@rdb.hgetall(CONFIG.node_prefix+nodeid.to_s)
|
|
40 |
|
|
|
41 |
|
#build structured data
|
|
42 |
|
CONFIG.metric_names.each do |metric,name|
|
|
43 |
|
node.metrics[metric] = {}
|
|
44 |
|
node.metrics[metric][:name] = name
|
|
45 |
|
node.metrics[metric][:absolute] = all_values[metric].to_f
|
|
46 |
|
node.metrics[metric][:normalized] = all_values[metric+CONFIG.normalization_suffix].to_f
|
|
47 |
|
node.metrics[metric][:color_class] = ColorHelper.color_class_by_value(all_values[metric+CONFIG.normalization_suffix].to_f)
|
|
48 |
|
node.metrics[metric][:color_code] = ColorHelper.color_code_by_value(all_values[metric+CONFIG.normalization_suffix].to_f)
|
|
49 |
|
end
|
|
50 |
|
CONFIG.score_names.each do |score,name|
|
|
51 |
|
node.scores[score] = {}
|
|
52 |
|
node.scores[score][:name] = name
|
|
53 |
|
node.scores[score][:absolute] = all_values[score].to_f
|
|
54 |
|
node.scores[score][:color_class] = ColorHelper.color_class_by_value(all_values[score].to_f)
|
|
55 |
|
node.scores[score][:color_code] = ColorHelper.color_code_by_value(all_values[score].to_f)
|
|
56 |
|
end
|
|
57 |
|
|
|
58 |
|
node.neighbors = JSON.parse(@@rdb.smembers(CONFIG.node_neighbors_prefix+nodeid.to_s)[0])
|
|
59 |
|
|
|
60 |
|
return node
|
|
61 |
|
end
|
|
62 |
|
|
|
63 |
|
|
|
64 |
|
|
|
65 |
|
def self.get_metric_nodes(metric_name, page=1)
|
|
66 |
|
nodes = {}
|
|
67 |
|
@@rdb.zrevrange(CONFIG.metric_prefix+metric_name, 0, -1, {withscores: true}).each do |value|
|
|
68 |
|
nodes[value[0]] = {:id => value[0]}
|
|
69 |
|
nodes[value[0]][:absolute] = value[1].to_f
|
|
70 |
|
end
|
|
71 |
|
|
|
72 |
|
@@rdb.zrevrange(CONFIG.metric_prefix+metric_name+CONFIG.normalization_suffix, 0, -1, {withscores: true}).each do |value|
|
|
73 |
|
nodes[value[0]][:normalized] = value[1].to_f
|
|
74 |
|
nodes[value[0]][:color_class] = ColorHelper.color_class_by_value(value[1].to_f)
|
|
75 |
|
end
|
|
76 |
|
return nodes.to_a.paginate(:page => page, :per_page => CONFIG.nodes_per_page)
|
|
77 |
|
end
|
|
78 |
|
|
|
79 |
|
def self.get_all_metric_values_normalized(metric_name)
|
|
80 |
|
return @@rdb.zrevrange(CONFIG.metric_prefix+metric_name+CONFIG.normalization_suffix, 0, -1, {withscores: true}).map{|score| score[1]}
|
|
81 |
|
end
|
|
82 |
|
|
|
83 |
|
|
|
84 |
|
def self.get_score_nodes(score_name, page=1)
|
|
85 |
|
nodes = {}
|
|
86 |
|
@@rdb.zrevrange(CONFIG.score_prefix+score_name, 0, -1, {withscores: true}).each do |value|
|
|
87 |
|
nodes[value[0]] = {:id => value[0]}
|
|
88 |
|
nodes[value[0]][:absolute] = value[1].to_f
|
|
89 |
|
nodes[value[0]][:color_class] = ColorHelper.color_class_by_value(value[1].to_f)
|
|
90 |
|
end
|
|
91 |
|
return nodes.to_a.paginate(:page => page, :per_page => CONFIG.nodes_per_page)
|
|
92 |
|
end
|
|
93 |
|
|
|
94 |
|
def self.get_all_score_values(score_name)
|
|
95 |
|
return @@rdb.zrevrange(CONFIG.score_prefix+score_name, 0, -1, {withscores: true}).map{|score| score[1]}
|
|
96 |
|
end
|
|
97 |
|
|
|
98 |
|
def self.get_absolute_metric_statistics
|
|
99 |
|
data_metrics_absolute = {}
|
|
100 |
|
CONFIG.metric_names.each do |metric,mname|
|
|
101 |
|
metric_data = {}
|
|
102 |
|
CONFIG.statistical_indicators.each do |indicator,iname|
|
|
103 |
|
value = @@rdb.hget(CONFIG.statistics_prefix+metric, indicator)
|
|
104 |
|
metric_data[indicator] = value
|
|
105 |
|
end
|
|
106 |
|
metric_data['display_name'] = mname
|
|
107 |
|
data_metrics_absolute[metric] = metric_data
|
|
108 |
|
end
|
|
109 |
|
return data_metrics_absolute
|
|
110 |
|
end
|
|
111 |
|
|
|
112 |
|
def self.get_normalized_metric_statistics
|
|
113 |
|
data_metrics_normalized = {}
|
|
114 |
|
CONFIG.metric_names.each do |metric,mname|
|
|
115 |
|
metric_data = {}
|
|
116 |
|
CONFIG.statistical_indicators.each do |indicator,iname|
|
|
117 |
|
value = @@rdb.hget(CONFIG.statistics_prefix+metric+CONFIG.normalization_suffix, indicator)
|
|
118 |
|
metric_data[indicator] = value
|
|
119 |
|
end
|
|
120 |
|
metric_data['display_name'] = mname
|
|
121 |
|
data_metrics_normalized[metric] = metric_data
|
|
122 |
|
end
|
|
123 |
|
return data_metrics_normalized
|
|
124 |
|
end
|
|
125 |
|
|
|
126 |
|
def self.get_score_statistics
|
|
127 |
|
data_scores = {}
|
|
128 |
|
CONFIG.score_names.each do |score,sname|
|
|
129 |
|
score_data = {}
|
|
130 |
|
CONFIG.statistical_indicators.each do |indicator,iname|
|
|
131 |
|
value = @@rdb.hget(CONFIG.statistics_prefix+score, indicator)
|
|
132 |
|
score_data[indicator] = value
|
|
133 |
|
end
|
|
134 |
|
score_data['display_name'] = sname
|
|
135 |
|
data_scores[score] = score_data
|
|
136 |
|
end
|
|
137 |
|
return data_scores
|
|
138 |
|
end
|
|
139 |
|
|
|
140 |
|
def self.get_metric_correlations
|
|
141 |
|
correlation_data = {}
|
|
142 |
|
CONFIG.metric_names.each do |metric1,m1name|
|
|
143 |
|
correlation_data[metric1] = {:from => m1name, :correlation => {}}
|
|
144 |
|
CONFIG.metric_names.each do |metric2,m2name|
|
|
145 |
|
corr = @@rdb.hget(CONFIG.statistics_prefix+'correlations:'+metric1+':'+metric2, 'correlation')
|
|
146 |
|
conf = @@rdb.hget(CONFIG.statistics_prefix+'correlations:'+metric1+':'+metric2, 'confidence')
|
|
147 |
|
color_code = ColorHelper.color_code_by_value(corr.to_f.abs)
|
|
148 |
|
correlation_data[metric1][:correlation][metric2] = {:to => m2name, :correlation => corr, :confidence => conf, :color_code => color_code}
|
|
149 |
|
end
|
|
150 |
|
end
|
|
151 |
|
return correlation_data
|
|
152 |
|
end
|
|
153 |
|
|
|
154 |
|
|
|
155 |
|
end
|
File views/layout.erb changed (mode: 100644) (index 00a5740..2fda8a6) |
22 |
22 |
</form>
|
</form>
|
23 |
23 |
|
|
24 |
24 |
</div>
|
</div>
|
25 |
|
<div class="btn-group pull-right">
|
|
|
25 |
|
|
|
26 |
|
<div class="btn-group btn-group-lg pull-right">
|
|
27 |
|
|
|
28 |
|
<button class="btn btn-default btn-lg btn-primary" type="button" onclick="window.location.href='/statistics/'">
|
|
29 |
|
<span class="glyphicon glyphicon-eye-open"></span> Statistics
|
|
30 |
|
</button>
|
|
31 |
|
|
26 |
32 |
<button class="btn btn-default btn-lg btn-primary dropdown-toggle" type="button" data-toggle="dropdown">
|
<button class="btn btn-default btn-lg btn-primary dropdown-toggle" type="button" data-toggle="dropdown">
|
27 |
33 |
<span class="glyphicon glyphicon-list-alt"></span> List By Metrics
|
<span class="glyphicon glyphicon-list-alt"></span> List By Metrics
|
28 |
34 |
</button>
|
</button>
|
29 |
35 |
<ul class="dropdown-menu">
|
<ul class="dropdown-menu">
|
30 |
|
<% Node.metric_names.each do |metric,name| %>
|
|
|
36 |
|
<% CONFIG.metric_names.each do |metric,name| %>
|
31 |
37 |
<li><a href="/metric/<%= metric %>/"><%= name %></a></li>
|
<li><a href="/metric/<%= metric %>/"><%= name %></a></li>
|
32 |
38 |
<% end %>
|
<% end %>
|
33 |
39 |
<li class="divider">
|
<li class="divider">
|
34 |
|
<% Node.score_names.each do |score,name| %>
|
|
35 |
|
<li><a href="/metric/<%= score %>/"><%= name %></a></li>
|
|
|
40 |
|
<% CONFIG.score_names.each do |score,name| %>
|
|
41 |
|
<li><a href="/score/<%= score %>/"><%= name %></a></li>
|
36 |
42 |
<% end %>
|
<% end %>
|
37 |
43 |
</ul>
|
</ul>
|
38 |
44 |
</div>
|
</div>
|
File views/metric_details.erb changed (mode: 100644) (index 795b041..c2ac59d) |
12 |
12 |
</div>
|
</div>
|
13 |
13 |
|
|
14 |
14 |
<div class="row">
|
<div class="row">
|
15 |
|
<div class="metric_slider col-md-10 col-md-offset-1">
|
|
16 |
|
<% @nodes.each do |node|
|
|
17 |
|
name = node[0]
|
|
18 |
|
value = node[1].to_f
|
|
19 |
|
%>
|
|
20 |
|
<p class="metric_text text-center">
|
|
21 |
|
<a href="/node/<%= name %>"><span class="list_heading label label-default">Node <%= name %> <span class="glyphicon glyphicon-link"></span></span></a>
|
|
22 |
|
</p>
|
|
|
15 |
|
<table class="table table-striped">
|
|
16 |
|
<tr>
|
|
17 |
|
<th>Node</th>
|
|
18 |
|
<th>Absolute Value</th>
|
|
19 |
|
<th class="col-md-4">Value</th>
|
|
20 |
|
<th>Normalized Value</th>
|
23 |
21 |
|
|
24 |
|
|
|
25 |
|
<div class="metric_bar">
|
|
26 |
|
<div class="progress">
|
|
27 |
|
<div class="progress-bar progress-bar-<%= Node.color_type_by_value(value).to_s %>" role="progressbar" aria-valuenow="<%= value*100 %>" aria-valuemin="0" aria-valuemax="100" style="width: <%= value*100 %>%;">
|
|
28 |
|
<span class="sr-only"><%= value*100.round(2) %>%</span>
|
|
|
22 |
|
</tr>
|
|
23 |
|
<% @nodes.each do |node, data|
|
|
24 |
|
name = data[:id]
|
|
25 |
|
absolute = data[:absolute].to_f
|
|
26 |
|
normalized = data[:normalized].to_f
|
|
27 |
|
color_class = data[:color_class]
|
|
28 |
|
%>
|
|
29 |
|
<tr>
|
|
30 |
|
<td><a href="/node/<%= node %>">Node <%= node %></a></td>
|
|
31 |
|
<td><%= absolute.round(5) %></td>
|
|
32 |
|
<td>
|
|
33 |
|
<div class="metric_bar">
|
|
34 |
|
<div class="progress">
|
|
35 |
|
<div class="progress-bar progress-bar-<%= color_class %>" role="progressbar" aria-valuenow="<%= normalized*100 %>" aria-valuemin="0" aria-valuemax="100" style="width: <%= normalized*100 %>%;">
|
|
36 |
|
<span class="sr-only"><%= normalized*100 %>%</span>
|
|
37 |
|
</div>
|
29 |
38 |
</div>
|
</div>
|
30 |
|
</div>
|
|
31 |
|
</div>
|
|
32 |
|
<div class="text-center <%= Node.color_type_by_value(value).to_s %>">
|
|
33 |
|
<p><%= (value*100).round(2) %>%</p>
|
|
34 |
|
</div>
|
|
35 |
|
|
|
|
39 |
|
</div>
|
|
40 |
|
</td>
|
|
41 |
|
<td><span class="<%= color_class %>"><%= (normalized*100).round(2) %>%</span></td>
|
|
42 |
|
</tr>
|
36 |
43 |
<% end %>
|
<% end %>
|
37 |
|
|
|
38 |
|
</div>
|
|
|
44 |
|
</table>
|
39 |
45 |
</div>
|
</div>
|
|
46 |
|
|
40 |
47 |
<div class="row">
|
<div class="row">
|
41 |
|
<div class="col-md-10 col-md-offset-1">
|
|
42 |
48 |
<%= will_paginate @nodes %>
|
<%= will_paginate @nodes %>
|
43 |
49 |
</div>
|
</div>
|
44 |
50 |
</div>
|
</div>
|
45 |
|
|
|
46 |
|
|
|
47 |
|
|
|
48 |
|
|
|
File views/node_details.erb changed (mode: 100644) (index 6a315f0..bf989c9) |
1 |
1 |
<div class="row">
|
<div class="row">
|
2 |
|
<h1 class="text-center">Details for Node <%= @node.data[:id] %></h1>
|
|
|
2 |
|
<h1 class="text-center">Details for Node <%= @node.id %></h1>
|
3 |
3 |
</div>
|
</div>
|
4 |
4 |
|
|
5 |
|
|
|
6 |
|
|
|
7 |
|
<div id="carousel-example-generic" class="carousel slide">
|
|
8 |
|
<!-- Indicators -->
|
|
9 |
|
<ol class="carousel-indicators">
|
|
10 |
|
<li data-target="#carousel-example-generic" data-slide-to="0" class="active"></li>
|
|
11 |
|
<li data-target="#carousel-example-generic" data-slide-to="1"></li>
|
|
12 |
|
<li data-target="#carousel-example-generic" data-slide-to="2"></li>
|
|
13 |
|
</ol>
|
|
14 |
|
|
|
15 |
|
<!-- Wrapper for slides -->
|
|
16 |
|
<div class="carousel-inner">
|
|
17 |
|
|
|
18 |
|
<!-- NORMALIZED -->
|
|
19 |
|
<div class="item active metric_slider col-md-8 col-md-offset-2">
|
|
20 |
|
<div class="carousel-caption">
|
|
21 |
|
<div class="alert default">
|
|
22 |
|
<strong>Normalized Node Metrics</strong>
|
|
23 |
|
</div>
|
|
24 |
|
</div>
|
|
25 |
|
|
|
26 |
|
<% Node.metric_names.each do |metric,name| %>
|
|
27 |
|
<% metric_normalized = metric+'_normalized' %>
|
|
28 |
|
<p class="metric_text text-center">
|
|
29 |
|
<a href="/metric/<%= metric %>/"><span class="list_heading label label-default"><%= name %> <span class="glyphicon glyphicon-link"></span></span></a>
|
|
30 |
|
</p>
|
|
31 |
|
<div class="metric_bar">
|
|
32 |
|
<div class="progress">
|
|
33 |
|
<div class="progress-bar progress-bar-<%= @node.color_type(metric_normalized).to_s %>" role="progressbar" aria-valuenow="<%= @node.data[metric_normalized.to_sym]*100 %>" aria-valuemin="0" aria-valuemax="100" style="width: <%= @node.data[metric_normalized.to_sym]*100 %>%;">
|
|
34 |
|
<span class="sr-only"><%= @node.data[metric_normalized.to_sym]*100 %>%</span>
|
|
|
5 |
|
<div class="row">
|
|
6 |
|
<h2 class="text-center">Metric Values</h2>
|
|
7 |
|
<table class="table table-hover">
|
|
8 |
|
<tr>
|
|
9 |
|
<th>Metric</th>
|
|
10 |
|
<th>Absolute Value</th>
|
|
11 |
|
<th class="col-md-4">Normalized Value</th>
|
|
12 |
|
<th>[%]</th>
|
|
13 |
|
</tr>
|
|
14 |
|
<% @node.metrics.each do |metric,data| %>
|
|
15 |
|
<tr>
|
|
16 |
|
<td><a href="/metric/<%= metric %>/"><%= data[:name] %></a></td>
|
|
17 |
|
<td><%= data[:absolute].round(5) %></td>
|
|
18 |
|
<td>
|
|
19 |
|
<div class="metric_bar">
|
|
20 |
|
<div class="progress">
|
|
21 |
|
<div class="progress-bar progress-bar-<%= data[:color_class] %>" role="progressbar" aria-valuenow="<%= data[:normalized]*100 %>" aria-valuemin="0" aria-valuemax="100" style="width:
|
|
22 |
|
<%= data[:normalized]*100 %>%;">
|
|
23 |
|
<span class="sr-only"><%= data[:normalized]*100 %>%</span>
|
|
24 |
|
</div>
|
35 |
25 |
</div>
|
</div>
|
36 |
|
</div>
|
|
37 |
|
</div>
|
|
38 |
|
<div class="text-center <%= @node.color_type(metric_normalized).to_s %>">
|
|
39 |
|
<p><%= (@node.data[metric_normalized.to_sym]*100).round(2) %>%</p>
|
|
40 |
|
</div>
|
|
41 |
|
<% end %>
|
|
42 |
|
|
|
43 |
|
</div>
|
|
44 |
|
|
|
45 |
|
<!-- ABSOLUTE -->
|
|
46 |
|
<div class="item metric_slider col-md-8 col-md-offset-2">
|
|
47 |
|
<div class="carousel-caption">
|
|
48 |
|
<div class="alert default">
|
|
49 |
|
<strong>Absolute Node Metrics</strong>
|
|
50 |
|
</div>
|
|
51 |
|
</div>
|
|
52 |
|
|
|
53 |
|
<% Node.metric_names.each do |metric,name| %>
|
|
54 |
|
<p class="metric_text text-center"><%= name %></p>
|
|
55 |
|
<p class="lead text-center metric_value_display"><%= @node.data[metric.to_sym] %></p>
|
|
56 |
|
|
|
57 |
|
<% end %>
|
|
58 |
|
|
|
59 |
|
</div>
|
|
60 |
|
|
|
61 |
|
<!-- SCORES -->
|
|
62 |
|
<div class="item metric_slider col-md-8 col-md-offset-2">
|
|
63 |
|
<div class="carousel-caption">
|
|
64 |
|
<div class="alert default">
|
|
65 |
|
<strong>Scores</strong>
|
|
66 |
|
</div>
|
|
67 |
|
</div>
|
|
|
26 |
|
</div>
|
|
27 |
|
</td>
|
68 |
28 |
|
|
69 |
|
<% Node.score_names.each do |score,name| %>
|
|
|
29 |
|
<td>
|
|
30 |
|
<span class="<%= data[:color] %>">
|
|
31 |
|
<%= (data[:normalized]*100).round(2) %>%
|
|
32 |
|
</span>
|
|
33 |
|
</td>
|
70 |
34 |
|
|
|
35 |
|
</tr>
|
|
36 |
|
<% end %>
|
|
37 |
|
</table>
|
|
38 |
|
</div>
|
71 |
39 |
|
|
72 |
|
<p class="metric_text text-center">
|
|
73 |
|
<a href="/metric/<%= score %>/"><span class="list_heading label label-default"><%= name %> <span class="glyphicon glyphicon-link"></span></span></a>
|
|
74 |
|
</p>
|
|
75 |
40 |
|
|
76 |
|
<div class="metric_bar">
|
|
77 |
|
<div class="progress">
|
|
78 |
|
<div class="progress-bar progress-bar-<%= @node.color_type(score).to_s %>" role="progressbar" aria-valuenow="<%= @node.data[score.to_sym]*100 %>" aria-valuemin="0" aria-valuemax="100" style="width: <%= @node.data[score.to_sym]*100 %>%;">
|
|
79 |
|
<span class="sr-only"><%= @node.data[score.to_sym]*100 %>%</span>
|
|
|
41 |
|
<div class="row">
|
|
42 |
|
<h2 class="text-center">Score Values</h2>
|
|
43 |
|
<table class="table table-hover">
|
|
44 |
|
<tr>
|
|
45 |
|
<th>Score</th>
|
|
46 |
|
<th class="col-md-4">Value</th>
|
|
47 |
|
<th>[%]</th>
|
|
48 |
|
</tr>
|
|
49 |
|
<% @node.scores.each do |score,data| %>
|
|
50 |
|
<tr>
|
|
51 |
|
<td><a href="/metric/<%= score %>/"><%= data[:name] %></a></td>
|
|
52 |
|
<td>
|
|
53 |
|
<div class="metric_bar">
|
|
54 |
|
<div class="progress">
|
|
55 |
|
<div class="progress-bar progress-bar-<%= data[:color_class] %>" role="progressbar" aria-valuenow="<%= data[:absolute]*100 %>" aria-valuemin="0" aria-valuemax="100" style="width: <%= data[:absolute]*100 %>%;">
|
|
56 |
|
<span class="sr-only"><%= data[:absolute]*100 %>%</span>
|
|
57 |
|
</div>
|
80 |
58 |
</div>
|
</div>
|
81 |
|
</div>
|
|
82 |
|
</div>
|
|
83 |
|
<div class="score_value text-center <%= @node.color_type(score).to_s %>">
|
|
84 |
|
<p><%= (@node.data[score.to_sym]*100).round(2) %>%</p>
|
|
85 |
|
</div>
|
|
86 |
|
<% end %>
|
|
|
59 |
|
</div>
|
|
60 |
|
</td>
|
87 |
61 |
|
|
88 |
|
</div>
|
|
89 |
|
</div>
|
|
90 |
|
</div>
|
|
91 |
|
<div class="row">
|
|
92 |
|
<h1 class="text-center">Node Neighborhood</h1>
|
|
|
62 |
|
<td>
|
|
63 |
|
<span class="<%= data[:color_class] %>">
|
|
64 |
|
<%= (data[:absolute]*100).round(2) %>%
|
|
65 |
|
</span>
|
|
66 |
|
</td>
|
|
67 |
|
|
|
68 |
|
</tr>
|
|
69 |
|
<% end %>
|
|
70 |
|
</table>
|
93 |
71 |
</div>
|
</div>
|
|
72 |
|
|
94 |
73 |
<div class="row">
|
<div class="row">
|
95 |
|
<div class="col-md-8 col-md-offset-2" id="graph">
|
|
96 |
|
|
|
97 |
|
</div>
|
|
|
74 |
|
<h2 class="text-center">Node Neighborhood</h2>
|
|
75 |
|
<div class="col-md-10 col-md-offset-1" id="graph">
|
|
76 |
|
</div>
|
98 |
77 |
</div>
|
</div>
|
|
78 |
|
|
99 |
79 |
|
|
100 |
80 |
<script type="text/javascript">
|
<script type="text/javascript">
|
101 |
|
var node_id=<%= @node.data[:id] %>;
|
|
|
81 |
|
var node_id=<%= @node.id %>;
|
102 |
82 |
</script>
|
</script>
|
103 |
83 |
<script src="/js/fisheye.js"></script>
|
<script src="/js/fisheye.js"></script>
|
104 |
84 |
<script src="/js/graph.js"></script> |
<script src="/js/graph.js"></script> |
File views/statistics.erb added (mode: 100644) (index 0000000..fccdbc0) |
|
1 |
|
<div class="row">
|
|
2 |
|
<h1 class="text-center">Statistical Information about the Dataset</h1>
|
|
3 |
|
</div>
|
|
4 |
|
|
|
5 |
|
<div class="row">
|
|
6 |
|
<h2 class="text-center">Absolute Metric Values</h2>
|
|
7 |
|
<table class="table table-hover">
|
|
8 |
|
<tr>
|
|
9 |
|
<th>Name</th>
|
|
10 |
|
<th>Minimum</th>
|
|
11 |
|
<th>Maximum</th>
|
|
12 |
|
<th>Mean</th>
|
|
13 |
|
<th>Median</th>
|
|
14 |
|
<th>Standard Deviation</th>
|
|
15 |
|
</tr>
|
|
16 |
|
<% @data_metrics_absolute.each do |metric,values| %>
|
|
17 |
|
<tr>
|
|
18 |
|
<td><a href="/metric/<%= metric%>/"><%= values['display_name'] %></a></td>
|
|
19 |
|
<td><%= values['min'].to_f.round(5) %></td>
|
|
20 |
|
<td><%= values['max'].to_f.round(5) %></td>
|
|
21 |
|
<td><%= values['average'].to_f.round(5) %></td>
|
|
22 |
|
<td><%= values['median'].to_f.round(5) %></td>
|
|
23 |
|
<td><%= values['standard_deviation'].to_f.round(5) %></td>
|
|
24 |
|
</tr>
|
|
25 |
|
<% end %>
|
|
26 |
|
</table>
|
|
27 |
|
</div>
|
|
28 |
|
|
|
29 |
|
<div class="row">
|
|
30 |
|
<h2 class="text-center">Normalized Metric Values</h2>
|
|
31 |
|
<table class="table table-hover">
|
|
32 |
|
<tr>
|
|
33 |
|
<th>Name</th>
|
|
34 |
|
<th>Minimum</th>
|
|
35 |
|
<th>Maximum</th>
|
|
36 |
|
<th>Mean</th>
|
|
37 |
|
<th>Median</th>
|
|
38 |
|
<th>Standard Deviation</th>
|
|
39 |
|
</tr>
|
|
40 |
|
<% @data_metrics_normalized.each do |metric,values| %>
|
|
41 |
|
<tr>
|
|
42 |
|
<td><a href="/metric/<%= metric%>/"><%= values['display_name'] %></a></td>
|
|
43 |
|
<td><%= values['min'].to_f.round(5) %></td>
|
|
44 |
|
<td><%= values['max'].to_f.round(5) %></td>
|
|
45 |
|
<td><%= values['average'].to_f.round(5) %></td>
|
|
46 |
|
<td><%= values['median'].to_f.round(5) %></td>
|
|
47 |
|
<td><%= values['standard_deviation'].to_f.round(5) %></td>
|
|
48 |
|
</tr>
|
|
49 |
|
<% end %>
|
|
50 |
|
</table>
|
|
51 |
|
</div>
|
|
52 |
|
|
|
53 |
|
<div class="row">
|
|
54 |
|
<h2 class="text-center">Score Values</h2>
|
|
55 |
|
<table class="table table-hover">
|
|
56 |
|
<tr>
|
|
57 |
|
<th>Name</th>
|
|
58 |
|
<th>Minimum</th>
|
|
59 |
|
<th>Maximum</th>
|
|
60 |
|
<th>Mean</th>
|
|
61 |
|
<th>Median</th>
|
|
62 |
|
<th>Standard Deviation</th>
|
|
63 |
|
</tr>
|
|
64 |
|
<% @data_scores.each do |score,values| %>
|
|
65 |
|
<tr>
|
|
66 |
|
<td><a href="/score/<%= score %>/"><%= values['display_name'] %></a></td>
|
|
67 |
|
<td><%= values['min'].to_f.round(5) %></td>
|
|
68 |
|
<td><%= values['max'].to_f.round(5) %></td>
|
|
69 |
|
<td><%= values['average'].to_f.round(5) %></td>
|
|
70 |
|
<td><%= values['median'].to_f.round(5) %></td>
|
|
71 |
|
<td><%= values['standard_deviation'].to_f.round(5) %></td>
|
|
72 |
|
</tr>
|
|
73 |
|
<% end %>
|
|
74 |
|
</table>
|
|
75 |
|
</div>
|
|
76 |
|
|
|
77 |
|
<div class="row">
|
|
78 |
|
<h2 class="text-center">Metric Pearson Correlation</h2>
|
|
79 |
|
<table class="table table-hover">
|
|
80 |
|
<tr>
|
|
81 |
|
<td> </td>
|
|
82 |
|
<% CONFIG.metric_names.each do |metric,name| %>
|
|
83 |
|
<td><a href="/metric/<%= metric%>/"><%= name %></a></td>
|
|
84 |
|
<% end %>
|
|
85 |
|
</tr>
|
|
86 |
|
<% CONFIG.metric_names.each do |metric1,name1| %>
|
|
87 |
|
<tr>
|
|
88 |
|
<td><a href="/metric/<%= metric1%>/"><%= name1 %></a></td>
|
|
89 |
|
<% CONFIG.metric_names.each do |metric2,name2| %>
|
|
90 |
|
<td>
|
|
91 |
|
<span class="confidence_tooltip" data-toggle="tooltip" data-placement="top" title=""
|
|
92 |
|
data-original-title="Confidence: <%= @data_correlations[metric1][:correlation][metric2][:confidence].to_f %>"
|
|
93 |
|
style="color:<%= @data_correlations[metric1][:correlation][metric2][:color_code] %>">
|
|
94 |
|
<%= @data_correlations[metric1][:correlation][metric2][:correlation].to_f.round(2) %>
|
|
95 |
|
</span>
|
|
96 |
|
</td>
|
|
97 |
|
<% end %>
|
|
98 |
|
</tr>
|
|
99 |
|
<% end %>
|
|
100 |
|
</table>
|
|
101 |
|
</div>
|
|
102 |
|
|
|
103 |
|
<script type="text/javascript">
|
|
104 |
|
$(".confidence_tooltip").tooltip();
|
|
105 |
|
</script>
|