I've successfully created several plots with d3 by parsing XML files such as this one.
Now I'm wondering how to deal with incomplete datasets. In my particular example, some sub-elements are missing in some elements. In that case I want d3 to discard the element and not display anything. At the moment, I am applying a filter to the dataset before feeding it into d3's data() function.
Is there a smarter of way of doing this on the fly? Ideally I'd just like to return null when setting an attribute and the required sub-element turns out not to exist.
Full disclaimer: I'm just starting to learn d3.js.
This can be obtained by setting the display property on the data joined DOM elements:
elemSelection.style("display", function (d) {
return is_data_NA(d) ? "none" : null;
});
Here is a short mock example: http://jsfiddle.net/rU4XL/
Note that by default, the function which accept value as a function such as .attr, .style, etc., will remove the attribute or content from the selection if the value function returns null. Hence, in this case, the display attribute would be removed from the elements in the elemSelection which have valid data.
Related
I wish to get handles of all the charts in a stage in order to modify background settings.
I noticed there is a stage.forEachChild(function(element) { … }) method that allows you to fire up a function for each stage element.
For example:
stage.forEachChild(function(element) {
alert(element.id());
});
The problem is that "element" type is anychart.graphics.vector.Element; instead I need a anychart.core.Chart object in order to call the background() method. Is there a way to do that?
Unfortunately, is a GraphicsJS entity and it returns its graphic vector elements as children. It doesn't control charts. You can store all chart in an object or array and iterate them, or apply a unique ID to every chart and get access to them at any moment by anychart.getChartById('CHART_ID');. For details, check the sample by the link in a comment below.
I'm trying to create a stacked bar chart visualization via a jsFiddle. I've input my data into some pre tags, however, I am not seeing anything when I try to display my visualization.
Any ideas what might be going on?
Example is here: http://jsfiddle.net/9pom9mu3/
There are a few small problems in how you're trying to access your data.
text() is a function provided on D3 selections, rather than an attribute. Thus in order to extract the text value from your <pre id='data_csv'>...</pre>, you need to do d3.select('#data_csv').text().
You're using d3.csv.parse, which takes as input a string, and therefore is synchronous. Thus you don't pass it a function as an argument, but can just take the return value.
var data = d3.csv.parse(d3.select('#data_csv').text());
Your data is comma- and space-separated (i.e. ", "), rather than just comma-separated (","). In addition, there were four spaces in front of each row. Try this instead:
<pre id='data_csv'>Variable,Year,Country
36,1996,Canada
34,1996,Mexico
38,1998,Canada
32,1998,Mexico
42,2002,Canada
37,2002,Mexico
</pre>
If you make these changes, data will look like this:
[{"Variable":"36","Year":"1996","Country":"Canada"},
{"Variable":"34","Year":"1996","Country":"Mexico"},
{"Variable":"38","Year":"1998","Country":"Canada"},
{"Variable":"32","Year":"1998","Country":"Mexico"},
{"Variable":"42","Year":"2002","Country":"Canada"},
{"Variable":"37","Year":"2002","Country":"Mexico"}]
Note that there are still some issues with your fiddle that prevent your barchart from showing up. For example, there is no "Medal Count" or "Gender" data, which are used in a number of places.
With d3 the selection returned by *.enter() is special in that it is only a placeholder for coming elements. Unfortunately this means I can not get the data related to the entering elements using *.data() (as is possible with *.exit().data()).
I'm currently in a situation where the timing of several transitions is dependant on the content of the entering elements before these elements are initialised.
My question is thus: How do I obtain an array of the data objects that will be linked to the entering elements in a data join, before these have been instantiated?
You can access the data structures inside the selection directly. At the top level, there's a single element array. The element contains the placeholder elements with the data bound to them for the enter selection. You just need to iterate over those elements.
var enterData = selection.data(data)
.enter()[0].map(function(d) { return d.__data__; });
Complete demo here.
I'm attempting to create a d3 plugin ala this stackoverflow question:
How to make a d3 plugin?
But within his shown example
(function() {
d3.selection.prototype.editable = d3.selection.enter.prototype.editable = function() {
return this.attr('data-editable', true);
};
})();
I don't see how he can actually retrieve the data associated with the selection. Is this something that can even be retrieved with this extension of d3.selection? I mucked through the d3 source a little bit but found myself far more confused than before.
Can someone who has written a d3 extension/plugin guide me in the right direction?
In javascript, the object that this refers to is (usually, and in your example code above) determined by the object which calls the function where this appears.
Hence the line return this.attr('data-editable', true); will return the exact same d3 selection object that calls editable.
So you will get back the normal old d3 selection object, just as you would in the ordinary d3 method chaining pattern. Once you have that, getting the data is just a matter of looking up the API for the d3 selection object.
If you are interested specifically in how to get the data back, take a look at the data method. From the link above, when that method is called with no arguments:
If values is not specified, then this method returns the array of data
for the first group in the selection. The length of the returned array
will match the length of the first group, and the index of each datum
in the returned array will match the corresponding index in the
selection. If some of the elements in the selection are null, or if
they have no associated data, then the corresponding element in the
array will be undefined.
What exactly does extra select() on enter() selection do and why does it not have selectAll()?
Now here I am probably supposed to post more text to "meet your quality standards", but I am quite sure the question is precise enough and hopefully not too stupid. I spent few days reading through various d3 tutorials and docs, and this part still escaped from me.
Calling select on the enter selection is rare; it is much more common to use append or insert instead. Yet the end result of all three of these methods is the same: it specifies how to instantiate elements in the enter selection.
When you perform a data-join, three new selections are returned:
the update selection: selected elements that correspond to the data
the exit selection: any leftover elements (no corresponding data)
the enter selection: any leftover data (no corresponding elements)
Since the enter selection is leftover data, there are by definition no corresponding elements. The enter selection thus initially contains placeholder nodes which you must instantiate into proper elements. You almost never see these nodes because you immediately tell D3 how to create the missing elements, typically by calling append or insert. These methods create new elements and insert them into the DOM. (The parent node is determined by the previous select, as described in the nested selections tutorial.)
In rare cases, you might want to do something beyond the standard append or insert for instantiating entering nodes. For example, the standard append method always creates elements of the same name (such as "div" or "rect"). If you wanted to specify the name dynamically, you could use select instead and pass in a function to create the new elements (as discussed in this thread in the d3-js mailing list):
enterSelection.select(function(d) {
return this.appendChild(document.createElement(d.name));
});
In fact, if you look at how append is implemented, you'll see that it's just a wrapper on top of select. A slightly simplified implementation is:
d3.selection.prototype.append = function(name) {
return this.select(function() {
return this.appendChild(document.createElement(name));
});
};
These example implementations are simplified because they don't deal with namespaced SVG elements. For this reason it's easier to use the built-in methods, and these examples are solely to explain how D3 works internally.
Calling .select() on an .enter() selection does the same thing it does for other selections -- you can use it to narrow down what you select further. Having .selectAll() wouldn't really make sense as the .enter() selection refers to things that are not actually there yet. Therefore you would only be able to select the entire selection again (as there're no distinguishing characteristics).