How to select individual rows in a D3 table - d3.js

Currently learning D3 and I'm a bit confused with tables. I was able to find this code in the internet which creates a simple HTML table:
function tabulate(data, columns) {
var table = d3.select("#container").append("table"),
thead = table.append("thead"),
tbody = table.append("tbody");
// append the header row
thead.append("tr")
.selectAll("th")
.data(columns)
.enter()
.append("th")
.text(function(column) { return column; });
// create a row for each object in the data
var rows = tbody.selectAll("tr")
.data(data)
.enter()
.append("tr");
// create a cell in each row for each column
var cells = rows.selectAll("td")
.data(function(row) {
return columns.map(function(column) {
return {column: column, value: row[column]};
});
})
.enter()
.append("td")
.text(function(d) { return d.value; });
return table;
}
And I have this as my JSON file:
[
{"name": "John", "age": 11},
{"name": "Jane", "age": 20},
{"name": "Robert", "age": 35},
{"name": "Meg", "age": 56},
{"name": "Ryan", "age": 80},
{"name": "Emma", "age": 11},
{"name": "Dale", "age": 20},
{"name": "Sam", "age": 35},
{"name": "Belle", "age": 56},
{"name": "Snow", "age": 80}
]
It's going to create a simple two-column table. Now my question is, how can I select individual rows? if I use selectAll ("tbody tr"), it will of course select all the rows. But if I use select("tbody tr"), it will only select the first one.
Please keep in mind that I'm a complete newbie at this. I learn mostly through reading and trial and error.

Related

d3 stratify - missing data field

I am using stratify to build a d3 tree from a flat data structure. However, some fields are missing when I try to call them with d.data.fieldname
Here is my data structure:
var flatData = [
{"name": "Data Encrypted", "parent": null, "category": "test", "score": null },
{"name": "Malware on Target", "parent": "Data Encrypted", "category": "test", "score": null },
{"name": "Malware executed", "parent": "Data Encrypted", "category": "test", "score": "1" },
{"name": "Files modified", "parent": "Data Encrypted", "category": "test", "score": "1" },
];
I am building the hierarchical data structure with this stratify command:
var treeData = d3.stratify()
.id(function(d) { return d.name; })
.parentId(function(d) { return d.parent; })
(flatData);
The d3 tree is displayed correctly, and I can expand / collapse nodes etc, and display the ID and Name of each node using d.data.id and d.data.name respectively. If I try and use d.data.score or d.data.category to display data I get an 'undefined' error.
Any information that can help me get past this issue would be greatly appreciated.

Using d3.js v4 - using parentId to resolve ambiguity

I am trying to understand the right usage to achieve my collapsible tree d3 but unable to establish the proper parent/child references since I cannot use "parent". Attempting to use parentID.
This is my dataset I am testing with:
var result = [
{ "id": 1, "name": "Top Level", "parent": null, "parentId": "" },
{ "id": 2, "name": "PROD", "parent": "Top Level", "parentId": 1 },
{ "id": 3, "name": "QAT", "parent": "Top Level", "parentId": 1 },
{ "id": 4, "name": "App1", "parent": "PROD", "parentId": 2 },
{ "id": 5, "name": "App1", "parent": "QAT", "parentId": 3 },
{ "id": 6, "name": "ServerPROD001", "parent": "App1", "parentId": 4 },
{ "id": 7, "name": "ServerQAT001", "parent": "App1", "parentId": 5 }
];
and based on the collapsible tree:
// convert the flat data into a hierarchy
var treeData = d3.stratify()
.id(function (d) { return d.name; })
.parentId(function (d) { return d.parent })
(result);
This works fine if I do not include items 6 and 7. If I do include these I get an ambiguity error which makes sense because it cannot determine which "App1" to associate to.
I tried changing the code to use the parentId but just get an error of "missing:1" now.
// convert the flat data into a hierarchy
var treeData = d3.stratify()
.id(function (d) { return d.name; })
.parentId(function (d) { return d.parentId })
(result);
Note - I cannot change the "App1" name values to something unique as they will exist in multiple areas with that given name.
Since you have the id that is unique and not the name:
// convert the flat data into a hierarchy
var treeData = d3.stratify()
.id(function (d) { return d.id; }) // return the id instead of the name
.parentId(function (d) { return d.parentId })
(result);
and then set the name you need to be displayed like this:
// assign the name to each node as the initial name
treeData.each(function(d) {
d.name = d.data.name;
});
A working example can be found here, based on this
:)
Good luck!

tickformat for d3.js time scale

I am using a d3.js time.scale like this:
var xScale = d3.time.scale()
.domain(d3.extent(data, function(d) { return d.date; }))
.range([0, chartWidth]);
The data is like this:
var testData = [
{
"date": "2015-04-01T00:00:00.000Z",
"value": 200.00
},
{
"date": "2015-05-01T00:00:00.000Z",
"value": 2000.00
},
{
"date": "2015-06-01T00:00:00.000Z",
"value": 4000.01
},
{
"date": "2015-07-01T00:00:00.000Z",
"value": 1000.00
},
{
"date": "2015-08-01T00:00:00.000Z",
"value": 750.00
},
{
"date": "2015-09-01T00:00:00.000Z",
"value": 1568.00
},
{
"date": "2015-10-01T00:00:00.000Z",
"value": 3789.00
},
{
"date": "2015-11-01T00:00:00.000Z",
"value": 5678.00
},
{
"date": "2015-12-01T00:00:00.000Z",
"value": 4898.00
},
{
"date": "2016-01-01T00:00:00.000Z",
"value": 9002.00
},
{
"date": "2016-02-01T00:00:00.000Z",
"value": 3320.00
},
{
"date": "2016-03-01T00:00:00.000Z",
"value": 12000.00
}
];
But the ticks and the ordering are not as I would expect:
I would expect the ticks to be ordered from april 2015 to march 2016 and I do not understand where the 2016 tick is coming from.
How can I order the ticks as I would expect and also where is the 2016 tick coming from?
Here is a jsbin that shows the problem
If you want the ticks to show the month name and the year, add this to the axis:
.tickFormat(d3.time.format("%B %Y"));
Alternatively, you can display the abbreviated month name:
.tickFormat(d3.time.format("%b %Y"));
Here is the updated jsbin: http://jsbin.com/wikafuluqu/1/edit?js,output
PS: To show the first tick, add nice() to the scale. This is the jsbin with nice():
http://jsbin.com/loyupelazu/1/edit?js,output

amCharts, non-numeric yaxis and dates

I want to plot a graph between place and time. Y-axis will show 5 countries (USA, UK, Canada, France, Germany) and X-axis will show the time. The data is in pairs of (date, place). I am trying to display it by replacing the numeric values of Y-Y-axis with strings but no luck. Any simple working example will be helpful.
The value axis' labelFunction would be perfect for this task. With it, you can define a custom function that would be called for each label, which in turn could replace the number with a string. I.e.:
"valueAxes": [{
// other value axis settings
// ...
"labelFunction": function(value) {
var labels = {
"1": "USA",
"2": "UK",
"3": "Canada",
"4": "France",
"5": "Germany"
};
return labels[value] || "";
}
}]
Another option that you have is to disable value axis labels altogether ("labelsEnabled": false) and using guides to place country labels at specific values. I.e.:
"valueAxes": [{
"labelsEnabled": false,
"guides": [{
"value": 1,
"label": "USA"
}, {
"value": 2,
"label": "UK"
}, {
"value": 3,
"label": "Canada"
}, {
"value": 4,
"label": "France"
}, {
"value": 5,
"label": "Germany"
}]
}]
Whichever works for your purposes better, or seems easier.

How to use nest and rollup functions in D3 to create a bar chart

I'm new to D3 and struggling understand the nest function. I'm trying to get it working to produce a bar chart that will have three different bars for the years '2013', '2014' and '2015' and the length of each bar to be the number of entries for that year.
I've looked at lots of examples, but I'm missing some of the steps. I'd like to know how to view / troubleshoot what nest does to my data (listing keys and values etc.) And I'd also like to know how to utilise the data in a simple bar chart (what data do I call and what do I return for 'height' etc.)
I have made a fiddle here http://jsfiddle.net/hellococomo/zz81pwkm/4/ but can't figure out why I can't get any height on the bars. I'd really appreciate any help.
This is my example code:
var fruit = [
{"name": "Apple", "year": 2013, "win": "1"},
{"name": "Banana", "year": 2013, "win": "1"},
{"name": "Orange", "year": 2013, "win": "1"},
{"name": "Grapefruit", "year": 2013, "win": "0"},
{"name": "Grape", "year": 2014, "win": "0"},
{"name": "Pineapple", "year": 2014, "win": "1"},
{"name": "Melon", "year": 2014, "win": "1"},
{"name": "Grape", "year": 2014, "win": "1"},
{"name": "Pineapple", "year": 2014, "win": "1"},
{"name": "Pineapple", "year": 2015, "win": "1"},
];
data = d3.nest()
.key(function(d){ return d.year }) // `GROUP BY date`
.rollup(function(values){
// `values` is all the rows of a particular date
var counts = {}, keys = ['name', 'win']
keys.forEach(function(key){
counts[key] = d3.sum(values, function(d){ return d[key] })
})
return counts
})
.entries(fruit)
var svg =
d3.select('svg g')
.selectAll('rect')
.data(data)
.enter();
svg.append('rect')
.attr('x', function(d, i) {return i * 60 })
.attr('y', 50)
.attr('width', 50)
.attr('height', function(d) { return d['win'] })
.style('fill', 'steelblue');
Check this out: http://jsfiddle.net/yojm65nk/7/
.rollup(function(values){
// `values` is all the rows of a particular date
var counts = {}; var keys = ['name', 'win']
values.forEach(function(d){
for (var i = 0; i<keys.length; i++) {
counts[keys[i]] = d3.sum(values, function(d){ return d[keys[i]] })
}
Basically in your nest function, especially in your roll up you need to iterate through the data to expose your data variables. Once you have that you can draw you bar graph accordingly.
If you log the value of each of the Objects in your data (for example, using the Console in Chrome), you'll see that the Objects do not have a "win" property.
{"key":"2013","values":{"name":0,"win":3}}
As a result, the height of the <rect>s is not being set correctly (all of them are being set to null).
However, you can also see that you can access the "win" property of your data through the "values" Object:
.attr('height', function(d) { return d.values.win }) // <---- access .values first!
which will set the "height" according to the "wins" value in fruit.

Resources