running total in highcharts - javascript

So I am able to populate an array with values in json format in highcharts by writing the following code:
var processed_json = new Array();
for (i = 0; i < data.length; i++) {
processed_json.push({
x: data[i].duration,
y: data[i].count
});
}
My problem lies with trying to create a running total of duration on the x-axis.
I have thought about creating a second array to loop over the first and to then add the values, but how do I add the values in the second array, if I refer to the values by their title '.duration' in the first?
I need to populate an array with cumulative sum values, to then plot on the x axis. I hope this makes sense?
Does their exist an easier way to solve my issue?
I am quite new to javascript and highcharts, so apologies if there is an easier way to solve this.
Thank you for your help.

I hope that I understood what you are trying to achieve. You must have somewhere declared variable with JSON containing options for generating Highcharts chart. I assume that it's name is highchartsOptions.
highchartsOptions.xAxis.categories = [];
var processed_json = new Array(),
durationSum = 0;
for (i = 0; i < data.length; i++) {
processed_json.push({
x: data[i].duration,
y: data[i].count
});
durationSum += data[i].duration;
highchartsOptions.xAxis.categories.push(durationSum);
}
This shall add categories axis. And every category with index i will be sum of all data duration preceeding.

Related

How do I input an specific cell for every i in a loop on google script?

One of my projects is making a sales spreadsheet.
The sales spreadsheet contains the names of the products and their prices are in the documentation, the challenge is getting the prices to automatically show up on the cell right next to the product name in the spreadsheet.
Here's what I did:
function Autoprice() {
var sales = SpreadsheetApp.getActive().getSheetByName('Sales')
var salesrow = sales.getRange('D2:D'+sales.getLastRow())
var productnames = salesrow.getValues()
size = productnames.length+1
for (var i = 0; i< size; i++){
if (productnames[i+1]=='Diary')
{
sales.getRange('F'+i).setValue(31.90)
}
And I just input all the prices manually.
The thing is, google script does not read the sales.getRange('F'+1) as I thought it would, and I can't find the correct way to read that for every item in 'DI' cell, i want to put a price on 'FI' cell.
Try using this script, I modified a couple of lines in the sample you shared and added comments next to it to explain.
function Autoprice() {
var sales = SpreadsheetApp.getActive().getSheetByName('Sales')
var salesrow = sales.getRange('D2:D'+sales.getLastRow())
var productnames = salesrow.getValues()
size = productnames.length+1
for (var i = 0; i< size; i++){
if (productnames[i]=='Diary') //If you do productnames[i+1], you're not starting from the beginning of the range, basically you're starting from D3 instead of D2
{
sales.getRange(i+2,6).setValue(31.90) //You can try getRange(row, column) instead
}
}
}
Reference:
getRange(row, column)
You are trying to loop through a 2-dimensionall array (not technically... but each element is a single array).
So to see D2's value you would need productnames[0][0]
However, you can easily fix this using the flat() function. Modify one line of code below:
var productnames = salesrow.getValues().flat();
Also consider learning to use the debugger. If you step through your code, this is easy to see.

Problem with create list using for loop in Javascript

I'm trying to crate a code that will count number of images I have and then will create a list with the number of images (for example, if I have 5 images, I'll get this :
[0,1,2,3,4].
My code runs and I think it creates a list that is empty:
This is my code (I have tried to put only the relevant part):
//First I filter my image collection according to the number of pixels each image has
//Filter according to number of pixels
var ndviWithCount = withNDVI.map(function(image){
var countpixels = ee.Number(image.reduceRegion({
reducer: ee.Reducer.count(),
geometry: geometry,
crs: 'EPSG:4326',
scale: 30,
}).get('NDVI'));
return image.set('count', countpixels);
});
print(ndviWithCount, 'ndviWithCount');
//Here I count what is the maximum number of pixels that image has and then I create new collection with //only "big images"
var max = ndviWithCount.reduceColumns(ee.Reducer.max(), ["count"]);
print(max.get('max'));
var max_pix=max.get('max');
//filter between a range
var filter = ndviWithCount.filter(ee.Filter.rangeContains(
'count', max_pix, max_pix));
print(filter, 'filtered');
//Here I try to grab the number of images so I can create a list
var num_images=filter.size();
//creating the list of images
var listOfImages =(filter.toList(filter.size()));
//Here is the loop that diesn't work
//I have tried to determine i=0, and then that it will iterate untill i is equal to the number of images
//I try to say, i=0, so add 1 and the nadd it to my list.
for (i = 0; i < num_images; i++) {
var listOfNumbers=[];
i=i.add(1);
listOfNumbers.push(i);
}
my end goal is to have list that contains nmbers from 0 or 1 to the number of images I have.
for (i = 0; i < num_images; i++) {
var listOfNumbers=[];
i=i.add(1);
listOfNumbers.push(i);
}
You are initiating the array inside the for loop which isn't what you intend. I'm also not sure what i = i.add(1) is supposed to be. May be helpful to check out info on for loops.
let listOfNumbers = [];
for (let i = 0; i < num_images; i++) {
listOfNumbers.push(i);
}
I found the solution. The reason for the error is because of the GEE envorinment.
This code works:
var serverList = ee.List.sequence(0,NumberOfImages.subtract(1));
serverList = serverList.map(function(n) {
return ee.Number(n).add(1);
});
print(serverList);

How to Multiply two arrays and dynamically plot into HighCharts?

new to javascript. I am trying to make a new series in Highcharts using one already graphed series multiplied by another already graphed series. How do I add the new series with its own y-axis? I am using some base code that I have not done myself.
ChartOptions.Series[index].data holds an array of arrays: so for example :[1563480488000, 12.144] would be timestamp and datavalue for every data point in the series.
So I would want something like this:
[1563480488000, 12.144] * [1563480488000, 1.0] = [1563480488000, 12.144]
that's 12.144*1.0, and the timestamp is kept.
dynamicChart is a new Highcharts.StockChart(chartOptions) its just away from the snippet I am working with.
I've tried the following code.
var voltSeries = chartOptions.series[0].data;
var ampSeries = chartOptions.series[1].data;
var wattSeries = [];
for(var i = 0; i <= voltSeries.length; i++){
var valu = chartOptions.series[1].data[i,1]*chartOptions.series[0].data[i,1];
wattSeries[i,1] = valu;
wattSeries[i,0] = valu;
}
eval('window.console && console.log(voltSeries)');
eval('window.console && console.log(wattSeries)');
dynamicChart.addSeries({
name: 'Watts',
data: wattSeries
});
dynamicChart.redraw();
the output of wattSeries is an Array of (2) [NaN, NaN] but It should be the timestamp and the multiplied value.
and It seems like I cannot graph it no matter what I do.
The problem is incorrectly getting values from the array. For nested arrays you should use several parentheses: array[x][x]
var dynamicChart = Highcharts.chart('container', chartOptions);
var voltSeries = chartOptions.series[0].data,
ampSeries = chartOptions.series[1].data,
wattSeries = [],
valu;
for (var i = 0; i < voltSeries.length; i++) {
valu = voltSeries[i][1] * ampSeries[i][1];
wattSeries.push([ampSeries[i][0], valu]);
}
dynamicChart.addSeries({
name: 'Watts',
data: wattSeries,
yAxis: 1
});
Live demo: http://jsfiddle.net/BlackLabel/vpzLou6r/
API Reference: https://api.highcharts.com/class-reference/Highcharts.Chart#addSeries

qualtrics javascript: autopopulate matrix table using previous answers

I ask the same matrix table (multiple answer) question twice in my Qualtrics survey. When I display the question to the user the second time, I want the answers to be auto populated from the first time the user answered the question. I've looked at the code snippets in the documentation, so I know how to select the checkboxes in the current question, e.g.
for (var i = 1; i <= rows; i++) {
for (var j = 1; j <= cols; j++) {
this.setChoiceValue(i, j, true);
}
}
My issue is that I can't figure out how to get the selected answers from the previous question. I have tried something like this but it doesn't work (cannot read property 'attr' of null):
var isChecked = $("#QR~QID2~" + i + "~" + j").attr('checked');
This page from the documentation suggests using piped text, something along the lines of:
var selectedChoice = "${q://QID2/ChoiceGroup/SelectedChoices}";
This seems to give me the unique statements in the rows of the survey that have been selected, but I need to get the selected answer (col) for each statement (row) in the question. I'm not sure how to formulate the correct piped text.
Any advice would be much appreciated! Thanks.
Edit 1: Here is the code I ended up using.
Qualtrics.SurveyEngine.addOnload(function()
{
/*Place Your Javascript Below This Line*/
var numChecks = $(this.getQuestionContainer()).select('input[type="checkbox"]');
var numCols = 4;
var numRows = numChecks.length / numCols;
var map = {};
//I won't have more than 20 rows in the matrix
map[1] = "${q://QID53/SelectedAnswerRecode/1}";
map[2] = "${q://QID53/SelectedAnswerRecode/2}";
map[3] = "${q://QID53/SelectedAnswerRecode/3}";
map[4] = "${q://QID53/SelectedAnswerRecode/4}";
map[5] = "${q://QID53/SelectedAnswerRecode/5}";
map[6] = "${q://QID53/SelectedAnswerRecode/6}";
map[7] = "${q://QID53/SelectedAnswerRecode/7}";
map[8] = "${q://QID53/SelectedAnswerRecode/8}";
map[9] = "${q://QID53/SelectedAnswerRecode/9}";
map[10] = "${q://QID53/SelectedAnswerRecode/10}";
map[11] = "${q://QID53/SelectedAnswerRecode/11}";
map[12] = "${q://QID53/SelectedAnswerRecode/12}";
map[13] = "${q://QID53/SelectedAnswerRecode/13}";
map[14] = "${q://QID53/SelectedAnswerRecode/14}";
map[15] = "${q://QID53/SelectedAnswerRecode/15}";
map[16] = "${q://QID53/SelectedAnswerRecode/16}";
map[17] = "${q://QID53/SelectedAnswerRecode/17}";
map[18] = "${q://QID53/SelectedAnswerRecode/18}";
map[19] = "${q://QID53/SelectedAnswerRecode/19}";
map[20] = "${q://QID53/SelectedAnswerRecode/20}";
for (var i = 1; i <= numRows; i++) {
//Get the recode values for row i
var rowValues = map[i].split(",");
//Loop through all the recode values for the current row
for (var c = 0 ; c < rowValues.length; c++) {
var val = parseInt(rowValues[c].trim());
//Select the current question's checkboxes corresponding to the recode values
this.setChoiceValue(i, val, true);
}
}
});
Edit 2:
I'm getting some strange behavior now. I'm trying to populate a table with only 3 rows, so I would think that
"${q://QID53/SelectedAnswerRecode/1}";
"${q://QID53/SelectedAnswerRecode/2}";
"${q://QID53/SelectedAnswerRecode/3}";
would give me the values for the first three rows from the previous table for question "QID53" . But actually those return empty strings, and it's not until calling
"${q://QID53/SelectedAnswerRecode/5}";
"${q://QID53/SelectedAnswerRecode/6}";
"${q://QID53/SelectedAnswerRecode/7}";
that I get the first three values.
For a table of 14 rows, nothing returns until calling
"${q://QID53/SelectedAnswerRecode/4}";
and it leaves the last 3 rows in the table empty.
Am I wrong in assuming that the number after "SelectedAnswerRecode" is the row number? Is there something about an offset that I'm missing?
I think you'll want to pipe in the recode values. Something like:
var r1ar = parseInt("${q://QID2/SelectedAnswerRecode/1}");
var r2ar = parseInt("${q://QID2/SelectedAnswerRecode/2}");
Then set the values:
this.setChoiceValue(1, r1ar, true);
this.setChoiceValue(2, r2ar, true);
Make sure your recode values match the column ids.
Edits/additions based on comments below:
Piped values in the javascript get resolved server side before the page is sent to the browser, so they are fixed values. There is no way to make them dynamic in javascript. If your question has a variable number of rows due to display logic or carryover, you'll have to include all the possible piped values in the javascript, then check them to see which ones are valid.
For a multiple answer matrix, you can convert the comma separated list into an array using str.split(',') then loop through the array. Qualtrics includes spaces after the commas in comma separated lists, so you'll have to trim() the strings in the array.

Google visualization DataTable: calculate totals

I'm searching a way to add a row of totals to a simple DataTable. This is my code:
// Create and populate the data table.
var dt = new google.visualization.DataTable();
dt.addColumn('string', 'Name');
dt.addColumn('number', 'Height');
dt.addRows([
['Tong Ning mu', 174],
['Huang Ang fa', 523],
['Teng nu', 86]
]);
var myTotal;
/* calculate total sum of column Height */
dt.addRow(['TOTAL', myTotal]);
// Create and draw the visualization.
visualization = new google.visualization.Table(document.getElementById('table'));
visualization.draw(dt, null);
How to calculate myTotal from dt DataTable?
Is it possible to make the last row(Totals) bold?
Is there any more elegant way to add totals to a table?
create the following function:
function getSum(data, column) {
var total = 0;
for (i = 0; i < data.getNumberOfRows(); i++)
total = total + data.getValue(i, column);
return total;
}
call it with your created google datatable, and column array index. In your case:
var total = getSum(dt,1);
Then, you can add that total into a new raw or what ever you want to do with it.
As #Danny's reply is the same solution as I would say for suming the column, I won't write it.
To set a cell property you dataTable.setProperty(columnIndex,rowIndex,'style','font-weight:bold;');
so in your case you'd write
dt.setProperty(0, 3, 'style','font-weight:bold;');
dt.setProperty(1, 3, 'style','font-weight:bold;');
Say you provide a bit bigger dataTable, it might be inconvenient to type this for all cells, you could use a for loop like (to make the whole last row bold):
var lastRow = dt.getNumberOfRows()-1
for (i=0, n=dt.getNumberOfColumns(); i < n; i++) {
dt.setProperty(i, lastRow, 'style', 'font-weight:bold;');
}
Sadly you're unable to set properties to a whole row/column (see the documentation about custom properties regarding this).

Categories