function myFunction() {
dd = document.getElementsByClassName("addin");
ds = document.getElementsByClassName("slidfi");
var arr = [];
for(var i = 0;i< dd.length;i++){
var obj = {};
obj["check"] = dd[i].checked;
obj["value"] = ds[i].value;
obj["headers"] = dd[i].value;
arr.push(obj)
}
return arr;
}
status variable in the below function have details of value and status[i]["header"] which is column value for corresponding header and I want to divide each of the value with the max value in the whole column. It should be basically something like this -
temp.push((d[status[i]["headers"]]/Math.max(temp)) * status[i]["value"])
but I am not able to get max for entire column.
Here is the current code but also want to take max and divide by each value to normalize it then multiply by status[i]["value"].
function UpdatedData() {
var status = myFunction();
d3.csv('cars.csv', function(error, data) {
data.forEach(function(d){
var temp=[];
for(var i=0;i<status.length;i++){
if (status[i]["check"]){
temp.push(d[status[i]["headers"]] * status[i]["value"])
}
}
});
});
}
status is an array with this format.
0 {check: false, value: "0.5", headers: "W"}
1 {check: false, value: "0.5", headers: "X"}
2 {check: true, value: "0.5", headers: "Y"}
3 {check: true, value: "0.5", headers: "Z"}
So last two are checked,so in this case temp will be an array of dim 2. One will be correspond to header Y and other to corresponding header Z. I want the max for the all column value corresponding to Y and Z but not the max within Y and Z
You need to calculate the max of the entire column in a loop first, doing something like
maxTemp = 0;
for(var i=0;i<status.length;i++){
if (status[i]["check"]){
if(maxTemp < d[status[i]["headers"]])
maxTemp = d[status[i]["headers"]];
}
}
Then divide the using the maxTemp in another loop
for(var i=0;i<status.length;i++){
temp.push((d[status[i]["headers"]]/maxTemp) * status[i]["value"])
}
**Pseudo Code **
maxTemp = 0;
data.forEach(function(d){
//some code
if(maxTemp < d[status[i]["headers"]])
maxTemp = d[status[i]["headers"]];
}
})
data.forEach(function(d){
//some code
temp.push(value /maxTemp)
})
As your question's title is a bit different from your question's text, I'll address the question's title only. I hope that it suits you.
You can find the maximum of any column using the D3 method d3.max, which:
Returns the maximum value in the given array using natural order. If the array is empty, returns undefined. An optional accessor function may be specified, which is equivalent to calling array.map(accessor) before computing the maximum value.
So, given this bogus CSV:
foo, bar, baz
12, 14, 65
26, 75, 39
67, 11, 93
19, 42, 17
We can find the maximum of the foo column with:
var maxFoo = d3.max(data, function(d){ return d.foo});
For finding the maximum of two or more columns, we can simply create an array with the individual maximum values:
var maxFooBar1 = d3.max([maxFoo, maxBar]);
Or, alternatively, we can find the maximum in each object:
var maxFooBar2 = d3.max(data, function(d){ return d3.max([d.foo, d.bar])});
Here is a demo (I'm using a pre element to simulate the CSV):
var data = d3.csvParse(d3.select("#csv").text());
data.forEach(function(d) {
d.foo = +d.foo;
d.bar = +d.bar;
d.baz = +d.baz;
})
var maxFoo = d3.max(data, function(d) {
return d.foo
});
var maxBar = d3.max(data, function(d) {
return d.bar
});
var maxFooBar1 = d3.max([maxFoo, maxBar]);
var maxFooBar2 = d3.max(data, function(d) {
return d3.max([d.foo, d.bar])
});
console.log("The max of foo is: " + maxFoo)
console.log("The max of foo and bar is (method 1): " + maxFooBar1)
console.log("The max of foo and bar is (method 2): " + maxFooBar2)
pre {
display: none;
}
<script src="https://d3js.org/d3.v4.min.js"></script>
<pre id="csv">foo,bar,baz
12,14,65
26,75,39
67,11,93
19,42,17</pre>
Related
I'm trying to adapt this jQuery DataTables example to a d3 chart that I've been developing.
Here's a link to the semi-working Plunker: http://plnkr.co/edit/kXvBjNsCbblC3ykkuPsL?p=preview
The problem is that some of the values are showing up in the table, while others are not (in particular, the values that come from an array within an array).
Oddly enough, the error message I'm getting, Cannot read property '0' of undefined, refers to line 1074, on which recordCol is defined. This is strange because the values for recordCol and stateName both show up just fine in the DataTable. Also strange is that all of the column headers do appear, even for the nested array (though not their values).
Here's the problematic code:
function tables(dataset) {
var recordCol = Object.keys(dataset[0])[0];
var stateName = Object.keys(dataset[0])[3];
var dateCol = Object.keys(dataset[0].values[0])[0];
var valCol = Object.keys(dataset[0].values[0])[1];
var monthDateFormat = d3.time.format("%B");
var yearDateFormat = d3.time.format("%Y");
var properDateFormat = d3.time.format("%B %Y");
var tableData = dataset.map(function(d) {
d[recordCol] = d[recordCol].toString().slice(0, 15);
d[stateName] = d[stateName].toString().slice(0, 20);
d[dateCol] = d[dateCol];//.toString().slice(0, 20);
d[valCol] = d[valCol];///.toString().slice(0, 20);
return d;
})
$(".data-table").empty();
if (dataTable) {
dataTable.destroy();
}
dataTable = $(".data-table").DataTable({
data: tableData,
columns: [{
"data": recordCol
}, {
"data": stateName
}, {
"data": dateCol
}, {
"data": valCol
}]
});
d3.selectAll("thead th").each(function(d, i) {
if (i === 0) {
this.textContent = recordCol;
} else if (i === 1) {
this.textContent = stateName;
} else if (i === 2) {
this.textContent = dateCol;
} else if (i === 3) {
this.textContent = valCol;
}
});
}
As you'll see in my semi-working Plunker, I've been beating a dead horse in console.log, trying to troubleshoot the error messages I've been getting, the other of which is this.
In sum, what I'm trying to do is get all the values for x and y to appear in the DataTable alongside state and record -- as well as relabel the column headers that currently read x and y as as date and value, respectively.
In advance, thanks very much for any assistance you're able to offer.
Update:
The following changes, I've discovered, make the full subarray, containing all the x and y values, appear in every row of the DataTable:
dataTable = $(".data-table").DataTable({
data: tableData,
columns: [{
"data": recordCol
}, {
"data": stateName
}, {
"data": "values[, ].x"
}, {
"data": "values[, ].y"
}]
});
Here's an updated Plunker. The search for a solution continues.
Update 2:
The following changes make the x and y value appear as Sun May 01 2011 00:00:00 GMT-0400 (Eastern Daylight Time) and 2761, but the same in every row:
var tableData = dataset.map(function(d) {
d[recordCol] = d[recordCol].toString().slice(0, 15);
d[stateName] = d[stateName].toString().slice(0, 20);
for (var i = 0; i < dataset.length; i++) {
d[dateCol] = dataset[0].values[i].x;
d[valCol] = dataset[0].values[i].y;
}
dataTable = $(".data-table").DataTable({
data: tableData,
columns: [{
"data": recordCol
}, {
"data": stateName
}, {
"data": dateCol
}, {
"data": valCol
}]
});
Another updated Plunker. Obviously, this is wrong; still searching for a solution.
Update 3:
Still searching for a solution, but in this third updated Plunker, I discovered how to take all of the values contained in the subarray of the parent array's first row, and (incorrectly) map them onto all of the rows of the parent array. Here's an illustration of what's going wrong:
Is anyone able to demonstrate a solution?
You need to change your table map. Try it:
var table_map = [];
for (var i = 0; i < dataset.length; i++) {
for (var j = 0; j < dataset[i].values.length; j++) {
var table_row = {};
table_row[recordCol] = dataset[i][recordCol];
table_row[stateName] = dataset[i][stateName];
table_row[dateCol] = dataset[i].values[j][dateCol];
table_row[valCol] = dataset[i].values[j][valCol];
table_map.push(table_row);
}
}
I'd like to create a stacked bar chart using DC.JS.
I've tried to utilize the documentation from DC.JS (graph,source code) to no avail - Below is my attempt (here is my attempt in jsfiddle) and my most recent attempt in CodePen.
I'd like the 'Name' as the X axis and 'Type' as the stacks.
HTML
<script src="https://cdnjs.cloudflare.com/ajax/libs/d3/3.5.17/d3.js"></script>
<script src="https://rawgithub.com/NickQiZhu/dc.js/master/web/js/crossfilter.js"></script>
<script src="https://cdnjs.site44.com/dc2.js"></script>
<div id="chart"></div>
Javascript
var data = [ {"Name":"Abby","Type":"Apple"}, {"Name":"Abby","Type":"Banana"}, {"Name":"Bob","Type":"Apple"} ]
data.forEach(function(x) {
x.Speed = +x.Type;
});
var ndx = crossfilter(data)
var xdim = ndx.dimension(function (d) {return d.Name;});
function root_function(dim,stack_name) {
return dim.group().reduce(
function(p, v) {
p[v[stack_name]] = (p[v[stack_name]] || 0) + v.Speed;
return p;},
function(p, v) {
p[v[stack_name]] = (p[v[stack_name]] || 0) - v.Speed;
return p;},
function() {
return {};
});}
var ydim = root_function(xdim,'Type')
function sel_stack(i) {
return function(d) {
return d.value[i];
};}
var chart = dc.barChart("#chart");
chart
.x(d3.scale.ordinal().domain(xdim))
.dimension(xdim)
.group(ydim, "1", sel_stack('1'))
.xUnits(dc.units.ordinal);
for(var i = 2; i<6; ++i)
chart.stack(ydim, ''+i, sel_stack(i));
chart.render();
I've been fiddling with this for some time and I have some additional findings:
When I replace the data array with the following it works
data = [ {"Name":"Abby","Type":"1"}, {"Name":"Abby","Type":"2"}, {"Name":"Bob","Type":"1"} ]
But it only works when I swapped out dc 1.7.5 (https://cdnjs.cloudflare.com/ajax/libs/dc/1.7.5/dc.min.js) with dc 2.1.0-dev (https://github.com/dc-js/dc.js/blob/develop/web/js/dc.js)
However when I replace the data array with the following it doesn't work:
data = [ {"Name":"Abby","Type":"3"}, {"Name":"Abby","Type":"4"}, {"Name":"Bob","Type":"2"} ]
I believe the root issue lies in the root_function.
v.Speed is always NaN in your current example. Because +x.Type attempts to convert a string like "Apple" into a number and fails. If you just want to count, then add or subtract 1 in your reducer, rather than v.Speed. Then you need to update your sel_stack code and chart code to handle this change, of course.
Here's a working example for the 2 types in your data. You'll have to update it to handle arbitrary numbers of types, probably by building an array of all your types up front and then looping through it to add stacks to the chart: http://codepen.io/anon/pen/GjjyOv?editors=1010
var data = [ {"Name":"Abby","Type":"Apple"}, {"Name":"Abby","Type":"Banana"}, {"Name":"Bob","Type":"Apple"} ]
var ndx = crossfilter(data)
var xdim = ndx.dimension(function (d) {return d.Name;});
In the reducer, just add and subtract 1 to count:
var ydim = xdim.group().reduce(
function(p, v) {
p[v.Type] = (p[v.Type] || 0) + 1;
return p;},
function(p, v) {
p[v.Type] = (p[v.Type] || 0) - 1;
return p;},
function() {
return {};
});
sel_stack no longer takes a number, but a key:
function sel_stack(valueKey) {
return function(d) {
return d.value[valueKey];
};}
var chart = dc.barChart("#chart");
Here we hard-code the stack key, for the purpose of the example:
chart
.x(d3.scale.ordinal().domain(xdim))
.dimension(xdim)
.group(ydim, "Apple", sel_stack('Apple'))
.xUnits(dc.units.ordinal);
Again, the other hard-coded stack key. You'll need to recreate the loop after creating some sort of data structure that holds all of your stack values.
//for(var i = 2; i<6; ++i)
chart.stack(ydim, 'Banana', sel_stack('Banana'));
chart.render();
I'm trying to get just one value from d3's max function but it's returning an entire array. Here is an example:
var data = {
"Jim" : [
{
"Value" : [10,11,12]
}
]
}
var myMax = d3.max(data.Jim, function(d){
var maxVal = d["Value"];
return maxVal;
})
console.log(myMax + "max")
It returns 10,11,12max. It should return 12.
you're trying to find the maximum of the array data.Jim which only has one element = {"Value" : [10,11,12]} which d3 promptly returns as the maximum using your given accessor function. Try changing your code to the following:
var myMax = d3.max(data.Jim, function(d){
var maxVal = d3.max(d["Value"]);
return maxVal;
})
I have this in my code
series: [{
name: 'Velocidad',
turboThreshold: 5000,
data: (function() {
// generate an array of random data
var data = [],
i;
for (i = 0; i < valor; i++) {
data.push({
x: dataUtc[i],
y: dataVel[i],
id: i
});
}
return data;
})(),
tooltip: {
valueDecimals: 0,
valueSuffix: 'Kms/H'
}
}]
When I try to get the maximum value I only get the x or y value.
I need to get the id value though.
What can I do?
I tried the following:
var chart = $('#containerVelocidad').highcharts();
min = chart.xAxis[0].min;
max = chart.xAxis[0].max;
Unfortunately that didn't help.
First of all, use yAxis.dataMax not yAxis.max. The second one is returning actual extremes, when sometimes you may have different extremes, than just from one series (zooming, setting extremes, multiple series etc.).
Demo: http://jsfiddle.net/ez4hjazk/1/
And code:
var max = chart.yAxis[0].dataMax,
maxIndex = chart.series[0].yData.indexOf(max), //get index from yData, read more about .indexOf() !
data = chart.series[0].data;
// make sure point is within actual extremes
if(maxIndex > -1) {
console.log("max = " + max, 'id = ' + data[maxIndex].id);
}
Do you need to get the maximum/minimum of id?
If so, try chart.series[0].data[i].id. Here's an example: http://jsfiddle.net/ez4hjazk/
I am creating a column chart w/ d3. I have 263 data points, and showing all columns makes the chart too crowded. To filter the datapoints, I simply grab every nth item (starting from the reverse of the array, so I ensure I get the most recent datapoint).
I define the y axis tick values to include the min and max from the unfiltered dataset, so the user can see the real min and max of the dataset. I calculate the min and max before I filter the data:
var v = new Array();
data.forEach(function (d) {
d.date = parseDate(d.date);
d.close = +d.close;
v.push(d.close); // v holds ALL our values...before we filter them
});
yAxisValues = [Math.min.apply(null, v),Math.max.apply(null, v)];
if(data.length > 100){ // make it so that the chart isn't as crowded
var len = data.length;
var n = Math.round(len/100); // ideally, we want no more than 100 items
var tempData = [];
data = data.reverse();
for( var k = 0; k < len; k += n ){
tempData.push( data[ k ] );
}
data = tempData;
data = data.reverse();
}
However, now my y-axis is screwed up, with -0.02 showing below the x-axis. What did I do wrong? My fiddle. (To see the y-axis behave normally, simply comment out the part where I filter the data)
You are creating your Y Axis values before the filtering, but you are still creating the scale on the filtered data:
var y = d3.scale.linear().range([height - 5, 5]);
// here is where it look at the min/max of the filtered data rather than the min/max of the original
y.domain(d3.extent(data, function (d) {
return d.close;
}));
var yAxis = d3.svg.axis().scale(y).orient('left').tickValues(yAxisValues);
If you move this part before the filtering it should be OK.