exit().remove() won't remove previous content js d3 - javascript

var datapoints = svg.selectAll('indPoints').data(filtered_up);
datapoints
.enter()
.append('circle')
.merge(datapoints)
.attr('cx', function (d) {
return x(d.callType) - jitterWidth / 2 + Math.random() * jitterWidth;
})
.attr('cy', function (d) {
return y(d.time);
})
.attr('r', 1.5)
.style('fill', function (d) {
return myColor(+d.time);
});
datapoints
.transition() // and apply changes to all of them
.duration(1000);
datapoints.exit().remove();
The above code won't remove previous datapoints after I change the data (filtered_up) content.
edit:
var boxes = svg.selectAll('boxes').data(sumstat);
boxes
.enter()
.append('rect')
.transition()
.duration(2000)
.attr('x', function (d) {
return x(d.key) - boxWidth / 2;
})
.attr('y', function (d) {
return y(d.value.q3);
})
.attr('height', function (d) {
return y(d.value.q1) - y(d.value.q3);
})
.attr('width', boxWidth)
.attr('stroke', 'black')
.style('fill', 'blue');
boxes.exit().remove();
Same is happening for the code above. Is it something about the indPoints/boxes that are selected with the append?

Try to use:
.html("");
example
d3.select('#graph').html("");

Related

SVG: positioning RECT based on value

I'm wanting to recreate this graph
<div class="discrete" data-value="1,0,1,0,0,1,0,0,1,1,1,1,1,0,1,0,1,1,1,1"></div>
For each 1 I want to make a top half line, and 0 the opposite.
function discreteChart(self, dataset) {
var w = parseInt(d3.select(self).style("width")),
h = parseInt(d3.select(self).style("height")),
svg = d3.select(self)
.append("svg")
.attr("width", w)
.attr("height", h),
yScale = d3.scale
.linear()
.domain([0, d3.max(dataset)])
.range([0, h]);
svg.selectAll("rect")
.data(dataset)
.enter()
.append("rect")
.attr('fill', '#363636')
.attr('rx', '1')
.attr('ry', '1')
.attr("x", function(d, i) {
return i * 3;
})
.attr("y", function(d) {
return h - yScale(d) / 1;
})
.attr("width", 1) // width of bar
.attr("height", function(d) {
return yScale(d);
});
}
My problem is I'm not entirely sure how to do this. I have the rectangles made but I can't place them into position.
http://jsfiddle.net/everina/1eec20xe/
You can make line instead of rectangle as pointed by Anko.
Here is how you can make a line:
svg.selectAll("line")
.data(dataset)
.enter()
.append("line")
.attr('stroke', '#363636')
.attr('x1', function(d, i) {
return (i + 1) * 10;//xposition of line
})
.attr('x2', function(d, i) {
return (i + 1) * 10;
})
.attr('y1', function(d, i) {
return 10;//starting point of line
})
.attr('y2', function(d, i) {
if (d) {
return 0; //if 0 then line should be below
} else {
return 20;//if non 0 then line should be above
}
})
working example here
Hope this helps!
If you want to make the chart scaleable, so the positions are correct for any height:
svg.selectAll("rect")
.data(dataset)
.enter()
.append("rect")
.attr('fill', '#363636')
.attr('rx', '1')
.attr('ry', '1')
.attr("x", function(d, i) {
return i * 3;
})
.attr("y", function(d) {
return d ? h / 2 : 0;
})
.attr("width", 1) // width of bar
.attr("height", function(d) {
return h/2;
});

D3 bar chart using time scale rectangles not aligning to x axis

hello world> I have been battling this problem for a while now. Im trying to create a bar graph that will take an array of objects as data with time being a date object and value being a number.
My Scale looks like this
d3.time.scale.utc()
.domain(d3.extent(data, function (d) { return d.time; }))
.rangeRound([20, this.state.width - 60]).nice(data.length);
My rectangles are being drawn like this, using the same scale
const self = this,
xScale = this.state.xScale,
yScale = this.state.yScale,
barWidth = this.getBarWidth(data.length),
bars = chart.selectAll('rect')
.data(data);
// UPDATE
bars
.transition()
.duration(500)
.style('fill', color)
.attr('x', function(d) {
console.log(xScale(d.time)- (barWidth / 2));
return xScale(d.time) - (barWidth / 2);
})
.attr('width', barWidth)
.attr('y', function(d) { return yScale(d.value); })
.attr('height', function(d) { return self.state.height - yScale(d.value); });
// ENTER
bars
.enter()
.append('rect')
.style('fill', color)
.attr('class', 'bar')
.attr('x', function(d) {
console.log(xScale(d.time) - barWidth);
return xScale(d.time) - barWidth;
})
.attr('width', barWidth + (barWidth / data.length))
.attr('y', function(d) { return yScale(d.value); })
.attr('height', function(d) { return self.state.height - yScale(d.value); });
// EXIT
bars
.exit()
.transition()
.duration(500)
.style('fill', 'red')
.style('opacity', 0)
.remove();
I get the problem below where the ticks have some length and the axis another and the tick marks don't match the bars.
Please friends, help me find a solution to the below problem.
My bar problem

D3: Attach text to circle such that it has same priority as circle object

I am able to add text to my sketch, but I would like it if I could make my text attached directly to the circle. This means that if a circle gets over-written by another circle, the text will as well. On a higher level not, I am finding the d3 model hard for constructing objects in a way that makes them composable with different shapes, etc. The code seems very procedural to mean so any tips would be greatly appeciated :)
JSFiddle link
var link = "https://api.github.com/orgs/csci-4830-002-2014/repos"
d3.json(link, function(error, data) {
var w = 10000;
var h = 1000;
var svg = d3.select("body")
.append("svg")
.attr("width", w)
.attr("height", h);
svg.selectAll("line")
.data(data)
.enter()
.append("line")
.attr("x1", 5)
.attr("y1", 5)
.attr("x2", function (d,i){
return 30*d.forks_count;
})
.attr("y2", function (d,i){
return 30*d.open_issues_count;
})
.attr("stroke-width", 2)
.attr("stroke", "black");
svg.selectAll("circle")
.data(data)
.enter()
.append("circle")
.attr("r", 40)
.attr("cx", function(d){ return 30*d.forks_count; })
.attr("cy", function(d){ return 30*d.open_issues_count; })
.attr("stroke", "black")
.attr("stroke-width", 2)
.attr("fill", "white")
svg.selectAll("text")
.data(data)
.enter()
.append("text")
.attr("dx", function(d,i){ return 30*d.forks_count; })
.attr("dy", function(d,i){ return 30*d.open_issues_count; })
.text(function(d){
if (d.name.indexOf("challenge") != -1)
return "C";
else
return "H";
});
});
With the way your code written right now, all the lines will be added first, then all the circles, and finally the texts. SVG will always put elements added later on top. So to achieve what you want, you will need to group them up. To do this, you will need to add a g element for each element of your data
var element = svg.selectAll(".element")
.data(data)
.enter()
.append("g")
.attr("class","element");
Now you can add the line, circle, and text to it
element.append("line")
.attr("x1", 5)
.attr("y1", 5)
.attr("x2", function (d, i) {
return 30 * d.forks_count;
})
.attr("y2", function (d, i) {
return 30 * d.open_issues_count;
})
.attr("stroke-width", 2)
.attr("stroke", "black");
element.append("circle")
.attr("r", 30)
.attr("cx", function (d) {
return 30 * d.forks_count;
})
.attr("cy", function (d) {
return 30 * d.open_issues_count;
})
.attr("stroke", "black")
.attr("stroke-width", 2)
.attr("fill", "white")
element
.append("text")
.attr("dx", function (d, i) {
return 30 * d.forks_count;
})
.attr("dy", function (d, i) {
return 30 * d.open_issues_count+6;
})
.style("text-anchor", "middle")
.text(function (d) {
if (d.name.indexOf("challenge") != -1) return "C";
else return "H";
});
You can check the updated JSFiddle at http://jsfiddle.net/9tp1yun7/2/

Remove and update groups on redraw with D3

visibleData is updated when resizing or moving a brush.
I want to remove the groups (rectangle+text) that are no longer in visibleData and update the rectangles positions and dimensions from the groups that are still part of visibleData:
First variant of the redraw function:
var grp = items.selectAll('g')
.data(visibleData);
var item = grp.enter().append('g')
.attr('transform', function (d) {
return 'translate(' + d.x + ', ' + d.y + ')';
});
item.append('rect')
.attr('width', rectWidth)
.attr('height', rectHeight)
.style('fill', 'gray');
item.append('text')
.text(function (d) {
return d.id;
})
.attr('x', 10)
.attr('y', 15);
grp.exit().remove();
Second variant:
var grp = items.selectAll('g')
.data(visibleData);
var item = grp.enter().append('g');
item.append('rect')
.attr('x', function (d) {
return d.x
})
.attr('y', function (d) {
return d.y;
})
.attr('width', rectWidth)
.attr('height', rectHeight)
.style('fill', 'gray');
item.append('text')
.text(function (d) {
return d.id;
})
.attr('x', function (d) {
return d.x + 5
})
.attr('y', function (d) {
return d.y + 15;
});
grp.exit().remove();
Here is the full code for the first variant : http://jsfiddle.net/vvorm/F62kt/1/
As you can see, neither of them work properly when resizing the brush from the left. I haven't managed to update the rectangles' positions and dimensions but I think it's more important to handle the removal first.
Thanks for your help.
Solved my problem using the identity function:
.data(vm.visibleData, function (d) {
return vm.visibleData.indexOf(d);
})
Thanks to http://orangevolt.blogspot.fr/2013/04/update-d3js-data-using-enterexit-with.html

on click event D3.js only works first time

I have a table that has different rows. Every row is a different data set.
I have an on click event attached to the rows that gives an extra chart when you click on the specific row.
But it only works the first time. After you first click on a specific row that data is shown in the chart, but if you click on another row the chart doesn't change.
Here is some of my code:
var chart = d3.select("body").append("svg")
.attr("class", "chart")
.attr("width", w * 24)
.attr("height", h);
//saturday
var saturday = d3.select(".saturday")
.selectAll("td")
.data(d3.values(twitterDays[5][5]))
.enter()
.append("td")
.attr("class", function(d) { return "hour h" + color(d); });
d3.select(".saturday").on("click", function() {
chart.selectAll("rect")
.data(d3.values(twitterDays[5][5]))
.enter().append("rect")
.attr("x", function(d, i) { return x(i) - .5; })
.attr("y", function(d) { return h - y(d) - .5; })
.attr("width", w)
.attr("height", function(d) { return y(d); })
chart.append("line")
.attr("x1", 0)
.attr("x2", w * d3.values(twitterDays[5][5]).length)
.attr("y1", h - .5)
.attr("y2", h - .5)
.style("stroke", "#000");
});
//sunday
var sunday = d3.select(".sunday")
.selectAll("td")
.data(d3.values(twitterDays[6][6]))
.enter()
.append("td")
.attr("class", function(d) { return "hour h" + color(d); });
d3.select(".sunday").on("click", function() {
chart.selectAll("rect")
.data(d3.values(twitterDays[6][6]))
.enter().append("rect")
.attr("x", function(d, i) { return x(i) - .5; })
.attr("y", function(d) { return h - y(d) - .5; })
.attr("width", w)
.attr("height", function(d) { return y(d); })
chart.append("line")
.attr("x1", 0)
.attr("x2", w * d3.values(twitterDays[6][6]).length)
.attr("y1", h - .5)
.attr("y2", h - .5)
.style("stroke", "#000");
});
Your are only taking care of the so-called enter selection; meaning only the creation but not the update or removal of the rects is implemented in your code.
See the General Update Pattern: General Update Pattern, I
// DATA JOIN
// Join new data with old elements, if any.
var text = svg.selectAll("text")
.data(data);
// UPDATE
// Update old elements as needed.
text.attr("class", "update");
// ENTER
// Create new elements as needed.
text.enter().append("text")
.attr("class", "enter")
.attr("x", function(d, i) { return i * 32; })
.attr("dy", ".35em");
// ENTER + UPDATE
// Appending to the enter selection expands the update selection to include
// entering elements; so, operations on the update selection after appending to
// the enter selection will apply to both entering and updating nodes.
text.text(function(d) { return d; });
// EXIT
// Remove old elements as needed.
text.exit().remove();
}
Make sure to have a look at Mike's Thinking with Joins.

Categories