I'm working on DC.js charts and I'm trying to understand of how to create an overall "Total" variable of a column in the dimension.group() function. Lets say a column is called packages and its just integers. The dimensions is Area (North, South, East, West). When I develop the DC.js rowChart, I have to create the groups. Is it possible to create an overall total of package column inside the group() function?
Here is a simple create groups code below.
function createGroup(dimension, config) {
return dimension.group().reduce(
function(p,v) {
p.Total += v.packages;
/* p.TotalOverall = ??*/
return p;
},
function(p,v) {
p.Total -= v.packages;
return p;
},
function() {
return {
Total : 0,
}
}
); // end of return
}
within the reduce function, is it possible to create a variable or object that will state only total overall package column? In the p object, I just want to add a total Overall package. I know there's a way using the groupAll() but I want my charts to have the total Overall Packages number (Object) available so I can display that in the tooltip, etc. This object will not change during the filter, I just need that total.
Related
Is it possible using the framework ag-grid in JS to apply a conditional background color formatting of a cell based on its value such as Excel conditional formatting (eg the second table formatting in this link is a great example of what I am trying to achieve).
Basically, cells containing the highest values are green and tend to be red as they lower, being yellow when they reach the median (the inverse is applied in above link)
As you see, it is not a simple CellClassRules as the cell color depends cell values across the table and not only a specific row or column.
I didn’t find such option on ag-grid documentation.
Write a function for the cellStyle and have this function look at each and every value in the table, determine it's ranking, then have it return the relevant colour for the cell, i.e. the lower it is, return a more "reddish" colour, the higher it is, return a "greener" colour. Something like this:
function myCellStyleFunction(params) {
const totalCellCount = params.api.getDisplayedRowCount() * columnsCount;
let allValuesInTable = [];
rowData.forEach((x) => {
const valuesForRow = Object.keys(x).map(function (k) {
return x[k];
});
allValuesInTable = allValuesInTable.concat(valuesForRow);
});
const valuesForTableOrdered = allValuesInTable.sort(function (a, b) {
return a - b;
});
const valueIndex = valuesForTableOrdered.indexOf(params.value);
console.log(valueIndex)
debugger;
const bgColour = generateColor('#FF0000','#00FF00',totalCellCount,valueIndex)
return { backgroundColor: '#' + bgColour };
}
And apply this cellStyle in defaultColDef so it is applied to every cell.
Demo.
Why don't you use the Gradient Column feature and it will do it all for you with a couple of clicks?
https://demo.adaptabletools.com/style/aggridgradientcolumndemo
I'm learning crossfilter and want to filter some data.
So I have this big json file (It's actually csv) with almost 4 million lines of data.
The file looks like this:
timestamp,speed,power,distance,temperature,heart_rate,cadence,altitude,lat,long
1514806362,6569,172,6.63,14,90,87,2548,500870453,33664825
And all I'm trying to do is filter the distance.
d3.csv('data2.json').then(function(data) {
data.forEach(function(d, i) {
d.date = parseDate(d.timestamp);
});
// Create instance of crossfilter with dataset
var cf = crossfilter(data);
// Ask crossfilter how many rows it has / Size of data
dataSize = cf.size();
console.log("Data size: " + dataSize);
function parseDate(d) {
return new Date(d*1000);
}
var distanceDimension = cf.dimension(function(d) { return d.distance; });
console.log("Creating delay dimension");
// List top 3 distance
distanceDimensionTop3 = distanceDimension.top(3);
console.log("Top 3 distance");
console.table(distanceDimensionTop3);
// List bottom 3 distance
distanceDimensionBottom3 = distanceDimension.bottom(3);
console.log("Bottom 3 distance");
console.table(distanceDimensionBottom3);
// Apply filter to get only distance above 5000 meters
distanceDimension.filterFunction(function(d) {return d > 5000;});
console.log("Appliyng distance filter for only distance above 5000 meters");
// List bottom 3 distance
console.log("Bottom 3 distance with filter applied");
console.table(distanceDimension.bottom(3));
});
But somehow my code fails right at the beginning listing the top 3 distance.
I get a value of 99999.88 but in my data file, I have bigger values.
Also when I apply the filter to my dimension it doesn't filter right.
Thanks in advance.
We have scatter plots working great in our dashboard, but we have been thrown a curve ball. We have a new dataset that provides multiple y values for a single key. We have other datasets were this occurs but we had flatten the data first, but we do not want to flatten this dataset.
The scatter plot should us the uid for the x-axis and each value in the inj field for the y-axis values. The inj field will always be an array of numbers, but each row could have 1 .. n values in the array.
var data = [
{"uid":1, "actions": {"inj":[2,4,10], "img":[10,15,25], "res":[15,19,37]},
{"uid":2, "actions": {"inj":[5,8,15], "img":[5,8,12], "res":[33, 45,57]}
{"uid":3, "actions": {"inj":[9], "img":[2], "res":[29]}
];
We can define the dimension and group to plot the first value from the inj field.
var ndx = crossfilter(data);
var spDim = ndx.dimension(function(d){ return [d.uid, d.actions.inj[0]];});
var spGrp = spDim.group();
But are there any suggestions on how to define the scatter plot to handle multiple y values for each x value?
Here is a jsfiddle example showing how I can display the first element or the last element. But how can I show all elements of the array?
--- Additional Information ---
Above is just a simple example to demonstrate a requirement. We have developed a dynamic data explorer that is fully data driven. Currently the datasets being used are protected. We will be adding a public dataset soon to show off the various features. Below are a couple of images.
I have hidden some legends. For the Scatter Plot we added a vertical only brush that is enabled when pressing the "Selection" button. The notes section is populated on scatter plot chart initialization with the overall dataset statistics. Then when any filter is performed the notes section is updated with statistics of just the filtered data.
The field selection tree displays the metadata for the selected dataset. The user can decide which fields to show as charts and in datatables (not shown). Currently for the dataset shown we only have 89 available fields, but for another dataset there are 530 fields the user can mix and match.
I have not shown the various tabs below the charts DIV that hold several datatables with the actual data.
The metadata has several fields that are defined to help use dynamically build the explorer dashboard.
I warned you the code would not be pretty! You will probably be happier if you can flatten your data, but it's possible to make this work.
We can first aggregate all the injs within each uid, by filtering by the rows in the data and aggregating by uid. In the reduction we count the instances of each inj value:
uidDimension = ndx.dimension(function (d) {
return +d.uid;
}),
uidGroup = uidDimension.group().reduce(
function(p, v) { // add
v.actions.inj.forEach(function(i) {
p.inj[i] = (p.inj[i] || 0) + 1;
});
return p;
},
function(p, v) { // remove
v.actions.inj.forEach(function(i) {
p.inj[i] = p.inj[i] - 1;
if(!p.inj[i])
delete p.inj[i];
});
return p;
},
function() { // init
return {inj: {}};
}
);
uidDimension = ndx.dimension(function (d) {
return +d.uid;
}),
uidGroup = uidDimension.group().reduce(
function(p, v) { // add
v.actions.inj.forEach(function(i) {
p.inj[i] = (p.inj[i] || 0) + 1;
});
return p;
},
function(p, v) { // remove
v.actions.inj.forEach(function(i) {
p.inj[i] = p.inj[i] - 1;
if(!p.inj[i])
delete p.inj[i];
});
return p;
},
function() { // init
return {inj: {}};
}
);
Here we assume that there might be rows of data with the same uid and different inj arrays. This is more general than needed for your sample data: you could probably do something simpler if there is indeed only one row of data for each uid.
To flatten out the resulting group, with we can use a "fake group" to create one group-like {key, value} data item for each [uid, inj] pair:
function flatten_group(group, field) {
return {
all: function() {
var ret = [];
group.all().forEach(function(kv) {
Object.keys(kv.value[field]).forEach(function(i) {
ret.push({
key: [kv.key, +i],
value: kv.value[field][i]
});
})
});
return ret;
}
}
}
var uidinjGroup = flatten_group(uidGroup, 'inj');
Fork of your fiddle
In the fiddle, I've added a bar chart to demonstrate filtering by UID. Filtering on the bar chart works, but filtering on the scatter plot does not. If you need to filter on the scatter plot, that could probably be fixed, but it could only filter on the uid dimension because your data is too course to allow filtering by inj.
I need to create a rowchart in dc.js with inputs from multiple columns in a csv. So i need to map a column to each row and each columns total number to the row value.
There may be an obvious solution to this but i cant seem to find any examples.
many thanks
S
update:
Here's a quick sketch. Apologies for the standard
Row chart;
column1 ----------------- 64 (total of column 1)
column2 ------- 35 (total of column 2)
column3 ------------ 45 (total of column 3)
Interesting problem! It sounds somewhat similar to a pivot, requested for crossfilter here. A solution comes to mind using "fake groups" and "fake dimensions", however there are a couple of caveats:
it will reflect filters on other dimensions
but, you will not be able to click on the rows in the chart in order to filter anything else (because what records would it select?)
The fake group constructor looks like this:
function regroup(dim, cols) {
var _groupAll = dim.groupAll().reduce(
function(p, v) { // add
cols.forEach(function(c) {
p[c] += v[c];
});
return p;
},
function(p, v) { // remove
cols.forEach(function(c) {
p[c] -= v[c];
});
return p;
},
function() { // init
var p = {};
cols.forEach(function(c) {
p[c] = 0;
});
return p;
});
return {
all: function() {
// or _.pairs, anything to turn the object into an array
return d3.map(_groupAll.value()).entries();
}
};
}
What it is doing is reducing all the requested rows to an object, and then turning the object into the array format dc.js expects group.all to return.
You can pass any arbitrary dimension to this constructor - it doesn't matter what it's indexed on because you can't filter on these rows... but you probably want it to have its own dimension so it's affected by all other dimension filters. Also give this constructor an array of columns you want turned into groups, and use the result as your "group".
E.g.
var dim = ndx.dimension(function(r) { return r.a; });
var sidewaysGroup = regroup(dim, ['a', 'b', 'c', 'd']);
Full example here: https://jsfiddle.net/gordonwoodhull/j4nLt5xf/5/
(Notice how clicking on the rows in the chart results in badness, because, what is it supposed to filter?)
Are you looking for stacked row charts? For example, this chart has each row represent a category and each color represents a sub-category:
Unfortunately, this feature is not yet supported at DC.js. The feature request is at https://github.com/dc-js/dc.js/issues/397. If you are willing to wade into some non-library code, you could check out the examples referenced in that issue log.
Alternatively, you could use a stackable bar chart. This link seems to have a good description of how this works: http://www.solinea.com/blog/coloring-dcjs-stacked-bar-charts
I'm trying to change the dimensions of my parallel sets chart dynamically, as previously asked in this question.
I'm using the reusable chart created by Jason Davies:
http://www.jasondavies.com/parallel-sets/
I create my chart using this code:
var chart = d3.parsets()
.dimensions(["Survived", "Sex", "Age", "Class"]);
var vis = d3.select("#vis").append("svg")
.attr("width", chart.width())
.attr("height", chart.height());
d3.csv("titanic.csv", function(error, csv) {
vis.datum(csv).call(chart);
});
I have created a button that when clicked should call a function change that should change the dimensions to ["Survived", "Sex", "Class"].
The function:
function change() {
vis.call(chart.dimensions(["Survived", "Sex", "Class"]));
}
When the function is called I get the error Uncaught TypeError: Cannot read property 'hasOwnProperty' of undefined on line 90 which is within the updateDimensions function in the reusable chart.
Anyone has a solution for this or should I solve it by using the workaround by creating a new svg object with the new dimensions and remove the old one as user1386906 mentions in a comment in the previously asked question?
Is there a way to make the parallel set take different values which are in json for a data entity
I have did with some random number generator
svg.datum(data)
.call(chart
.value(function(d, i) {
var v1, v2, v3;
v1 = d["Valu"];
v2 = d["Val"];enter code here
v3 = d["Value"];
console.log(v1);
console.log(v2);
console.log(v3);
var x = Math.floor((Math.random() * 10) + 1);
if (x < 5) {
return v2;
} else {
return v3;
}
})
.mapLevel(levelMap)
.dimensions(arrayOfDimensions)
//dimensions to be displayed by chart. (i.e "Cost Item", "Location" etc)
);
There is three different values named, Value, val, valu , I want nodes to take different values for parallel nodes , So that each set of parallel node has different size of nodes
example :
nodeP node Parallel to nodeP
] ]
]
has different size so ribbon connecting them has varying size from source node to destination node.