I am starting to use an try to understand dc.js.
Unfortunately, I cannot manage to make my graphs update when I select one value in one graph, as all the tutorials/examples are supposed to work.
I have made a jsfiddle here: http://jsfiddle.net/hqwzs3ko/12/
var ndx = crossfilter(dataSet);
dims = groups = {};
dims.countries = ndx.dimension(function(d) {
return d.countryCode;
});
dims.gender = ndx.dimension(function(d) {
return d.Gender;
});
dims.emailFlag = ndx.dimension(function(d) {
return d.emailFlag;
});
//dims.countries.filter("DEU");
groups.all = ndx.groupAll();
groups.countries = dims.countries.group();
groups.gender = dims.gender.group();
groups.emailFlag = dims.emailFlag.group();
The 3 graphs display 3 different dimensions, so filter applied to one show apply to the other?
Thanks in advance for your help.
Okay spotted.
All is working perfectly here: http://jsfiddle.net/hqwzs3ko/22/
The idea is to define a reduce function based on the value that you want to be counted on, in my case the number of records (clients).
Therefore the reduce function must be based on a different value than the one used for the dimension creation:
groups.clientsPerCountries = dims.countries.group().reduceCount(function (d) { return +d.key});
groups.clientsPerGender = dims.gender.group().reduceCount(function (d) { return +d.key});
groups.clientsPerEmailFlag = dims.emailFlag.group().reduceCount(function (d) { return +d.key});
With this everything is fine!
Related
I've got a chart with some random data. On button click I'd like to add another chart on top of the first one. That works fine. I've also included zoom and it works fine with only the first chart. Zooming with both charts somehow copies the data from the second chart to the first one.
Have a look at the example. You should be able to see the blue chart. Click the button to add the green one. Now try to zoom in. The blue one disappears. However it is not gone. It is simply hidden behind the green one. They are perfectly on top of each other although they should have different values.
https://codesandbox.io/s/31lz6zrln5
Any ideas?
Best regards,
Mirco
In the button callback you modify the data elements.
filtered = () => {
const values = [...data].map(d => {
d.value = rnd(25, 75);
return d;
});
this.chart.filtered(values);
};
You should return new objects based on the fields of the other objects
filtered = () => {
const values = [...data].map(d => {
return { timestamp: d.timestamp, value: rnd(25, 75) };
});
this.chart.filtered(values);
};
Also update the filtered path in the zoom callback
public zoom = () => {
const newXScale = event.transform.rescaleX(this.xScale);
const newYScale = event.transform.rescaleY(this.yScale);
this.xAxisGroup.call(this.xAxis.scale(newXScale));
this.yAxisGroup.call(this.yAxis.scale(newYScale));
this.xGridGroup.call(this.xGrid.scale(newXScale));
this.yGridGroup.call(this.yGrid.scale(newYScale));
this.line.x(d => newXScale(d.timestamp)).y(d => newYScale(d.value));
this.lineGroup.attr("d", this.line as any);
this.lineFiltered.attr("d", this.line as any); // removed the comment of this line
};
I lose data when creating a dc.js rowchart.
var ndx = crossfilter(data);
var emailDimemsion = ndx.dimension(function(d) {
return d.email;
});
var emailGroup = emailDimemsion.group().reduce(
function(p, d) {
++p.count;
p.totalWordCount += +d.word_count;
p.studentName = d.student_name;
return p;
},
function(p, d) {
--p.count;
p.totalWordCount -= +d.word_count;
p.studentName = d.student_name;
return p;
},
function() {
return {
count: 0,
totalWordCount: 0,
studentName: ""
};
});
leaderRowChart
.width(600)
.height(300)
.margins({
top: 0,
right: 10,
bottom: 20,
left: 5
})
.dimension(emailDimemsion)
.group(emailGroup)
.elasticX(true)
.valueAccessor(function(d) {
return +d.value.totalWordCount;
})
.rowsCap(15)
.othersGrouper(false)
.label(function(d) {
return (d.value.studentName + ": " + d.value.totalWordCount);
})
.ordering(function(d) {
return -d.value.totalWordCount
})
.xAxis()
.ticks(5);
dc.renderAll();
The fiddle is here, https://jsfiddle.net/santoshsewlal/6vt8t8rn/
My graph comes out like this:
but I'm expecting my results to be
Have I messed up the reduce functions somehow to omit data?
Thanks
Unfortunately there are two levels of ordering for dc.js charts using crossfilter.
First, dc.js pulls the top N using group.top(N), where N is the rowsCap value. Crossfilter sorts these items according to the group.order function.
Then it sorts the items again using the chart.ordering function.
In cases like these, the second sort can mask the fact that the first sort didn't work right. Crossfilter does not know how to sort objects unless you tell it what field to look at, so group.top(N) returns some random items instead.
You can fix your chart by making the crossfilter group's order match the chart's ordering:
emailGroup.order(function(p) {
return p.totalWordCount;
})
Fork of your fiddle: https://jsfiddle.net/gordonwoodhull/0kvatrb1/1/
It looks there is one student with a much longer word count, but otherwise this is consistent with your spreadsheet:
We plan to stop using group.top in the future, because the current behavior is highly inconsistent.
https://github.com/dc-js/dc.js/issues/934
Update: If you're willing to use the unstable latest version, dc.js 2.1.4 and up do not use group.top - the capping is determined by chart.ordering, capMixin.cap, and capMixin.takeFront only.
I would like to use the score from input field to change the data distribution in pie chart.
For example, the distribution "71% High/ 28% Low" with scoreThreshold 0.5 will be changed to "42% High/ 57% Low" with scoreThreshold 0.7.
I made this example here, but the result was not satisfactory: when typing 0.5 in the input field and clicking "check!", the pie chart distribution does not change.
This decides the distribution:
//## pie chart
var coreCount = ndx.dimension(function (d) {
var maxNumber=80;
if (typeof scoreThreshold!='number') {scoreThreshold=0.5}
//console.log(scoreThreshold)
if (d.scores >maxNumber*scoreThreshold)
{return 'High';}
else {return 'Low';}
});
I would like to renew the coreCount function to reassign the distribution using input score threshold. But it does not work:
$('#scoreThresholdBt').click(function () {
scoreThreshold=document.getElementById('scoreThreshold').value
scoreThreshold=parseFloat(scoreThreshold);
console.log(scoreThreshold,typeof scoreThreshold);
function redo_coreCount () {
var coreCount = ndx.dimension(function (d) {
var maxNumber=80;
console.log(scoreThreshold);
if (d.count >maxNumber*scoreThreshold)
{return 'High';}
else {return 'Low';}
});
}; redo_coreCount();
coreCount.group();/**/
dc.renderAll();
dc.redrawAll();
});
How can I realize this function?
I really appreciate any help.
You are essentially putting the new dimension in a temporary variable which gets thrown away immediately. coreCount in the click function is unrelated to the variable with the same name at the global level.
Likewise, coreCount.group() is not an action; it's constructing a group object which will also get lost if you don't use it.
You need to assign the new dimension and group to your chart, since it doesn't track the value of the global or the local coreCount.
So let's change the function to return a new dimension based on reading the score threshold from the input:
function coreCount_from_threshold() {
var scoreThreshold=document.getElementById('scoreThreshold').value;
scoreThreshold=parseFloat(scoreThreshold);
console.log(scoreThreshold,typeof scoreThreshold);
if (isNaN(scoreThreshold)) {scoreThreshold=0.5}
return ndx.dimension(function (d) {
var maxNumber=80;
if (d.scores >maxNumber*scoreThreshold)
{return 'High';}
else {return 'Low';}
});
}
Note that we need to use isNaN here, because typeof NaN === 'number'
We can use this both at initialization time:
var coreCount = coreCount_from_threshold();
and on click:
$('#scoreThresholdBt').click(function () {
coreCount.dispose();
coreCount = coreCount_from_threshold();
coreCountGroup = coreCount.group();
coreYesNoPieChart
.dimension(coreCount)
.group(coreCountGroup);
dc.redrawAll();
});
Note that we are assigning to the same global variables coreCount and coreCountGroup (because we don't use var here). We first dispose the old dimension, because otherwise it would continue to filter and take up resources. Then we assign the new dimension and group to the chart (because otherwise it won't know about them).
We only need to do a redraw (not a render) here, because dc.js charts can just update when they get new data.
Here is a working fork of your fiddle.
I took example source from this link.
My data looks like this:
var data = [{ known_technologies : ["prepaid billing", " postpaid billing"],company : "A",YearsOfExp:0},
{ known_technologies : ["prepaid billing", " postpaid billing"],company:"B",YearsOfExp:1}];
My dimensions:
var ndx = crossfilter(data);
var yearDim2 = ndx.dimension(function(d)
{
return [d.known_technologies,d.company];
});
var spendPerYear2 = yearDim2.group();
I got something like below:
But I wanted in below way:
jsfiddle here
How do I make the dimensions. Any suggestions? Thanks in advance.
If you want to render two different sunbursts you need two different elements to grab on your html page. You can control the inner and out rings by changing the order of the dimensions in the array you are returning in the year2 dimension. Create appropriate groups, select both items from the DOM and create your charts as in the jsfiddle. Don't forget to call dc.renderAll() so you actually create the charts.
const ndx = crossfilter(data);
const yearDimX = ndx.dimension(function(d){
return [d.company, d.known_technologies];
});
const yearDimY = ndx.dimension(function(d){
return [d.known_technologies,d.company];
});
const spendPerYearX = yearDimX.group();
const spendPerYearY = yearDimY.group();
I have a parameter that ranges from (0-1.0). I am trying to create a dc.js bar chart, so that there are 10 bars representing (0-0.1) (0.1-0.2) and so on.
I am using crossfilter.js to create dimension and group data, but it does not seem to create groups as required.
I tried the following code
var fluctuation = ndx.dimension(function (d) {
return d.value;
});
var fluctuationGroup = fluctuation.group(function(d){
return Math.round(d*10)/10;
});
I also tried doing it another way.
var fluctuation = ndx.dimension(function (d) {
return Math.round(d.value*10)/10;
});
var fluctuationGroup = fluctuation.group(function(d){
return d;
});
Output:
Sorry folks, it was not a crossfilter problem. It was a rendering problem.
I was not using
xUnits(d3.scale.linear().domain([0, 1])) with the chart.
Please suggest if I should delete this question ? Or update it ??