How filter using crossfilter in D3 - javascript

I'm trying to filter my dataset using crossfilter but with no luck (the full result is returned in my filterType var). My code appears to be inline with similar examples online but I must be missing something obvious. The data is for my newborn's sleep patterns, hence this may be contributing to my demise.
Can anyone enlighten me on my oversight?
//Load sample sleep data
var dataset = [
{day: 1, type: 'day', totalSleep: 8},
{day: 1, type: 'night', totalSleep: 7},
{day: 2, type: 'day',totalSleep: 8},
{day: 2, type: 'night', totalSleep: 7}
];
//Crossfilter data
var cf = crossfilter(dataset);
//Create type dimension
var typeDim = cf.dimension(function(d) {return d.type});
//Reduce type by sleep
var sleepByType = typeDim.group().reduceSum(item => item.totalSleep);
//Display result
var allTypes = sleepByType.all();
console.log('All types:');
console.log(allTypes);
//Filter on type
typeDim.filter('day');
//Filtered result
var filterTypes = sleepByType.all();
console.log('Filtered types:');
console.log(filterTypes);

By design, a group does not observe its own dimension's filters.
This is because you usually don't want a chart to filter out its own data. For example, except in rare cases, if you brush an area of the x axis of a line chart, you wouldn't want the line outside the brush to fall to zero.
If you create another dimension on the same field, and filter that, you will see an effect on sleepByType:
var typeDim2 = cf.dimension(function(d) {return d.type});
typeDim2.filter('day');

Related

google earth engine javascript error filteringdate

Hello I dont know anything to this but I just have one mistake in my code I dont know why
// Load country features from Large Scale International Boundary (LSIB) dataset.
var countries = ee.FeatureCollection('USDOS/LSIB_SIMPLE/2017');
var roi = countries.filter(ee.Filter.eq('country_co', 'CB'));
Map.addLayer(roi,{},'Cambodia')
//Let's centre the map view over our ROI
Map.centerObject(roi, 6);
// Filter the collection for the VV product from the descending track
var collectionVV = ee.ImageCollection('COPERNICUS/S1_GRD')
.filter(ee.Filter.eq('instrumentMode', 'IW'))
.filter(ee.Filter.listContains('transmitterReceiverPolarisation', 'VV'))
.filter(ee.Filter.eq('orbitProperties_pass', 'DESCENDING'))
.filterBounds(roi)
.select(['VV'])
.median();
// Filter the collection for the VH product from the descending track
var collectionVH = ee.ImageCollection('COPERNICUS/S1_GRD')
.filter(ee.Filter.eq('instrumentMode', 'IW'))
.filter(ee.Filter.listContains('transmitterReceiverPolarisation', 'VH'))
.filter(ee.Filter.eq('orbitProperties_pass', 'DESCENDING'))
.filterBounds(roi)
.select(['VH'])
.median();
// Adding the VV layer to the map at a specific date
var image = ee.Image(collectionVV.filterDate('2020-10-14', '2020-10-20').median());
Map.addLayer(image.clip(roi), {min: -25, max: 5}, 'Image_VV');
it is for the last line I get :
Line 29: collectionVV.filterDate is not a function
Thanks
Since you end your two expressions for collectionVV and collectionVH with the .median() operation, you already reduce both ImageCollections to an image (by taking the median of that collection). Simply removing the .median() statements will fix your error. Thus:
// Filter the collection for the VH product from the descending track
var collectionVH = ee.ImageCollection('COPERNICUS/S1_GRD')
.filter(ee.Filter.eq('instrumentMode', 'IW'))
.filter(ee.Filter.listContains('transmitterReceiverPolarisation', 'VH'))
.filter(ee.Filter.eq('orbitProperties_pass', 'DESCENDING'))
.filterBounds(roi)
.select(['VH'])
//.median();
// Adding the VV layer to the map at a specific date
var image = ee.Image(collectionVH.filterDate('2020-10-14', '2020-10-20').median());
Map.addLayer(image.clip(roi), {min: -25, max: 5}, 'Image_VV');

d3.js convert data using nest

I'm trying out d3.js for the first time and trying the stacked to grouped bars example.
My data is in the following format:
var data = [
{"year":2015, values:[1,2,3]},
{"year":2016, values:[10,20,30]},
{"year":2017, values:[100,200,300]}
];
I would like the x-axis to be year and the y-axis to be the values.
I am having trouble determining which parts of the api to use. Do I use nest, map, or both?
I need the data to be graphed as value1 (1,10,100), value2 (2,20,200), and value3 (3,30,300)
Thanks
Your data is like this
var data = [
{"year":2015, values:[1,2,3]},
{"year":2016, values:[10,20,30]},
{"year":2017, values:[100,200,300]}
];
Need a paser to parse your date
parse = d3.time.format("%Y").parse;
next group the data
//[0,1,2] index of the array so that the y can be calculated as d.values[grp]..here grp will be group which will have value 0 1 2
var newData = d3.layout.stack()([0,1,2].map(function(grp) {
return data.map(function(d) {
return {x: parse("" +d.year), y: +d.values[grp]};
});
}));
This will make the newData in the format you wish:
[[{"x":"2014-12-31T18:30:00.000Z","y":1,"y0":0},
{"x":"2015-12-31T18:30:00.000Z","y":10,"y0":0},
{"x":"2016-12-31T18:30:00.000Z","y":100,"y0":0}],
[{"x":"2014-12-31T18:30:00.000Z","y":2,"y0":1},
{"x":"2015-12-31T18:30:00.000Z","y":20,"y0":10},
{"x":"2016-12-31T18:30:00.000Z","y":200,"y0":100}],
[{"x":"2014-12-31T18:30:00.000Z","y":3,"y0":3},
{"x":"2015-12-31T18:30:00.000Z","y":30,"y0":30},
{"x":"2016-12-31T18:30:00.000Z","y":300,"y0":300}]]
Hope this helps!
Working sample here

Pass parameter to c3js tooltop after .generate() and before .load()

I'm trying to graph out metrics that don't have any relation to one another, so instead of plotting out the actual values, I've calculated an alternate set of values that are scaled between 0-1 like a percentage.
For example: [1, 2, 5] => [0.2, 0.4, 1]
So now I have 2 sets of data - the original and scaled versions. I have the scaled version plotting on to my graph just fine, but I want the tooltip to show the original value to the user. See what I mean?
I checked out http://c3js.org/samples/tooltip_format.html, which shows you can set tooltip as a function when you initially generate the C3 object. But I want to change the tooltip later on after I recalculate my original/scaled values and re-load() the graph.
All attempts I've made to explicitly change myGraph.tooltip.format.value = function (...) {...} after initially setting myGraph = C3.generate({...}) have been unsuccessful.
Any ideas how I can accomplish this without having to regenerate the graph from scratch every time?
You need to override internal.getTooltipContent
var data = ['data1', 30000, 20000, 10000, 40000, 15000, 250000];
// simple fake data
var fakeData = data.map(function (d, i) {
return i ? (d / 100) : d;
})
var chart = c3.generate({
data: {
columns: [
fakeData,
['data2', 100, 200, 100, 40, 150, 250]
],
}
});
// do code to take over mars and plant potatoes
// save the original
var originalGetTooltipContent = chart.internal.getTooltipContent;
chart.internal.getTooltipContent = function (data, defaultTitleFormat, defaultValueFormat, color) {
// we modified the first series, so let's change that alone back
var originalValue = {
id: data[0].id,
index: data[0].index,
name: data[0].name,
// unfaked
value: data[0].value * 100,
x: data[0].x
};
var originalValues = data.map(function (d, i) {
return i ? d : originalValue;
})
return originalGetTooltipContent.call(this, originalValues, defaultTitleFormat, defaultValueFormat, color)
}
I assume you are already doing something about the scaled y axis label?
Fiddle - http://jsfiddle.net/puf248en/
Thanks potatopeelings,
I did turn out solving this one by simply loading the form data in all at once, and then programmatically show/hide certain metrics. So that allowed me to use all the generate() options as intended.
Did try out your solution, and it seemed to do the trick till I found the simpler option. Thanks!

D3 sorting with an ordinal scale and selecting top 5

I am trying to sort then select the top 5 in a D3 chart.
I have two series: "OL" and "NOL". The first thing I want to be able to do is to sort and have the labels match on the y axis. The second thing I want to do is to only show the top 5 with the two series still together udner one name in the y axis.
jsfiddle
Data is like so:
var values = feature.properties;
var data = [
{key: "N11", name:"N11OL",value:values["N11OL"]},
{key: "N11", name:"N11NOL",value:values["N11NOL"]},
{key: "N21", name:"N21OL",value:values["N21OL"]},
{key: "N21", name:"N21NOL",value:values["N21NOL"]},
{key: "N22", name:"N22OL",value:values["N22OL"]},
{key: "N22", name:"N22NOL",value:values["N22NOL"]},
{key: "N23", name:"N23OL",value:values["N23OL"]},
{key: "N23", name:"N23NOL",value:values["N23NOL"]},
{key: "N31-33", name:"N31_33OL",value:values["N31_33OL"]},
{key: "N31-33", name:"N31_33NOL",value:values["N31_33NOL"]},
{key: "N41", name:"N41OL",value:values["N41OL"]},
{key: "N41", name:"N41NOL",value:values["N41NOL"]}
];
Right now, the chart works before I sort the bars. When I sort the data with the code below, the ordinal domain doesn't match the bars anymore.
data.sort(function (a, b) {
return d3.ascending(a.value, b.value);
});
I could use
domain(data.map(function(d) { return d.name; }))`
});
to get the names from the data to show on the axis but I want "OL" and "NOL" series to be under one name: N11, etc. not show with all bars. That is why I have set a domain with :
.domain(["NAICS11", "NAICS21", "NAICS22", "NAICS23", "NAICS31-33", "NAICS41"])
That is half of the problem. Once I have sorted and the names are matching with the axis, I would like to have only the top 5 for both series.
I would be very grateful for any suggestions on how to do this.
EDIT I added a key to the data for the pairs and modified the D3 code. I feel this will make it easier going forward to get this chart where I want it.
How about:
// create temporary array with data grouped by
// the first part of our name (cut off the OL/NOL)
var tmp = d3.nest().key(function(d){
return d.name.substring(0, 3);
}).entries(data);
// sort this array descending with the max of our
// now "paired" entries
tmp.sort(function(a,b){
return (d3.max([a.values[0].value,
a.values[1].value]) >
d3.max([b.values[0].value,
b.values[1].value])) ? -1 : 1;
});
// loop our tmp array and
// flatten the data back out
// also use our substring names to for the domain
data = [];
domain = [];
tmp.forEach(function(d){
domain.push(d.key);
data.push(d.values[0]);
data.push(d.values[1]);
});
Updated fiddle.

Creating a bar chart in D3 from subset of json data. Xaxis is ordinal

[
...
{
"RowID":85,
"Name":"Billy",
"B":2,
"S":2,
"S2":1,
"M":0,
"T":"0",
"H":1,
"S":0,
"W":1,
"N":2,
"Malty":1,
"Fruity":0,
"Floral":0
}
...
]
I need to create a bar chart. Just a regular bar chart.
There are a total of 86 JSON pieces of data (that is, you'll find 86 RowIDs). I only need to pick 5-10 that I want to work with. The x-axis are the "B", "S" ... "Floral" from the JSON. It does NOT include RowID or Name. So there should be "clumps" of 5 bars (colored corresponding to "Name") for each "B", ... "Floral" piece of data. The end goal is to make it easy for the user to visually compare 5 objects (distinguished by Name attribute) according to their attributes.
I've been working at least 24 hours on this problem. And I'm not making any progress. I've looked at tutorials and other posts on StackOverflow. I can't get any of them to work.
Anyone?
And no, this question does not have an answer somewhere else.
A fiddle: http://jsfiddle.net/zdy6d/3/
What you want to do is a grouped bar chart. The main thing you need to do is create 2 x-scales: one that gives the position of each group, or clump as you call it, in the screen and the other one that gives the position of each series (name in this case) inside the group.
// Where to position each clump inside svg chart
var x0 = d3.scale.ordinal();
x0.domain(d3.keys(data[0]).filter(function(key) { return key !== 'RowID' && key !== 'Name'; }));
x0.rangeRoundBands([0, width], 0.1);
// Where to position each name bar inside the clump
var x1 = d3.scale.ordinal();
x1.domain(data.map(function(d) { return d.Name; } ));
x1.rangeRoundBands([0, x0.rangeBand()]);
You then have to filter the data and maybe change its structure to a more convenient format (e.g. [{groupname: 'B', data: [{name: 'Bobby', value: 3}, {name: 'Tom', value: 5}, ... ]}, ...] should be similar to the one the example I linked uses)
Minimal working JSFiddle with example of data manipulation and rect creation: http://jsfiddle.net/LeartS/23huy/2/

Categories