我正在通過嵌套.csv文件構建分組條形圖。圖表也可以作爲折線圖查看,所以我想要一個適合線對象的嵌套結構。我原來的.csv看起來是這樣的:d3訪問分組條形圖中的嵌套數據
Month,Actual,Forecast,Budget
Jul-14,200000,-,74073.86651
Aug-14,198426.57,-,155530.2499
Sep-14,290681.62,-,220881.4631
Oct-14,362974.9,-,314506.6437
Nov-14,397662.09,-,382407.67
Dec-14,512434.27,-,442192.1932
Jan-15,511470.25,511470.25,495847.6137
Feb-15,-,536472.5467,520849.9105
Mar-15,-,612579.9047,596957.2684
Apr-15,-,680936.5086,465313.8723
May-15,-,755526.7173,739904.081
Jun-15,-,811512.772,895890.1357
,我的嵌套是這樣的:
d3.csv("data/net.csv", function(error, data) {
if (error) throw error;
var headers = d3.keys(data[0]).filter(function(head) {
return head != "Month";
});
data.forEach(function(d) {
d.month = parseDate(d.Month);
});
var categories = headers.map(function(name) {
return {
name: name, // "name": the csv headers except month
values: data.map(function(d) {
return {
date: d.month,
rate: +(d[name]),
};
}),
};
});
的代碼來構建我的圖表是:
var bars = svg.selectAll(".barGroup")
.data(data) // Select nested data and append to new svg group elements
.enter()
.append("g")
.attr("class", "barGroup")
.attr("transform", function (d) { return "translate(" + xScale(d.month) + ",0)"; });
bars.selectAll("rect")
.data(categories)
.enter()
.append("rect")
.attr("width", barWidth)
.attr("x", function (d, i) { if (i < 2) {return 0;} else {return xScale.rangeBand()/2;}})
.attr("y", function (d) { return yScale(d.rate); })
.attr("height", function (d) { return h - yScale(d.rate); })
.attr("class", function (d) { return lineClass(d.name); });
的摹元的罰款和單個條形圖正在映射到它們,並正確應用了x值和類。
我的問題是訪問數據的'rate'的高度和y值的酒吧。在上面的表格中給出了一個NaN。我已經使用類別數據附加g ^元素,然後追加rects用也試過:
.data(function(d) { return d.values })
這讓我訪問率數據,但所有36條映射到每個rangeBands的。
它也可以在平坦的數據結構中正常工作,但我似乎無法在嵌套兩個級別時使用它,儘管查看了大量示例和SO問題。
如何訪問費率數據?
針對西里爾的要求,這裏的全碼:
var margin = {top: 20, right: 18, bottom: 80, left: 50},
w = parseInt(d3.select("#bill").style("width")) - margin.left - margin.right,
h = parseInt(d3.select("#bill").style("height")) - margin.top - margin.bottom;
var customTimeFormat = d3.time.format.multi([
[".%L", function(d) { return d.getMilliseconds(); }],
[":%S", function(d) { return d.getSeconds(); }],
["%I:%M", function(d) { return d.getMinutes(); }],
["%I %p", function(d) { return d.getHours(); }],
["%a %d", function(d) { return d.getDay() && d.getDate() != 1; }],
["%b %d", function(d) { return d.getDate() != 1; }],
["%b", function(d) { return d.getMonth(); }],
["%Y", function() { return true; }]
]);
var parseDate = d3.time.format("%b-%y").parse;
var displayDate = d3.time.format("%b %Y");
var xScale = d3.scale.ordinal()
.rangeRoundBands([0, w], .1);
var xScale1 = d3.scale.linear()
.domain([0, 2]);
var yScale = d3.scale.linear()
.range([h, 0])
.nice();
var xAxis = d3.svg.axis()
.scale(xScale)
.tickFormat(customTimeFormat)
.orient("bottom");
var yAxis = d3.svg.axis()
.scale(yScale)
.orient("left")
.innerTickSize(-w)
.outerTickSize(0);
var svg = d3.select("#svgCont")
.attr("width", w + margin.left + margin.right)
.attr("height", h + margin.top + margin.bottom)
.append("g")
.attr("transform", "translate(" + margin.left + "," + margin.top + ")");
var thous = d3.format(",.0f")
var lineClass = d3.scale.ordinal().range(["actual", "forecast", "budget"]);
var tip = d3.tip()
.attr('class', 'd3-tip')
.offset([-10, 0])
.html(function(d) {
return "<p id='date'>" + displayDate(d.date) + "</p><p id='value'>$" + thous(d.rate);
})
d3.csv("data/net.csv", function(error, data) {
if (error) throw error;
var headers = d3.keys(data[0]).filter(function(head) {
return head != "Month";
});
data.forEach(function(d) {
d.month = parseDate(d.Month);
});
var categories = headers.map(function(name) {
return {
name: name,
values: data.map(function(d) {
return {
date: d.month,
rate: +(d[name]),
};
}),
};
});
var min = d3.min(categories, function(d) {
return d3.min(d.values, function(d) {
return d.rate;
});
});
var max = d3.max(categories, function(d) {
return d3.max(d.values, function(d) {
return d.rate;
});
});
var minY = min < 0 ? min * 1.2 : min * 0.8;
xScale.domain(data.map(function(d) { return d.month; }));
yScale.domain([minY, (max * 1.1)]);
var barWidth = headers.length > 2 ? xScale.rangeBand()/2 : xScale.rangeBand() ;
svg.call(tip);
svg.append("g")
.attr("class", "x axis")
.attr("transform", "translate(0," + h + ")")
.call(xAxis);
svg.append("g")
.attr("class", "y axis")
.call(yAxis);
var bars = svg.selectAll(".barGroup")
.data(data)
.enter()
.append("g")
.attr("class", "barGroup")
.attr("transform", function (d) { return "translate(" + xScale(d.month) + ",0)"; });
bars.selectAll("rect")
.data(categories)
.enter()
.append("rect")
.attr("width", barWidth)
.attr("x", function (d, i) { if (i < 2) {return 0;} else {return xScale.rangeBand()/2;}})
.attr("y", function (d) { return yScale(d.rate); })
.attr("height", function (d) { return h - yScale(d.rate); })
.attr("class", function (d) { return lineClass(d.name) + " bar"; });
var legend = svg.selectAll(".legend")
.data(headers)
.enter()
.append("g")
.attr("class", "legend");
legend.append("line")
.attr("class", function(d) { return lineClass(d); })
.attr("x1", 0)
.attr("x2", 40)
.attr("y1", function(d, i) { return (h + 30) + (i *14); })
.attr("y2", function(d, i) { return (h + 30) + (i *14); });
legend.append("text")
.attr("x", 50)
.attr("y", function(d, i) { return (h + 32) + (i *14); })
.text(function(d) { return d; });
svg.selectAll(".bar")
.on('mouseover', tip.show)
.on('mouseout', tip.hide);
});
更新2月18日'16。
看來我還沒有解釋我試圖做得足夠好。圖表的線條和條形版本將分開顯示,即用戶可以根據輸入的select元素查看其中的一個。另外請注意,我最初無法控制數據的輸入方式。
我a version of exactly how it should work here.
當我還是通過它的工作這有人提出疑問,但我從來沒有解決這個問題 - 我用做數據的兩個獨立的巢一種解決方法。
你可以發佈你的完整代碼..我認爲是有一個問題與yscale。 – Cyril
嗨西里爾, 我會後在某一時刻的全部代碼,但我相信它不是問題yScale。我已經通過將一個數字放在d.rate的地方進行了檢查,並且在嵌套數據處於更平坦的格式時,它也可以工作。規模在下面。 var yScale = d3.scale.linear()。range([h,0]).nice(); – tgerard
@tgerard確認 - 是否需要一個分組條形圖,其中日期爲x軸,值爲y軸?如果是這樣,目前還不清楚你打算如何使用類別對象。所提供的代碼查看d.rate的類別對象。但類別對象的形狀爲:{name:「Actual」,值:[{date:「」,rate:0}]}。所以它不會有屬性d.rate。你能確認你想要建立的是什麼,我可以建議如何最好地解決它? –