问题
I have some data that I want to visualize them using parallel coordinates.
My data consists of 200 rows (cases) and 100 columns (features). I just need to visualize some part of data (200x8), including feature1, feature2, ..., feature8. Also I have 4 columns of data (A, B, C and D) that their values are either 0 or 1. For example if the value of column A for one case(row) is 1, it means that case of data is type A.
I already have the code for plotting parallel coordinates :
<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>
Now, I want to add 4 check box that the user can select which types he/she wants to see in parallel coordinates. For example, if the user checks A-type, that cases (rows) with value of 1 in their A column should be visualized.
How should I do that?
I would really appreciate any help you could provide :)
This (5x31) chunk of data is something similar to my data:
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,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,
回答1:
It is fairly hard to give you an advice or solution without knowing your data and code organization, so I will try to use someone else's similar and good example. Eventually, the solution to your question may look entirely different, but I post this answer as a guideline to you, and I hope it may help you.
Take a look at this fine example of usage of parallel coordinates: (it has the feature of selecting and deselecting groups of items - the exact feature you need)
JavaScript code for this example is here.
Data is in a csv file, and the first few lines are as follows:
"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
Second column is "group", and this field is used for item classification. In this example, there is also definition of color used for each group:
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]
};
The function that creates list "Food Groups" in the middle of the diagram is 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;
}
As you can see, the list is implemented as a series of divs, that have tooltips "Show group" or "Hide group" depending on whether the group in question is in the list "excluded_groups". Also, "onclick" event removes the group in question from or adds it to the list "excluded_groups". In the code that redraws parallel coordinates, list "excluded_groups" is used for filtering. You do the similar in your code. That is all.
This example uses underscore.js for various purposes, if you do not want this, you may need to rewrite and adjust some code portions.
来源:https://stackoverflow.com/questions/24710672/parallel-coordinates-with-check-box