Working solution: Right now I'm working on styling and on solving some of the issues regarding my problem with creating chart consisting of multiple-data series with values tracking. I will try as soon as I can to give you a sample of working code soo if anybody will came across the same or similar problem as I did, could work on it as a base. For now most of the tips which I used are in the comments below.
This will be my first question on StackOverflow and I'm looking forward to seeing what answers you might have to my problem.
Recently I got project in which I have to write Javascript code for generating charts and in which I would be able to read Y values from every line of the chart at the same time. I very new to D3 framework and by now I'm able to read csv data, create multi-series chart and track and read Y value but only when I'm creating chart from a single data series. I was trying to create multiple similar functions that would track data from diferent series of data but it won't work and in console i see that the Y is showing as null from what I can understand. I was using examples from D3 website to try to learn it and for now code will be very similar to those examples.
Later on I would need to do some other things with it but i think that after solving that problem i will be able to keep going. There will be like:
- reduce data from csv by code because I will need to delete header infromation
- change visual style of the chart and edit axis scaling
For now I have something like that. Sorry if it is a little bit messy but I'm still learning and trying a lot of different things. I have added also screenshot from what it looks like for me and some console information that i could get. I hope it will help you guys see what I'm doing wrong and what I would need to learn. Also this is not my only approach and it would be too long to show them all.
EDIT: I'm trying a little bit different approach. On the bottom of the page i will show what I have done by now.
EDIT2: Sorry if i was't precise enough about my goal. What I'm trying to do with this is I want to be able to read all Y-axis values of drawn lines (it will be 4 of them) at the same time on one X-axis value. I have added screenshot of the second code in which I'm able to read only one Y-axis value and can't read the over one.
<!DOCTYPE html>
<meta charset="utf-8">
<style>
body {
font: 10px sans-serif;
}
.axis path,
.axis line {
fill: none;
stroke: #000;
shape-rendering: crispEdges;
}
.x.axis path {
display: none;
}
.line {
fill: none;
stroke: steelblue;
stroke-width: 1.5px;
}
.overlay {
fill: none;
pointer-events: all;
}
.focus circle {
fill: none;
stroke: steelblue;
}
</style>
<body>
<script src="d3.min.js"></script>
<script>
var margin = {top: 20, right: 80, bottom: 30, left: 200},
//-margin.left
width = 960 - margin.right,
height = 750 - margin.top - margin.bottom;
var parseDate = d3.time.format("%Y-%M-%d %H:%M").parse,
//dodane do sledzenia myszy i rysowania kuleczek
bisectDate = d3.bisector(function(d) { return d.date; }).left,
formatValue = d3.format(",.2f"),
formatCurrency = function(d) { return "$" + formatValue(d); };
var x = d3.time.scale()
.range([0, width]);
var y = d3.scale.linear()
.range([height, 0]);
var color = d3.scale.category10();
var xAxis = d3.svg.axis()
.scale(x)
.orient("bottom");
var yAxis = d3.svg.axis()
.scale(y)
.orient("left");
var line = d3.svg.line()
.interpolate("basis")
.x(function(d) { return x(d.date); })
.y(function(d) { return y(d.transfers); });
var svg = d3.select("body").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 + ")");
d3.csv("data2.csv", function(error, data) {
color.domain(d3.keys(data[0]).filter(function(key) { return key !== "date"; }));
data.forEach(function(d) {
d.date = parseDate(d.date);
});
var bitrates = color.domain().map(function(name) {
return {
name: name,
values: data.map(function(d) {
return {date: d.date, transfers: +d[name]};
})
};
});
console.log(bitrates);
//data.sort(function(a, b) {
//return a.date - b.date;
//});
x.domain(d3.extent(data, function(d) { return d.date; }));
y.domain([
d3.min(bitrates, function(c) { return d3.min(c.values, function(v) { return v.transfers; }); }),
d3.max(bitrates, function(c) { return d3.max(c.values, function(v) { return v.transfers; }); })
]);
svg.append("g")
.attr("class", "x axis")
.attr("transform", "translate(0," + height + ")")
.call(xAxis);
svg.append("g")
.attr("class", "y axis")
.call(yAxis)
.append("text")
.attr("transform", "rotate(-90)")
.attr("y", 6)
.attr("dy", ".71em")
.style("text-anchor", "end")
.text("Transfers");
var chart = svg.selectAll(".chart")
.data(bitrates)
.enter().append("g")
.attr("class", "chart");
chart.append("path")
.attr("class", "line")
.attr("d", function(d) { return line(d.values); })
//.attr("d", line);
.style("stroke", function(d) { return color(d.name); });
chart.append("text")
.datum(function(d) { return {name: d.name, value: d.values[d.values.length - 1]}; })
.attr("transform", function(d) { return "translate(" + x(d.value.date) + "," + y(d.value.transfers) + ")"; })
.attr("x", 3)
.attr("dy", ".35em");
//.text(function(d) { return d.name; });
//sledzenie myszy i rysowanie kuleczek
var focus = svg.append("g")
.attr("class", "focus")
.style("display", "none");
focus.append("circle")
.attr("r", 4.5);
focus.append("text")
.attr("x", 9)
.attr("dy", ".35em");
svg.append("g").append("rect")
.attr("class", "overlay")
.attr("width", width)
.attr("height", height)
.on("mouseover", function() { focus.style("display", null); })
.on("mouseout", function() { focus.style("display", "none"); })
.on("mousemove", mousemove);
function mousemove() {
var x0 = x.invert(d3.mouse(this)[0]),
i = bisectDate(data, x0, 1),
d0 = data[i - 1],
d1 = data[i],
d = x0 - d0.date > d1.date - x0 ? d1 : d0;
focus.attr("transform", "translate(" + x(d.date) + "," + y(d.value) + ")");
focus.select("text").text(formatCurrency(d.value));
}
});
</script>
It looks like for me like this:
Generated chart
CSV data file looks like this:
date,?redni wych.:,?redni wch.:,Maks. wych.:,Maks. wch.:
2014-02-14 15:40,86518717581,101989990772,88304882317,108036052338
2014-02-14 16:00,85739038102,98312113056,87060053514,107154908503
Some over information that I inspected while trying to understand what is wrong:
[Object, Object, Object, Object]
0: Object
name: "?redni wych.:"
values: Array[504]
__proto__: Object
1: Object
2: Object
name: "Maks. wych.:"
values: Array[504]
[0 … 99]
[100 … 199]
100: Object
date: Thu Jan 16 2014 01:00:00 GMT+0100 (?rodkowoeuropejski czas stand.)
transfers: 49305177944
__proto__: Object
101: Object
date: Thu Jan 16 2014 01:20:00 GMT+0100 (?rodkowoeuropejski czas stand.)
transfers: 42169641572
__proto__: Object
102: Object
date: Thu Jan 16 2014 01:40:00 GMT+0100 (?rodkowoeuropejski czas stand.)
transfers: 39400112189
__proto__: Object
103: Object
104: Object
105: Object
106: Object
107: Object
108: Object
109: Object
110: Object
I would really appreciate any help from you. I know some Object Oriented Programming, HTML, CSS, but for now I wasn't really working with any framework and it is fun to learn but on the over hand could be really frustrating while trying to figure out what the heck I'm doing wrong.
EDIT
Now I'm trying drawing two lines separately. It is working great and it could make it easier for me to change lines style later on. Now i need to use mousemove function for each of those lines. Then it would be fairly easy to just pass readed values to some variables and show them in some box or something.
This is the code for the my second try(sorry for post getting long):
Screenshot for the second code is called Chart2.jpg
<!DOCTYPE html>
<meta charset="utf-8">
<style>
body {
font: 10px sans-serif;
}
.axis path,
.axis line {
fill: none;
stroke: #000;
shape-rendering: crispEdges;
}
.x.axis path {
display: none;
}
.line {
fill: none;
stroke: steelblue;
stroke-width: 1.5px;
}
.overlay {
fill: none;
pointer-events: all;
}
.focus circle {
fill: none;
stroke: steelblue;
}
</style>
<body>
<script src="d3.js"></script>
<script>
var margin = {top: 20, right: 50, bottom: 30, left: 100},
width = 960 - margin.left - margin.right,
height = 500 - margin.top - margin.bottom;
var parseDate = d3.time.format("%d-%b-%y").parse,
bisectDate = d3.bisector(function(d) { return d.date; }).left,
formatValue = d3.format(",.2f"),
formatCurrency = function(d) { return "$" + formatValue(d); };
var x = d3.time.scale()
.range([0, width]);
var y = d3.scale.linear()
.range([height, 0]);
var xAxis = d3.svg.axis()
.scale(x)
.orient("bottom");
var yAxis = d3.svg.axis()
.scale(y)
.orient("left");
var line = d3.svg.line()
.x(function(d) { return x(d.date); })
.y(function(d) { return y(d.close); });
var valueline2 = d3.svg.line()
.x(function(d) { return x(d.date); })
.y(function(d) { return y(d.open); });
var svg = d3.select("body").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 + ")");
d3.csv("data.csv", function(error, data) {
data.forEach(function(d) {
d.date = parseDate(d.date);
d.close = +d.close;
d.open = +d['open data'];
});
data.sort(function(a, b) {
return a.date - b.date;
});
x.domain([data[0].date, data[data.length - 1].date]);
y.domain([0, d3.max(data, function(d) { return Math.max(d.close, d.open); })]);
svg.append("g")
.attr("class", "x axis")
.attr("transform", "translate(0," + height + ")")
.call(xAxis);
svg.append("g")
.attr("class", "y axis")
.call(yAxis)
.append("text")
.attr("transform", "rotate(-90)")
.attr("y", 6)
.attr("dy", ".71em")
.style("text-anchor", "end")
.text("Price ($)");
svg.append("path")
.datum(data)
.attr("class", "line")
.attr("d", line);
svg.append("path")
.datum(data)
.attr("class", "line")
.style("stroke", "red")
.attr("d", valueline2);
var focus = svg.append("g")
.attr("class", "focus")
.style("display", "none");
focus.append("circle")
.attr("r", 4.5);
focus.append("text")
.attr("x", 9)
.attr("dy", ".35em");
svg.append("