how to move circles(data points) in d3.js - javascript

I have 2 lines in the form of waves plotted in x-y axis based on randomly generated data and i am showing circles on the waves denoting the data points on it.
Based on setInterval of 200 ms, I am updating the original data and the lines(waves) are moving to the left, but the issue is that the only circles which are there in the initial interval are moving and for 2nd interval onward the circles are not showing up on the waves.
see the jsfiddle for the running code : https://jsfiddle.net/rajatmehta/tm5166e1/10/
here is the code :
chartBody.append("path") // Add the valueline path
.datum(globalData)
.attr("id", "path1")
.attr("class", "line")
.attr("d", valueline);
chartBody.selectAll(null)
.data(globalData)
.enter()
.append("circle")
.attr("class", "dot1")
.attr("r", 3)
.attr("cx", function(d) {
console.log(d);
return x(d.timestamp);
})
.attr("cy", function(d) {
return y(d.value);
});
chartBody.selectAll(null)
.data(globalDataNew)
.enter()
.append("circle")
.attr("class", "dot2")
.attr("r", 3)
.attr("cx", function(d) {
return x(d.timestamp);
})
.attr("cy", function(d) {
return y(d.value);
});
chartBody.append("path") // Add the valueline path
.datum(globalDataNew)
.attr("id", "path2")
.attr("class", "line")
.attr("d", valueline2);
any idea how to do that ?

You need to create new circles based on the updated data. Currently, you are only updating the data to selection, but not appending circles, and then moving existing circles to the left.
For example, you could to this:
chartBody.selectAll(".dot1")
.data(globalData, function(d){ return d.timestamp; })
.enter()
.append("circle")
.attr("class", "dot1")
.attr("r", 3)
.attr("cx", function(d) {
return x(d.timestamp);
})
.attr("cy", function(d) {
return y(d.value);
});
chartBody.selectAll(".dot2")
.data(globalDataNew, function(d){ return d.timestamp; })
.enter()
.append("circle")
.attr("class", "dot2")
.attr("r", 3)
.attr("cx", function(d) {
return x(d.timestamp);
})
.attr("cy", function(d) {
return y(d.value);
});
d3.selectAll(".dot1")
//.data(globalData)
.transition()
.duration(duration)
.ease("linear")
.attr("transform", "translate(" + String(dx) + ")");
d3.selectAll(".dot2")
//.data(globalDataNew)
.transition()
.ease("linear")
.duration(duration)
.attr("transform", "translate(" + String(dx) + ")");
See here: https://jsfiddle.net/tm5166e1/11/
This appends the data, using the timestamp as a key so you only create new circles for newly added datums.
(There is an issue when they are first added which is beyond the scope of this question, but it will be worth checking out these examples: https://bl.ocks.org/tomshanley/15a2b09a95ccaf338650e50fd207fcbf and https://bl.ocks.org/mbostock/1642874)

Related

How to create a line in d3js from an array

I need to draw horizontal lines in a d3.js chart.
Using the below code I was able to draw lines.
g.append("line")
.attr("x1", x(0.5))
.attr("y1", y(1))
.attr("x2", x(3.5))
.attr("y2", y(1))
.style("stroke-width", 5)
.style("stroke", "blue")
.style("fill", "none");
But I need to draw around 8 lines in the chart.
Currently I have copy pasted the above code 8 times and entered the values manually.
Is there a way to pass the coordinates from an array, instead of copy pasting it 8?
I tried to do something like this but it did not work.
method 1:
var dataTest = [{x1:4,y1:3,x2:6,y2:3}]
g.append("g")
.selectAll('line')
.data(dataTest)
.enter()
.append('g').attr('class', 'line').append('g')
.attr({'x1':function(d,i){ console.log(d); return d.x1; },
'y1':function(d){ return d.y1; },
'x2':function(d,i){ return d.x2; },
'y2':function(d){ return d.y2; },
})
.style("stroke-width", 2)
.style("stroke", "blue")
.style("fill", "none");
method 2:
g.append("line")
.attr("d", line(dataTest))
.style("stroke-width", 2)
.style("stroke", "green")
.style("fill", "none");
where the line function returned the x and y values.
var dataTest = [{x:4,y:3},{x:6,y:3}]
var line = d3.svg.line()
.x(function (d) {
console.log(d.x);
return (d.x);
})
.y(function (d) {
return (d.y);
});

delay in adding circles in d3.js

i have a line(x-y axis) and some data points on that line. line is moving from right to left based on some fixed interval of 200ms and the data points on the line are also moving along with the line.
But the issue is that, there is some delay in the movement of circles. See the jsfiddle(scroll to the right on fiddle page to see the issue i.e. delay in circle movement)
https://jsfiddle.net/rajatmehta/tm5166e1/13/
chartBody.selectAll(".dot1")
.data(globalData, function(d){ return d.timestamp; })
.enter()
.append("circle")
.attr("class", "dot1")
.attr("r", 3)
.attr("cx", function(d) {
return x(d.timestamp);
})
.attr("cy", function(d) {
return y(d.value);
});
chartBody.selectAll(".dot2")
.data(globalDataNew, function(d){ return d.timestamp; })
.enter()
.append("circle")
.attr("class", "dot2")
.attr("r", 3)
.attr("cx", function(d) {
return x(d.timestamp);
})
.attr("cy", function(d) {
return y(d.value);
});
d3.selectAll(".dot1")
//.data(globalData)
.transition()
.duration(duration)
.ease("linear")
.attr("transform", "translate(" + String(dx) + ")");
d3.selectAll(".dot2")
//.data(globalDataNew)
.transition()
.ease("linear")
.duration(duration)
.attr("transform", "translate(" + String(dxNew) + ")");
how to prevent this delay ?
You can select dot1 and dot2 at same time and apply transition.
Currently you are selecting them and apply transition to each of them separately hence the delay

Data missing when using group-element as opposed to dots

I use this code:
svg.selectAll(".dot")
.data(data)
.enter().append("circle")
.attr("class", "dot")
.attr("r", function(d) { return domainOnlyScale(parseFloat(d.Size)+0.01); } )
.attr("cx", function(d) {return x(d.x+(Math.random() * 0.25) - 0.125); })
.attr("cy", function(d) { return y(d.y+(Math.random() * 0.25) - 0.125); })
.style("fill", function(d) { return color(d.color); })
.style("stroke-width", "1px")
.style("stroke", function(d) { return strokecolor(d.color); });
And everything works. All data points show up. Now I change this part of the code to:
console.log(data); // Shows all data points!
var groupings = svg.selectAll("g")
.data(data)
.enter()
.append("g")
.attr("transform", function(d){return "translate("+(x(d.x+(Math.random() * 0.25) - 0.125))+","+y(d.y+(Math.random() * 0.25) - 0.125)+")"}); //used console.log here)
groupings.append("circle")
.attr("class", "dot")
.attr("r", function(d) { return domainOnlyScale(parseFloat(d.size)+0.01); } )
.style("fill", function(d) { return color(d.color); })
.style("stroke-width", "1px")
.style("stroke", function(d) { return strokecolor(d.color); });
groupings.append("text")
.attr("class", "bubbletext")
.attr("dx", function(d){ return -4 })
.attr("dy", function(d){ return +5 })
.text( function(d) { return d.category.substring(0,1); } );
I used another console.log inside the function of the transform of the groupings-creation, and the data is already filtered there. From a few tries it seems as if the first ~15 entries are missing.
Thanks in advance!
The problem is that you have g elements on the page already. These are getting selected through svg.selectAll("g") and then matched to data. Hence, the enter selection doesn't contain all the elements you expect to be there.
The fix is simple -- assign a class to those g elements you're using here to be able to distinguish them from the rest and select accordingly:
svg.selectAll("g.dot")
.data(data)
.enter()
.append("g")
.attr("class", "dot");

D3 Get Variable Value

This is a very basic question, but how do I access the value of attributes in d3?
I just started learning today, so I haven't figured this out yet
Suppose I have this as part of my code here
http://jsfiddle.net/matthewpiatetsky/nCNyE/9/
var node = svg.selectAll("circle.node")
.data(nodes)
.enter().append("circle")
.attr("class", "node")
.attr("r", function (d) {
if (width < height){
return d.count * width/100;
} else {
return d.count * height/100;
}
})
.on("mouseover", animateFirstStep)
.on("mouseout",animateSecondStep)
.style("fill", function(d,i){return color(i);})
.call(force.drag);
For my animation the circle gets bigger when you mouse over it, and I want the circle to return to its normal size when you move the mouse away. However, i'm not sure how to get the value of the radius.
i set the value here
.attr("r", function (d) {
if (width < height){
return d.count * width/100;
} else {
return d.count * height/100;
}
I tried to do node.r and things like that, but i'm not sure what the correct syntax is
Thanks!
You can access an attribute of a selection with:
var node = svg.selectAll("circle.node")
.data(nodes)
.enter().append("circle")
.attr("class", "node")
.attr("r", function (d) { return rScale(d.count); })
.on("mouseover", function(d) {
d3.select(this)
.transition()
.duration(1000)
.attr('r', 1.8 * rScale(d.count));
})
.on("mouseout", function(d) {
d3.select(this)
.transition()
.duration(1000)
.attr('r', rScale(d.count));
})
.style("fill", function (d, i) {
return color(i);
})
.call(force.drag);
in this context, this points to the DOM element binded with d. Normally, the area of a circle must be proportional to the quantities that you are showing, take a look at the documentation of Quantitative Scales. A fork of your fiddle is here.

D3.js identifying links between nodes to change link thickness

I have been setting up graphs to dynamically scale in reference to the width and height of the svg or bounding box, and with nodes and node borders this is relatively simple. By using d.depth and assigning the desired ratio to assign a relative radius to a node at a certain depth, this is giving me no problems and nodes at lower depths become smaller to avoid overlap. Then, for the node border I assign a ratio between the node radius and the thickness of the border.
This has proven to be an ideal solution to a problem that arises when adding a zoom feature by scaling the container. This is the problem:
The text, the nodes, and the node borders no longer bunch up, but the links remain the same weight.
I would also like to scale the thickness of the edges between nodes but I do not know how to identify edges so that I can either assign a thickness in relation to the radius of the parent or child node
d3.json("aviation.json", function(root) {
var nodes = balloon.nodes(root),
links = balloon.links(nodes);
var link= svg.selectAll("path")
.data(links)
.enter().append("path")
.attr("d",diagonal)
.attr("stroke", "black")
.attr("shape-rendering", "auto")
.attr("fill", "none")
.data(nodes)
.attr("stroke-width", function(d) {return (1/5000*diameter);});
var node = svg.selectAll("g.node")
.data(nodes)
.enter()
.append("g")
.attr("class", "node");
node.append("circle")
.attr("r", function(d) { return d.r;})
.attr("cx", function(d) { return d.x; })
.attr("cy", function(d) { return d.y; })
.attr("fill", "white")
.attr("opacity", "0.05")
.attr("stroke-width", function(d) {return d.r/600;}) //here I am referecing d.r
//to find the stroke width.
.attr("stroke-opacity", ".5")
.on("Click", function(d) { return zoomClick});
var text = svg.selectAll("g.text")
.data(nodes)
.enter()
.append("text")
.attr("dx", function(d) { return d.x })
.attr("dy", function(d) { return d.y })
.attr("font-family", "Helvetica")
.attr("font-size", function(d) {return d.children ? d.r/7 : d.r/4;})
.attr("stroke-width", function(d) {return d.r/400;})
.attr("stroke-opacity", "1")
.attr("fill", "white")
.attr("pointer-events", "all")
.style("text-anchor", "middle")
.text(function(d) { return d.name; })

Categories

Resources