I feel like this has a really simple solution but I have been struggling for a while now. I have a d3 line graph and I want to draw a line on the graph that represents the average of the data. I am trying to do this with the line attribute but I keep getting the same errors. The errors I keep getting are:
"Unexpected value NaN parsing y1 attribute.
Unexpected value NaN parsing y2 attribute. "
Here is the code where I try to draw the line:
student_av_data.forEach(function(d) {
d.student_average = +d.student_average;
});
svg.append("line")
.style("stroke", "orange")
.style("opacity", 1)
.attr("x1", 0)
.attr("y1", y0(function(d) {return y0(d.student_average);}))
.attr("x2", width)
.attr("y2", y0(function(d) {return y0(d.student_average);}));
function(d) {return y0(d.student_average);} should just be a number and that should work in the y0 arguments.
Not really sure what is wrong. Any suggestions would be appreciated. Thanks!
EDIT:
As a reference, this works and is basically what I am trying to do but with d.student_average in y0():
svg.append("line")
.style("stroke", "black")
.style("opacity", .2)
.attr("x1", 0)
.attr("y1", y0(24))
.attr("x2", width)
.attr("y2", y0(24));
Try replacing with this:
svg.append("line")
.style("stroke", "orange")
.style("opacity", 1)
.data(student_av_data)
.attr("x1", 0)
.attr("y1", function(d) {return y0(d.student_average);})
.attr("x2", width)
.attr("y2", function(d) {return y0(d.student_average);});
which will take d from the data elem
Related
I've got a basic heatmap from here.
Now I want to be able to highlight a whole column of the plot, like drawing a rectangle around all values (Could also be something simpler):
I'm also using react to keep track of which column should be highlighted.
Therefore I need to be able to change this highlighting programmatically without any mouse actions.
Does anyone know how to style a whole column without using mouse events? is that even possible?
You can append a highlight element when you're creating your heatmap, and update the position/opacity of the highlight element when your variable changes.
Note that you will also need to store the d3 scale function in a variable.
const svg = "however you're selecting the svg here"
svg.append('rect')
.attr("id", "highlight")
.attr("width", xScale.bandwidth())
.attr("height", 'height of the heatmap')
.attr("x", 0)
.attr("y", 0)
.attr("opacity", 0)
.attr("stroke", '#ffffff')
.attr("stroke-width", 2)
When the variable is changed programatically, use d3 to select that element and update its position
function changePosition(column) {
const svg = "however you're selecting the svg here"
const xScale = "that variable where you put the xScale function when you appended your heatmap"
svg.select("#highlight")
.attr("x", xScale(column))
.attr("opacity", 1)
}
I solved this by using mouseover. You can get coordinates and size of a single rect by using:
var mouseover = function(event, d) {
x_coordinate = this.x.animVal.value
y_coordinate = his.y.animVal.value
height_of_rect = this.height.animVal.value
width_of_rect = this.width.animVal.value
}
To draw a line over a heatmap you need to apppend that line on its parent component. I used svg:
const drawLine = function(x, rectWidth) {
svg.append('line')
.style("stroke", "black")
.style("stroke-width", 2)
.attr("x1", x)
.attr("y1", 0)
.attr("x2", x)
.attr("y2", height);
svg.append('line')
.style("stroke", "black")
.style("stroke-width", 2)
.attr("x1", x+rectWidth)
.attr("y1", 0)
.attr("x2", x+rectWidth)
.attr("y2", height);
svg.append('line')
.style("stroke", "black")
.style("stroke-width", 2)
.attr("x1", x)
.attr("y1", 0)
.attr("x2", x+rectWidth)
.attr("y2", 0);
svg.append('line')
.style("stroke", "black")
.style("stroke-width", 2)
.attr("x1", x)
.attr("y1", height)
.attr("x2", x+rectWidth)
.attr("y2", height);
}
drawLine function will vertically highlight a column of a rect and it is placed inside of mouseover. Here x is x coordinate, rectWidth is width of one rect component and height is heat map height. To remove highlight put in mouseleave function:
d3.selectAll("line").remove()
I am new to d3 javascript library. I am trying to draw line over a circle using d3. I am able to create circle but somehow line does not appear on circle. See sample code attached. Any help is highly appreciated.
diag_circles.data(circle_data)
.enter()
.append("circle")
.attr("cx", function (d) {
console.log("d.x", d.x);
return d.x
})
.attr("cy", function (d) {
return d.y
})
.attr("r", function (d) {
return d.r
})
.append('line')
.attr("x1", function(d){return d.x- d.r})
.attr("y1", function(d){return d.y})
.attr("x2", function (d) { return d.x+ d.r})
.attr("y2", function(d){return d.y})
.attr("stroke-width", 20)
.attr("stroke", "black");
https://jsfiddle.net/c58859xy/
In a nutshell: you cannot append a line element to a circle element.
When creating your SVG, you have to know which elements allow appended children and what children they can have.
Solution: You'll have to append the lines to the SVG:
var lines = svg.selectAll('line')
.data(circle_data)
.enter()
.append("line")
.attr("x1", function(d){return d.x- d.r})
.attr("y1", function(d){return d.y})
.attr("x2", function (d) { return d.x+ d.r})
.attr("y2", function(d){return d.y})
.attr("stroke-width", 20)
.attr("stroke", "black");
Here is the updated fiddle: https://jsfiddle.net/c58859xy/1/
I have a data model which is an array of object with start time and end time.
Now I want to render gantt chart type cart with it.
It is easy to bind data and render a single line with it:
chart.data(myDataList).enter().append("line")
.attr("x1", function(d){return d.x})
.attr("y1", lineHeight)
.attr("x2", function(d){return d.y})
.attr("y2", lineHeight)
The data could be like
myDataList = [ [start time, end time],
[start time 2, end time 2],
[start time 3, end time 3]]
Now I need to render something like this with each data item:
O-------------------O
That is addition to the line, there will be circle in both end of the line.
Circle cx data will be coming from d.x and d.y.
However, I am not quite sure how to bind the same data element in three elements.
Any help?
First you make the line:
chart.data(myDataList).enter().append("line")
.attr("x1", function(d){return d.x})
.attr("y1", lineHeight)
.attr("x2", function(d){return d.y})
.attr("y2", lineHeight)
now make circles
//make inner circle
chart.selectAll(".in").data(dataset).enter()
.append("circle")
.attr("class", "in")
.attr("cx", function(d) {
return xScale(d[0])
})
.attr("cy", function(d) {
return xScale(d[0])
})
.attr("r", 2);
//make outer circle
chart.selectAll(".out").data(dataset).enter()
.append("circle")
.attr("class", "out")
.attr("cx", function(d) {
return xScale(d[1])
})
.attr("cy", function(d) {
return xScale(d[0])
})
.attr("r", 2);
Working code here
First,cache the line code in a variable.
var line=chart.data(myDataList).enter().append("line")
.attr("x1", function(d){return d.x})
.attr("y1", lineHeight)
.attr("x2", function(d){return d.y})
.attr("y2", lineHeight)
Then,now using the variable,we can add circles using the same data element as
line.append("circle")
.attr("cx", function(d){return d.x})
.attr("cy", lineHeight)
.attr("r", 4);//First circle
now,the second circle ...
line.append("circle")
.attr("cx", function(d){return d.y})
.attr("cy", lineHeight)
.attr("r", 4);//Second circle
I have a graph which I build using d3js and I want to draw red line or other kind of indicator on the graph to indicate when the graphs blue line's value hits 0(in this case its 6th of june). The example of a graph http://jsfiddle.net/wRDXt/81/
My starting point is:
if(dataset.value = 0){
//draw line
}
But I have no clue where to go from here. Any help would be greatly appreciated.
There are a few different ways to do this. One way would be to filter the dataset to create a new array that only had the entries with a value of 0.
var zeroData = dataset.filter(function(d){
if (d.value == 0) return d;
});
This new array could be used to draw lines at each zero point with a separate svg.selectAll(".redlines") using the new array as the data.
// plot lines
svg.selectAll(".redline")
.data(zeroData)
.enter()
.append("line")
.attr("class", "redline")
.attr("x1", function(d) { return xScale(d.date); })
.attr("x2", function(d) { return xScale(d.date); })
.attr("y1", 0)
.attr("y2", 250)
.style("stroke", "#ff0000");
http://jsfiddle.net/wRDXt/85/
Another way is to start by appending a "g" element for each data point instead of a circle then adding a circle and a line for each point. Styling can be used to make only the value == 0 points visible.
// plot data points as g elements
var datapts = svg.selectAll(".data-point")
.data(dataset);
var dataptsEnter = datapts
.enter()
.append("g")
.attr("class", "data-point")
.attr("transform", function(d) {
return "translate(" + xScale(d.date) + "," + yScale(d.value) + ")";
});
dataptsEnter
.append("circle")
.attr("class", "data-point-circle")
.attr("cx", 0)
.attr("cy", 0)
.attr("r", 5);
dataptsEnter
.append("line")
.attr("x1", 0)
.attr("y1", 0)
.attr("x2", 0)
.attr("y2", -50)
.style("stroke", "#ff0000")
.style("opacity", function(d) {
if (d.value == 0) return 1;
return 0;
});
http://jsfiddle.net/wRDXt/82/
In the second approach, there is a red line for each datapoint but opacity is used to make only the zero value visible.
The first approach is the one I'd use.
Please see the working example of d3.js script below. The vertical line, mline1 is located at x-axis value of 16000. The line sloping down, dline is supposed to represent the equation
x = 48000 - 16000*y. The intersection of mline1 and dline should occur at value of x=16000 and y=2. I draw a circle with center at x=16000 and y=2, and I expect it to be at the intersection of the two lines above. But it is not. Would really appreciate if you could help me understand this, or let me know if this is a bug in d3.js scaling behavior, or some other bug.
Thanks in advance.
The Code
<html>
<head>
<script src="http://d3js.org/d3.v2.js"></script>
</head>
<body>
<div id="viz"></div>
<script type="text/javascript">
var paddingH = 50;
var paddingV = 50;
var width = 700;
var height = 400
cv = d3.select("#viz").append("svg:svg")
.attr("width", width)
.attr("height", height)
var xs = d3.scale.linear()
.domain([0,50000])
.range([paddingH,width-paddingH]);
var ys = d3.scale.linear()
.domain([0,5.5])
.range([height-paddingV,paddingV]);
xline = cv.append("svg:line")
.attr("x1", xs(0))
.attr("x2", xs(50000))
.attr("y1", ys(0))
.attr("y2", ys(0))
.style("stroke", "darkgray");
yline = cv.append("svg:line")
.attr("x1", xs(0))
.attr("x2", xs(0))
.attr("y1", ys(0))
.attr("y2", ys(5))
.style("stroke", "darkgray");
dline = cv.append("svg:line")
.attr("x1", xs(0))
.attr("y1", ys(4))
.attr("x2", xs(48000))
.attr("y2", ys(0))
.style("stroke", "steelblue")
.style("stroke-width", 2);
mline1 = cv.append("svg:line")
.attr("x1", xs(16000))
.attr("y1", ys(0))
.attr("x2", xs(16000))
.attr("y2", ys(5))
.style("stroke", "green");
circleIntersect = cv.append("svg:circle")
.attr("cx", xs(16000))
.attr("cy", ys(2))
.attr("r",4)
.style("stroke", "red")
.style("fill", "red");
</script>
</body>
</html>
Your dline does not represent x = 48000 - 16000y; if that were the case, it should cross the y axis at a value of 3, not 4 (16 * 4 = 64).
Either your dline should start at y = 3, or your circle should be at y =~ 2.67.
You can see for yourself here.