Bir .csv dosyası yerleştirerek gruplandırılmış bir çubuk grafik yapıyorum. Grafik ayrıca bir çizgi grafik olarak görülebilir, bu yüzden çizgi nesnesine uyan bir yuvalama yapısı istiyorum.d3 Gruplandırılmış çubuk grafikte iç içe geçmiş verilere erişme
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
ve benim yuvalama şu şekildedir:: My orijinal .csv şöyle Çizelgemi inşa etmek
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]),
};
}),
};
});
kodudur:
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); });
gr elemanları ince ve Tek tek çubuklar, x değeri ve sınıf doğru şekilde uygulandığında, onlara eşlenir.
Sorunum, çubukların yükseklik ve y değeri için 'oran' verilerine erişmeye geliyor. Yukarıdaki formda bir NaN verir. Ben de birlikte rects gr öğelerini eklemeniz kategori verilerini kullanarak ve daha sonra ekleme denedim:
.data(function(d) { return d.values })
Bu bana oran verilere erişmek için izin verir, fakat rangeBands her birine 36 bar eşler.
Ayrıca, daha düz bir veri yapısında gayet iyi çalışıyor, ancak çok sayıda örnek ve SO sorularına bakmasına rağmen, iki seviye aşağı yuvalandığında onu kullanamıyorum.
Ücret verisine nasıl erişirim?
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);
});
Güncelleme 18 Şubat '16: Cyril'ın talebine yanıt olarak
, burada tam kod.
Yeterince iyi yapmaya çalıştığım şeyi açıklamamışım gibi görünüyor. Çizelgenin çizgi ve çubuk versiyonları ayrı olarak görülecektir, yani kullanıcılar bir seçime göre girdiye göre birini görebilirler. Ayrıca, başlangıçta verilerin nasıl geldiğine dair kontrolüm olmadığını da unutmayın.
Ben a version of exactly how it should work here.
Bu soru hala içinden çalışırken kaldırdı ama sorunu çözüldü asla - Ben verinin iki ayrı yuvalar yapmanın bir geçici çözüm kullanılır.
bars.selectAll("rect").data(categories)
Bildiğim kadarıyla gördüğünüz gibi kategorilerde (çalışan bir demo whithout):
Tam kodunuzu gönderirsiniz ... yscale ile ilgili bir sorun olduğunu düşünün. – Cyril
Merhaba Cyril, birazdan tam kod göndeririz, ama söz konusu yScale değil eminim. Ben d.rate yerine bir sayı koyarak kontrol ettik ve ben de iç içe geçmiş veri daha düz bir biçimde olduğunda çalıştım. Ölçek aşağıdadır. var yScale = d3.scale.linear(). Aralığı ([h, 0]) .nice(); – tgerard
@tgerard onaylamak için - Eğer y ekseni olarak x ekseni olarak tarih ve değerlere sahip bir gruplandırılmış çubuk grafik istiyorsun? Öyleyse, kategoriler nesnesini nasıl kullanmayı planladığınız belli değildir. Sağlanan kod, d.rate için kategoriler nesnesine bakmaktır. Ancak kategoriler nesnesi şu şekildedir: {name: "Gerçek", değerler: [{date: "", rate: 0}]}. Yani mülkün üzerinde durmayacak. Oluşturmaya çalıştığınız şeyi doğrulayabilir misiniz ve bunu en iyi nasıl çözeceğimize dair tavsiyede bulunabilir miyim? –