Hi I'm a newbie in JS and Crossfilter. I'm using crossfilter with my data (.csv file) and retrieved distinct values in a column using
var scoreDim = ppr.dimension(function (d) {
return d.score;
});
Also I could get the counts for each value using
var scoreDimGroup = scoreDim.group().reduceCount();
I could use dc.js to plot the chart and the result looks correct. But how do I retrieve the values in scoreDim and scoreDimGroup so that I can use it for further processing in my code. When I look at the object using a debugger, I could see a bunch of functions but could not see the actual values contained in the objects.
scoreDim.top(Infinity)
will retrieve the records.
scoreDimGroup.top(Infinity)
will retrieve the groups (key-value pairs of the dimension value and the count).
Generally, this kind of thing is covered well in the Crossfilter API documentation.
You can use the top method of the group object:
var groupings = teamMemberGroup.top(Infinity);
This returns an array of groups, which will have the structure that you built in the reduce method. For example, to output the key and value you can do this:
groupings.forEach(function (x) {
console.log(x.key + x.value.projectCount);
});
You can access the dimension values in the same way:
var dimData = teamMemberDimension.top(Infinity);
dimData.forEach(function (x) {
console.log(JSON.stringify(x));
});
Here is a simple example of this: http://jsfiddle.net/djmartin_umich/T5v4N/
Rusty has a nice tutorial on how this works at http://blog.rusty.io/2012/09/17/crossfilter-tutorial/
If you are looking to view these values in the console then you can use this print_filter function that was mentioned in the tutorial!
(http://www.codeproject.com/Articles/693841/Making-Dashboards-with-Dc-js-Part-1-Using-Crossfil)
Basically you would include this bit of code in your javascript rendering of the crossfilter charts before you define your data source or your ndx variable:
function print_filter(filter) {
var f = eval(filter);
if (typeof(f.length) != "undefined") {}else{}
if (typeof(f.top) != "undefined") {f=f.top(Infinity);}else{}
if (typeof(f.dimension) != "undefined") {f=f.dimension(function(d) { return "";}).top(Infinity);}else{}
console.log(filter+"("+f.length+") = "+JSON.stringify(f).replace("[","[\n\t").replace(/}\,/g,"},\n\t").replace("]","\n]"));
};
Then you can simply run print_filter(scoreDim) in your console! It's that simple! You can use this to see all of the objects you create using crossfilter including groups, etc.
Hope this helps!
Related
I have a dictionary of the number of messages sent for each person in a facebook conversation stored in a variable that looks like this:
data = {
"Person1": 55132,
"Person2": 3556,
"Person3": 4848,
"Person4": 21184,
"Person5": 4364,
"Person6": 20716,
"Person7": 51172
}
I want to make a bar chart with dc.js. I've seen examples where people make it work by creating crossfilter dimension. So far, here's what I've got:
var msgCountChart = dc.barChart("#msg-count-row-chart");
var ndx = crossfilter([data]);
authorDimension = ndx.dimension(function(d) {return Object.keys(d);});
sumGroup = authorDimension.group().reduceSum(function(d) {return d;});
msgCountChart
.width(300)
.height(280)
.x(d3.scale.ordinal().domain(Object.keys(data)))
.y(d3.scale.linear().domain([0, Math.ceil(Math.max(...Object.values(data)) / 10000) * 10000]))
.xUnits(dc.units.ordinal)
.brushOn(false)
.dimension(authorDimension)
.yAxisLabel("Messages sent")
.barPadding(0.1)
.outerPadding(0.05)
.group(sumGroup);
msgCountChart.render();
I based my code on this example which had a kind of similar data structure: https://github.com/dc-js/dc.js/blob/master/web/examples/ordinal-bar.html
The data in ndx seems to be null. How can I put my data in the crossfilter instance to make it work?
Is there another simpler solution to make the bar chart?
Crossfilter takes an array as input. You’ve got an object.
The dimension constructor takes a function returning the key for each row. So your current setup gives you one row of data with an array of all the keys as its key. Probably not null but probably not what you want.
The easiest way to get an array from an object, if you’re targeting modern browsers, is Object.entries(). This will give you an array of [key, value] pairs.
So:
var ndx = crossfilter(Object.entries(data)),
authorDimension = ndx.dimension(d => d[0]),
sumGroup = authorDimension.group().reduceSum(d => d[1]);
You don’t usually need to set the domain of X and Y scales; using .elasticX(true).elasticY(true) will usually figure that out for you.
Basically I have a complex object that retrieves the GPT API (google publisher tag) with this function:
googletag.pubads().getSlots();
The object value is something like this:
I need to know if there is a way to compare the value of each property with an X value without getting a problem of recursivity (because the object is huge and i need to to that validation several times)
Also, I tried to convert that object into a JSON with JSON.stringify(), and then tried to get the value with a regex, faster, but with this option, I have the problem with Cyclic Object Value.
Any suggestions ?
it's more simple. try it to convert it into an array and later use a filter for comparative with your value.
var objGoogle = {};
var arrayObjectGoogle = [objGoogle];
var filter = arrayObjectGoogle.filter(function(obj){
obj.yourAttr == yourValue; });
this will give you a second array with the values found it. later, index the array for pick up the value do you need.
I'm stuck with a quite simple problem and need help.
I have a big CSV file with 50 columns which i absolutely can't modifie.
Now i want to make a chart where i only need 5-6 columns out of it.
My idea was now to make a new "data2" which contains only these 5-6 columns (with key and evertything) and work with this data2.
But i'm not able to create this data2.
To filter which columns i need i wanted to work with regex. Something like this:
d3.keys(data[0]).filter(function(d) { return d.match(/.../); })
But how do i create the new data2 then? I'm sure i need to work with d3.map but even with the api i'm not able to understand how it works correctly.
Can someone help me out?
Firstly, your question's title is misleading: you're not asking about making a smaller CSV file, since the file itself is not changed. You're asking about changing the data array created by D3 when that CSV was parsed.
That brings us to the second point: you don't need to do that. Since you already lost some time/resources loading the CSV and parsing that CSV, the best idea is just keeping it the way it is, and using only those 5 columns you want. If you try to filter some columns out (which means deleting some properties from each object in the array) you will only add more unnecessary tasks for the browser to execute. A way better idea is changing the CSV itself.
However, if you really want to do this, you can use the array property that d3.csv creates when it loads an CSV, called columns, and a for...in loop to delete some properties from each object.
For instance, here...
var myColumns = data.columns.splice(0, 4);
... I'm getting the first 4 columns in the CSV. Then, I use this array to delete, in each object, the properties regarding all other columns:
var filteredData = data.map(function(d) {
for (var key in d) {
if (myColumns.indexOf(key) === -1) delete d[key];
}
return d;
})
Here is a demo. I'm using a <pre> element because I cannot use a real CSV in the Stack snippet. My "CSV" has 12 columns, but my filtered array keeps only the first 4:
var data = d3.csvParse(d3.select("#csv").text());
var myColumns = data.columns.splice(0, 4);
var filteredData = data.map(function(d) {
for (var key in d) {
if (myColumns.indexOf(key) === -1) delete d[key];
}
return d;
})
console.log(filteredData)
pre {
display: none;
}
<script src="https://d3js.org/d3.v4.min.js"></script>
<pre id="csv">foo,bar,baz,foofoo,foobar,foobaz,barfoo,barbar,barbaz,bazfoo,bazbar,bazbaz
1,2,5,4,3,5,6,5,7,3,4,3
3,4,2,8,7,6,5,6,4,3,5,4
8,7,9,6,5,6,4,3,4,2,9,8</pre>
I'm creating a flot graph using some php-script. The php generates the data and uses json_encodeto pass this data to some javascript-flot code where I parse using jQuery.parseJson.
I was using the data-array filled with (x,y) values. Plotting this doesn't seem to work. If I encapsulate the array within an object flot is plotting it without problems. Why doesn't the first method work? I've added a jsFiddle below.
var data = '[["201518","1"],["201519","3"],["201520","6"]]',
data2 = '{"data":[["201518","1"],["201519","3"],["201520","6"]]}';
var set = jQuery.parseJSON(data),
set2 = jQuery.parseJSON(data2);
var placeholder = $('#placeholder');
$.plot(placeholder, [set2.data]);
//$.plot(placeholder, set); <= not working? Why?
jsfiddle
You need to pass an array:
$.plot(placeholder, [set])
// instead of `$.plot(placeholder, set)`
Two problems. First you need numbers and not strings when passing as an array (see here where it says
Note that to simplify the internal logic in Flot both the x and y
values must be numbers (even if specifying time series, see below for
how to do this). This is a common problem because you might retrieve
data from the database and serialize them directly to JSON without
noticing the wrong type. If you're getting mysterious errors, double
check that you're inputting numbers and not strings.
Second (as pointed out in another answer), you need the [array] around set. The following works:
$(document).ready(function () {
var data = '[[201518,1], [201519,3], [201520,6]]',
data2 = '{"data":[["201518","1"],["201519","3"],["201520","6"]]}';
var set = jQuery.parseJSON(data),
set2 = jQuery.parseJSON(data2);
var placeholder = $('#placeholder');
//$.plot(placeholder, [set2.data]);
$.plot(placeholder, [set]);
});
I'm using the jqPlot library to build charts. I'm using some JS to fetch a JSON file, build a string using values from the JSON file, convert it to a nested array (the only format that jqPlot likes) and then passing to jqplot. jqPlot is reading the arry just fine and is plotting the correct values, but its adding a 0 value at the end.
Here's the string code:
$(function () {
$.getJSON("test.json", chartData);
function chartData(data) {
$.each(data.values, function(index,val){
chartValues += val + ",";
});
};
here's the code that converts it into a nested array:
var temp = new Array();
temp = chartValues.split(',');
var temp2 = new Array(temp);
alert(temp2);
So when temp2 is passed to jqplot it adds a zero, but when I pass it an identical nested array called test that is declared manually, it doesn't add the zero. Here they are for comparison:
var test = [[12,32,21,23,34,43,52,86,25,]];
and here's temp2
[[12,32,21,23,34,43,52,86,25,]]
Any ideas? I'd also appreciate any help with my logic in this, as I feel like I could be creating the nested array more elegantly.
I'm not sure 100% at this point but I think in .....86,25,]] is not right. That might be the reason to add a zero value. Try eliminating this. Another thing is that you can access the data arrays in json files directly using basic access methods. Try at json org.
Removing the last character in the string (before converting to an array) was the solution in this case.
newStr = chartValues.substring(0, chartValues.length-1);