Below is my code to load a D3 multine chart in a leaflet map popup everything works fine but i am not able to load tooltips the mouse events are not picking up. Even console.log on mousemove over the element is not working also i am able to inspect the element on right click. I also do not see anything related to this element in event listners.
var chartdiv = document.createElement("div");
chartdiv.className = "pricechart";
// set the dimensions and margins of the graph
var margin = {top: 25, right: 70, bottom: 80, left: 50},
width = 480 - margin.left - margin.right,
height = 240 - margin.top - margin.bottom;
// parse the date / time
//var parseTime = d3.timeParse("%Y-%m-%d");
// set the ranges
var x = d3.scaleTime().range([0, width]);
var y = d3.scaleLinear().range([height, 0]);
var yrain = d3.scaleLinear().range([height, 0]);
// define the line
var smi_line = d3.line()
.x(function(d) { return x(d.date); })
.y(function(d) { return y(d.smi); })
var rain_line = d3.line()
.x(function(d) { return x(d.date); })
.y(function(d) { return y(d.rain); });
// gridlines in x axis function
function make_x_gridlines() {
return d3.axisBottom(x)
}
// gridlines in y axis function
function make_y_gridlines() {
return d3.axisLeft(y).ticks(5)
}
// 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
var svg = d3.select(chartdiv).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 + ")");
// Scale the range of the data
x.domain(d3.extent(stats, function(d) { return d.date; }));
y.domain([d3.min(stats, function(d) { return Math.min(d.smi, d.rain, 0); }) , d3.max(stats, function(d) { return Math.max(d.smi, d.rain, 100); })]);
svg.append("linearGradient")
.attr("id", "temperature-gradient")
.attr("gradientUnits", "userSpaceOnUse")
.attr("x1", 0).attr("y1", y(0))
.attr("x2", 0).attr("y2", y(100))
.selectAll("stop")
.data([
{offset: "0%", color: "rgb(252, 0, 23)"},
{offset: "25%", color: "rgb(252, 0, 23)"},
{offset: "26%", color: "rgb(255, 254, 52)"},
{offset: "50%", color: "rgb(255, 254, 52)"},
{offset: "51%", color: "rgb(44, 255, 254)"},
{offset: "75%", color: "rgb(44, 255, 254)"},
{offset: "76%", color: "rgb(4, 20, 251)"},
{offset: "100%", color: "rgb(4, 20, 251)"}
])
.enter().append("stop")
.attr("offset", function(d) { return d.offset; })
.attr("stop-color", function(d) { return d.color; });
// add the X gridlines
svg.append("g")
.attr("class", "grid")
.attr("transform", "translate(0," + height + ")")
.call(make_x_gridlines()
.tickSize(-height)
.tickFormat("")
)
// add the Y gridlines
svg.append("g")
.attr("class", "grid")
.call(make_y_gridlines()
.tickSize(-width)
.tickFormat("")
)
// Add the SMI path.
svg.append("path")
.data([stats])
.attr("class", "smi-line")
//.style("stroke", "#ff0000")
.attr("d", smi_line);
// Add the Rain path.
svg.append("path")
.data([stats])
.attr("class", "rain-line")
//.style("stroke", "#ff0000")
.attr("d", rain_line);
// Add the X Axis
svg.append("g")
.attr("transform", "translate(0," + height + ")")
.call(d3.axisBottom(x)
.tickFormat(d3.timeFormat("%d-%b-%y")))
.selectAll("text")
.style("text-anchor", "end")
.attr("dx", "-.8em")
.attr("dy", ".15em")
.attr("transform", "rotate(-45)");
// text label for the x axis
svg.append("text")
.attr("transform",
"translate(" + (width/2) + " ," +
(height + margin.bottom -30) + ")")
.style("text-anchor", "middle")
.attr("dy", "1em")
.text("Date");
// Add the Y Axis
svg.append("g")
.call(d3.axisLeft(y).ticks(5));
// text label for the y axis
svg.append("text")
.attr("transform", "rotate(-90)")
.attr("y", 0 - margin.left)
.attr("x",0 - (height / 2))
.attr("dy", "1em")
.style("text-anchor", "middle")
.text("Soil Moisture Index");
// Add the Right Y Axis
svg.append("g")
.attr("transform", "translate(" + width + " ,0)")
.call(d3.axisRight(y).ticks(5)
.tickFormat(d => (d + " mm")));
// text label for the y axis
svg.append("text")
.attr("transform", "rotate(-90)")
.attr("y", width + margin.right -15)
.attr("x",0 - (height / 2))
.attr("dy", "1em")
.style("text-anchor", "middle")
.text("Rainfall");
var g = svg.append("g")
.attr("transform", "translate(" + margin.left + "," + margin.top + ")");
var focus = g.append("g")
.attr("class", "focus")
.style("display", "none");
focus.append("line")
.attr("class", "x-hover-line hover-line")
.attr("y1", 0)
.attr("y2", height);
focus.append("line")
.attr("class", "y-hover-line hover-line")
.attr("x1", width)
.attr("x2", width);
focus.append("circle")
.attr("r", 7.5);
focus.append("text")
.attr("x", 15)
.attr("dy", ".31em");
svg.append("rect")
.attr("transform", "translate(" + margin.left + "," + margin.top + ")")
.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);
var bisectDate = d3.bisector(function(d) { return d.year; }).left;
function mousemove() {
console.log('mousemove');
var x0 = x.invert(d3.mouse(this)[0]),
i = bisectDate(data, x0, 1),
d0 = data[i - 1],
d1 = data[i],
d = x0 - d0.year > d1.year - x0 ? d1 : d0;
focus.attr("transform", "translate(" + x(d.year) + "," + y(d.value) + ")");
focus.select("text").text(function() { return d.value; });
focus.select(".x-hover-line").attr("y2", height - y(d.value));
focus.select(".y-hover-line").attr("x2", width + width);
}
Related
I would like to add a tooltip to the line chart, where each data point displays a text box upon hover, as follows:
-----------------|
x-coordinate: ## |
y-coordinate: ## |
-----------------|
The working snippet for the working graph is posted below. But I will comment out the tooltip block to plot the chart.
Thanks.
var margin = {top: 50, right: 50, bottom: 50, left: 50}
, width = window.innerWidth - margin.left - margin.right
, height = window.innerHeight - margin.top - margin.bottom;
//labels
var labels = ['Mon','Tue','Thur','Frid'];
var yvals = [12,11,0,18];
// X scale
var xScale = d3.scalePoint()
.domain(labels) // input
.range([0, width-1]); // output
// Y scale
var yScale = d3.scaleLinear()
.domain([0, 20])
.range([height,0]);
var line = d3.line()
.x(function(d, i) { return xScale(labels[i]); })
.y(function(d) { return yScale(d.y); })
.curve(d3.curveMonotoneX)
var dataset = d3.range(yvals.length).map(function(d,i) { return {"y": yvals[i]} })
//Tooltip
//var tip = d3.select('body')
//.append('div')
//.attr('class', 'tip')
//.html('number:'+ function(d,i) return {data[data.i]})
// .style('border', '1px solid steelblue')
// .style('padding', '5px')
//.style('position', 'absolute')
// .style('display', 'none')
//.on('mouseover', function(d, i) {
// tip.transition().duration(0);
// })
// .on('mouseout', function(d, i) {
// tip.style('display', 'none');
// });
// SVGs
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 + ")");
svg.append("rect")
.attr("width", "100%")
.attr("height", "100%")
.attr("fill", "white");
svg.append("g")
.attr("transform", "translate(" + margin.left + "," + margin.top + ")");
// x axis call
svg.append("g")
.attr("class", "x axis")
.attr("transform", "translate(0," + height + ")")
//.call(d3.axisBottom(xScale));
.call(d3.axisBottom(xScale));
// y axis call
svg.append("g")
.attr("class", "y axis")
.call(d3.axisLeft(yScale));
svg.append("path")
.datum(dataset)
.attr("class", "line")
.attr("d", line);
// 12. Appends a circle for each datapoint
svg.selectAll(".dot")
.data(dataset)
.enter().append("circle") // Uses the enter().append() method
.attr("class", "dot") // Assign a class for styling
.attr("cx", function(d, i) { return xScale(labels[i]) })
.attr("cy", function(d,i) { return yScale(yvals[i]) })
.attr("r", 3);
//.on('mouseover', function(d, i) {
// tip.transition().duration(0);
// })
svg.append("text")
.attr("class", "title")
.attr("x", width/2)
.attr("y", 0 - (margin.top / 2))
.attr("text-anchor", "middle")
.text("Testing");
.line {
fill: none;
stroke: orange;
stroke-width: 1;
}
.dot {
fill: brown;
stroke: #fff;
}
<!DOCTYPE html>
<meta charset="utf-8">
<style type="text/css">
</style>
<body>
</body>
<script src="https://d3js.org/d3.v5.min.js"></script>
<script>
</script>
I have just made a few changes to the mousemove event.
var margin = {
top: 50,
right: 50,
bottom: 50,
left: 50
},
width = window.innerWidth - margin.left - margin.right,
height = window.innerHeight - margin.top - margin.bottom;
//labels
var labels = ['Mon', 'Tue', 'Thur', 'Frid'];
var yvals = [12, 11, 0, 18];
// X scale
var xScale = d3.scalePoint()
.domain(labels) // input
.range([0, width - 1]); // output
// Y scale
var yScale = d3.scaleLinear()
.domain([0, 20])
.range([height, 0]);
var line = d3.line()
.x(function(d, i) {
return xScale(labels[i]);
})
.y(function(d) {
return yScale(d.y);
})
.curve(d3.curveMonotoneX)
var dataset = d3.range(yvals.length).map(function(d, i) {
return {
"y": yvals[i]
}
})
var tip = d3.select('body').append("div")
.attr("class", "tip");
// SVGs
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 + ")");
svg.append("rect")
.attr("width", "100%")
.attr("height", "100%")
.attr("fill", "white");
svg.append("g")
.attr("transform", "translate(" + margin.left + "," + margin.top + ")");
// x axis call
svg.append("g")
.attr("class", "x axis")
.attr("transform", "translate(0," + height + ")")
//.call(d3.axisBottom(xScale));
.call(d3.axisBottom(xScale));
// y axis call
svg.append("g")
.attr("class", "y axis")
.call(d3.axisLeft(yScale));
svg.append("path")
.datum(dataset)
.attr("class", "line")
.attr("d", line);
// 12. Appends a circle for each datapoint
svg.selectAll(".dot")
.data(dataset)
.enter().append("circle") // Uses the enter().append() method
.attr("class", "dot") // Assign a class for styling
.attr("cx", function(d, i) {
return xScale(labels[i])
})
.attr("cy", function(d, i) {
return yScale(yvals[i])
})
.attr("r", 3)
.on("mouseover", function() {
tip.style("display", null);
})
.on("mouseout", function() {
tip.style("display", "none");
})
.on("mousemove", function(d) {
return tip
.style("left", d3.event.pageX + "px")
.style("top", d3.event.pageY + 10 + "px")
.style("visibility", "visible")
.html(function() {
return '<div style="border:1px solid #ccc;">' +
'<p style="font-weight:bold;">' + d.y + '</p>' +
'</div>';
})
})
svg.append("text")
.attr("class", "title")
.attr("x", width / 2)
.attr("y", 0 - (margin.top / 2))
.attr("text-anchor", "middle")
.text("Testing");
.line {
fill: none;
stroke: orange;
stroke-width: 1;
}
.dot {
fill: brown;
stroke: #fff;
}
.tip {
position: absolute;
border: 1px solid steelblue;
visibility: hidden;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/d3/5.0.0/d3.min.js"></script>
Here is the working jsFiddle
Hope it helps :)
Here is the template for my Django where I am visualizing training using D3:
.line {
fill: none;
stroke: gray;
stroke-width: 2px;
}
<meta charset="utf-8">
<body>
<script src="https://d3js.org/d3.v4.min.js"></script>
<script>
var real = {{values.real0|safe}}, pred = {{values.got0|safe}};
var margin = {top: 20, right: 20, bottom: 110, left: 50},
margin2 = {top: 430, right: 20, bottom: 30, left: 40},
width = 960 - margin.left - margin.right,
height = 500 - margin.top - margin.bottom,
height2 = 500 - margin2.top - margin2.bottom;
var x = d3.scaleLinear().range([0, width]).domain([0, Object.keys(real).length]),
x2 = d3.scaleLinear().range([0, width]).domain([0, Object.keys(real).length]),
y = d3.scaleLinear().range([height, 0]).domain([0, 1]),
y2 = d3.scaleLinear().range([height2, 0]).domain([0, 1]);
var xAxis = d3.axisBottom(x),
xAxis2 = d3.axisBottom(x2),
yAxis = d3.axisLeft(y);
var brush = d3.brushX()
.extent([[0, 0], [width, height2]])
.on("brush", brushed);
var svg = d3.select("body").append("svg")
.attr("width", width + margin.left + margin.right)
.attr("height", height + margin.top + margin.bottom);
svg.append("defs").append("clipPath")
.attr("id", "clip")
.append("rect")
.attr("width", width)
.attr("height", height);
var formain = d3.line()
.x(function(d,i) { return x(i); })
.y(function(d) { return y(d); });
var forbrush = d3.line()
.x(function(d,i) { return x2(i); })
.y(function(d) { return y2(d); });
var focus = svg.append("g")
.attr("class", "focus")
.attr("transform", "translate(" + margin.left + "," + margin.top + ")");
var context = svg.append("g")
.attr("class", "context")
.attr("transform", "translate(" + margin2.left + "," + margin2.top + ")");
// Real starts
var color = d3.scaleLinear()
.domain([0, 0.5, 1])
.range(["red", "dodgerblue", "lime"]);
// x.domain(d3.extent(data, function(d) { return d.date; }));
// y.domain([0, d3.max(data, function(d) { return d.price; })+200]);
// x2.domain(x.domain());
// y2.domain(y.domain());
// append scatter plot to main chart area
var dots = focus.append("g");
dots.attr("clip-path", "url(#clip)");
dots.selectAll("dot")
.data(real)
.enter().append("circle")
.attr('class', 'dot')
.attr("r",5)
.style("opacity", .5)
.attr("cx", function(d,i) { return x(i); })
.attr("cy", function(d) { return y(d); })
.attr("fill",(function (d) { return color(d) }));
focus.append("g")
.attr("class", "axis axis--x")
.attr("transform", "translate(0," + height + ")")
.call(xAxis);
focus.append("g")
.attr("class", "axis axis--y")
.call(yAxis);
focus.append("text")
.attr("transform", "rotate(-90)")
.attr("y", 0 - margin.left)
.attr("x",0 - (height / 2))
.attr("dy", "1em")
.style("text-anchor", "middle")
.text(Object.keys({{values|safe}}));
// console.log(Object.keys({{values|safe}}));
svg.append("text")
.attr("transform",
"translate(" + ((width + margin.right + margin.left)/2) + " ," +
(height + margin.top + margin.bottom) + ")")
.style("text-anchor", "middle")
.text("index");
// append scatter plot to brush chart area
var dots = context.append("g");
dots.attr("clip-path", "url(#clip)");
dots.selectAll("dot")
.data(real)
.enter().append("circle")
.attr('class', 'dotContext')
.attr("r",3)
.style("opacity", .5)
.attr("cx", function(d,i) { return x2(i); })
.attr("cy", function(d) { return y2(d); })
.attr("fill",(function (d) { return color(d) }));
context.append("g")
.attr("class", "axis axis--x")
.attr("transform", "translate(0," + height2 + ")")
.call(xAxis2);
context.append("g")
.attr("class", "brush")
.call(brush)
.call(brush.move, x.range());
focus.append("path")
.data([real])
.attr("class", "line")
.attr("d", formain);
context.append("path")
.data([real])
.attr("class", "line")
.attr("d", forbrush);
//create brush function redraw scatterplot with selection
function brushed() {
var selection = d3.event.selection;
x.domain(selection.map(x2.invert, x2));
focus.selectAll(".dot")
.attr("cx", function(d,i) { return x(i); })
.attr("cy", function(d) { return y(d); });
context.selectAll(".line")
.attr("cx", function(d,i) { return x(i); })
.attr("cy", function(d) { return y(d); });
focus.select(".axis--x").call(xAxis);
context.select(".axis--x").call(xAxis2);
}
</script>
The output I received is something like the following:
What I want is the the magnifier focus should display the respective contents of the line and the dots. Plus I want to have the line in the background and dots on the foreground.
Please help me modify the sample for my use. There is some attribute I guess I am missing.
The sample csv need is : Sample Csv
Try to change the few thing and it will work. see below:
var focus = svg.append("g")
.attr("class", "focus")
.attr("transform", "translate(" + margin.left + "," + margin.top + ")");
var context = svg.append("g")
.attr("class", "context")
.attr("transform", "translate(" + margin2.left + "," + margin2.top + ")");
focus.append("path")
.data([real])
.attr("class", "line")
.attr("d", formain);
context.append("path")
.data([real])
.attr("class", "line")
.attr("d", forbrush);
Place it just as mentioned.
Change the brushed() function like the following:
function brushed() {
var selection = d3.event.selection;
x.domain(selection.map(x2.invert, x2));
focus.selectAll(".dot")
.attr("cx", function(d,i) { return x(i); })
.attr("cy", function(d) { return y(d); });
focus.selectAll(".line")
.attr("d",formain)
}
See the output of mine. It worked.:
Hope this will help you.
I'm creating a bar chart from two different (flat) arrays, one array with count data and one array with date data. I am having difficulty grabbing the x-axis data point (date) to display in the tooltip. I've tried d3.zip to combine the arrays but can't seem to figure out how to index the values that way either. Any suggestions welcome!
var parseDate = d3.timeParse('%Y-%m-%d');
var newECdailyArray = [1, 1, 4, 5, 9];
var newEDdailyArray = ["2016-01-05", "2016-01-10", "2016-02-01", "2016-02-15", "2016-03-05"];
var tooltip = d3.select("body").append("div")
.attr("class", "toolTip")
.style("opacity", "0")
.style("position", "absolute");
var width = 500
var height = 500
var margin = {
top:30,
bottom:70,
right:30,
left:30
}
var y = d3.scaleLinear()
.domain([0, d3.max(newECdailyArray)])
.rangeRound([height, 0]);
var x = d3.scaleTime()
.domain(d3.extent(newEDdailyArray, function(d) {
return parseDate(d);
}))
.range([0, width])
.nice(d3.timeMonth);
var yAxis = d3.axisLeft(y);
var xAxis = d3.axisBottom(x);
var svg = d3.select('#thing').append('svg')
.attr("width", width + margin.left + margin.right)
.attr("height", height + margin.top + margin.bottom);
var ChartGroup = svg.append("g")
.attr("transform", "translate(" + margin.left + "," + margin.top + ")")
ChartGroup.selectAll('rect')
.data(newECdailyArray)
.enter().append('rect')
.attr('width', 5)
.attr("height", function(d) {
return height - y(d);
})
.attr('x', function(d, i) {
return x(parseDate(newEDdailyArray[i]));
})
.attr("y", function(d) {
return y(d);
})
.attr('fill', "blue")
.on("mousemove", function(d, i) {
tooltip
.style("opacity", "1")
.style("left", d3.event.pageX - 50 + "px")
.style("top", d3.event.pageY - 70 + "px")
.style("display", "inline-block");
console.log(parseDate(newEDdailyArray[i]));
tooltip.html("count: " + d + "<br>" + "date: ");
})
.on("mouseout", function(d) {
tooltip.style("display", "none");
});
ChartGroup.append('g')
.attr("class", "axis y")
.call(yAxis);
ChartGroup.append('g')
.attr("class", "axis x")
.attr("transform", "translate(0," + height + ")")
.call(d3.axisBottom(x)
.tickFormat(d3.timeFormat("%Y-%m-%d")))
.selectAll("text")
.style("text-anchor", "end")
.attr("dx", "-.8em")
.attr("dy", ".15em")
.attr("transform", "rotate(-65)");
ChartGroup.append("text")
.attr("transform", "rotate(-90)")
.attr("y", 0 - margin.left)
.attr("x", 0 - (height / 2))
.attr("dy", "1em")
.style("text-anchor", "middle")
.text("Event Count");
ChartGroup.append("text")
.attr("transform", "translate(" + (width / 2) + " ," + (height + margin.top + 60) + ")")
.style("text-anchor", "middle")
.text("Date");
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/d3/4.13.0/d3.min.js"></script>
<div id='thing'></div>
I had to boil down my longer code to just the necessary parts for this question (please excuse anything I may have left out, and feel free to comment for clarification.)
You can merge your arrays in this way:
var newECdailyArray = [1, 1, 4, 5, 9];
var newEDdailyArray = ["2016-01-05", "2016-01-10", "2016-02-01", "2016-02-15", "2016-03-05"];
var data=[]
for (i in newECdailyArray){
var val = {};
val['date'] = newEDdailyArray[i];
val['value'] = newECdailyArray[i];
data.push(val)
}
console.log(data)
and then reference them using d.date and d.value
Also I tried your code and it works fine. I can see the date and the value in the tooltip. Here's the fiddle.
var parseDate = d3.timeParse('%Y-%m-%d');
var newECdailyArray = [1, 1, 4, 5, 9];
var newEDdailyArray = ["2016-01-05", "2016-01-10", "2016-02-01", "2016-02-15", "2016-03-05"];
var tooltip = d3.select("body").append("div")
.attr("class", "toolTip")
.style("opacity", "0")
.style("position", "absolute");
var height = 400;
var width = 600;
var margin = {
left: 30,
right: 30,
top: 30,
bottom:70,
}
var x = d3.scaleTime()
.domain(d3.extent(newEDdailyArray, function(d) {
return parseDate(d);
}))
.range([0, width],0.4)
.nice(d3.timeMonth);
var y = d3.scaleLinear()
.domain([0, d3.max(newECdailyArray)])
.rangeRound([height, 0]);
var xAxis = d3.axisBottom(x);
var yAxis = d3.axisLeft(y);
var svg = d3.select('#thing').append('svg')
.attr("width", width + margin.left + margin.right)
.attr("height", height + margin.top + margin.bottom);
var ChartGroup = svg.append("g")
.attr("transform", "translate(" + margin.left + "," + margin.top + ")")
ChartGroup.selectAll('rect')
.data(newECdailyArray)
.enter().append('rect')
.attr('width', 15)
.attr("height", function(d) {
return height - y(d);
})
.attr('x', function(d, i) {
return x(parseDate(newEDdailyArray[i]));
})
.attr("y", function(d) {
return y(d);
})
.attr('fill', "blue")
.on("mousemove", function(d, i) {
tooltip
.style("opacity", "1")
.style("left", d3.event.pageX - 50 + "px")
.style("top", d3.event.pageY - 70 + "px")
.style("display", "inline-block");
console.log(parseDate(newEDdailyArray[i]));
tooltip.html("count: " + d + "<br>" + "date: " + newEDdailyArray[i]);
})
.on("mouseout", function(d) {
tooltip.style("display", "none");
});
ChartGroup.append('g')
.attr("class", "axis y")
.call(yAxis);
ChartGroup.append('g')
.attr("class", "axis x")
.attr("transform", "translate(0," + height + ")")
.call(d3.axisBottom(x)
.tickFormat(d3.timeFormat("%Y-%m-%d")))
.selectAll("text")
.style("text-anchor", "end")
.attr("dx", "-.8em")
.attr("dy", ".15em")
.attr("transform", "rotate(-65)");
ChartGroup.append("text")
.attr("transform", "rotate(-90)")
.attr("y", 0 - margin.left)
.attr("x", 0 - (height / 2))
.attr("dy", "1em")
.style("text-anchor", "middle")
.text(" Event Count");
ChartGroup.append("text")
.attr("transform", "translate(" + (width / 2) + " ," + (height + margin.top + 60) + ")")
.style("text-anchor", "middle")
.text("Date");
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/d3/4.13.0/d3.min.js"></script>
<div id='thing'></div>
The idiomatic (and more reliable) way to store the data in a D3 code is keeping all the different properties in a single object, and storing all the different objects (one for each data point) in an array.
However, since the two arrays you have contain the data in the same sequence (i.e., their indices match), just use the index:
tooltip.html("count: " + d + "<br>" + "date: " + newEDdailyArray[i]);
//index here ----------------------------------------------------^
Here is your code with that change only:
var parseDate = d3.timeParse('%Y-%m-%d');
var newECdailyArray = [1, 1, 4, 5, 9];
var newEDdailyArray = ["2016-01-05", "2016-01-10", "2016-02-01", "2016-02-15", "2016-03-05"];
var tooltip = d3.select("body").append("div")
.attr("class", "toolTip")
.style("opacity", "0")
.style("position", "absolute");
var width = 500
var height = 500
var margin = {
top:30,
bottom:70,
right:30,
left:30
}
var y = d3.scaleLinear()
.domain([0, d3.max(newECdailyArray)])
.rangeRound([height, 0]);
var x = d3.scaleTime()
.domain(d3.extent(newEDdailyArray, function(d) {
return parseDate(d);
}))
.range([0, width])
.nice(d3.timeMonth);
var yAxis = d3.axisLeft(y);
var xAxis = d3.axisBottom(x);
var svg = d3.select('#thing').append('svg')
.attr("width", width + margin.left + margin.right)
.attr("height", height + margin.top + margin.bottom);
var ChartGroup = svg.append("g")
.attr("transform", "translate(" + margin.left + "," + margin.top + ")")
ChartGroup.selectAll('rect')
.data(newECdailyArray)
.enter().append('rect')
.attr('width', 5)
.attr("height", function(d) {
return height - y(d);
})
.attr('x', function(d, i) {
return x(parseDate(newEDdailyArray[i]));
})
.attr("y", function(d) {
return y(d);
})
.attr('fill', "blue")
.on("mousemove", function(d, i) {
tooltip
.style("opacity", "1")
.style("left", d3.event.pageX - 50 + "px")
.style("top", d3.event.pageY - 70 + "px")
.style("display", "inline-block");
console.log(parseDate(newEDdailyArray[i]));
tooltip.html("count: " + d + "<br>" + "date: " + newEDdailyArray[i]);
})
.on("mouseout", function(d) {
tooltip.style("display", "none");
});
ChartGroup.append('g')
.attr("class", "axis y")
.call(yAxis);
ChartGroup.append('g')
.attr("class", "axis x")
.attr("transform", "translate(0," + height + ")")
.call(d3.axisBottom(x)
.tickFormat(d3.timeFormat("%Y-%m-%d")))
.selectAll("text")
.style("text-anchor", "end")
.attr("dx", "-.8em")
.attr("dy", ".15em")
.attr("transform", "rotate(-65)");
ChartGroup.append("text")
.attr("transform", "rotate(-90)")
.attr("y", 0 - margin.left)
.attr("x", 0 - (height / 2))
.attr("dy", "1em")
.style("text-anchor", "middle")
.text("Event Count");
ChartGroup.append("text")
.attr("transform", "translate(" + (width / 2) + " ," + (height + margin.top + 60) + ")")
.style("text-anchor", "middle")
.text("Date");
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/d3/4.13.0/d3.min.js"></script>
<div id='thing'></div>
I have been trying to add labels to my bar chart as described in this question:
Adding label on a D3 bar chart
However, I can get the labels to display, but not over the appropriate bar (they are all lined up over/ on the first bar). Any help would be greatly appreciated. Here is my code:
var cdata = { title: "Sample Chart", Pod: 10, WOSNF : 201.57, SNFW: 8.89, YTDTarget: 15.14, AnnualTarget: 22.10, Max: 250 }
var margin = {top: 20, right: 20, bottom: 70, left: 40},
width = 500 - margin.left - margin.right,
height = 500 - margin.top - margin.bottom;
// Parse the categories
var x = d3.scale.ordinal().rangeRoundBands([0, width], .05);
var y = d3.scale.linear().range([height, 30]);
y.domain([0, 30]);
var xAxis = d3.svg.axis()
.scale(x)
.orient("bottom")
var yAxis = d3.svg.axis()
.scale(y)
.orient("left")
.ticks(10);
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) {
data.forEach(function(d) {
d.value = +d.value;
console.log(d.value);
});
x.domain(data.map(function(d) { return d.Category; }));
svg.append("g")
.attr("class", "x axis")
.attr("transform", "translate(0," + height + ")")
.call(xAxis)
.append("text")
.style("text-anchor", "end")
.attr("x", width/2)
.attr("y", 30)
.attr("dx", ".71em")
.attr("transform", "translate(40,20)" )
;
svg.append("g")
.attr("class", "y axis")
.call(yAxis)
.append("text")
.attr("transform", "translate(" + (width / 2) + ",-25)")
.attr("y", 6)
.attr("dy", ".71em")
.style("text-anchor", "middle")
.style("font-size", "14pt")
.text("Sample Chart");
svg.selectAll("bar")
.data(data)
.enter().append("rect")
.style("fill", "steelblue")
.style("fill-opacity", "0.5")
.attr("x", function(d) { return x(d.Category); })
.attr("width", x.rangeBand())
.attr("y", function(d) { return y(d.value) - 1;})
.attr("height", function(d) { return height - y(d.value);})
var yTextPadding = 20;
svg.selectAll("bartext")
.data(data)
.enter().append("text")
.attr("class", "bartext")
.attr("text-anchor", "middle")
.attr("fill", "black")
.attr("x", function(d, i) {
return x.rangeBand()/2;
})
.attr("y", function(d) {
return y(d.value);
})
.text(function(d){
return d.value;
});
});
var G3 = svg.append("g")
G3.append("line")
.attr("y1", y(cdata["YTDTarget"])-1)
.attr("y2", y(cdata["YTDTarget"])-1)
.attr("x1", 0)
.attr("x2", 500)
.attr("stroke-width", 2)
.attr("stroke", "black");
G3.append("text")
.attr("x",10)
.attr("y", y(cdata["YTDTarget"])+10)
.style("fill", "black")
.style("text-anchor", "start")
.text("RU YTD Target - " + cdata["YTDTarget"]);
var G4 = svg.append("g")
G4.append("line")
.attr("y1", y(cdata["AnnualTarget"])-1)
.attr("y2", y(cdata["AnnualTarget"])-1)
.attr("x1", 0)
.attr("x2", 500)
.attr("stroke-width", 2)
.attr("stroke", "black");
G4.append("text")
.attr("x", 10)
.attr("y", y(cdata["AnnualTarget"])+10)
.style("fill", "black")
.style("text-anchor", "start")
.text("RU Annual Target - " + cdata["AnnualTarget"]);
And here is the data:
Category,value
"Group1",27.2
"Group2",24.6
"Group3",27.1
The elements following the parsing of the data are to draw lines across the graph for reference.
Thanks!
You're currently setting the x position of the labels to half the width of the first bar (so they all end up on the left.
You want the x position of the bartext to start at the same spot as the current bar and add half the width of the bar:
.attr("x", function(d, i) {
return x(d.Category) + (x.rangeBand() / 2);
})
I tried now couple of things but I can not figure out why my ticks are wrong positioned. I used different sources to make this stacked barchart.
Here is the fiddle of my code: http://jsfiddle.net/azj7guec/
And here is the code itself:
var margin = {top: 20, right: 20, bottom: 70, left: 40},
width = 1000 - margin.left - margin.right,
height = 300 - margin.top - margin.bottom;
x = d3.scale.ordinal().rangeRoundBands([0, width], .50);
y = d3.scale.linear().range([height, 0]);
z = d3.scale.ordinal().range(["darkblue", "blue", "lightblue"])
console.log("RAW MATRIX---------------------------");
// 4 columns: ID,c1,c2,c3
var matrix = [
[22,45,34,65],
[23,66,12,22],
[24,32,44,76],
[25,12,76,32],
[26, 67, 34, 56]
];
console.log(matrix)
var keys = matrix.map(function(item){return item[0]});
console.log("REMAP---------------------------");
var remapped =["c1","c2","c3"].map(function(dat,i){
return matrix.map(function(d,ii){
return {x: d[0], y: d[i+1] };
})
});
console.log(remapped)
console.log("LAYOUT---------------------------");
var stacked = d3.layout.stack()(remapped)
console.log(stacked)
//var yMax= d3.max(stacked)
x.domain(keys);
y.domain([0, d3.max(stacked[stacked.length - 1], function(d) { return d.y0 + d.y; })]);
// show the domains of the scales
console.log("x.domain(): " + x.domain())
console.log("y.domain(): " + y.domain())
console.log("------------------------------------------------------------------");
var yAxis = d3.svg.axis()
.scale(y)
.ticks(10)
.orient("left");
var xAxis = d3.svg.axis()
.scale(x)
.tickValues(keys)
.orient("bottom");
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 + ")");
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");
// Add a group for each column.
var valgroup = svg.selectAll("g.valgroup")
.data(stacked)
.enter().append("g")
.attr("class", "valgroup")
.style("fill", function(d, i) { return z(i); })
.style("stroke", function(d, i) { return d3.rgb(z(i)).darker(); });
// Add a rect for each date.
var rect = valgroup.selectAll("rect")
.data(function(d){return d;})
.enter().append("rect")
.attr("width", 20)
.attr("x", function(d) { return x(d.x); })
.attr("y", function(d) { return y(d.y0 + d.y); })
.attr("height", function(d) { return y(d.y0) - y(d.y0 + d.y); });
//.attr("width", x.rangeBand());
Hope someone can help me.
The ordinal scale divides its output range into intervals based on the input domain. Your current positioning puts the bars at the beginning of those intervals, whereas the ticks are in the center. To match up the positions, add half the interval minus half the bar width to the beginning of the interval:
.attr("x", function(d) { return x(d.x) + (x.rangeBand() - 20) / 2; })
Complete demo here.