I'm trying to get the search terms and their values in the rising table here:
http://www.google.com/trends/explore#cat=0-14&date=today%207-d&cmpt=q
I can't work out what html tag/class/path they're in. How can I work it out? I tried looking at the source code but it wasn't much help.
Any help is really appreciated - Thx! Antoine
The following snippet will return an array of arrays (the overarching array contains values for each table in the page). Each array element has an array where each table row is an object, broken down into it's 'term' and 'value'.
var tableValues = [];
var t = document.querySelectorAll(".trends-table-data");
if(t.length>0){
var rows, row, cells, values;
for(var i=0; i<t.length; i++){
values = [];
rows = t[i].getElementsByTagName("tr");
for(var r=0; r<rows.length; r++){
row = rows[r];
if(row.className.indexOf('trends-table-row')===-1) continue;
cells = row.getElementsByTagName("td");
values.push({
term: cells[0].innerText.replace(/^\s+|\s+$/g, ''),
value: cells[1].innerText.replace(/^\s+|\s+$/g, '')
});
}
tableValues[i] = values;
}
console.log(tableValues);
}
Since there are two tables on the page, the output for the page you're referencing is:
tableValues = [[{"term":"friv","value":"100"},{"term":"baby","value":"55"},{"term":"hot","value":"50"},{"term":"girls","value":"45"},{"term":"games","value":"45"},{"term":"juegos","value":"30"},{"term":"العاب","value":"25"},{"term":"love","value":"25"},{"term":"bible","value":"20"},{"term":"india","value":"20"}],[{"term":"sophiya haque","value":"Breakout"},{"term":"temple run 2","value":"+3,200%"},{"term":"крещение","value":"+700%"},{"term":"dear abby","value":"+450%"},{"term":"temple run","value":"+200%"},{"term":"amber heard","value":"+130%"},{"term":"plein champ","value":"+130%"},{"term":"paranormal activity 4","value":"+90%"},{"term":"scientology","value":"+70%"},{"term":"mama","value":"+60%"}]]
Related
I am using google sheets quite a lot, but now I am trying to use google apps script to get and update dynamic data retrieved from formulas into a static table.
So, I have a sheet called 'dynamique', with formulas retrieving, filtering and sorting data from other spreadsheets.
I want to be able to work on this data, so I am trying to create a button which would copy all the values from the 'dynamique' sheet into another sheet called 'statique'. That is, I want a formula which would check if the values from the column C of the 'dynamique' sheet are in the column C of the 'statique' sheet. And if the values aren't there, I want the script to copy them. (columns A and B are empty)
I've managed to get my script to work for one column, but now, I want to copy the whole line.
For example, if the value in dynamique!C10 can't be found in statique!C:C, my script writes the value of dynamique!C10 in the first empty cell of the column statique!C:C. But I want it to write dynamique!C10:J10 into my destination sheet (say it's going to be maybe statique!C8:J8).
Here is my code, working for only one cell.
function dynamicToStatic() {
var dynSheet = SpreadsheetApp.getActiveSpreadsheet().getSheetByName("dynamique");
var staSheet = SpreadsheetApp.getActiveSpreadsheet().getSheetByName("statique");
var dynLength = dynSheet.getRange("C1:C").getValues().filter(String).length;//.getLastRow();
var staLength = staSheet.getRange("C1:C").getValues().filter(String).length;
var staRange = staSheet.getRange(6,3,staLength-1);
var staValues = staRange.getValues();
var rangeToCheck = dynSheet.getRange(6,3,dynLength-1,8);
var valuesToCheck = rangeToCheck.getValues();
var numRows = rangeToCheck.getNumRows();
var staNumRows = staRange.getNumRows();
for (i = 0; i<= numRows; i++) {
var row = valuesToCheck[i];
var index = ArrayLib.indexOf(staValues , -1 , row);
if (index == -1) {
//if (staValues.indexOf(row) != -1) {
staSheet.getRange(i+6,3,1,8).setValues(row);
}
}
var timestamp = new Date();
staSheet.getRange(4,3).setValue('List updated on the: '+timestamp);
}
Now I can't manage to retrieve the whole line of the array, so as to be able to copy it using range.setValues(). I always get error messages.
Any help would be more than appreciated...
function gettingFullRows() {
const ss=SpreadsheetApp.getActive();
const sh=ss.getSheetByName('Sheet1');
const shsr=2;//data startrow
const vA=sh.getRange(shsr,1,sh.getLastRow()-shsr+1,sh.getLastColumn()).getValues();
let html='';
vA.forEach((r,i)=>{
html+=Utilities.formatString('<br />Row:%s is %s',i+shsr,r.join(','));
});
SpreadsheetApp.getUi().showModelessDialog(HtmlService.createHtmlOutput(html), "Row");
}
So i did some re-writing to your code and made some comments in there. I hope this will make some things clear.
Array's are 0 indexed. So if the value is NOT found in the .indexOf then it would return -1. Also (for speed) i first push all the result to a array and then set the array in one "action" this saves a lot of time. The calls to and from a sheet takes the most time.
For the conversion to a 1d array i used spread operator
See this link for difference in const / var / let
The timestamp string i updated with the use of Template literals
If you have some questions, shoot! (also i did not test this ofcourse)
function dynamicToStatic() {
const dynSheet = SpreadsheetApp.getActiveSpreadsheet().getSheetByName("dynamique");
const staSheet = SpreadsheetApp.getActiveSpreadsheet().getSheetByName("statique");
const dynValues = dynSheet.getRange(1,3,dynSheet.getLastRow(),8).getValues();
//This is a 2d array
const staRaw = staSheet.getRange(6, 3, staSheet.getLastRow()).getValues();
//Convert to 1d array, for the indexoff later on, this way it is easier.
const staValues = [].concat(...staRaw);
//to store the output, as a 2d array, inside the if you see i push it in as array so you have the 2d array for the setValues.
const output = [];
for (let i = 0; i < dynValues.length; i++){
//i = the index of the array (row) inside the array of rows, the 0 would be the values of column C.
if (staValues.indexOf(dynValues[i][0]) >= 0){
output.push([dynValues[i]]);
}
}
//Start by the lastrow + 1, column C(3), ouput is a array of arrays(rows), then get the [0].lengt for the columns inside the row array.
staSheet.getRange(staSheet.getLastRow()+1, 3, output.length, output[0].lenght).setValues(output);
const timestamp = new Date();
staSheet.getRange(4,3).setValue(`List updated on the: ${timestamp}`);
}
I have a multidimensional array created by taking data from a google spreadsheet. I am attempting to seperate out the data based on results in a specific column. For example:
var j = {
["Mine", "House"],
["Your", "House"],
["his", "apt"]
}
Given that we want to seperate by column 2. We should get in theory:
var new = {
[["Mine", "House"] , ["Your", "House"]],
[["his", "apt"]]
}
Two entries being a house, and 1 being an apartment. I am haveing a huge issue with treating each entry as its own obj. Assuming it is even possible. I guess we would access specific parts of each object like so, new[0][1][1]? This obviously shouldnt work like this. Is there another way to seperate the entries in the way I am attempting? As it stands right now, I believe my code is just creating the same number of rows as in the original data.
var spreadsheet = SpreadsheetApp.getActive();
spreadsheet.insertSheet("Report");
var data_sheet =spreadsheet.getSheetByName("Data");
var genCounsel_data = data_sheet.getRange(240, 1, 96, 7).getValues(); //get genCounseling data
var report_sheet = spreadsheet.getSheetByName("Report");
//setup key values for columns in report sheet
report_sheet.appendRow(["Student Service", "Unit Student Service Outcome", "Indicators Data Sources", "How indicator was measured", "Benchmark Data", "Assigned to do Assessment", "Email"])
//seperate out by SS outcomes
var genCounselDataByOutcomes = new Array(new Array()); //all responses for each outcome, also parrellel
var outcomes_freq = new Array(); //parrellel arrays
var found = false;
//get services and frequency;
for(var i=0; i<genCounsel_data.length; ++i){
genCounsel_data[i][OUTCOMES_COL].toString().toLowerCase();
for(var j=0; j<genCounselDataByOutcomes.length && !found; ++j){
if(genCounselDataByOutcomes[j][OUTCOMES_COL] == genCounsel_data[i][OUTCOMES_COL]){
genCounselDataByOutcomes[j].push(genCounsel_data[i]); //ADD to row with same outcomes
++outcomes_freq[j]; //update amount of entries in said outcome
found = true;
}
}
if(found == false){
genCounselDataByOutcomes.push(new Array);
genCounselDataByOutcomes[genCounselDataByOutcomes.length-1].push([genCounsel_data[i]]);
outcomes_freq.push(1);
}
else
found = false;
}
for(var i=0; i<outcomes_freq.length;++i)
Logger.log(outcomes_freq[i]);
//for each outcome select a random one and move entire row to sheet;
for(var i=0; i<genCounselDataByOutcomes.length; ++i){
Logger.log(genCounselDataByOutcomes[i]);
}
QUESTION:
How can I seperate my data as multiple objects in a row of an array and be able to access specific components of each entry as shown in my example above? If this is not exactly possible in this way, is there another solution to this issue?
First of all, your j and new (which by the way is not a valid var name) need a key if they are objects or to be used as array, like below:
var j = [
["Mine", "House"],
["Your", "House"],
["his", "apt"]
];
var newVar = [
[["Mine", "House"] , ["Your", "House"]],
[["his", "apt"]]
];
That said and fixed, you can iterate over your array of arrays and use the column you want to use as filter to get the unique values to be used to group the final result.
Here is the final result:
var j = [
["Mine", "House"],
["Your", "House"],
["his", "apt"]
];
var uniqueValues = [];
var indexColumn = 1; //Here you specify the column you want to use to filter/group the elements from j
j.forEach(function(element){
if(!uniqueValues.includes(element[indexColumn])){
uniqueValues.push(element[indexColumn]);
}
});
//Now you use the `uniqueValues` to filter the `j` array and generate the `groupedArrays` array, which is the one you are looking for:
var groupedArrays = [];
uniqueValues.forEach(function(uniqueValue){
groupedArrays.push(j.filter(function(element){
return element[indexColumn] === uniqueValue;
}));
});
console.log(groupedArrays);
I hope this helps you.
Good luck.
I have a table that has, let's say 2 columns. Column A has names, column B has either empty or non-empty cells.
I want to create a separate list with names from column A where the opposite cell in B is empty.
When I execute the code it doesn't bring any errors, however the list that is created in the output range is only with the name of the first person that has empty cell in front of him, i.e. that name appears 10 times in my output list.
Can anyone help me understand what's wrong with my code?
Thanks in advance!
This is the code that I have.
function HLnames() {
var ss = SpreadsheetApp.getActiveSpreadsheet().getSheetByName("HL test");
var ind = 0;
var fullRange = ss.getRange("A3:B26").getValues();
var rangeList = [];
for (var i = 0; i < fullRange.length; i++) {
if (fullRange[i][1] === "") {
rangeList.push(fullRange[i][0]);
ind = ind + 1;
}
}
var outputRange = ss.getRange(30, 1, ind, 1);
outputRange.setValue(rangeList);
}
It appears you should be using setValues instead of setValue. – Google's Documentation.
Hope that helps :)
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.
I am trying to delete a row's data based on the active cell. I have looked through Google's documentation and I cannot figure out how to do this. I have also searched the forums and found a couple of similar scenarios, but I cannot get it to work. I tried to do this by lopping through an array of data and deleting the row based on the value in the array, but this does not work either. I am sure that I am overcomplicating things here. Here is the code that I have so far...
function clearProject() {
var ss = SpreadsheetApp.getActiveSpreadsheet();
var source = ss.getSheetByName('Projects');
var sourceArray = source.getRange(1,1,10).getValues();
var sourceCell = source.getActiveCell();
var sourceData = sourceCell.getValues();
//var sourceRow = sourceCell.getRange(sourceCell, );
var target = ss.getSheetByName('Timeline').getRange(1, 1, 10).getValues();
for (var i = 0; i < sourceArray.length; i++){
if(i == sourceData){
sourceCell.clearContent();
}
}
Thank you for any help that you can afford!
First of all you cannot compare like this if(i == sourceData) due to getValues returns
...the rectangular grid of values for this range. Returns a
two-dimensional array of values, indexed by row, then by column. The
values may be of type Number, Boolean, Date, or String, depending on
the value of the cell. Empty cells will be represented by an empty
string in the array. Remember that while a range index starts at 1, 1,
the JavaScript array will be indexed from [0][0].
And I didn't catch your goal, could you plesae add some more explanation?
It could be as simple as that :
function delRowsInActiveRange() {
var ss = SpreadsheetApp.getActiveSpreadsheet();
var source = ss.getActiveRange();
var height = source.getValues().length;
var rowPosition = source.getRowIndex();
ss.getActiveSheet().deleteRows(rowPosition, height);
}
This function deletes all the rows that include selected cells.