I have a set of circles defined as
nodes = [{
x: xRange(xvalue),
y: yRange(getY(xvalue)),
...
}]
vis.selectAll(".nodes")
.data(nodes)
.enter().append("circle")
.attr("class", "nodes")
.attr("cx", function (d) {
return d.x;
(coordinate display)
})
.attr("cy", function (d) {
return d.y;
})
.attr("r", "7px")
.attr("fill", "black")
.attr("transform", function (p) {
return "translate(" + p.x + "," + p.y + ")";
})
The problem that I am having with these circles is that the coordinates taken from nodes are undefined when the circles are being defined, despite being defined everywhere else. Here is a test case to represent this problem, where the coordinates of one of the dots should be displayed, but isn't, since it seems to be undefined. To prove that the axes work, I have placed a dot in the first quadrant of the graph. Is there any reason for why this is happening?
You're returning before you run the logic :
.attr("cx", function (d) {
return d.x;
(coordinate display)
})
change to :
.attr("cx", function (d) {
(coordinate display)
return d.x;
})
Related
I've got an old d3v3 bubble chart -- it had some animation aspects -- I am trying to upgrade it to a v4
//version 3
https://jsfiddle.net/497tmhu0/
There is always a desire to have some animation for when these bubbles load for the first time.
So here - bubbles are created very small and then they expand in size to their resting size.
// Enter
nodes.enter()
.append("circle")
.attr("class", "node")
.attr("cx", function (d) { return d.x; })
.attr("cy", function (d) { return d.y; })
.attr("r", 10)
.style("fill", function (d, i) {
return color(i);
})
.call(force.drag());
// Update
nodes
.transition()
.delay(300)
.duration(1000)
.attr("r", function (d) {
return d.radius * scale;
})
// Exit
nodes.exit()
.transition()
.duration(250)
.attr("cx", function (d) { return d.x; })
.attr("cy", function (d) { return d.y; })
.attr("r", 1)
.remove();
I was converting the chart but some parts of the force functions are no longer working.
https://bl.ocks.org/mbostock/ad70335eeef6d167bc36fd3c04378048
https://bl.ocks.org/shimizu/e6209de87cdddde38dadbb746feaf3a3
this is the current v4 I have - but the animation and force parts are broken.
//current version 4
https://jsfiddle.net/497tmhu0/2/
June 8th -- bubbles grow in size now -- but force aspects are not working - https://jsfiddle.net/vkoxrtwz/ - need to give the bubbles some force aspects - and if clicked on temporarily change their charge so it ripples through the chart and causes the circles to repel/attract each other slightly
You can just chain your animations after the first enter() method. Draw them small, and then add a transition immediately.
// Enter
nodes.enter()
.append("circle")
.attr("class", "node")
.attr("cx", function(d) {
return d.x;
})
.attr("cy", function(d) {
return d.y;
})
.attr("r", 1)
.style("fill", function(d, i) {
return color(i);
})
.transition()
.delay(300)
.duration(1000)
.attr("r", function(d) {
return d.radius * scale;
})
https://jsfiddle.net/vkoxrtwz/
I have followed an example from here https://bl.ocks.org/d3noob/4db972df5d7efc7d611255d1cc6f3c4f to create a similar graph. However, I have one additional column of data that I need to use to create circles that match the color of the line where the radius will be some scaled value of that column entry. So, col 3 has values like 873, 15, 1000, 1563, etc. I have tried to do something like
svg.selectAll('circle').data(data)
.enter().append("circle")
.attr("cx", function(d) { return x(d.date) })
.attr("cy", function(d) { return y(d.close) })
.attr("r", '5')
.attr("fill", "red");
right below the point we add the path (right after adding the value line path in the link), however, obviously this only enters circles for one line. I have to add them for both.
You actually need two circles' selections, one for open and another for close:
svg.selectAll(null).data(data)
.enter().append("circle")
.attr("cx", function(d) { return x(d.date) })
.attr("cy", function(d) { return y(d.close) })
.attr("r", '5')
.attr("fill", "steelblue");
svg.selectAll(null).data(data)
.enter().append("circle")
.attr("cx", function(d) { return x(d.date) })
.attr("cy", function(d) { return y(d.open) })
.attr("r", '5')
.attr("fill", "red");
Here is the resulting code: https://bl.ocks.org/GerardoFurtado/4179c63daf38d85a266fb11f8e8e4c17/3786e4a0594e45e6e9a41df84bae4c6a43a86c6f
I have a graph with a line, two areas and a few circles in it:
I wrote an update method, which works just fine for everything except the circles:
function updateGraph() {
xScale.domain([startDate.getTime(), endDate.getTime()]);
addTimedTickPadding(xAxis);
yScale.domain([0, d3.max(interpolatedData, function (d) {
return d.y0 + d.y1;
})]);
var updateGroup = parentGroup.transition();
updateGroup.select('.xaxis')
.duration(750)
.call(xAxis);
updateGroup.select('.yxaxis')
.duration(750)
.call(yAxis);
updateGroup.select('.xgrid')
.duration(750)
.call(verticalGridLine());
updateGroup.select('.area-top')
.duration(750)
.attr('d', areaTop(interpolatedData));
updateGroup.select('.area-bottom')
.duration(750)
.attr('d', areaBottom(interpolatedData));
updateGroup.select('.line')
.duration(750)
.attr('d', line(interpolatedData));
updateGroup.select('.post')
.duration(750)
.data(interpolatedData)
.attr('cx', function (d) {
return xScale(dateParser.parse(d.x))
})
.attr('cy', function (d) {
return yScale(d.y0 + d.y1)
});
}
Everything transitions as expected but the circles. They just stay in place. My thought was: I append the updated data to each element and alter the cx and cy attributes accordingly, so the circles transition to their new place. But they don't move :( What am I doing wrong here?
Here is the initial code for the circles:
dataGroup
.selectAll('.post')
.data(interpolatedData)
.enter()
.append('circle')
.classed('post', true)
.attr({
'r': circleRadius,
'fill': circleFillColor,
'stroke-width': circleStrokeWidth,
'stroke': circleStrokeColor,
'cx': (function (d) {
return xScale(dateParser.parse(d.x))
}),
'cy': (function (d) {
return yScale(d.y0 + d.y1)
})
});
PS: I read abaout enter() and exit() here but don't really know, how they could be useful for updating the data which is appended on the elements.
PPS: I tried selectAll() too, but it doesn't seem to have a data() function.
I'm trying to use d3 to make a circle that is draggable, but leaves a copy of the original in place. Here is the circle:
g.selectAll('circle')
.data([{
cx: 90,
cy: 80,
r: 30 }])
.enter().append('circle')
.attr('cx', function (d) {return d.cx})
.attr('cy', function (d) {return d.cy})
.attr('r', function(d) {return d.r})
.attr('class','original')
.call(dragOriginal);
Here is the drag behavior:
var dragOriginal = d3.behavior.drag()
.on('dragstart', cloneSpeciesMaker)
.on('drag', function (d, i) {
d.cx += d3.event.dx;
d.cy += d3.event.dy;
d3.select(this).attr('cx', d.cx).attr('cy', d.cy)
});
And here is the dragstart function:
function cloneSpeciesMaker(d) {
var svg = d3.select('svg');
//original becomes copy
d3.select(this)
.classed('original',false)
.attr('class','copy');
// creates new 'original' in place
var data = [{cx:d.cx,cy:d.cy,r:d.r}];
svg.append('circle')
.data(data)
.attr('class','original')
.attr("cx",function(d) {return d.x})
.attr("cy",function(d) {return d.y})
.attr("r",function(d) {return d.r})
.style("fill","purple")
.attr("class","original")
.call(dragOriginal);
}
Right now, I'm succeeding in making the original circle become a 'copy' and dragging it around, but it the part where I append a new circle in its old place isn't working, can anyone explain why?
One problem I can see from the code is in this section:
function cloneSpeciesMaker(d) {
var svg = d3.select('svg');
//original becomes copy
d3.select(this)
.classed('original',false)
.attr('class','copy');
// creates new 'original' in place
var data = [{cx:d.cx,cy:d.cy,r:d.r}];
svg.append('circle')
.data(data)
.attr('class','original')
.attr("cx",function(d) {return d.x})
.attr("cy",function(d) {return d.y})
.attr("r",function(d) {return d.r})
.style("fill","purple")
.attr("class","original")
.call(dragOriginal);
}
You are setting the data like this
var data = [{cx:d.cx,cy:d.cy,r:d.r}];
But you are doing which is incorrect d.x and d.y is not defined by you in data.
.attr("cx",function(d) {return d.x})
.attr("cy",function(d) {return d.y})
This should have been:
.attr("cx",function(d) {return d.cx})
.attr("cy",function(d) {return d.cy})
I'm new to d3.js, and I'm getting a ReferenceError: x is not defined.
I'm just trying to draw a line of points.
var points = svg.selectAll('.dots')
.data(data)
.enter()
.append("g")
.attr("class", "dots");
points.selectAll('.dot')
.data(function (d, index)
{
var a = [];
d.values.forEach(function (values, i)
{
a.push({'x': values.x, 'y': values.y});
});
return a;
})
.enter()
.append('circle')
.attr('class', 'dot')
.attr("r", 2.5)
.attr('fill', function (d, i)
{
return colors[i];
})
.attr("transform", function (d)
{
/* Line 268: Uncaught ReferenceError: x is not defined */
return "translate(" + x(d.x) + "," + y(d.y) + ")";
}
);
In a lot of internet samples, I see x() and y() being used in translate/transform when drawing stuff. What am I doing wrong? I even have other code samples using this x() and y() and they're not throwing errors. I can't figure out the difference or what I'm missing.
d.x is actually a date, and d.y is a number.
If I change Line 268 to:
/* Removing x() and y() fixes the error: */
/* d.index increments from 0 up; assume this exists */
return "translate(" + d.index + "," + d.y + ")";
I get a perfectly working collection of points drawn (not a line actually, so not exactly what I need, but at least thousands of points show up and the data is being read correctly).
Got it, silly me, you have to define x and y:
var x = d3.time.scale()
.domain([
d3.min(activeData, function(d) { return d.x; }),
d3.max(activeData, function(d) { return d.x; })
])
.range([0, width]);
var y = d3.scale.linear()
.domain([
(d3.min(activeData, function(d) { return d.y; })),
d3.max(activeData, function(d) { return d.y; })
])
.range([height, 0]);