dc.js group.top(5) not working in chart - dc.js

i am trying to display top 5 country based on revenue
i tried feeding in chart its not working
.group(countryGrp.top(10))
but when i tried console.log(countryGrp.top(10)) i can see the values though
var country = data.dimension(function(d){return d.PName});
var countryGrp = lead.group().reduceSum(function(d) {
return d.Amount;
});
var leadBarChart = dc.barChart("#country-chart")
leadBarChart.width(500).height(450).transitionDuration(750)
.margins({
top : 20,
right : 10,
bottom : 80,
left : 50
})
.dimension(country)
.group(countryGrp.top(10))
.ordinalColors([ "#1F77B4" ]).elasticY(true).centerBar(true)
.title(function(d) {
return d.Amount;
}).gap(6).xUnits(function() {
return 2;
})
.x(d3.scale.linear())
.renderHorizontalGridLines(true).xAxis().ticks(5)
.tickFormat(d3.format("d"));
i am getting this error uncaught TypeError: undefined is not a function can any one help me out here. Thanks in advance

So group.top(N) doesn't return a group object; it returns an array. You need to supply a group for the group argument.
Unfortunately the bar chart does not currently support capping but what you can do is prefilter the data as explained here:
https://github.com/dc-js/dc.js/wiki/FAQ#filter-the-data-before-its-charted
Basically you will create a "fake group" which has an .all() function which returns only the items you want.
I am planning to fix .data() so that it works for bar charts:
https://github.com/dc-js/dc.js/issues/584
(and it would also be nice to support capping) but for now I think you are stuck with the "fake group" workaround.
Please comment here if you can't get this to work, or add you example to the wiki linked above if you do get it to work!

You'll want to use something like the following:
function getTops(source_group) {
return {
all: function () {
return source_group.top(5);
}
};
}
var fakeGroup = getTops(groupToFindTopsFor);
You can then use .group(fakeGroup) to properly chart your data.

Related

How do I draw donut with absolute values intead of percents with Keen.io & c3?

I'm using Keen.io ("version": "3.4.1") JavaScript SDK, along with their integration with C3.js, to produce a donut graph by using the code below. However, I don't want percentages, but rather absolute numbers. i.e. Not 25%, but 7.
From reading the docs and looking at examples (see "var c3gauge") and example, I thought you could modify the output by applying the chartOptions. That doesn't seem to be working. At this point, I feel like I'm doing something stupid I'm just not catching.
How do I display absolute values in my donut, not percentages?
var c3donut = new Keen.Dataviz()
.library('c3')
.chartType('donut')
.el(document.getElementById(elem))
.title("Awesome Sauce")
.parseRawData(data)
.chartOptions({
donut: {
label: {
format: function (value) {
console.log("I never fire, why?");
return value;
}
}
}
})
.render();
This is possible with keen-dataviz.js library. I've created a working example here: https://jsfiddle.net/bx9efr4h/1/
Here's part of the code that made it work:
var chart = new Keen.Dataviz()
.el('#chart')
.type("donut")
.chartOptions({
donut: {
label: {
format: function(value) {
return value;
}
}
}
})
.prepare();
keen-js works a little differently because c3.js is not the default dataviz library for it. This is likely why it isn't working like expected for you.

exit().remove() doesn't remove obsolete elements

http://jsfiddle.net/brunoperel/z6qfttmr/
I'm trying to create elements on-the-fly, depending on the link which has been clicked on :
d3.select('#processes').selectAll('.processLaunch').data(helperProcessesData).enter()
.append('a')
.classed('processLaunch', true)
.attr('href', 'javascript:void(0)')
.text(function(d) { return d.text; })
.on('click', function(d) {
var currentProcess=d.name;
var filteredData = helperStepsData.filter(function(d) { return d.process === currentProcess; });
var helperStepsForProcess = d3.select('div#helperContainer').selectAll('.helperStep')
.data(filteredData);
console.log('Filtered data : '+JSON.stringify(filteredData));
console.log('Linked data : '+JSON.stringify(helperStepsForProcess.data()));
helperStepsForProcess.enter()
.append('div').text(function(d) { return 'Step '+d.step+' : '+d.title; });
helperStepsForProcess.exit().remove();
});
There are (at least !) two things that I don't understand here :
Each time I click on a link, related texts are added to the page, but obsolete ones are not removed even though I called .exit().remove() on the selection. Why ?
When I do a console.log of the data that is about to be bound to the selection's elements, it returns an array of objects, which is fine. But when, in the line after this, I retrieve the data which has been bound to the elements, I get an array of undefined objects. Why don't I get an array of objects as well ?
I think you just forgot to add the respective class on the steps:
helperStepsForProcess.enter()
.append('div')
.attr('class', 'helperStep');
helperStepsForProcess.text(function(d) {
return 'Step '+d.step+' : '+d.title; });
Adding this in your fiddle return the expected result.
I hope this helps!
Update: https://jsfiddle.net/chroth/z6qfttmr/2/

How to get data of parent node in d3.js

I am doing nesting in D3 and in a nested element, I need to reach data object on its parent.
Right now I am doing
d3.select(this).node().parentNode.__data__;
Is there a better way?
d3.select(this).node() is the same as just this in the context of a function passed to a D3 selection. You could rework it like this d3.select(this.parentNode).datum() and get the correct value back without having to use the ugly double-underscore property.
The other method I'm familiar with is to use .each() on the parent, and then deal with children within the closure:
d3.selectAll('.parent').each(function(parentDatum) {
d3.select(this).selectAll('.child').each(function(childDatum) {
// do stuff with parentDatum and childDatum here
});
});
I found this post when I had exactly the same issue. My solution, was to change the selection to pass on the data that I will need in the child, which I think might be a valid approach if you can live with the data redundancy in the node.
[
{
title: "Google",
link: "www.google.com",
languagePath : "en,fr,it"
},
...
]
To help explain, I've used this in the context of a table, with two columns. The first column has the title and the second column has an a for each of the accept-language items.
So I did a sub selections of the split of languagePath and for each enter call, I would create a a with the text being the language.
So at this point I also need the link, so that the a elements look like:
EN
FR
But the link is not part of the data passed to this child, so when I did the selection instead of doing:
var langLinks = tableRow
.append("td")
.selectAll("span")
.data(function(d) {
return d.languagePath.split(",")
})
I did
var langLinks = tableRow
.append("td")
.selectAll("span")
.data(function(d) {
return d.languagePath.split(",").map(function(item) {
return {
lang : item,
link : d.link
})
})
And so, when I'm processing data on the enter() of this selection I do have the parent's data.
Hope this is a valid alternative for some of you, it did help me.

turning pointLabels on and off in jqplot

I am trying to turn pointLabels on and off programmatically. I thought it would work something like this:
var data_ = [[1,1],[2,5],[4,9]];
var graph = $.jqplot(id_graph, [data_], {
series:[{pointLabels: { show:true } }]
}
);
graph.series[0].pointLabels.show=false;
graph.replot();
However, this still displays the point labels.
Thanks for any help!
althoug this post is old I found a solution for the problem:
var data_ = [[1,1],[2,5],[4,9]];
var graph = $.jqplot(id_graph, [data_], {
series:[{pointLabels: { show:true } }]
}
);
graph.series[0].plugins.pointLabels.show=false;
graph.replot();
Instead of using
graph.series[0].pointLabels.show=false;
use
graph.series[0].plugins.pointLabels.show=false;
In my case this worked.
Adding to Boro's answer, if you want to toggle the marker on a single series, it would be quicker to do:
graph.drawSeries({markerOptions:{show:false}},seriesIndex); //redraw single series
Calls to replot can be expensive with a large number of series.
Revved fiddle here.
I think what you want is actually showMarker option. Since in this code you are not setting point labels therefore they will never be show. The showMarker will let you switch the dots of the graph on/off.
Is that what you are in fact after? Otherwise please provide an example that you use.
Here is a sample made for a similar issue.
Please see this sample. There on the button click the change of makers visibility occurs.
Update:
This sample shows the solution, which uses the approach presented above, i.e. re-plotting the plot while changing the 'pointLabels' new parameter.
jQuery(document).ready(function () {
var data = [
[1, 1],
[2, 5],
[4, 9]
];
var graph;
var isShowPointLabels = true;
function makePlot(showPointLabels) {
graph = $.jqplot("chart", [data], {
series: [{
pointLabels: {
show: showPointLabels
}
}]
});
}
makePlot(isShowPointLabels);
$("#click").click(function () {
isShowPointLabels = !isShowPointLabels;
makePlot(isShowPointLabels);
graph.replot();
});
});
In this case I couldn't figure out how to use drawSeries(...) to re-plot just a single series, as #Mark shows for marker, which would be a good practice to do here.

prototype get inner html of multiple classes

I am new to prototype and finding it a lot more difficult than jquery. All i want to do is get the inner html of various classes.
$$('.book').each(function() {
var msg = this.down(".information");
alert(msg.innerHTML);
//new Tip(this, msg.innerHTML, {stem: 'topLeft', hook: { tip: 'topLeft', mouse: true }, offset: { x: 14, y: 14 }});
});
I'm trying to create tooltips for multiple items, but I'm not even getting the alert.
I think you can probably prevent the extra dom work of down() like this:
$$('.book .information').each(function(book) {
alert(book.innerHTML);
});
remember you also have the ability to use advanced CSS2 and CSS3 selectors in prototype like this for example:
$$('.book a[rel]').each(function(el) {
alert(el.rel);
});
see the bottom of this page for more examples http://www.prototypejs.org/api/utility/dollar-dollar
The this variable is not pointing to the element you're iterating over in Prototype, you have to explicitly use a parameter:
$$('.book').each(function(book) {
var msg = book.down(".information");
alert(msg.innerHTML);
});

Resources