I'm learning D3 js and tried following example. Somehow I've managed it to a Single line chart by removing non required code.
http://bl.ocks.org/gniemetz/4618602
Now, I want to enhance this example a way that once user do brush on the smaller one chart, whatever range comes between the brush, it's line point should animate tool-tip on interval of some seconds. But I'm not able to get the start and end points of the brush.
Sorry for the long long code ....
var main_margin = {top: 20, right: 80, bottom: 100, left: 40},
mini_margin = {top: 430, right: 80, bottom: 20, left: 40},
main_width = 960 - main_margin.left - main_margin.right,
main_height = 500 - main_margin.top - main_margin.bottom,
mini_height = 500 - mini_margin.top - mini_margin.bottom,
start = 0,
end = 100,
focus;
var formatDate = d3.time.format("%H:%M"),
parseDate = formatDate.parse,
bisectDate = d3.bisector(function(d) { return d.Uhrzeit; }).left,
formatOutput0 = function(d) { return formatDate(d.Uhrzeit) + " - " + d.Durchschn + " ms"; };
var main_x = d3.time.scale()
.range([0, main_width]),
mini_x = d3.time.scale()
.range([0, main_width]);
var main_y0 = d3.scale.sqrt()
.range([main_height, 0]),
mini_y0 = d3.scale.sqrt()
.range([mini_height, 0]);
var main_xAxis = d3.svg.axis()
.scale(main_x)
.tickFormat(d3.time.format("%H:%M"))
.orient("bottom"),
mini_xAxis = d3.svg.axis()
.scale(mini_x)
.tickFormat(d3.time.format("%H:%M"))
.orient("bottom");
var main_yAxisLeft = d3.svg.axis()
.scale(main_y0)
.orient("left");
var brush = d3.svg.brush()
.x(mini_x)
.on("brushstart",function(){
console.log(brush.extent()[0]);
})
.on("brush",brushMove)
.on("brushend", function(){
console.log(brush.extent()[1]);
});
var main_line0 = d3.svg.line()
.interpolate("cardinal")
.x(function(d) { return main_x(d.Uhrzeit); })
.y(function(d) { return main_y0(d.Durchschn); });
var mini_line0 = d3.svg.line()
.x(function(d) { return mini_x(d.Uhrzeit); })
.y(function(d) { return mini_y0(d.Durchschn); });
var svg = d3.select("body").append("svg")
.attr("width", main_width + main_margin.left + main_margin.right)
.attr("height", main_height + main_margin.top + main_margin.bottom);
svg.append("defs").append("clipPath")
.attr("id", "clip")
.append("rect")
.attr("width", main_width)
.attr("height", main_height);
var main = svg.append("g")
.attr("transform", "translate(" + main_margin.left + "," + main_margin.top + ")");
var mini = svg.append("g")
.attr("transform", "translate(" + mini_margin.left + "," + mini_margin.top + ")");
d3.csv("data.txt", function(error, data) {
data.forEach(function(d) {
d.Uhrzeit = parseDate(d.Uhrzeit);
d.Durchschn = +d.Durchschn;
});
data.sort(function(a, b) {
return a.Uhrzeit - b.Uhrzeit;
});
main_x.domain([data[0].Uhrzeit, data[data.length - 1].Uhrzeit]);
main_y0.domain(d3.extent(data, function(d) { return d.Durchschn; }));
mini_x.domain(main_x.domain());
mini_y0.domain(main_y0.domain());
main.append("path")
.datum(data)
.attr("clip-path", "url(#clip)")
.attr("class", "line line0")
.attr("d", main_line0);
main.append("g")
.attr("class", "x axis")
.attr("transform", "translate(0," + main_height + ")")
.call(main_xAxis);
main.append("g")
.attr("class", "y axis axisLeft")
.call(main_yAxisLeft)
.append("text")
.attr("transform", "rotate(-90)")
.attr("y", 6)
.attr("dy", ".71em")
.style("text-anchor", "end")
.text("Ø AWZ (ms)");
mini.append("g")
.attr("class", "x axis")
.attr("transform", "translate(0," + mini_height + ")")
.call(main_xAxis);
mini.append("path")
.datum(data)
.attr("class", "line")
.attr("d", mini_line0);
mini.append("g")
.attr("class", "x brush")
.call(brush)
.selectAll("rect")
.attr("y", -6)
.attr("height", mini_height + 7);
focus = main.append("g")
.attr("class", "focus")
.style("display", "none");
focus.append("line")
.attr("class", "x")
.attr("y1", main_y0(0) - 6)
.attr("y2", main_y0(0) + 6)
focus.append("line")
.attr("class", "y0")
.attr("x1", main_width - 6) // nach links
.attr("x2", main_width + 6); // nach rechts
focus.append("circle")
.attr("class", "y0")
.attr("r", 4);
focus.append("text")
.attr("class", "y0")
.attr("dy", "-1em");
main.append("rect")
.attr("class", "overlay")
.attr("width", main_width)
.attr("height", main_height)
.on("mouseover", showToolTip)
.on("mouseout", hideToolTip)
.on("mousemove", mousemove);
function mousemove() {
var x0 = main_x.invert(d3.mouse(this)[0]),
i = bisectDate(data, x0, 1),
d0 = data[i - 1],
d1 = data[i],
d = x0 - d0.Uhrzeit > d1.Uhrzeit - x0 ? i : (i-1);
showToolTipForIndex(d);
}
function showToolTipForIndex(i){
var d = data[i];
focus.select("circle.y0").attr("transform", "translate(" + main_x(d.Uhrzeit) + "," + main_y0(d.Durchschn) + ")");
focus.select("text.y0").attr("transform", "translate(" + main_x(d.Uhrzeit) + "," + main_y0(d.Durchschn) + ")").text(formatOutput0(d));
focus.select(".x").attr("transform", "translate(" + main_x(d.Uhrzeit) + ",0)");
focus.select(".y0").attr("transform", "translate(" + main_width * -1 + ", " + main_y0(d.Durchschn) + ")").attr("x2", main_width + main_x(d.Uhrzeit));
}
// set default brush on mini xAxis
defaultBrush(data,start,end);
// bind event listeners
document.getElementById('play').addEventListener('click',function(){
if( !brush.empty() ){
// here I want to get brush's start and end points.. I mean the range
}
});
});
function showToolTip(){
focus.style("display", null);
}
function hideToolTip(){
focus.style("display", "none");
}
function defaultBrush(data,start,end){
svg.select(".x.brush").call(brush.extent([data[start].Uhrzeit,data[end].Uhrzeit]));
main_x.domain([data[start].Uhrzeit,data[end].Uhrzeit]);
main.select(".line0").attr("d", main_line0);
main.select(".x.axis").call(main_xAxis);
}
function brushMove() {
main_x.domain(brush.empty() ? mini_x.domain() : brush.extent());
main.select(".line0").attr("d", main_line0);
main.select(".x.axis").call(main_xAxis);
}
function brushStart(){
}
function brushEnd(){
}
});
The start and end points of the selected region are contained in brush.extent(). This function returns an array of two points, start and end. So if you wanted to get start and end x coordinates, you would do something like this.
var extent = brush.extent(),
start = extent[0][0],
end = extent[1][0];
Related
https://i.stack.imgur.com/90isf.png
When visualizing the data, I got some troubles of X axis of line chart.
As picture shows, line of X axis disappeared, in fact, it only shows the scale of X axis. I wonder why this condition happens. Was it due to the illegal coding or because of the size of SVG was not big enough to contain the whole picture?
var margin = { top: 30, right: 120, bottom: 30, left: 50 },
width = 960 - margin.left - margin.right,
height = 600 - margin.top - margin.bottom,
tooltip = { width: 100, height: 100, x: 10, y: -30 };
var parseDate = d3.timeParse("%m-%d-%Y"),
bisectDate = d3.bisector(function(d) { return d.date; }).left,
formatValue = d3.format(","),
dateFormatter = d3.timeParse("%m-%d-%Y");
var x = d3.scaleTime()
.range([0, width]);
var y = d3.scaleLinear()
.range([height, 0]);
var xAxis = d3.axisBottom()
var yAxis = d3.axisLeft()
.scale(y);
var line = d3.line()
.x(function(d) { return x(d.date); })
.y(function(d) { return y(d.likes); });
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("output4.csv",
function(d){
return { date : d.framenum, likes : d.nSNR }
},
function(data) {
x.domain([0, d3.max(data, function(d) { return +d.date; })]);
y.domain([-d3.max(data, function(d) { return +d.likes; }), d3.max(data, function(d) { return +d.likes; })]);
svg.append("g")
.attr("class", "x axis")
.attr("transform", "translate(0," + height + ")")
.call(d3.axisBottom(x));
svg.append("g")
.attr("class", "y axis")
.call(yAxis)
.style("font-size","17px")
.append("text")
.attr("transform", "rotate(-90)")
.attr("y", 6)
.attr("dy", ".71em")
.style("text-anchor", "end")
.text("Number of Likes");
svg.append("path")
.datum(data)
.attr("class", "line")
.attr("d", line);
var focus = svg.append("g")
.attr("class", "focus")
.style("display", "none");
focus.append("circle")
.attr("r", 5);
focus.append("rect")
.attr("class", "tooltip")
.attr("width", 100)
.attr("height", 50)
.attr("x", 10)
.attr("y", -22)
.attr("rx", 4)
.attr("ry", 4);
focus.append("text")
.attr("class", "tooltip-date")
.attr("x", 18)
.attr("y", -2);
focus.append("text")
.attr("x", 18)
.attr("y", 18)
.text("Likes:");
focus.append("text")
.attr("class", "tooltip-likes")
.attr("x", 60)
.attr("y", 18);
svg.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.likes) + ")");
focus.select(".tooltip-date").text(dateFormatter(d.date));
focus.select(".tooltip-likes").text(formatValue(d.likes));
}
});
Why is the y-axis is not aligned with the graph. Graph response height exceeds y-axis data.
Expected output should not have graph height overflow from plot area/exceed y axis height.
Here is my javascript:
function getD3Chart(chartData){
var formattime = d3.time.format("%a-%d");
var widther = window.outerWidth - 35;
if(widther > 750){
widther = 430;
}
var margin = {top: 20, right: 20, bottom: 30, left: 30},
width = widther - margin.left - margin.right,
height = 235 - margin.top - margin.bottom;
var parseDate = d3.time.format("%d-%b-%Y:%H").parse,
bisectDate = d3.bisector(function(d) { return d.date; }).left,
formatValue = d3.format(",.3f"), // its use for after decimal we can show number of fractional digit
formatCurrency = function(d) { return 1000*formatValue(d)+"ms, "; };
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")
.innerTickSize(0)
.outerTickSize(0)
.tickPadding(10)
.tickFormat(formattime)
.ticks(7);
var yAxis = d3.svg.axis()
.scale(y)
.orient("left")
.innerTickSize(0)
.outerTickSize(0);
var area = d3.svg.area()
.x(function(d) { return x(d.date); })
.y0(height)
.y1(function(d) { return y(d.avgResponse); });
var line = d3.svg.line()
.x(function(d) { return x(d.date); })
.y(function(d) { return y(d.avgResponse); });
var svg = d3.select("svg")
.attr("width", width + margin.left + margin.right)
.attr("height", height + margin.top + margin.bottom)
.append("g")
.attr("transform", "translate(" + margin.left + "," + margin.top + ")");
var data = chartData.map(function(d) {
return{
date : parseDate(d.date),
avgResponse : d.avgResponse
};
});
data.sort(function(a, b) {
return a.date - b.date;
});
x.domain(d3.extent(data, function(d) { return d.date; }));
y.domain([0, d3.max(data, function(d) { return d.avgResponse; })]);
svg.append("path")
.data([data])
.attr("class", "area")
.attr("d", area);
svg.append("text")
.attr("transform", "rotate(-90)")
.attr("y", 6)
.attr("dy", ".71em")
.style("text-anchor", "end")
.style("position", "absolute")
.style("font-weight", "bold")
.text("Avg ResponseTime in ms");
svg.append("g")
.attr("class", "x axis")
.attr("transform", "translate(0," + height + ")")
.style("position", "absolute")
.call(xAxis);
svg.append("g")
.attr("class", "y axis")
.style("position", "absolute")
.call(yAxis);
svg.append("path")
.datum(data)
.attr("class", "line")
.attr("d", line);
var focus = svg.append("g")
.attr("class", "focus")
.style("display", "none");
focus.append("circle")
.attr("r", 6.5);
focus.append("text")
.attr("x", 9)
.attr("dy", ".35em");
svg.append("rect")
.attr("class", "overlay")
.attr("width", width)
.attr("height", height)
.attr("background-color", "#EDE3D1")
.attr('opacity', 0)
.on("mouseover", function() { focus.style("display", null); })
.on("mouseout", function() { focus.style("display", "none"); })
.on("mousemove", mousemove);
function mousemove() {
var months = ['Jan','Feb','Mar','Apr','May','Jun','Jul','Aug','Sep','Oct','Nov','Dec'];
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;
var hour = d.date.getHours();
hour = (hour < 10)? "0"+hour : hour;
focus.attr("transform", "translate(" + x(d.date) + "," + y(d.avgResponse) + ")");
focus.select("text").text(formatCurrency(d.avgResponse) +" "+months[d.date.getMonth()]+" "+ d.date.getDate()+"th " +hour+":00h");
focus.select("text").attr("class", "graphDataClass");
if(d3.mouse(this)[0] > 260) {
focus.select("text").attr("x", -120);
}else{
focus.select("text").attr("x", 9);
}
}
}
I've created a line chart using this http://bl.ocks.org/d3noob/6eb506b129f585ce5c8a code example. I've managed to recreate it.
that code is
<!DOCTYPE html>
<meta charset="utf-8">
<style> /* set the CSS */
body { font: 12px Arial;}
path {
stroke: steelblue;
stroke-width: 2;
fill: none;
}
.axis path,
.axis line {
fill: none;
stroke: grey;
stroke-width: 1;
shape-rendering: crispEdges;
}
</style>
<body>
<!-- load the d3.js library -->
<script src="http://d3js.org/d3.v3.min.js"></script>
<script>
// Set the dimensions of the canvas / graph
var margin = {top: 30, right: 20, bottom: 30, left: 50},
width = 600 - margin.left - margin.right,
height = 270 - margin.top - margin.bottom;
// Parse the date / time
var parseDate = d3.time.format("%d-%b-%y").parse,
formatDate = d3.time.format("%d-%b"),
bisectDate = d3.bisector(function(d) { return d.date; }).left;
// Set the ranges
// var x = d3.time.scale().range([0, width]);
var x = d3.scale.ordinal().rangePoints([0, width]);
var y = d3.scale.linear().range([height, 0]);
// Define the axes
var xAxis = d3.svg.axis().scale(x)
.orient("bottom").ticks(5);
var yAxis = d3.svg.axis().scale(y)
.orient("left").ticks(5);
// Define the line
var valueline = d3.svg.line()
.interpolate('basis')
.x(function(d) { return x(d.date); })
.y(function(d) { return y(d.close); });
// Adds the svg canvas
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 + ")");
var lineSvg = svg.append("g");
var focus = svg.append("g")
.style("display", "none");
// Get the data
var data = [
{
"date": "w1",
"close": 629.32
},
{
"date": "w2",
"close": 124.31
},
{
"date": "w3",
"close": 333.68
},
{
"date": "w4",
"close": 236.23
}
]
// data.forEach(function(d) {
// // d.date = parseDate(d.date);
// d.date = +d.date;
// d.close = +d.close;
// });
// Scale the range of the data
x.domain(data.map(function(d) { return d.date; }));
y.domain([0, d3.max(data, function(d) { return d.close; })]);
// Add the valueline path.
lineSvg.append("path")
.attr("class", "line")
.attr("d", valueline(data));
// Add the X Axis
svg.append("g")
.attr("class", "x axis")
.attr("transform", "translate(0," + height + ")")
.call(xAxis);
// Add the Y Axis
svg.append("g")
.attr("class", "y axis")
.call(yAxis);
// append the x line
focus.append("line")
.attr("class", "x")
.style("stroke", "blue")
.style("stroke-dasharray", "3,3")
.style("opacity", 0.5)
.attr("y1", 0)
.attr("y2", height);
// append the y line
focus.append("line")
.attr("class", "y")
.style("stroke", "blue")
.style("stroke-dasharray", "3,3")
.style("opacity", 0.5)
.attr("x1", width)
.attr("x2", width);
// append the circle at the intersection
focus.append("circle")
.attr("class", "y")
.style("fill", "none")
.style("stroke", "blue")
.attr("r", 4);
// place the value at the intersection
focus.append("text")
.attr("class", "y1")
.style("stroke", "white")
.style("stroke-width", "3.5px")
.style("opacity", 0.8)
.attr("dx", 8)
.attr("dy", "-.3em");
focus.append("text")
.attr("class", "y2")
.attr("dx", 8)
.attr("dy", "-.3em");
// place the date at the intersection
focus.append("text")
.attr("class", "y3")
.style("stroke", "white")
.style("stroke-width", "3.5px")
.style("opacity", 0.8)
.attr("dx", 8)
.attr("dy", "1em");
focus.append("text")
.attr("class", "y4")
.attr("dx", 8)
.attr("dy", "1em");
// append the rectangle to capture mouse
svg.append("rect")
.attr("width", width)
.attr("height", height)
.style("fill", "none")
.style("pointer-events", "all")
.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.select("circle.y")
.attr("transform",
"translate(" + x(d.date) + "," +
y(d.close) + ")");
focus.select("text.y1")
.attr("transform",
"translate(" + x(d.date) + "," +
y(d.close) + ")")
.text(d.close);
focus.select("text.y2")
.attr("transform",
"translate(" + x(d.date) + "," +
y(d.close) + ")")
.text(d.close);
focus.select("text.y3")
.attr("transform",
"translate(" + x(d.date) + "," +
y(d.close) + ")")
.text(formatDate(d.date));
focus.select("text.y4")
.attr("transform",
"translate(" + x(d.date) + "," +
y(d.close) + ")")
.text(formatDate(d.date));
focus.select(".x")
.attr("transform",
"translate(" + x(d.date) + "," +
y(d.close) + ")")
.attr("y2", height - y(d.close));
focus.select(".y")
.attr("transform",
"translate(" + width * -1 + "," +
y(d.close) + ")")
.attr("x2", width + width);
}
</script>
</body>
line is coming correctly but i m not able to set mouseover tooltip like above example..
I m facing error like invert fuction is not defined...
In the chart you linked to, he is using a time-scale for the x-axis (which has an invert-function). You are using an ordinal-scale (which do not have an invert-function).The invert-function is used to calculate the value on the x-axis for a given mouse-position.
A time-scale always has a corresponding x-value for each mouse-position (since it is continous, so no matter where your mouse is, you have a date-time for that position) while an ordinal scale does not have a corresponding x-value for all mouse-positions since it is discrete, i.e. what is the x-value when you have the mouse in-beteen for example w1 and w2?
So your solution would be to change to a time-scale (in which case you have to convert w1,w2,w3 e.t.c. to a date-time object).
Or, if you want to stick with your ordinal-scale, you have to remove the invert function. Since the invert-function is used to calculate the x-value for a given mouse-position, you have to create this logic by your self. Inspiration can be found in Inversion with ordinal scale. So replace var x0 = x.invert(d3.mouse(this)[0]) with
var xPos = d3.mouse(this)[0];
console.log("hovering at " + xPos);
var leftEdges = x.range();
var width = x.rangeBand();
var j;
for(j=0; xPos > (leftEdges[j] + width); j++) {}
//do nothing, just increment j until case fails
console.log("Clicked on " + x.domain()[j]);
var x0 = x.domain()[j];
I want to plot multiple lines and scatter plot on the same d3 chart.And I also define a mouse over function to calculate the distance between the scatter points and the line. Here is my js code:
import measurement from '../datasets/measurement';
// Parse the date / time
var parseDate = d3.time.format("%e/%_m/%Y %H");
// Get the data
d3.csv("../datasets/Book1.csv", function(error, data) {
data.forEach(function (d) {
d.date = parseDate.parse(d.dateHour);
d.estPressure = +d.x_inf;
d.lowPressure = +d.m1std;
d.upPressure = +d.p1std;
});
console.log(data);
// Set the dimensions of the canvas / graph
var margin = {top: 20, right: 50, bottom: 30, left: 66},
body_width = parseInt(d3.select('body').style('width').replace('px','')),
width = body_width - margin.left - margin.right,
height = 1000 - margin.top - margin.bottom;
// Adds the svg canvas
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 + ")");
// Set the ranges
var x = d3.time.scale()
.domain([parseDate.parse("1/5/2016 00"), parseDate.parse("14/5/2016 23")])
// .domain(data.date])
.nice(d3.time.week)
/*.domain(data.map(function (d) {
return d.date;
}))*/
.range([0, width]);
//.rangeRoundBands([0, width], 0.1);
var y = d3.scale.linear().range([height, 0]);
// Define the axes
var xAxis = d3.svg.axis()
.scale(x)
.orient("bottom")
.tickFormat(d3.time.format('%B %e %H:00'));
svg.append("g")
.attr("class", "x axis")
.attr("transform", "translate(0," + height + ")")
.call(xAxis);
svg.append("text")
.attr("x", 1780)
.attr("y", 940)// text label for the x axis
.style("text-anchor", "end")
.text("Time");
var yAxis = d3.svg.axis()
.scale(y)
.orient("left");
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("pressure");
y.domain([0, d3.max(data, function (d) {
return d.upPressure;
})]);
var line = d3.svg.line()
.x(function (d) {
return x(d.date);
})
.y(function (d) {
return y(d.estPressure);
});
// Draw line.
var linegraph = svg.selectAll("path.line").data([data], function (d) {
return d.date;
});
linegraph.attr('d', line).style("opacity", 1.0);
linegraph.enter().append("path")
.attr("class", "line")
.attr("d", line);
});
var data1 = measurement.map(function (d) {
Object.keys(d).forEach(function (key) {
d[key] = +d[key];
});
return d;
});
console.log(data1);
// Add the scatterplot
svg.selectAll(".dot")
.data(data1)
.enter().append("circle")
.attr("r", 4)
.attr("cx", function (d) {
return x(d.t);
})
.attr("cy", function (d) {
return y(d.est);
})
.on("mouseover", function (d) { //hover event
tooltip.transition()
.duration(100)
.style("opacity", .9)
.style("left", (d3.event.pageX + 20) + "px")
.style("top", (d3.event.pageY - 30) + "px");
var dist = 0, lowerbound;
data.forEach(function (n) {
if (n.t === d.t) {
dist = d.est - n.pressure ;
if (dist < 0) dist = dist * -1;
}
else if (n.time < d.t) { // linear interpolation for the t
lowerbound = n;
}
});
tooltip.html("<h1>" + "X: " + d.t + " Y: " + d.x + " distance:" + dist.toFixed(3) + "</h1>");
})
.on("mouseout", function (d) {
tooltip.transition()
.duration(200)
.style("opacity", 0);
});
And my csv data for the line chart is like this:
tHour,x_inf,p1std,m1std,dateHour
1,10,10.3,9.2,1/5/2016 00
2,12,16.8,7.2,1/5/2016 01
3,14,21.2,6.8,1/5/2016 02
4,15,19.8,10.2,1/5/2016 03
5,14.5,16.9,12.1,1/5/2016 04
6,18,22.96,13.04,1/5/2016 05
My jason data for the scatter points are like(measurement):
{
"t": 1,
"est": 1
},
{
"t": 3,
"est": 12
},
{
"t": 5,
"est": 14
},
{
Could anyone help me about the code? I am new to d3...And I just can plot only one line here using the dateHour as x and x_inf as y in the csv data. I want to use dateHour data as x and plot three lines using x_inf,p1std,m1std values. It would be so nice if you could also help me with the scatter points.
I have multiple d3-charts on one page and would like to add a mouseover effect for each chart.
At the moment only one chart is affected and has a mouseover effect.
I've created an example with multiple charts.
Here is the fiddle: http://jsfiddle.net/zumdpjzx/
for( var i= 1; i < 3; i++){
console.log(i);
var arrData = [
["2014-08-20", 100, 100],
["2014-08-21", 95, 85],
["2014-08-22", 93, 71],
["2014-08-23", 88, 57],
["2014-08-24", 86, 42],
["2014-08-25", 98, 28],
["2014-08-26", 117, 14],
["2014-08-27", 123, 0]
];
arrData = arrData.sort((function(index){
return function(a, b){
return (a[index] === b[index] ? 0 : (a[index] < b[index] ? -1 : 1));
};
})(0));
console.log("array: " + arrData);
var margin = {top: 40, right: 40, bottom: 60, left: 50},
width = 960 - margin.left - margin.right,
height = 500 - margin.top - margin.bottom;
var parseDate = d3.time.format("%Y-%m-%d").parse;
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")
.ticks(arrData.length)
.tickFormat(d3.time.format("%Y-%m-%d"));
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 line2 = d3.svg.line()
.x(function(d) { return x(d.date); })
.y(function(d) { return y(d.open); });
var svg = d3.select("#chart" + i).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 + ")");
var data = arrData.map(function(d) {
return {
//date: d[0],
date: parseDate(d[0]),
close: d[2],
open: d[1]
};
});
var length = arrData.length - 1;
// Scale the range of the data
x.domain(d3.extent(data, function(d) { return d.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)
.selectAll("text")
.style("text-anchor", "end")
.attr("dx", "-.8em")
.attr("dy", ".15em")
.attr("transform", function(d) {
return "rotate(-65)"
});
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("Open Issues");
svg.append("path")
.datum(data)
.attr("class", "line")
.attr("d", line);
svg.append("path") // Add the valueline2 path.
.attr("class", "line")
.style("stroke", "red")
.attr("d", line2(data))
.text("line2");
svg.append("text")
.attr("transform", "translate(" + (width+3) + "," + y(data[length].open) + ")")
.attr("dy", ".35em")
.attr("text-anchor", "start")
.style("fill", "red")
.text("Open");
svg.append("text")
.attr("transform", "translate(" + (width+3) + "," + y(data[length].close) + ")")
.attr("dy", ".35em")
.attr("text-anchor", "start")
.style("fill", "steelblue")
.text("Close");
//mouse over
var focus = svg.append("g")
.attr("class", "focus")
.style("display", "none");
focus.append("circle")
.attr("r", 4.5);
focus.append("circle")
.attr("r", 4.5);
var bisectDate = d3.bisector(function(d) { return d.date; }).left;
var formatValue = d3.format(",.2f");
var formatCurrency = function(d) { return + d; };
focus.append("text")
.attr("x", 9)
.attr("dy", ".35em");
svg.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", mousemoveOpen);
}
function mousemoveOpen() {
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.open) + ")");
focus.select("text").text(formatCurrency(d.open));
}
Edit:
I've found now a new solution. Here is the fiddle: http://jsfiddle.net/4h72u83h/1/
Thank you for your help!
You're pretty close to the mark, but you're not keeping track of which focus element you are updating in the mouseout, mouseover and mousemove handlers.
You could do something like this:
for (var i = 1; i < 3; i++) {
console.log(i);
var arrData = [
["2014-08-20", 100, 100],
["2014-08-21", 95, 85],
["2014-08-22", 93, 71],
["2014-08-23", 88, 57],
["2014-08-24", 86, 42],
["2014-08-25", 98, 28],
["2014-08-26", 117, 14],
["2014-08-27", 123, 0]
];
arrData = arrData.sort((function(index) {
return function(a, b) {
return (a[index] === b[index] ? 0 : (a[index] < b[index] ? -1 : 1));
};
})(0));
console.log("array: " + arrData);
var margin = {
top: 40,
right: 40,
bottom: 60,
left: 50
},
width = 960 - margin.left - margin.right,
height = 500 - margin.top - margin.bottom;
var parseDate = d3.time.format("%Y-%m-%d").parse;
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").ticks(arrData.length).tickFormat(d3.time.format("%Y-%m-%d"));
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 line2 = d3.svg.line()
.x(function(d) {
return x(d.date);
})
.y(function(d) {
return y(d.open);
});
var svg = d3.select("#chart" + i).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 + ")");
var data = arrData.map(function(d) {
return {
//date: d[0],
date: parseDate(d[0]),
close: d[2],
open: d[1]
};
});
console.log(data);
console.log(arrData.length);
var length = arrData.length - 1;
// Scale the range of the data
x.domain(d3.extent(data, function(d) {
return d.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)
.selectAll("text")
.style("text-anchor", "end")
.attr("dx", "-.8em")
.attr("dy", ".15em")
.attr("transform", function(d) {
return "rotate(-65)"
});
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("Open Issues");
svg.append("path")
.datum(data)
.attr("class", "line")
.attr("d", line);
svg.append("path") // Add the valueline2 path.
.attr("class", "line")
.style("stroke", "red")
.attr("d", line2(data))
.text("line2");
svg.append("text")
.attr("transform", "translate(" + (width + 3) + "," + y(data[length].open) + ")")
.attr("dy", ".35em")
.attr("text-anchor", "start")
.style("fill", "red")
.text("Open");
svg.append("text")
.attr("transform", "translate(" + (width + 3) + "," + y(data[length].close) + ")")
.attr("dy", ".35em")
.attr("text-anchor", "start")
.style("fill", "steelblue")
.text("Close");
//mouse over
var focus = svg.append("g")
.attr("class", "focus")
.style("display", "none");
focus.append("circle")
.attr("r", 4.5);
focus.append("circle")
.attr("r", 4.5);
var bisectDate = d3.bisector(function(d) {
return d.date;
}).left;
var formatValue = d3.format(",.2f");
var formatCurrency = function(d) {
return +d;
};
focus.append("text")
.attr("x", 9)
.attr("dy", ".35em");
svg.append("rect")
.attr("class", "overlay")
.attr("width", width)
.attr("height", height)
.on("mouseover", function() {
var thisFocus = d3.select(d3.select(this)[0][0].parentNode).select(".focus");
thisFocus.style("display", null);
})
.on("mouseout", function() {
var thisFocus = d3.select(d3.select(this)[0][0].parentNode).select(".focus");
thisFocus.style("display", "none");
})
.on("mousemove", mousemoveOpen);
}
function mousemoveOpen() {
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;
var thisFocus = d3.select(d3.select(this)[0][0].parentNode).select(".focus");
thisFocus.attr("transform", "translate(" + x(d.date) + "," + y(d.open) + ")");
thisFocus.select("text").text(formatCurrency(d.open));
}
body {
font: 10px sans-serif;
}
.axis path,
.axis line {
fill: none;
stroke: #000;
shape-rendering: crispEdges;
}
.line {
fill: none;
stroke: steelblue;
stroke-width: 1.5px;
}
.overlay {
fill: none;
pointer-events: all;
}
.focus circle {
fill: none;
stroke: steelblue;
}
.legend {
padding: 5px;
font: 10px sans-serif;
background: yellow;
box-shadow: 2px 2px 1px #888;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/d3/3.4.11/d3.min.js"></script>
<body>
<div id="chart1"></div>
<div id="chart2"></div>
</body>
Basically, what I've done there is to modify the mouseover, mouseout and mousemove, so that it grabs the right focus element to be updated and then updates it.
The important bit is:
var thisFocus = d3.select(d3.select(this)[0][0].parentNode).select(".focus");
thisFocus.attr("transform", "translate(" + x(d.date) + "," + y(d.open) + ")");
thisFocus.select("text").text(formatCurrency(d.open));
The first line grabs the focus that corresponds to the graph that is receiving the mouse events. You'll see similar lines in the mouseover and mouseout handlers.
I would probably recommend that you just keep track of the focus elements separately in an object to begin with, and then you can just use that reference in your mouse handling functions. Selecting it all the time can have performance impacts, though not so much in this case.
mousemoveOpen is called on both charts in your example. Looking at it, 'focus' and 'data' exist outside of the closure. By the time mousemoveOpen gets called both will be fetched from the global scope and use the last value they were set to. That's why the last chart always gets updated: the focus and data variables point reference the last chart.
I tried playing with your fiddle example, but I couldn't get it working. You could use underscore, or native javascript's 'bind'