javascript - Coordenadas paralelas con casilla de verificación
checkbox d3.js (1)
Tengo algunos datos que quiero visualizar usando coordenadas paralelas.
Mis datos constan de 200 filas (casos) y 100 columnas (características). Solo necesito visualizar alguna parte de los datos (200x8), incluyendo feature1, feature2, ..., feature8. También tengo 4 columnas de datos (A, B, C y D) que sus valores son 0 o 1. Por ejemplo, si el valor de la columna A para un caso (fila) es 1, significa que el caso de los datos es de tipo A.
Ya tengo el código para trazar coordenadas paralelas:
<div class="filter_options">
<input class="filter_button" id="a_button" type="checkbox">A</input><br>
<input class="filter_button" id="b_button" type="checkbox">B</input><br>
<input class="filter_button" id="c_button" type="checkbox">C</input><br>
<input class="filter_button" id="d_button" type="checkbox">D</input><br>
</div>
<body>
<script type="text/javascript">
var m = [30, 10, 10, 10],
w = 1300 - m[1] - m[3],
h = 500 - m[0] - m[2];
var x = d3.scale.ordinal().rangePoints([0, w], 1),
y = {},
dragging = {};
var line = d3.svg.line(),
axis = d3.svg.axis().orient("left"),
background,
foreground;
var svg = d3.select("body").append("svg:svg")
.attr("width", w + m[1] + m[3])
.attr("height", h + m[0] + m[2])
.append("svg:g")
.attr("transform", "translate(" + m[3] + "," + m[0] + ")");
d3.csv("myData.csv")
.row(function(d) {
return {
// Features that are needed to be visualize
feature1 : d.feature1,
feature2 : d.feature2,
feature3 : d.feature3,
feature4 : d.feature4,
feature5 : d.feature5,
feature6 : d.feature6,
feature7 : d.feature7,
feature8 : d.feature8,
A : d.A,
B : d.B,
C : d.C,
D : d.D
};
})
.get(function(e, data) {
x.domain(
dimensions = d3.keys(data[0])
.filter(function(d) {
return d != "source" &&
(y[d] = d3.scale.linear()
.domain(d3.extent(data, function(p) { return +p[d]; }))
.range([h, 0]));
}
));
// Add grey background lines for context.
background = svg.append("svg:g")
.attr("class", "background")
.selectAll("path")
.data(data)
.enter().append("svg:path")
.attr("d", path);
// Add blue foreground lines for focus.
foreground = svg.append("svg:g")
.attr("class", "foreground")
.selectAll("path")
.data(data)
.enter().append("svg:path")
.attr("d", path);
// Add a group element for each dimension.
var g = svg.selectAll(".dimension")
.data(dimensions)
.enter().append("svg:g")
.attr("class", "dimension")
.attr("transform", function(d) { return "translate(" + x(d) + ")"; })
.call(d3.behavior.drag()
.on("dragstart", function(d) {
dragging[d] = this.__origin__ = x(d);
background.attr("visibility", "hidden");
})
.on("drag", function(d) {
dragging[d] = Math.min(w, Math.max(0, this.__origin__ += d3.event.dx));
foreground.attr("d", path);
dimensions.sort(function(a, b) { return position(a) - position(b); });
x.domain(dimensions);
g.attr("transform", function(d) { return "translate(" + position(d) + ")"; })
})
.on("dragend", function(d) {
delete this.__origin__;
delete dragging[d];
transition(d3.select(this)).attr("transform", "translate(" + x(d) + ")");
transition(foreground)
.attr("d", path);
background
.attr("d", path)
.transition()
.delay(500)
.duration(0)
.attr("visibility", null);
}));
// Add an axis and title.
g.append("svg:g")
.attr("class", "axis")
.each(function(d) { d3.select(this).call(axis.scale(y[d])); })
.append("svg:text")
.attr("text-anchor", "middle")
.attr("y", -9)
.text(String);
// Add and store a brush for each axis.
g.append("svg:g")
.attr("class", "brush")
.each(function(d) { d3.select(this).call(y[d].brush = d3.svg.brush().y(y[d]).on("brush", brush)); })
.selectAll("rect")
.attr("x", -8)
.attr("width", 16);
});
function position(d) {
var v = dragging[d];
return v == null ? x(d) : v;
}
function transition(g) {
return g.transition().duration(500);
}
// Returns the path for a given data point.
function path(d) {
return line(dimensions.map(function(p) { return [position(p), y[p](d[p])]; }));
}
// Handles a brush event, toggling the display of foreground lines.
function brush() {
var actives = dimensions.filter(function(p) { return !y[p].brush.empty(); }),
extents = actives.map(function(p) { return y[p].brush.extent(); });
foreground.style("display", function(d) {
return actives.every(function(p, i) {
return extents[i][0] <= d[p] && d[p] <= extents[i][1];
}) ? null : "none";
});
}
</script>
</body>
Ahora, quiero agregar 4 casillas de verificación para que el usuario pueda seleccionar qué tipos quiere ver en coordenadas paralelas. Por ejemplo, si el usuario verifica el tipo A, se deben visualizar los casos (filas) con valor de 1 en su columna A.
¿Cómo debo hacer eso?
Realmente agradecería cualquier ayuda que pudieras proporcionar :)
Este (5x31) fragmento de datos es algo similar a mis datos:
path,Ktype,label,CGX,CGY,C_1,C_2,C_3,C_4,total1,total2,totalI3,total4,feature1,feature2,feature3,feature4,feature5,feature6,feature7,feature8,feature9,feature10,feature11,feature12,A,B,C,D,feature13,feature14,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,
./Mydata/Case1,k1,1,42,33,0,57.44534,0,52597,71,16,10,276,4038,3789.631,0.6173469,0.6499337,2.103316,0.6661285,1.065539,248.3694,0.630161,0.000192848,0.9999996,0.000642777,1,0,0,1,9.60E-05,3136.698,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,
./Mydata/Case2,k1,2,163,29,0,43.28862,0,49050,71,16,10,248,2944,2587.956,0.5726808,0.5681185,2.130387,0.601512,1.137578,356.0444,0.6335613,0.000327267,1.000029,0.001271235,1,0,0,1,0.00010854,2676.418,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,
./Mydata/Case3,k1,3,774,19,0,45.26291,0,53455,71,16,10,212,2366,1982.547,0.408179,0.4579566,1.994296,0.6615351,1.193415,383.4534,0.7153812,0.000264522,1.000031,0.001210507,1,1,0,0,9.54E-05,3221.289,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,
./Mydata/Case4,k1,4,1116,25,0,80.76469,0,57542,71,16,10,284,3908,3453.988,0.3549117,0.4811547,1.982244,0.6088744,1.131446,454.0122,0.6166388,0.000314288,0.9999836,0.00129846,0,1,1,0,0.000140592,2143.42,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,
./Mydata/Case5,k1,5,1364,59,1,52.96776,0,49670,71,16,10,228,2725,2642.675,0.4328255,0.475517,1.859871,0.6587288,1.031152,82.32471,0.5775694,0.000466264,0.9999803,0.001765345,0,1,1,0,0.00012014,2439.636,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,
Es bastante difícil darle un consejo o solución sin conocer sus datos y la organización del código, así que intentaré utilizar el ejemplo bueno y similar de otra persona. Eventualmente, la solución a su pregunta puede parecer completamente diferente, pero publico esta respuesta como una guía para usted, y espero que pueda ayudarlo.
Eche un vistazo a este excelente ejemplo de uso de coordenadas paralelas : (tiene la función de seleccionar y anular la selección de grupos de elementos, la función exacta que necesita)
El código de JavaScript para este ejemplo está aquí .
Los datos están en un archivo csv, y las primeras líneas son las siguientes:
"name","group","protein (g)","calcium (g)","sodium (g)","fiber (g)","vitaminc (g)","potassium (g)","carbohydrate (g)","sugars (g)","fat (g)","water (g)","calories","saturated (g)","monounsat (g)","polyunsat (g)","id"
"Beverage, instant breakfast powder, chocolate, not reconstituted","Dairy and Egg Products",19.9,0.285,0.385,0.4,0.07690000000000001,0.947,66.2,65.8,1.4,7.4,357,0.56,0.314,0.278,27481
"Beverage, instant breakfast powder, chocolate, sugar-free, not reconstituted","Dairy and Egg Products",35.8,0.5,0.717,2,0.138,1.705,41,39,5.1,7.4,358,2.162,1.189,1.027,27482
"Beverage, milkshake mix, dry, not chocolate","Dairy and Egg Products",23.5,0.88,0.78,1.6,0.0012,2.2,52.9,51.3,2.6,12.8,329,2.059,0.332,0.06,27483
"Butter oil, anhydrous","Dairy and Egg Products",0.28,0.004,0.002,,0,0.005,,,99.48,0.24,876,61.924,28.732,3.694,27484
"Butter, salted","Dairy and Egg Products",0.85,0.024,0.714,,0,0.024,0.06,0.06,81.11,15.87,717,51.368,21.021,3.043,27485
"Butter, whipped, with salt","Dairy and Egg Products",0.85,0.024,0.827,,0,0.026,0.06,0.06,81.11,15.87,717,50.489,23.426,3.012,27486
"Butter, without salt","Dairy and Egg Products",0.85,0.024,0.011,,0,0.024,0.06,0.06,81.11,17.94,717,51.368,21.021,3.043,27487
"Cheese fondue","Dairy and Egg Products",14.23,0.476,0.132,,0,0.105,3.77,,13.47,61.61,229,8.721,3.563,0.484,27488
"Cheese food, cold pack, american","Dairy and Egg Products",19.66,0.497,0.966,,0,0.363,8.32,,24.46,43.12,331,15.355,7.165,0.719,27489
"Cheese food, imitation","Dairy and Egg Products",22.4,0.552,1.239,,0,0.336,8.8,8.21,1.3,63.8,137,0.81,0.38,0.048,27490
La segunda columna es "grupo", y este campo se usa para la clasificación de los artículos. En este ejemplo, también hay una definición del color utilizado para cada grupo:
var colors = {
"Baby Foods": [185,56,73],
"Baked Products": [37,50,75],
"Beef Products": [325,50,39],
"Beverages": [10,28,67],
"Breakfast Cereals": [271,39,57],
"Cereal Grains and Pasta": [56,58,73],
"Dairy and Egg Products": [28,100,52],
"Ethnic Foods": [41,75,61],
"Fast Foods": [60,86,61],
"Fats and Oils": [30,100,73],
"Finfish and Shellfish Products": [318,65,67],
"Fruits and Fruit Juices": [274,30,76],
"Lamb, Veal, and Game Products": [20,49,49],
"Legumes and Legume Products": [334,80,84],
"Meals, Entrees, and Sidedishes": [185,80,45],
"Nut and Seed Products": [10,30,42],
"Pork Products": [339,60,49],
"Poultry Products": [359,69,49],
"Restaurant Foods": [204,70,41],
"Sausages and Luncheon Meats": [1,100,79],
"Snacks": [189,57,75],
"Soups, Sauces, and Gravies": [110,57,70],
"Spices and Herbs": [214,55,79],
"Sweets": [339,60,75],
"Vegetables and Vegetable Products": [120,56,40]
};
La función que crea la lista "Grupos de alimentos" en el medio del diagrama es create_legend ():
function create_legend(colors,brush) {
// create legend
var legend_data = d3.select("#legend")
.html("")
.selectAll(".row")
.data( _.keys(colors).sort() )
// filter by group
var legend = legend_data
.enter().append("div")
.attr("title", "Hide group")
.on("click", function(d) {
// toggle food group
if (_.contains(excluded_groups, d)) {
d3.select(this).attr("title", "Hide group")
excluded_groups = _.difference(excluded_groups,[d]);
brush();
} else {
d3.select(this).attr("title", "Show group")
excluded_groups.push(d);
brush();
}
});
legend
.append("span")
.style("background", function(d,i) { return color(d,0.85)})
.attr("class", "color-bar");
legend
.append("span")
.attr("class", "tally")
.text(function(d,i) { return 0});
legend
.append("span")
.text(function(d,i) { return " " + d});
return legend;
}
Como puede ver, la lista se implementa como una serie de divs, que tienen información sobre herramientas "Mostrar grupo" u "Ocultar grupo" dependiendo de si el grupo en cuestión está en la lista "excluidos_grupos". Además, el evento "onclick" elimina el grupo en cuestión o lo agrega a la lista "excluded_groups". En el código que vuelve a dibujar coordenadas paralelas, la lista "excluidos_grupos" se usa para filtrar. Haz lo similar en tu código. Eso es todo.
Este ejemplo usa underscore.js para varios propósitos, si no lo desea, puede necesitar reescribir y ajustar algunas porciones de código.