Transit / Duration Errors in d3js and Meteor - d3.js

I've been looking for a solution for this but no luck. I can't get rid of this error, yet every example for d3 in Meteor that I've seen has it.
Array Getting Passed to d3:
{categoryName:"Shooter", count:"19"}
{categoryName:"Action",
count:"23"}
Error Encountered in Console:
"TypeError: slice.transition is not a function"
"TypeError: slice.duration is not a function"
Guide I've Been Following:
http://bl.ocks.org/dbuezas/9306799
Code:
https://gist.github.com/mayvn10/83d062eb7fd257b07c33
If anyone can shed some light on why transition and duration don't work, I'm all ears!
Thanks!

Move the enter like this...
var slice = svg.select(".slices")
.selectAll("path")
.data(pie(resultArray), function(d) { return d.data.categoryName; });
slice.enter()
.append("path")
.attr("class", "slice")
.attr("d", arc)
.attr("fill", function(d) {
return color(d.data.categoryName);
});
The enter object has reduced functionality, it doesn't have a .transition property for example. The object returned by .data() is a normal selection object and has all selection.prototype methods, including transition.

Related

Show/hide D3 data points dynamically

I'm using Svelte and D3 to create a scatter-point graph.
I need it to dynamically show and hide data points depending on the length of an array of years.
If the array is empty, I want to show all of the points.
If the array is populated, I want to show only the data points which occur on years which are present in the array.
The array is coming from a parent component, I've logged it with a reactive statement and the array is correctly updated in the child component as it needs to be.
My component is currently set up as follows:
onMount(() => {
drawGraph();
plotPoints();
});
$: filterYears.length,
destroyPoints();
plotPoints();
function drawGraph() {
logic to render the graph with axis and titles relevant to the data input.
this works fine.
}
function plotPoints() {
svg.selectAll("dot")
.data(dataArray2)
.enter()
.append("circle")
.attr("r", 3)
.attr("cx", function(d) { return x(d.year); })
.attr("cy", function(d) { return yRight(d.value); })
.style("stroke", "#f8ff2a")
.style('stroke-width', '1px')
.style("fill", "#f8ff2a55")
.style("display", d => (filterYears.length > 0 && !filterYears.includes(d.year)) ? "none" : "inline")
.on('mouseover', function (event, datum) {
d3.select(this).transition()
.duration('100')
.attr("r", 7);
div2.transition()
.duration(100)
.style("opacity", 1)
div2.html((datum.value).toFixed(2))
.style("left", (event.offsetX + 25) + "px")
.style("top", (event.offsetY - 10) + "px")
})
.on('mouseout', function (event, datum) {
d3.select(this).transition()
.duration('200')
.attr("r", 3);
div2.transition()
.duration('200')
.style("opacity", 0);
});
console.log('plot point');
}
I have 2 sets of data being rendered, the above is one of them.
function destroyPoints() {
console.log('destroying points');
svg.selectAll("dot").remove()
}
All variables are correctly scoped and all functions have access to what they need.
The reactive statement seems to be called initially on component render and was triggering destroyPoints() which was trying to access svg before initialisation, causing an error, I have gotten around this with a really hacky setTimeout. If somebody could shed some light on why this happens and a better workaround I would love to hear it.
The real issue is that on change of filterYears, the points are not updating in the graph.
Could somebody give me a hand here?
Thanks!
Regular component code, including reactive statements, is executed before anything it mounted at which point DOM elements will not exist yet. It is common to just add a condition to reactive statements that depend on DOM bindings:
$: if (svg) {
filterYears;
destroyPoints();
plotPoints();
}
There seems to be another error here which is obfuscated by deceptive formatting, the correct format of the original code is:
$: filterYears.length,
destroyPoints();
plotPoints();
plotPoints() is not part of the reactive statement due to the ;.
(Also, in case you modify filterYears using functions like push: An assignment has to be used to trigger reactivity.)
I am new to d3.js, but wouldnt a pre-refinement of the inputdata be more straight forward?
svg.selectAll("dot")
.remove()
.data(filteredDataArray.any() ? filteredDataArray : dataArray2)
.enter()
.append("circle")
or maybe even more outside. just filter the dataArray

d3 stacked area tooltip

I have this stacked area chart and I am trying to get the correct value, but have no real idea how.
I was trying to place a transparent rectangle over the chart, but then realized that I still have no idea, how to get the values.
.on("mousemove", function(d) {
tooltip
.style("display", "inline-block")
.html(d[0][1]);
})
This will give me only a fix value.
Here is my plunker
Maybe you guys have an idea.
If you inspect the data object (d), though it is array-like, you can see it also has key and index properties, and that should lead you to the right data.
.on("mousemove", function(d) {
tooltip
.style("display", "inline-block")
.html(d[d.index].data[d.key]);
})
The key is determined by the key accessor stack.keys(...) that you have defined in your plunker.
Also see the docs for the stack generator: https://github.com/d3/d3-shape/blob/master/README.md#stacks

d3js: Calling different data from the same CSV - transitions

OK, this is a pretty basic question about transitions and updating data in d3js. (I'm a level 0.1 noob.) I'm importing GeoJSON and CSV data for city populations in Tanzania. It looks like this so far:
I now want to update the values, going back in time to see the 2002, 1998, 1988, etc. city populations. These previous population values are separate columns in my CSV. And I'm at a loss of how to call them. What I'm trying is this:
d3.select(window)
.on("click", function() {
svg.selectAll("circle")
.data(data)
.transition()
.append("circle")
.attr("cx", function(d) {
return projection([d.lon, d.lat])[0];
})
.attr("cy", function(d) {
return projection([d.lon, d.lat])[1];
})
.attr("r", function(d) {
return Math.sqrt(parseInt(d.y2002) * 0.0004);
})
.style("fill", "gold")
.style("opacity", 0.75);
});
The full code is here. My basic idea is that I need to go back up a level, call all the circles, re-join the data, and then re-define all the attributes. But the latter seems inefficient. And I'm getting confused: I'm worried about the asyncronicity of the CSV call, and I'm worried about which "level" of parent/child I'm at (and how I can move "up" levels?).
I'm very new to JavaScript and d3js, so this is a pretty basic question. I've read through the great tutorials by Scott Murray, and I understand transitions/updates in principle. But I'm confused about how to apply them now: especially when calling data from the same source (just a different column in a spreadsheet!).
You have the data already, so there's no need to call d3.csv again. The positions of the cities are also the same, so the only thing you need to update is the radius (and the tooltip) -- you don't even need to rebind the data. This would look like this.
svg.selectAll("circle")
.transition()
.attr("r", function(d) {
return Math.sqrt(parseInt(d.y2003) * 0.0004);
});
Note that I've changed the referenced column here. That's the only change you need to make.

D3 stacked area with brushing - only first nested element shows

I have an odd problem that I can't seem to figure out. I have a stacked area chart with a smaller context chart below where I can brush similar to this: http://bl.ocks.org/mbostock/1667367
The brush is working, but only for the first layer (I have left the clipping off as it is easier to see what is happening).
If I check the data in the console the brush function does only have that first key and if I change the order of the data the key in the chart changes so it is always whatever the first key happens to be.
Here is a JSFiddle: http://jsfiddle.net/goodspeedj/7Qzt4/
Here is the brushed function - the 3rd line in the function has the console.log statement showing the data only has the 'ABORTED' key (first layer).
function brushed() {
main_x.domain(brush.empty() ? mini_x.domain() : brush.extent());
//main.select(".layer").attr("d", main_area);
main.select(".layer").attr("d", function(d) { console.log(d); return main_area(d.values); })
main.select(".x.axis").call(main_xAxis);
}
I'm guessing this is something really simple - I just can't seem to see it. Thanks!
I figured this out. I should have been calling selectAll instead of select in the brushed function.
This:
main.selectAll(".layer").attr("d", function(d) { console.log(d); return main_area(d.values); })
Instead of this:
main.select(".layer").attr("d", function(d) { console.log(d); return main_area(d.values); })

Adding a data-* attribute to charts with r2d3.js

I am trying to add data-link attributes within charts created with d3.js, the issue I'm having is once the charts go through r2d3.js for ie8 support the data-link attribute "gets lost" somehow, I'm not sure what happens. Here is my code:
var path = group.selectAll("path")
.data(pie(tempObj))
.enter().append("path")
.attr("data-link", function () { return obj.Name.Target; })
.attr("fill", function (d, i) { return color(i) })
.attr("d", arc)
.on('click', function (d) {
alert('click');
});
The ultimate goal of making the VML shape elements, produced by r2d3.js in the process of converting charts for ie8, interactive breaks jQuery and therefore not worth the trouble. If anyone else is reading this I suggest trying another way of making interactive charts with d3.js and r2d3.js. I have used anchor tags and text within charts to accomplish this.
http://bugs.jquery.com/ticket/7071
http://blogs.microsoft.co.il/blogs/rotemb/archive/2011/04/10/asp-net-mvc-jquery-unobtrusive-ajax-failed.aspx
https://github.com/jquery/jquery/pull/13

Resources