У меня есть файл data.csv
сделанный таким образом:
CODE,YEAR,MODALITY,VALUE
AB,2000,first,15
AB,2000,second,
AB,2000,third,33
AB,2001,first,20
AB,2001,second,25
AB,2001,third,87
AB,2002,first,6
AB,2002,second,
AB,2002,third,16
AB,2003,first,50
AB,2003,second,50
AB,2003,third,10
AB,2004,first,20
AB,2004,second,55
AB,2004,third,8
AC,2000,first,
AC,2000,second,97
AC,2000,third,77
AC,2001,first,42
AC,2001,second,5
AC,2001,third,81
AC,2002,first,
AC,2002,second,63
AC,2002,third,14
AC,2003,first,5
AC,2003,second,7
AC,2003,third,0
AC,2004,first,5
AC,2004,second,7
AC,2004,third,0
AD,2000,first,11
AD,2000,second,2
AD,2000,third,36
AD,2001,first,95
AD,2001,second,78
AD,2001,third,88
AD,2002,first,89
AD,2002,second,32
AD,2002,third,79
AD,2003,first,5
AD,2003,second,32
AD,2003,third,9
AD,2004,first,7
AD,2004,second,32
AD,2004,third,91
AE,2000,first,15
AE,2000,second,78
AE,2000,third,1
AE,2001,first,5
AE,2001,second,2
AE,2001,third,64
AE,2002,first,44
AE,2002,second,51
AE,2002,third,
AE,2003,first,40
AE,2003,second,52
AE,2003,third,85
AE,2004,first,45
AE,2004,second,50
AE,2004,third,80
Я создал файл index.html
состоящий из некоторых выбираемых пользователем элементов (в примере для простоты я выбрал 4 круга с кодами AB, AC, AD или AE) и 3 переключателя (первый, второй и третий).
Пользователь может выбрать один или несколько кругов, а также выбрать переключатель.
Поэтому у меня есть codes
массивов, которые содержат коды выбранных кругов и переменную modalitySelected
которая содержит выбранную радиокнопку.
То, что я хотел бы сделать, это линейная диаграмма, представляющая данные на основе выбора, сделанного пользователем.
Пример:
Для каждого выбранного кода есть строка, и значения соответствуют тем, которые соответствуют выбранному переключателю.
В этом примере есть некоторые недостающие данные, и пунктирная линия именно это. (Пока это не важно представлять).
Это мой код. Вначале управляется выбор окружностей и создается массив codes
который содержит коды выбранных элементов. Затем создается линейная диаграмма.
index.html:
<body>
<div id="circles">
<svg>
<circle id="AB" cx="10" cy="10" r="10" fill="purple" />
<circle id="AC" cx="60" cy="60" r="5" fill="red" />
<circle id="AD" cx="110" cy="110" r="15" fill="orange" />
<circle id="AE" cx="90" cy="50" r="7" fill="yellow" />
</svg>
</div>
<button type="button" id="finalSelection">Finish</button>
<span style="display:block;margin-top: 10px;">Selected codes: <span class="values"></span></span><br>
<div id="modality-selector-container">
<form id="modality-selector">
<input type="radio" name="modality-selector" id="rb-first" value="first" checked />
<label for="rb-first">First</label>
<input type="radio" name="modality-selector" id="rb-second" value="second" />
<label for="rb-second">Second</label>
<input type="radio" name="modality-selector" id="rb-third" value="third" />
<label for="rb-third">Third</label>
</form>
</div>
<div id="line-chart-container"></div>
<script src="./script.js"></script>
</body>
script.js:
var codes = [];
modalitySelected = document.querySelector('input[name=modality-selector]:checked').value;
var filtered_data = null;
// set the dimensions and margins of the graph
var margin = {top: 20, right: 20, bottom: 30, left: 50};
var width = 600 - margin.left - margin.right;
var height = 400 - margin.top - margin.bottom;
// set the ranges
var x = d3.scaleTime().range([0, width]);
var y = d3.scaleLinear().range([height, 0]);
// parse the date/time
var parseTime = d3.timeParse("%Y");
var svg = null;
var valueline = null;
d3.selectAll('#circles svg circle').on('click', function() {
var id = d3.select(this).attr('id');
if(d3.select(this).classed('clicked')) {
d3.select(this).classed('clicked', false).style('stroke', null);
codes.splice(codes.indexOf(id), 1);
}
else {
if(codes.length) {
if(d3.event.ctrlKey) {
d3.select(this).classed('clicked', true).style('stroke', 'blue');
codes.push(id);
}
else {
d3.selectAll(".clicked").classed('clicked', false).style('stroke', null);
codes = [];
d3.select(this).classed('clicked', true).style('stroke', 'blue');
codes.push(id);
}
}
else {
d3.select(this).classed('clicked', true).style('stroke', 'blue');
codes.push(id);
}
}
$('span.values').html(codes.join(', '));
});
$('button#finalSelection').click(function() {
$('span.values').html(codes.join(', '));
console.log("compare: " + codes);
compareCodes();
});
function compareCodes() {
// define the line
valueline = d3.line()
.x(function(d) {
return x(d.YEAR);
})
.y(function(d) {
return y(d.VALUE);
});
// append the svg obgect to the body of the page
// appends a 'group' element to 'svg'
// moves the 'group' element to the top left margin
svg = d3.select("#line-chart-container").append("svg")
.attr("width", width + margin.left + margin.right)
.attr("height", height + margin.top + margin.bottom)
.append("g")
.attr("transform", "translate(" + margin.left + "," + margin.top + ")");
getData();
}
function getData() {
d3.queue()
.defer(d3.csv, './data.csv')
.await(makeLineChart);
}
function makeLineChart(error, data) {
if(error) {
console.log(error);
}
// radio button change
d3.selectAll("input[name='modality-selector']")
.on("change", function(){
console.log(this.value);
modalitySelected = this.value;
// filter data
filtered_data = data.filter(function(d) {
return d.MODALITY == modalitySelected && d.CODE == codes[0];
});
// format the data
filtered_data.forEach(function(d) {
d.YEAR = parseTime(d.YEAR);
d.VALUE = +d.VALUE;
});
updateGraph(filtered_data);
}); // end radio on change
// generate initial line chart - filter data
filtered_data = data.filter(function(d) {
return d.MODALITY == modalitySelected && d.CODE == codes[0];
});
updateGraph(filtered_data);
}
function updateGraph(data) {
var numTickXaxis = data.length;
// scale the range of the data
x.domain(d3.extent(filtered_data, function(d) {
return d.YEAR;
}));
y.domain([0, d3.max(filtered_data, function(d) {
return d.VALUE;
})]);
// add the valueline path
svg.append("path")
.data([filtered_data])
.attr("class", "line")
.attr("d", valueline);
// add the X Axis
svg.append("g")
.attr("class", "axis")
.attr("transform", "translate(0," + height + ")")
.call(d3.axisBottom(x)
.tickFormat(d3.timeFormat("%Y"))
.ticks(numTickXaxis))
.selectAll("text")
.style("text-anchor", "end")
.attr("dx", "-.8em")
.attr("dy", ".15em")
.attr("transform", "rotate(-65)");
// add the Y Axis
svg.append("g")
.attr("class", "axis")
.call(d3.axisLeft(y));
var state = svg.selectAll(".line");
state.exit().remove();
}
Полный код ЗДЕСЬ.
В этом коде есть две проблемы:
state.exit().remove();
)codes
. Я не знаю, как обрабатывать случай, когда codes
состоят из нескольких элементов и показывают больше строк. Я могу рассмотреть идею изменения структуры data.csv
сохраняющей один и тот же контент. Например, я мог бы редактировать файл следующим образом:
CODE,YEAR,FIRST,SECOND,THIRD
AB,2000,15,50,33
AB,2001,20,25,87
AB,2002,6,,16
AB,2003,50,50,10
AB,2004,20,55,8
AC,2000,,97,77
AC,2001,42,5,81
AC,2002,,63,14
AC,2003,5,7,0
AC,2004,5,7,0
AD,2000,11,2,36
AD,2001,95,78,88
AD,2002,89,32,79
AD,2003,5,32,9
AD,2004,7,32,91
AE,2000,15,78,1
AE,2001,5,2,64
AE,2002,44,51,
AE,2003,40,52,85
AE,2004,45,50,80
Кто-нибудь знает, как мне помочь? Спасибо!
Следуя этому примеру, я смог решить проблему.
ЗДЕСЬ код.
Теперь у меня есть небольшая (я надеюсь) графическая проблема. На этой картине мы можем четко видеть, в чем проблема.
Линии начинаются перед осями. Зачем?
Проблема заключалась в том, что "transform", "translate("
в вашем createAxis()
переместило вашу ось в сторону.
Поэтому я добавил
.append("g")
.attr("transform", "translate(" + margin.left + "," + margin.top + ")");
Для вашей исходной переменной svg
чтобы она совпадала с осью и удалила
.attr("transform", "translate(" + 0 + "," + 0 + ")");
Из createAxis()
Здесь ссылка: Plunker