I am trying to create a google chart that has a list of all fixtures from a certain week and how many posts each one has.
This is the code I am running:
<script type="text/javascript">
google.charts.load('current', {'packages':['bar']});
google.charts.setOnLoadCallback(drawChart);
function drawChart() {
var stringArray = [];
<c:forEach items="${posts}" var="post" varStatus="count">
stringArray.push("<c:out value='${post.fixture.home.teamName}v${post.fixture.away.teamName}'/>", 1);
</c:forEach>
var newArray = [["Games", "Amount of Posts"]];
var postArray = [1,2,3,4,5,6,7,8];
var x = 1;
while(x <= stringArray.length){
var games = stringArray[x];
var numbers = postArray[x];
console.log("Game " + games);
newArray.push([games, numbers]);
x++;
}
console.log(newArray[1]);
var data = google.visualization.arrayToDataTable(newArray);
var options = {
chart: {
title: 'Referee Performance',
subtitle: 'Season 20-21',
},
bars: 'horizontal'
};
var chart = new google.charts.Bar(document.getElementById('barchart_material'));
chart.draw(data, google.charts.Bar.convertOptions(options));
}
</script>
Lets take a closer look at this section
var newArray = [["Games", "Amount of Posts"]];
var postArray = [1,2,3,4,5,6,7,8];
var x = 1;
while(x <= stringArray.length){
var games = stringArray[x];
var numbers = postArray[x];
console.log("Game " + games);
newArray.push([games, numbers]);
x++;
}
So the newArray is what will be used to draw the table because it has the headers, I then have an array with all the fixtures in (stringArray) and another array of how many posts each one has (postArray). I am trying to add the first index of string array and postArray to the next index in newArray. This isn't working and is doing something weird. I've added console.log and this is the output I am getting.
Game 1
2:50 Game Crystal PalacevSouthampton
2:50 Game 1
2:50 Game Crystal PalacevSouthampton
2:50 Game 1
2:50 Game undefined
2:54 (2) [1, 2]
So there is 2 problems with this. For some reason x isn't incrementing and it isn't saving the team Names its saving a 1 for some reason. I'm not sure if I'm doing something stupid or not?
So how can I fix the error above?
Thank you for your time
Related
I have a list of 290 items with 4 columns, which I need to duplicate. I have in a Spreadsheet Row some departements and under it a lot of systems. for each system I need to duplicated the 290 values and add one index column at the front, the department in column 6 and the system in column 7.
I am using the following code:
const ssOrg = SS.getSheetByName("OrgStructure");
function myFunction() {
var afinal = [];
var aDevs = ssDeliverables.getDataRange().getValues();
aDevs.shift();
var lastRow = ssOrg.getLastRow();
var lastColum = ssOrg.getLastColumn();
var count = 1
for (var spalte = 1; spalte <lastColum; spalte++){
var squad = ssOrg.getRange(3,spalte).getValue();
for (var reihe=5; reihe <lastRow; reihe++) {
var system = ssOrg.getRange(reihe,spalte).getValue();
if (system !== ""){
aDevs.map(function(row){
row[0] = count;
row[5] = squad;
row[6] = system;
count ++
return row
})
Logger.log(system);
afinal = afinal.concat(aDevs);
}
}
}
var lastDataRow = ssAssessmentLogic.getLastRow();
ssAssessmentLogic.getRange(2,1,lastDataRow-1,10).clearContent();
var rngResult = ssAssessmentLogic.getRange(2,1,afinal.length,7);
rngResult.setValues(afinal);
}
The problem is that the array at the end (16000 rows) has the same value for each row in column 6 and 7. It is allways the last system & department combination that appears in all 16000 rows.
Where am I wrong?
The question was a little confusing for me but I followed your specifics in the comments section where you explain what exactly info to copy and how and where to paste it.
This gets the job done:
const ss = SpreadsheetApp.getActive();
// this gets the "deliverables" and the "departments", this last ones in a list
// and for each department runs the function to add the complete new modified array to the spreadsheet
function fillsNewSheet(){
var newSheet = ss.getSheetByName('List_DeliverablesALL');
// hardcoded the titles
newSheet.getRange(1, 1, 1, 6).setValues([['taskHasDeliverableNumber', 'Deliverable Description', 'SDP Task', 'SDP Milestone', 'Group', 'Department']])
var deliverables = getDeliverables();
var departments = getDepartments();
for(i=0;i<departments.length;i++){
var departmentsGroup = departments[i];
for(j=0;j<departmentsGroup.length;j++){
addsNewSection(deliverables, departmentsGroup[j])
}
}
}
// this just gets de array of values we are gonna paste for each department in the structure sheet.
function getDeliverables(){
var deliSheet =ss.getSheetByName('Deliverables1');
var deliValues = deliSheet.getRange(2, 2, deliSheet.getLastRow()-1, 4).getValues();
return deliValues;
}
// As the departments are in different columns with different row counts,
// I go over the whole columns and rows and create a single list with all "department" and "group" pairs
function getDepartments(){
var structureSheet = ss.getSheetByName('OrgStructure');
var cols = structureSheet.getLastColumn();
var groups = structureSheet.getRange(3, 1, 1, cols).getValues()[0]
var departments = [];
for(i=1;i<=cols;i++){
var group = groups[i-1];
var groupDeps = structureSheet.getRange(5, i, structureSheet.getLastRow(), 1).getValues();
var subDeps = []
for(j=0;j<groupDeps.length;j++){
subDeps.push([group, groupDeps[j][0]])
}
var filtered = subDeps.filter( function (data) { return data[1] != "" });
departments.push(filtered);
}
return departments;
}
// finally this gets the complete list of "deliverables" from the first sheet, and one specific department.
function addsNewSection(deliverables, department){
var newSheet = ss.getSheetByName('List_DeliverablesALL');
// and in every row of the deliverables list we add the corresponding department/group pair to get the new modified array.
var newSection = []
for(k=0;k<deliverables.length;k++){
var newRow = deliverables[k].concat(department)
newSection.push(newRow)
}
// when this is complete I paste the whole new array in the third sheet.
newSheet.getRange(newSheet.getLastRow()+1, 1, newSection.length, 6).setValues(newSection)
}
The problem is: I have big spreadsheet (more than 4500 rows) with a lot of data in the first column - for ex. with types of fruits, which are not unique, like this:
APPLE
BANANA
APRICOTS
APPLE
BLACKCURRANT
APPLE
BANANA
APRICOTS
etc.
What I need - locate each BANANA, to be able to put in cell beside some info, for ex. YES. I tried to loop solution from Locating a cell's position in google sheets using a string or an integer but for sure my code is wrong. I already spent a lot of hours to invent something, but still don't understand what I'm missing.
function test(){
var dispatch = SpreadsheetApp.getActiveSpreadsheet().getSheetByName("FRUITS");
var find = dispatch.getRange("A:A").getValues();
var name = "BANANA";
var lastRow = dispatch.getLastRow();
var n = 1;
var temp = dispatch.getRange(n, 2).getValue();
var i = 0;
while (temp != ""){
for(var n in find){
if(find[n][0] === name){break}
}
n++;
var n = n + i;
dispatch.getRange(n, 2).setValue("YES");
var temp = dispatch.getRange(n, 2).getValues();
var find = dispatch.getRange(n, 2, lastRow).getValues();
var i = n;
}
}
I will be very grateful for the help.
The code example is below:
function test(){
var dispatch = SpreadsheetApp.getActiveSpreadsheet().getSheetByName("FRUITS");
var range = dispatch.getRange(1, 1, dispatch.getLastRow(), 2);
var values = range.getValues();
values.map(function(row) {
if (row[0] == "BANANA")
row[1] = "YES";
});
range.setValues(values);
}
JS array map() method does the most part of work. We convert range values to JS array and back after mapping completes.
I'm using Google's histogram functionality in JavaScript to graph the output of a stochastic model, and it's overlaying extra bars on top of an otherwise nice chart.
The chart is generated by running the calculate_display_coverage() function hundreds of times with different inputs. I assure you the inner workings of the function aren't a problem here (I can't really post my whole Fiddle, but I show what the data look like in my code snippet).
gender = {
gender1: "Male",
gender2: "Female"
};
device = {
device1: "Tablet",
device2: "Mobile",
device3: "Desktop"
};
var paramstring = "";
resultArray = [];
resultArray[0] = ['Run','Coverage'];
var q = 1;
for (var x = 0; x < 100; x++) {
for (var y in gender) {
for (var w in device) {
for (var z = 1950; z < 1980; z++) {
paramstring = "09/21/";
paramstring += z.toString();
resultArray[q] = [q,calculate_display_coverage('SIW', y, paramstring, w).displayed];
q++
}
}
}
}
// dataset looks like [['Run','Coverage'],[1,80000],[2,42000],...]
google.charts.load("current", {packages:["corechart"]});
google.charts.setOnLoadCallback(drawChart);
function drawChart() {
var data = google.visualization.arrayToDataTable(resultArray);
var options = {
title: 'Model output by coverage',
legend: { position: 'none' },
};
var chart = new google.visualization.Histogram(document.getElementById('chart_div'));
chart.draw(data, options);
}
With HTML:
<script type="text/javascript" src="https://www.gstatic.com/charts/loader.js">
</script>
<body>
<div id="chart_div" style="width: 900px; height: 500px;"></div>
</body>
In this case, where x = 100, the histogram includes these extra bars
Somewhat different formatting but same issue for more runs, where x = 2000.
Anyone seen this before?
The problem is that both columns of your data are numeric. Currently it has the format
[['Run','Count'],[1,80000],[2,42000],...]
So the histogram is including the index values as datapoints. You need to cast them as strings, so in the above code, the statement should be
resultArray[q] = [q.toString(),calculate_display_coverage('SIW', y, paramstring, w).displayed];
// [['Run','Count'],['1',80000],['2',42000],...]
That will remove the extra bars.
I currently have a list with two columns. The first column is student name, and the second column is the number of points they have.
I imported this list from multiple spreadsheets so there were many duplicates on the names of the students. I am able to remove the duplicates, but I want to keep a tally on the total points they have. For example:
Amy 10
Bob 9
Carol 15
Amy 12
would turn into:
Amy 22
Bob 9
Carol 15
This is what I have so far:
var target = SpreadsheetApp.getActiveSpreadsheet();
var sheet = target.getSheetByName("Sheet2");
var data = sheet.getRange("A2:B1000").getValues();
var newData = new Array();
var k = 0
var finallist = []
for(i in data){
k++;
var row = data[i];
var duplicate = false;
for(j in newData){
if(row[0] == newData[j][0]){
duplicate = true;
var storedHour = sheet.getRange("B"+k).getValue();
var position = finallist.indexOf(row[0]);
var originalCell = sheet.getRange("B"+(position+1));
var originalHour = originalCell.getValue();
originalCell.setValue(originalHour + storedHour);
sheet.getRange(k,2).setValue("")
sheet.getRange(k,1).setValue("")
}
}
if(!duplicate){
newData.push(row);
finallist.push(row[0])
}
}
}
The problem I'm having is that we have a really large data sample and I'm afraid it may run over Google's 5 minute maximum execution time. Is there another more efficient way to achieve my goal?
Your code is running slow because Spreadsheets API methods (like getRange) are time consuming and much slower then other JavaScript code.
Here is optimized function with reduced number of such Spreadsheets API calls:
function calcNumbers()
{
var target = SpreadsheetApp.getActiveSpreadsheet();
var sheet = target.getSheetByName("Sheet2");
var lastRow = sheet.getLastRow();
var dataRange = sheet.getRange(2, 1, lastRow-1, 2);
var data = dataRange.getValues();
var pointsByName = {};
for (var i = 0; i < data.length; i++)
{
var row = data[i];
var curName = row[0];
var curNumber = row[1];
// empty name
if (!curName.trim())
{
continue;
}
// if name found first time, save it to object
if (!pointsByName[curName])
{
pointsByName[curName] = Number(curNumber);
}
// if duplicate, sum numbers
else
{
pointsByName[curName] += curNumber;
}
}
// prepare data for output
var outputData = Object.keys(pointsByName).map(function(name){
return [name, pointsByName[name]];
});
// clear old data
dataRange.clearContent();
// write calculated data
var newDataRange = sheet.getRange(2, 1, outputData.length, 2);
newDataRange.setValues(outputData);
}
Sorting before comparing allows looking at the next item only instead of all items for each iteration. A spillover benefit is finallist result is alphabatized. Execution time reduction significant.
function sumDups() {
var target = SpreadsheetApp.getActiveSpreadsheet();
var sheet = target.getSheetByName("Sheet2");
var data = sheet.getRange("A2:B" + sheet.getLastRow()).getValues().sort();
var finallist = [];
for(var i = 0; i<= data.length - 1; i++){
var hours = data[i][1];
while((i < data.length - 1) && (data[i][0] == data[i+1][0])) {
hours += data[i+1][1];
i++;
};
finallist.push([data[i][0], hours]);
};
Logger.log(finallist);
}
Edit: the simple data structure with the name being in the first column allows this to work. For anything more complex understanding and applying the methods shown in #Kos's answer is preferable
I'm converting XML results to CSV using the following code. It will automatically increment the 'row' but I am having to set each 'column' value. I attempted to alter the code but the outcome was not functional. I believe the issue lies within the 'new XML' line but I haven't been able to find any information relating to this. So my question is can how can this be coded to auto increment the column value as well?'
Thank you - Matt
var length = msg['result'].length();
var x = 0;
for(var i=0;i<length;i++)
{
tmp['row'][x] = new XML("<row/>");
tmp['row'][x]['column1'] = '"'+msg['result'][i]['this'].toString()+'"';
tmp['row'][x]['column2'] = '"'+msg['result'][i]['that'].toString()+'"';
tmp['row'][x]['column3'] = '"'+msg['result'][i]['other'].toString()+'"';
x++;
}
So after some more testing and guesswork, I came up with the following that is fucntional and returns the output I am needing:
var length = msg['result'].length();
var x = 0;
// This is the number of columns I know will be returned
var z = 3;
for(var i=0;i<length;i++)
{
tmp['row'][x] = new XML("<row/>");
tmp['column'][z] = new XML("<column/>");
tmp['row'][x]['column'][z] = '"'+msg['result'][i]['this'].toString()+'"';
tmp['row'][x]['column'][z] = '"'+msg['result'][i]['that'].toString()+'"';
tmp['row'][x]['column'][z] = '"'+msg['result'][i]['other'].toString()+'"';
z++;
x++;
}