#javascript #arrays #d3.js #bar-chart
#javascript #массивы #d3.js #столбчатая диаграмма
Вопрос:
Я нигде не могу найти пример этого, и я потратил недели (включительно), пытаясь разобраться в этом. Проще говоря, я хочу отобразить данные в виде графика в виде стека с ‘x’ в качестве даты и ‘y’ в качестве числового значения, используя D3js. Я смог заставить работать только стек, и я смог заставить работать столбчатую диаграмму, но их объединение стало головной болью.
Моя последняя итерация использует этот пример здесь [http://chimera.labs.oreilly.com/books/1230000000345/ch11.html#_stack_layout ] и сокращает его до самого простого, что только может быть. Все, кроме самих данных (и, я думаю, цветов), жестко запрограммировано, чтобы устранить как можно больше проблем. Ниже приведен исходный ‘dataset’ и мои различные итерации моих собственных наборов данных, пытающихся обнаружить корень проблемы. В какой-то момент у меня был правильный график (см. Ссылку JSBin ниже), за исключением того, что он не укладывался должным образом. Кажется, что x и y подавались для построения графика, но y0 не был установлен. Ошибки out были минимальными и никоим образом не помогли.
JSBin к графику без правильной укладки: http://jsbin.com/bekanowo/1/edit
var dataset = [
[
{ x: 0, y: 5 },
{ x: 1, y: 4 },
{ x: 2, y: 2 },
{ x: 3, y: 7 },
{ x: 4, y: 23 }
],
[
{ x: 0, y: 10 },
{ x: 1, y: 12 },
{ x: 2, y: 19 },
{ x: 3, y: 23 },
{ x: 4, y: 17 }
],
[
{ x: 0, y: 22 },
{ x: 1, y: 28 },
{ x: 2, y: 32 },
{ x: 3, y: 35 },
{ x: 4, y: 43 }
]
];
var backupArray = [
[{y: 50, x: 2014-06-15},{y: 40, x: 2014-06-16},{y: 30, x: 2014-06-18}],[{y: 30, x: 2014-06-19}],
[{y: 35, x: 2014-06-17}],
[{y: 45, x: 2014-06-15}],
[{y: 85, x: 2014-06-19},{y: 65, x: 2014-06-20},{y: 75, x: 2014-06-21},{y: 60, x: 2014-06-22}]
];
var staticArray = [
[{date: "2014-06-15", value: 50},{date: "2014-06-16", value: 40},{date: "2014-06-18", value: 30}],
[{date: "2014-06-15", value: 30}],
[{date: "2014-06-17", value: 35}],
[{date: "2014-06-15", value: 45}],
[{date: "2014-06-19", value: 85},{date: "2014-06-20", value: 65},{date: "2014-06-21", value: 75},{date: "2014-06-22", value: 60}]
];
parseDate = d3.time.format("%Y-%m-%d").parse
var staticArray2 = [
{ category: "test1", values: [{date: parseDate("2014-06-15"), value: 50},{date: parseDate("2014-06-16"), value: 40},{date: parseDate("2014-06-18"), value: 30}] },
{ category: "test1", values: [{date: parseDate("2014-06-15"), value: 30}] },
{ category: "test1", values: [{date: parseDate("2014-06-17"), value: 35}] },
{ category: "test1", values: [{date: parseDate("2014-06-15"), value: 45}] },
{ category: "test1", values: [{date: parseDate("2014-06-19"), value: 85},{date: parseDate("2014-06-20"), value: 65},{date: parseDate("2014-06-21"), value: 75},{date: parseDate("2014-06-22"), value: 60}] }
];
var staticArray3 = [
{ name: "test1", values: [{x: parseDate("2014-06-15"), y: 50},{x: parseDate("2014-06-16"), y: 40},{x: parseDate("2014-06-18"), y: 30}] },
{ name: "test2", values: [{x: parseDate("2014-06-15"), y: 30}] },
{ name: "test3", values: [{x: parseDate("2014-06-17"), y: 35}] },
{ name: "test4", values: [{x: parseDate("2014-06-15"), y: 45}] },
{ name: "test5", values: [{x: parseDate("2014-06-19"), y: 85},{x: parseDate("2014-06-20"), y: 65},{x: parseDate("2014-06-21"), y: 75},{x: parseDate("2014-06-22"), y: 60}] }
];
Ниже приведен исходный код (без наборов данных). Я не хотел терять ни один из своих образцов таблиц данных, поэтому я просто оставил их в том виде, в каком я выполнял итерации по тестам, и просто установил текущий массив в несколько строк.
<script type="text/javascript">
//Width and height
var w = 500;
var h = 300;
//set test array
var dataset = staticArray3;
//Set up stack method
var stack = d3.layout.stack()
.offset("zero")
.y(function(d) { return d.values; });
//Set up scales
var xScale = d3.time.scale()
.domain([parseDate("2014-06-15"), d3.time.day.offset(parseDate("2014-06-22"), 1)])
.rangeRound([0, w], 0.05);
var yScale = d3.scale.linear()
.domain([0,100])
.range([0, h]);
//Easy colors accessible via a 10-step ordinal scale
var colors = d3.scale.category10();
//Create SVG element
var svg = d3.select("body")
.append("svg")
.attr("width", w)
.attr("height", h);
// Add a group for each row of data
var groups = svg.selectAll("g")
.data(stack(dataset))
.enter()
.append("g")
.style("fill", function(d, i) { return colors(i); });
// Add a rect for each data value
var rects = groups.selectAll("rect")
.data(function(d) { return d; })
.enter()
.append("rect")
.attr("x", function(d) { return xScale(d.date); })
.attr("y", function(d) { return yScale(d.y0); })
.attr("height", function(d) { return yScale(d.value); })
.attr("width", 60);
</script>
Ответ №1:
проблема может заключаться в том, что вы неправильно используете макет стека, из-за чего ваш набор данных остается без y0. причина, по которой это, похоже, работает, заключается в том, что ваш код рисует прямоугольники, начиная с отсутствующего y0 и заканчивая высотой ваших значений.
во-первых, вы должны попытаться получить согласованный набор данных, что означает, что каждый массив должен содержать все даты, просто установите отсутствующие значения равными нулю. и, похоже, вам нужно изменить «значение» на «y»:
var staticArray2 = [
[{date: parseDate("2014-06-15"), y: 50},{date: parseDate("2014-06-16"), y: 40},{date: parseDate("2014-06-17"), y: 0},{date: parseDate("2014-06-18"), y: 30},{date: parseDate("2014-06-19"), y: 0},{date: parseDate("2014-06-20"), y: 0},{date: parseDate("2014-06-21"), y: 0},{date: parseDate("2014-06-22"), y: 0}],
[{date: parseDate("2014-06-15"), y: 30},{date: parseDate("2014-06-16"), y: 0},{date: parseDate("2014-06-17"), y: 0},{date: parseDate("2014-06-18"), y: 0},{date: parseDate("2014-06-19"), y: 0},{date: parseDate("2014-06-20"), y: 0},{date: parseDate("2014-06-21"), y: 0},{date: parseDate("2014-06-22"), y: 0}],
[{date: parseDate("2014-06-15"), y: 0},{date: parseDate("2014-06-16"), y: 0},{date: parseDate("2014-06-17"), y: 35},{date: parseDate("2014-06-18"), y: 0},{date: parseDate("2014-06-19"), y: 0},{date: parseDate("2014-06-20"), y: 0},{date: parseDate("2014-06-21"), y: 0},{date: parseDate("2014-06-22"), y: 0}],
[{date: parseDate("2014-06-15"), y: 45},{date: parseDate("2014-06-16"), y: 0},{date: parseDate("2014-06-17"), y: 0},{date: parseDate("2014-06-18"), y: 0},{date: parseDate("2014-06-19"), y: 0},{date: parseDate("2014-06-20"), y: 0},{date: parseDate("2014-06-21"), y: 0},{date: parseDate("2014-06-22"), y: 0}],
[{date: parseDate("2014-06-15"), y: 0},{date: parseDate("2014-06-16"), y: 0},{date: parseDate("2014-06-17"), y: 0},{date: parseDate("2014-06-18"), y: 0},{date: parseDate("2014-06-19"), y: 85},{date: parseDate("2014-06-20"), y: 65},{date: parseDate("2014-06-21"), y: 75},{date: parseDate("2014-06-22"), y: 60}]];
затем используйте
var stack = d3.layout.stack();
var dataset = stack(staticArray2);
и, наконец, измените свой d.value
на
.attr("height", function(d) { return yScale(d.y); })
вывод может выглядеть немного странно, потому что многие из ваших значений равны нулю, поэтому некоторые стеки начинаются с базовой линии, но поскольку они не являются «стеком 0», они имеют другой — соответствующий — цвет.
смотрите jsbin здесь, я добавил наведение курсора мыши для записи значений столбцов в консоль: http://jsbin.com/bekanowo/9 /
надеюсь, это поможет.
Комментарии:
1. Большое вам спасибо! Короче говоря, стек требует, чтобы каждая дата (в данном случае) существовала, даже если значение равно 0? Есть ли какой-либо способ обойти это, поскольку кажется неуклюжим иметь массив, который потенциально содержит так много пустых данных.
2. хотя я не уверен на 10%, что я так думаю, да — это необходимо, чтобы функция могла расположить данные правильным образом. что вы могли бы сделать, так это взять исходные данные и выполнить цикл по ним, сохраняя каждую дату в массиве. затем возьмите этот массив и повторите цикл с вашими данными еще раз, и если в одном из «подмассивов» отсутствует дата, просто добавьте к нему
y:0
и дату. таким образом, вам не придется исправлять это самостоятельно.