Skip to content
This repository has been archived by the owner on Nov 20, 2021. It is now read-only.

visualization matrix-datagram #7

Merged
merged 1 commit into from May 6, 2016
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
37 changes: 37 additions & 0 deletions datagramas/visualizations/matrix-datagram/__init__.py
@@ -0,0 +1,37 @@


VISUALIZATION_CONFIG = {
'authors': 'Morin Roa and Eduardo Graells, based on code by Mike Bostock',
'requirements': ['d3', 'datagramas'],
'visualization_name': 'datagramas.matrix',
'figure_id': None,
'container_type': 'svg',
'data': {
'graph': None,
},
'options': {
'background_color': None,
'allowed_events': ['node_click', 'cell_click']
},
'variables': {
'order_by': 'id',
'width': 960,
'height': 960,
'padding': {'left': 100, 'top': 100, 'right': 100, 'bottom': 50},
'node_label': 'id',
'na_value': None,
'na_color': None,
'row_normalization_exponent': 0,
'normalized_value_name': 'normalized_weight',
'grid_color': 'white',
'index_name': 'index',
'norm_epsilon': 0.00000001,
'transition_duration': 1000,
'label_font_size': 12,
'node_info_length': 10
},
'colorables': {
'item_color': {'value': 'grey', 'palette': None, 'scale': None, 'legend': False, 'n_colors': None},
'column_color': {'value': 'grey', 'palette': None, 'scale': None, 'legend': False, 'n_colors': None}
}
}
36 changes: 36 additions & 0 deletions datagramas/visualizations/matrix-datagram/functions.js
@@ -0,0 +1,36 @@

var normalize = function(matrix) {
matrix.forEach(function(row) {
var norm = 0;
row.forEach(function(d) {
var abs_value = Math.abs(datagramas.get(d, _item_color_value));
norm += Math.pow(abs_value, _row_normalization_exponent);
});

norm = Math.pow(norm, 1 / _row_normalization_exponent);

row.forEach(function (d) {
d[_normalized_value_name] = norm > _norm_epsilon ? datagramas.get(d, _item_color_value) / norm : 0.0;
});
});
};

var draw_row = function(row) {
var cell = d3.select(this).selectAll(".cell")
.data(row);

cell.enter().append("rect")
.attr("class", "cell")
.attr("x", function (d, j) {
return x(j);
})
.attr("width", x.rangeBand())
.attr("height", y.rangeBand());

cell.exit().remove();
};

var cell_color = function(d) {
return _row_normalization_exponent !== null && _row_normalization_exponent ?
_item_color(d, _normalized_value_name) : _item_color(d);
};
260 changes: 260 additions & 0 deletions datagramas/visualizations/matrix-datagram/template.js
@@ -0,0 +1,260 @@
datagramas.prepare_graph(_data_graph);

var matrix = new Array(_data_graph.nodes.length);

//Agrega la propiedad index a cada nodo con el valor del indice.
_data_graph.nodes.forEach(function(node, i) {
node[_index_name] = i;
matrix[i] = new Array(_data_graph.nodes.length);
});

// Insertar valores a la matriz. El valor de un elemento de la matriz es un objeto link.
_data_graph.links.forEach(function(link) {
var src_index = datagramas.get(link.source, _index_name);
var dst_index = datagramas.get(link.target, _index_name);

matrix[src_index][dst_index] = link;

if (!_data_graph.directed) { //Cuando el grafo no es dirigido se duplica el valor del elemento de la matriz con la dirección opuesta.
var other = {};
var k;

for (k in link) {
if (link.hasOwnProperty(k)) {
other[k] = link[k];
}
}

other.source = link.target;
other.target = link.source;

matrix[dst_index][src_index] = other;
}
});

//Si se entrega un valor como parámetro a las casillas que no tienen valor desde el grafo.
if (_na_value !== null){
d3.range(0, _data_graph.nodes.length).forEach(function(i) {
d3.range(0, _data_graph.nodes.length).forEach(function(j) {
if (matrix[i][j] == undefined) {
matrix[i][j] = {};
datagramas.set(matrix[i][j], _item_color_value, _na_value);
}
else{
var existe_propiedad = datagramas.get(matrix[i][j],_item_color_value );
if(existe_propiedad == null){ //No existe la propiedad en el enlace entonces se crea
datagramas.set(matrix[i][j], _item_color_value, _na_value);
}
}

});
});
}

//En el caso de querer color normalizado por fila // EDU: hice que la norma calculada fuese parametrizable. color relativo es un número así que color relativo puede ser mayor a 0
if (_row_normalization_exponent > 0) {
normalize(matrix);
}

var proxy_links = [];
matrix.forEach(function(row) {
row.forEach(function(d) {
proxy_links.push(d);
});
});

//Recorrer los nombres nodos y por cada uno agregar un text en container
_data_graph.nodes.forEach(function(node, i) {
container.append('text').attr("class", "text_hidden")
.attr("x", 0)
.attr("y", 0)
.attr("dy", ".32em")
.attr("text-anchor", "end")
.text(function() {
return datagramas.get(_data_graph.nodes[i], _node_label);
})
.style("visibility","hidden");
});

//Ajustar verticalmente y horizontalmente la matriz, respecto a los textos.
var etiquetas = container.selectAll('.text_hidden');
var anchos = [];

etiquetas.each(function(d) {
anchos.push(this.getBBox().width);
});

var max_ancho_texto = d3.max(anchos);

var height_matriz = _vis_height - max_ancho_texto - 35;
var y = d3.scale.ordinal().rangeBands([0, height_matriz]);

var width_matriz = _vis_width - max_ancho_texto - 35;
var x = d3.scale.ordinal().rangeBands([0, width_matriz]);

var container_vis;
if (container.select('g').empty()) {
container_vis = container.append("g");
container_vis.attr("transform", "translate(" + (max_ancho_texto+35) + ", " + (max_ancho_texto+35) + ")");
} else{
container_vis = container.select("g");
}


// ahora el atributo que tiene los valores es un parámetro opcional
_item_color_update_scale_func(proxy_links, _row_normalization_exponent > 0 ? _normalized_value_name : _item_color_value);
_column_color_update_scale_func(_data_graph.nodes);


x.domain(d3.range(_data_graph.nodes.length).sort(function(a, b) {
return d3.ascending(datagramas.get(_data_graph.nodes[a], _order_by), datagramas.get(_data_graph.nodes[b], _order_by));
}));

y.domain(d3.range(_data_graph.nodes.length).sort(function(a, b) {
return d3.ascending(datagramas.get(_data_graph.nodes[a], _order_by), datagramas.get(_data_graph.nodes[b], _order_by));
}));

var dist_text_rectinf = 5; //Distancia horizontal entre el texto (por fila) y el rect de color que informa sector
var dist_rectinf_matrix = 10; //Distancia horizontal entre rect de color que informa sector y matriz
var dist_text_matrix = dist_text_rectinf + _node_info_length + dist_rectinf_matrix; //Distancia horizontal entre el texto y la matriz.

var row = container_vis.selectAll(".row")
.data(matrix);

row.enter().append("g")
.attr("class", "row")
.attr("transform", function(d, i) {
return "translate(0," + y(i) + ")";
});

var tran = container_vis.transition().duration(_transition_duration);

tran.selectAll(".row")
.delay(function(d, i) {
return x(i) * 4;
})
.attr("transform", function(d, i) {
return "translate(0," + y(i) + ")";
})
.selectAll(".cell")
.delay(function(d, j) {
return x(j) * 4;
})
.attr("x", function(d, j) {
return x(j);
});

row.each(draw_row);

row.each(function(d, i) {

var l = d3.select(this).selectAll('line').data([1]);

l.enter().append("line");

l.style("stroke", _grid_color)
.attr("x2", width_matriz);

l.exit().remove();

var t = d3.select(this).selectAll('text').data([1]);

t.enter().append('text');

t.attr("x", -dist_text_matrix)
.attr("y", y.rangeBand() / 2)
.attr("dy", ".32em")
.attr("text-anchor", "end")
.attr('font-size', _label_font_size)
.text(function() {
return datagramas.get(_data_graph.nodes[i], _node_label);
});

//Para crea la columna informativa al lado de los textos
var column_inf = d3.select(this).selectAll(".col_inf").data([1]);

column_inf.enter().append('rect').attr("class", "col_inf");

column_inf.attr("x", -(_node_info_length + dist_rectinf_matrix))
.attr("y", 0)
.attr("width", _node_info_length)
.attr("height", y.rangeBand()-2)
.attr("fill", function(){
return _column_color(_data_graph.nodes[i]);
});

t.exit().remove();
});

row.exit().remove();

var column = container_vis.selectAll(".column")
.data(matrix);

//Cuando se crean por primera vez los elementos .column
column.enter().append("g")
.attr("class", "column")
.attr("transform", function(d, i) {
return "translate(" + x(i) + ")rotate(-90)";
});

tran.selectAll(".column")
.delay(function(d, i) { return x(i) * 4; })
.attr("transform", function(d, i) {
return "translate(" + x(i) + ")rotate(-90)";
});


column.each(function(d, i) {
var l = d3.select(this).selectAll('line').data([1]);

l.enter().append("line");

l.style("stroke", _grid_color)
.attr("x1", - height_matriz);

l.exit().remove();

var t = d3.select(this).selectAll('text').data([1]);

t.enter().append("text");

t.attr("x", dist_text_matrix)
.attr("y", x.rangeBand() / 2)
.attr("dy", ".32em")
.attr("text-anchor", "start")
.attr('font-size', _label_font_size)
.text(function() {
return datagramas.get(_data_graph.nodes[i], _node_label);
});

//Para crear la fila informativa al lado de los textos
var fila_inf = d3.select(this).selectAll('.fila_inf').data([1]);

fila_inf.enter().append('rect').attr("class", "fila_inf");

fila_inf.attr("x", dist_rectinf_matrix)
.attr("y", 0)
.attr("width", _node_info_length)
.attr("height", x.rangeBand()-2)
.attr("fill", function(){
return _column_color(_data_graph.nodes[i]);
});

t.exit().remove();
});

column.exit().remove();


//Selecciona todas las celdas de la matriz para colorearlas.
container_vis.selectAll('.row')
.selectAll("rect.cell")
.attr("fill", function(d) {
if (d === undefined) {
return _na_color;
}

return datagramas.get(d,_item_color_value) !== null ? cell_color(d) : _na_color;
});