Nuevo Gráfico de Barras
Vamos a usar la estructura de gráficos reusables con el código del scatter plot creado antes. Definimos los datos nuevamente.
var datosA = [
{nombre: 'Manzana', color: '#ff0000', calorias: 52, grasa: 0.2, proteinas: 0.3, azucar: 14},
{nombre: 'Hamburguesa', color: '#993300', calorias: 295, grasa: 14, proteinas: 17, azucar: 24},
{nombre: 'Pizza', color: '#cc9900', calorias: 266, grasa: 10, proteinas: 11, azucar: 33},
{nombre: 'Palta', color: '#004400', calorias: 160, grasa: 15, proteinas: 2, azucar: 9},
{nombre:'Platano', color:'#ffcc00', calorias: 89, grasa: 0.3, proteinas: 1.1, azucar: 23},
{nombre:'Nuez', color:'#cc6600', calorias: 576, grasa: 49, proteinas: 21, azucar: 22},
{nombre:'Almendra', color:'#660033', calorias: 576, grasa: 49, proteinas: 21, azucar: 22},
{nombre:'Pollo', color:'#cc9900', calorias: 219, grasa: 12, proteinas: 27, azucar: 0},
{nombre:'Pavo', color:'#ffcc33', calorias: 111, grasa: 0.7, proteinas: 25, azucar: 0.1},
{nombre:'Baggel', color:'#cc9966', calorias: 250, grasa: 1.5, proteinas: 10, azucar: 49},
{nombre:'Brocoli', color:'#00bb00', calorias: 34, grasa: 0.4, proteinas: 2.8, azucar: 7},
{nombre:'Pan', color:'#cc6633', calorias: 289, grasa: 1.8, proteinas: 12, azucar: 56},
{nombre:'Papas fritas', color:'#ffcc00', calorias: 536, grasa: 35, proteinas: 7, azucar: 53},
{nombre:'Vino', color:'#660066', calorias: 83, grasa: 0, proteinas: 0.1, azucar: 2.7},
{nombre:'Uva', color:'#66cc66', calorias: 67, grasa: 0.4, proteinas: 0.6, azucar: 17},
{nombre:'Granola', color:'#ff9900', calorias: 471, grasa: 20, proteinas: 10, azucar: 64},
{nombre:'Zanahoria', color:'#ff3300', calorias: 41, grasa: 0.2, proteinas: 0.9, azucar: 10},
{nombre:'Tomate', color:'#ff0000', calorias: 18, grasa: 3.9, proteinas: 0.9, azucar: 3.9},
{nombre:'Naranja', color:'#ff6600', calorias: 47, grasa: 0.1, proteinas: 0.9, azucar: 12},
{nombre:'Pera', color:'#00ff00', calorias: 57, grasa: 0.1, proteinas: 0.4, azucar: 15},
{nombre:'Nutella', color:'#550000', calorias: 500, grasa: 27, proteinas: 5, azucar: 50},
{nombre:'Arroz', color:'#ffffcc', calorias: 111, grasa: 0.9, proteinas: 2.6, azucar: 23},
{nombre:'Chocolate', color:'#330000', calorias: 546, grasa: 31, proteinas: 4.9, azucar: 61},
{nombre:'Rabano', color:'#cc0033', calorias: 16, grasa: 0.1, proteinas: 0.7, azucar: 3.4},
{nombre:'Soya', color:'#004400', calorias: 446, grasa: 20, proteinas: 36, azucar: 30},
{nombre:'Aceite', color:'#007700', calorias: 884, grasa: 100, proteinas: 0, azucar: 0},
{nombre:'Leche', color:'#eeeeee', calorias: 42, grasa: 1, proteinas: 3.4, azucar: 5},
{nombre:'Queso', color:'#ffff00', calorias: 371, grasa: 32, proteinas: 18, azucar: 3.7},
{nombre:'Pan Pita', color:'#660033', calorias: 275, grasa: 1.2, proteinas: 9, azucar: 56},
{nombre:'Vacuno', color:'#660000', calorias: 250, grasa: 15, proteinas: 26, azucar: 0},
{nombre:'Zapayo', color:'#ff6600', calorias: 26, grasa: 0.1, proteinas: 1, azucar: 6},
{nombre:'Piña', color:'#ffff99', calorias: 50, grasa: 0.1, proteinas: 0.5, azucar: 13},
{nombre:'Coco', color:'#ffffcc', calorias: 354, grasa: 33, proteinas: 3.3, azucar: 15}
];
Creamos la estructura básica de los gráficos reutilizables, para crear el gráfico de barras. Esta función no hace nada, sólo la escribimos como referencia.
function barChart() {
// Atributos del grafico
var width = 600,
height = 400;
// Creación y actualización del grafico
function chart(selection) {
selection.each(function(data) {
});
}
// Funciones de configuración
chart.width = function(newWidth) {
if (!arguments.length) { return width; }
width = newWidth;
return chart;
};
return chart;
}
Ahora, agregamos los valores de configuración al gráfico y reemplazamos el contenido de la función chart
con el código de creación del scatter plot.
function barChart() {
// Atributos por defecto del gráfico
var width = 800,
height = 300,
margin = {top: 30, right: 20, bottom: 20, left: 40},
duration = 1e3,
label = function(d) { return d.x; },
x = function(d) { return d.y; };
// Creación y actualización del grafico
function chart(selection) {
selection.each(function(data) {
var div = d3.select(this),
svg = div.selectAll('svg').data([data]);
var svgEnter = svg.enter().append('svg');
// Setup SVG
svgEnter
.attr('width', width)
.attr('height', height);
svgEnter.append('g').attr('class', 'chart');
svgEnter.append('g').attr('class', 'axis xaxis');
// Update groups
var gchart = svg.selectAll('g.chart').data([data]),
gxaxis = svg.selectAll('g.xaxis').data([data]),
gyaxis = svg.selectAll('g.yaxis').data([data]);
svg.attr('width', width).attr('height', height);
gchart.attr('transform', 'translate(' + 0 + ',' + margin.top + ')');
gxaxis.attr('transform', 'translate(' + margin.left + ',' + (height - margin.bottom) + ')');
// Escalas
var xScale = d3.scale.linear()
.domain([0, d3.max(data, x)])
.range([0, width - margin.left - margin.right]);
var yScale = d3.scale.ordinal()
.domain(d3.range(data.length))
.rangeBands([0, height - margin.top - margin.bottom], 0.1);
// Axis
var xAxis = d3.svg.axis()
.scale(xScale)
.orient('bottom');
gxaxis.call(xAxis);
// Rectangles
var rect = gchart.selectAll('rect.bars').data(data);
rect.enter().append('rect')
.attr('class', 'bars')
.attr('x', margin.left)
.attr('y', function(d, i) { return yScale(i); })
.attr('width', 0)
.attr('height', yScale.rangeBand());
rect.transition().duration(duration)
.attr('width', function(d) { return xScale(x(d)); });
rect.exit().remove();
// Labels
var labels = gchart.selectAll('text.label').data(data);
labels.enter().append('text')
.attr('class', 'label')
.attr('text-anchor', 'end')
.attr('x', margin.left - 10)
.attr('y', function(d, i) { return yScale(i) + yScale.rangeBand(); })
.text(label);
labels.transition().delay(duration)
.text(label);
labels.exit().remove();
});
}
// Funciones de configuración
chart.height = function(value) {
if (!arguments.length) { return height; }
height = value;
return chart;
};
chart.width = function(value) {
if (!arguments.length) { return width; }
width = value;
return chart;
};
chart.margin = function(value) {
if (!arguments.length) { return margin; }
margin = value;
return chart;
};
chart.x = function(value) {
if (!arguments.length) { return x; }
x = value;
return chart;
};
chart.label = function(value) {
if (!arguments.length) { return label; }
label = value;
return chart;
};
return chart;
}
Usando el gráfico
Podemos usar el gráfico usando la misma sintaxis que con el scatter plot. Podemos configurar los atributos del gráfico usando method chaining . Al igual que en el ejemplo del scatter plot, seleccionamos el div contenedor, vinculamos los datos e invocamos el gráfico usando call
.
var barchart = barChart()
.x(function(d) { return d.calorias; })
.label(function(d) { return d.nombre.toUpperCase(); })
.margin({top: 10, right: 10, bottom: 30, left: 100})
.width(600)
.height(600);
d3.select('#ejemplo-a04')
.data([datosA])
.call(barchart);
Grasa
Proteinas
Azúcar
Calorías
Para hacer más interesante este ejemplo también, agregamos botones para graficar distintas cosas y agregamos listeners para el evento click . El callback del evento será reconfigurar el gráfico, vincular los datos nuevamente e invocar el gráfico.
d3.select('#boton-g').on('click', function() {
barchart.x(function(d) { return d.grasa; });
d3.select('#ejemplo-a04')
.data([datosA])
.call(barchart);
});
d3.select('#boton-p').on('click', function() {
barchart.x(function(d) { return d.proteinas; });
d3.select('#ejemplo-a04')
.data([datosA])
.call(barchart);
});
d3.select('#boton-a').on('click', function() {
barchart.x(function(d) { return d.azucar; });
d3.select('#ejemplo-a04')
.data([datosA])
.call(barchart);
});
d3.select('#boton-c').on('click', function() {
barchart.x(function(d) { return d.calorias; });
d3.select('#ejemplo-a04')
.data([datosA])
.call(barchart);
});