I'm new to d3.js and trying to understand how to retrieve elements that are already on an html page.
If I try something like the following, 'd' is undefined when I look in the console log. I can access some of the td information via the 'this' keyword, but looking at the d3 API https://github.com/mbostock/d3/wiki/Selections#wiki-style, it says if style takes a value as a function, it passes the current 'datum' and index.
I can get the index fine, but datum is always undefined. Is there something obvious I'm missing to retrieve the values, or have the wrong way around ?
<table class="results">
<tr><td>13/1/0014</td><td>81</td><td>3</td><td></td></tr>
<tr><td>12/1/0014</td><td>690</td><td>47</td><td></td></tr>
<tr><td>5/1/0014</td><td>450</td><td>26</td><td></td></tr>
</table>
d3.selectAll(".results td:nth-child(4n+2)")
.style("background-color", function(d) {
console.log( d );
//change style depending on d, but d is always undefined
//I can access the elements via this, but not d ?
});
jsfiddle http://jsfiddle.net/a5WkH/2/
D3 assumes that you bind data to the elements using .data() or .datum(). If you haven't done that, something like function(d) { ... } won't work. Technically what happens is that D3 adds the data bound to a DOM element as the .__data__ attribute to that element. So if you really don't want to use .data() or .datum(), you could do something like this.
d3.selectAll(".results").each(function() { this.__data__ = d3.select(this).text(); });
This is what I have done here. It is usually better to use .data() though.
Related
I have a similar issue as in Updating SVG Element Z-Index With D3
My preferred solution would be to have two groups within my svg as described in the answer by notan3xit.
But I have one data set, and a boolean flag on one of the data properties determines to which group the svg element belongs.
svg.selectAll("path")
.data(d)
.enter()
.if(d.property).appendToGroup1()
.else.appendToGroup2()
This obviously doesn't work, but something like this.
I only want to iterate through the data once, and during runtime append the generated svg elements to the according groups.
Any ideas how to go about achieving that with d3.js?
Try
.each(function(d){
var toAppend = $(this);
if (!!d.property){
toAppend.appendtoGroup1();
} else {
toAppend.appendToGroup2();
}
})//...
The general idea would be to pass d into a callback, and apply the right append method inside that callback.
It should be cleaner to first save reference to what you want to append to, in an enclosing scope so you can easily call .append() on it.
Try this:
var selectedPath=svg.selectAll("path").data(d);
svg.selectAll("path").each(function(d,i){
if(d3.select(this).attr("property's name"))
selectedPath.append("some data to group 1")
else
selectedPath.append("some data to group 2")
});
If I had your code better able to help.
Is there a way to call a function when data enters using data().enter()?
For example, in this current jsfiddle: http://jsfiddle.net/p3m8A/4/ , I have a function that draws a group and I want to call this function when new data enters. The current jsfiddle doesn't do anything but the objective is to click on the red square and using .data.enter draw a purple square when the red square is clicked.
The specific part I'm trying to get to work is :
canvas.selectAll("#boxGroup")
.data(data)
.enter().function(d,i) {
drawBox(150,20,d);
};
Thanks
The callback passed to the call method is actually passed the selection, not the data.
enterSelection.call(function(selection){/* this === selection */});
So, what you were probably looking for is the each method.
enterSelection.each(function(d, i){/* this is selection */ drawBoxes(150,20,d);});
You want the method .call(function(d))
This will run your function once, passing d as the array of all of the data you have provided. i is not defined for using call after enter().
If you want to draw multiple boxes, based on d, your code would look something like this:
canvas.selectAll("boxGroup")
.data(data)
.enter()
.call(function(d){drawBoxes(150,20,d);});
I've created a basic fiddle of this here.
Note that this is what you want to use if you want to call a function on the selection returned by .enter() in the same spot as you're using it. It's also possible to bind a function to the enter event of a given DOM element by using .on('enter',function), but this would require that the element that you are entering data into already exist.
I'm using http://bl.ocks.org/mbostock/1283663
and I'm trying to change the following code
d3.json("readme.json", function(root) {
hierarchy.nodes(root);
x.domain([0, root.value]).nice();
down(root, 0);
});
to a JSON.parse (some data). I don't have a problem pulling the JSON data but I am totally confused about what is being setup in the rest of the d3.json process with the hierarchy.node(root), x.domain and down(root)
You're probably going to have to read a little more documentation before having a working understanding of what's going in this function. This is a tricky example to start with; I'm just going to walk you through what my process of trying to understand would look like. Going line by line:
d3.json("readme.json", function(root) {
This loads the referenced json file and calls function with it. 'root' starts out equal to the json file.
hierarchy.nodes(root);
Looking through the code, we find where hierarchy is declared:
var hierarchy = d3.layout.partition()
.value(function(d) { return d.size; });
So hierarchy is some kind of layout and hierarchy.nodes will add some useful attributes to root that will make it easier to graph.
x.domain([0, root.value]).nice();
searching for "x" in the example we find x = d3.scale.linear().range([0, w]). Tt appears that x is a linear scale. Basically, the x function will transform values in the domain - [0, root.value] to the range [0, w]. w is the width of the svg. root.value is a little trickier. The node page says
value - the node value, as returned by the value accessor
But what is the value accessor? The initial declaration of indicates it has something todo with root's 'size' attribute, but what? At this point, the documentation starts to get pretty confusing so you might want to pop open the debugger and see exactly what the value attribute of root and root's children looks like.
down(root, 0);
The down function is unique to the example and well commented. Try reading through it while referencing the documentation and see if you can figure it out.
I have a d3 scatterplot and want to know how to get the value of the data appended to one single record (circle) in order to call it later in the code.
Say we have the following data:
ID X Y
A 1 1
B 2 2
C 3 3
How can I get the X value of the record B?
Does anyone have an idea how to do it?
thx
You may need to show more code, as it depends on how you're attaching the data. But assuming that you have something like
var circle = svg.selectAll("circle").data(myArrayOfDataObjects)
.enter().append("circle");
You can assign an ID or class to the DOM element you create:
circle.attr("id", function(d) { return "dataRow" + d.ID; });
Now you can use d3, plain JS, or the library of your choice to get a handle on the DOM element later on. D3 attaches its data as a __data__ property on the DOM element, so you can reference that to get your datum. D3 also provides the .datum() method to get this value:
var myDataRow = d3.selectAll("#dataRowB").datum();
var xValue = myDataRow.X;
Or, in plain JavaScript:
var myDataRow = document.getElementById("#dataRowB").__data__;
// etc
If jQuery is an option, in your d3 you can use the jQuery .data() function to attach the d3 data directly to the SVG element. Simply run something like .each(function(d){ $(this).data(d) }).
You can then access the data anywhere by using $(selector).data(), where selector points to the DOM element or elements that you're interested in, with something like '#RecordB'.
If your data is more complex, (say, d = {foo: 'foo', bar: 'bar'}), you'd use $(selector).data()[foo] to grab whatever data is keyed to 'foo' in the data associated with whatever is pointed at by the selector.
Is it possible to use selection.attr() after selection.each()? I have the following simple code:
var line = d3.svg.line()...;
chart
.selectAll('.gw')
.selectAll('path.line')
.each(function(d, i) {
$this.computeXXX(d, ....);
})
.attr('d', line);
I've checked that the 'attr' function is being called, but for some reason when I go back and try to check the 'path' elements that make up the selection, they never have the 'd' attribute set. What's the return from the 'each' call? I checked the d3 API docs and it didn't mention that there was any type of return value, yet there does seem to be.
Any suggestions on how I can fix this?
You can certainly use .attr() after .each(). I've made a very ugly example based on a pre-made chart from tributary. Anyway, you can see it uses .each() to draw an orange stroke and then modifies other attributes after. If you post more details of your code or put in on a fiddle or tributary we/I can probably help you fix it.