% Find a VISA-GPIB object.
obj1 = instrfind('Type', 'visa-gpib', 'RsrcName', 'GPIB8::1::INSTR', 'Tag', '');
% Create the VISA-GPIB object if it does not exist
% otherwise use the object that was found.
if isempty(obj1)
obj1 = visa('TEK', 'GPIB8::1::INSTR');
else
fclose(obj1);
obj1 = obj1(1);
end
% Connect to instrument object, obj1.
fopen(obj1);
t = timer;
t.TasksToExecute = 3;
t.Period = 30;
t.ExecutionMode = 'fixedRate';
t.TimerFcn = #(myTimerObj, thisEvent)disp(query(obj1,'CALCulate:SPECtrum:MARKer0:Y?'));
start(t)
This is my program where I have to save the output values which displays
Query('CALCulate:SPECtrum:MARKer0:Y?') in a array.
You will need to create a variable to hold the outputs of query(obj1, 'CALCulate:SPECtrum:MARKer0:Y?'). You can then append to this variable from within the timer callback function.
%// Initialize a cell array (because I'm not sure of your datatype)
results = {};
%// Define a function to be called when the timer fires
function timerCallback(varargin)
newresult = query(obj1,'CALCulate:SPECtrum:MARKer0:Y?');
%// Display the result (like you currently are)
disp(newresult)
%// Append the result to your results container
results{end+1} = newresult;
end
%// Then set your timer callback
t = timer('TasksToExecute', 3, ...
'Period', 30, ...
'ExecutionMode', 'FixedRate', ...
'TimerFcn', #timerCallback);
start(t)
All of your other setup code would remain the same.
Related
I have a simple example of a function I am working on. I am trying to loop through a column of unique item IDs. If the item ID is found in the item ID column of another sheet, it pulls adjacent attributes from the data table, and assigns them in the same row. I have a function and it works, however, this is a base example. In reality I need to do this for 1000+ rows, and much larger data sets. It is currently taking 30-60 mins to run. I believe there is a much faster way to do this with arrays and using foreach and getvalues I'm just not sure how to get started. Any help would be greatly appreciated.
function example() {
var list = SpreadsheetApp.getActiveSpreadsheet().getSheetByName("List");
var data = SpreadsheetApp.getActiveSpreadsheet().getSheetByName("Data")
var listendRow = list.getLastRow();
var dataendRow = data.getLastRow();
var dataid = data.getDataRange().getValue();
for (var i = 2; i <= listendRow; i++) {
for (var j = 2; j <= dataendRow; j++){
var idnum = [list.getRange(i, 2,listendRow).getValue()];
var id = data.getRange(j, 3).getValue();
var name = data.getRange(j, 4).getValue();
var weight = data.getRange(j, 5).getValue();
if (idnum == id){
list.getRange(i, 3).setValue(name);
list.getRange(i, 4).setValue(weight);
}
}
}
}
Here is the link to the sheet:
https://docs.google.com/spreadsheets/d/1PPZKRXhiAAfFG1d-CU02MV_CSrqbdsCsyo_QADz5yiA/edit?usp=sharing
I believe your goal is as follows.
Your script works fine. Under this condition, you want to reduce the process cost of your script.
Modification points:
When I saw your sample Spreadsheet, V8 runtime is not used. Please enable V8 runtime. When V8 runtime is used, the process cost of the script can be reduced.
In your script, getValue and setValue are used in a loop. In this case, the process cost becomes high. Ref
SpreadsheetApp.getActiveSpreadsheet() can be declared one time.
In order to reduce the process cost of your script, how about the following modification?
Modified script:
Before you run this script, please enable V8 runtime.
function example2() {
var ss = SpreadsheetApp.getActiveSpreadsheet();
var list = ss.getSheetByName("List");
var data = ss.getSheetByName("Data");
var obj = data.getRange("C2:E" + data.getLastRow()).getValues().reduce((o, [a, ...b]) => (o[a] = b, o), {});
var range = list.getRange("B2:B" + list.getLastRow());
var values = range.getValues().map(([b]) => obj[b] || [null, null]);
range.offset(0, 1, values.length, 2).setValues(values);
}
When this script is run, the values are retrieved from "Data" sheet and create an object for searching the ID. And, the values are retrieved from "List" sheet and an array for putting to the sheet is created. And also, the array is put to "List" sheet.
Note:
When you try to use this script without enabling V8 runtime, an error like Syntax error occurs. Please be careful about this.
This modified script is for your sample Spreadsheet. If your actual Spreadsheet is differnt structure from your provided sample one, this modified script might not be able to be used. Please be careful about this.
If you cannot use V8 runtime, please test the following modified script.
function example2b() {
var ss = SpreadsheetApp.getActiveSpreadsheet();
var list = ss.getSheetByName("List");
var data = ss.getSheetByName("Data");
var obj = data.getRange("C2:E" + data.getLastRow()).getValues()
.reduce(function (o, [a, b, c]) {
o[a] = [b, c];
return o
}, {});
var range = list.getRange("B2:B" + list.getLastRow());
var values = range.getValues().map(function ([b]) { return obj[b] || [null, null] });
range.offset(0, 1, values.length, 2).setValues(values);
}
References:
getValues()
setValues(values)
reduce()
map()
I am trying to filter the array 'employee_name' consisting of NaNs and one string element, to exclude any element BUT the string. The context is that I have a spreadsheet containing employee's birth dates, and I'm sending an email notification in case there's a birthday two days from today. My variables look like this:
var ss = SpreadsheetApp.getActiveSpreadsheet().getSheetByName('Employees');
var range = ss.getRange(2, 1, ss.getLastRow()-1, 1); // column containing the birth dates
var birthdates = range.getValues(); // get the `values` of birth date column
var today = new Date ();
var today = new Date(today.getTime());
var secondDate = new Date(today.getTime() + 48 * 60 * 60 * 1000);
var employee_name = new Array(birthdates.length-1);
And the loop:
for (var i=0;i<=birthdates.length-1;i=i+1){
var fDate = new Date(birthdates[i][0]);
if (fDate.getDate() == secondDate.getDate() &&
fDate.getMonth() == secondDate.getMonth()){
//define variables for outgoing email
for (var j=0; j<=birthdates.length-1;j=j+1){
employee_name[j] = [NaN];
}
employee_name[i] = ss.getRange(i+2,6);
employee_name[i] = employee_name[i].getValues();
}
}
after which the array in question looks like this
Logger.log(employee_name);
[[[Mia-Angelica]], [NaN], [NaN], [NaN], ..., [NaN]]
I have already tried the filter(Boolean), but this isn't working:
employee_name_filtered = employee_name.filter(Boolean);
Logger.log(employee_name_filtered);
returns [[[Mia-Angelica]], [NaN], [NaN], [NaN], ..., [NaN]].
I have also tried filling the non-string array entries with numeric values (instead of NaN) and then apply
employee_name_filtered = employee_name.filter(isFinite);
Logger.log(employee_name_filtered);
returns [[1.0], [2.0], [3.0], ..., [72.0]], so this filter method is working, but then I would need the 'inverse' of that because I want to keep the string.
I need the array within array to store the values at the position of the counter variable where the condition's met (similar to How to store data in Array using For loop in Google apps script - pass array by value).
This is my first time posting a question on SO, so if I overlooked any 'rules' about posting, just let me know and I will provide additional info.
Any help will be appreciated!
EDIT:
what I would like to receive in the end is simply
[[Mia-Angelica]].
The array you are using a 2 dimensional array - meaning it's an array of arrays so the filter method you are using cannot be applied in the same manner.
For this, I suggest you try the below snippet.
function cleanArray() {
var initialArray = [
['Mia-Angelica'],
['Space'],
['2'],
[NaN],
[NaN],
[NaN],
[NaN]
];
var finalArray = [];
for (let i = 0; i < initialArray.length; i++) {
var midArray = initialArray[i].filter(item => (Number.isFinite(item) && item.id !== 0) || !Object.is(item, NaN));
finalArray.push(midArray);
}
console.log(finalArray.filter(item => item != ''));
}
Note
Please bear in mind that getValues will return an Object[][] which is a two-dimensional array of values.
Reference
Apps Script Range Class;
Array.prototype.filter().
I am new to coding.
I am trying to edit and set values from an entire row but want to skip certain columns, because there are formulas in it.
In short: I want to / have to keep track of sing-in and sign-out times, which then will be calculated in the spreadsheet but shouldn't be overwritten by the array. Is there a way to skip every 3rd "value"/index (as these are the columns which have the formulas)?
In fact I want to skip the columns: TOTAL, day1tot, day2tot, day3tot .... day14tot.
function editCustomerByID(id,customerInfo){
const ss = SpreadsheetApp.getActiveSpreadsheet();
const ws = ss.getSheetByName("DATA");
const custIds = ws.getRange(2, 1, ws.getLastRow()-1, 1).getDisplayValues().map(r => r[0].toString().toLowerCase());
const posIndex = custIds.indexOf(id.toString().toLowerCase());
const rowNumber = posIndex === -1 ? 0 : posIndex +2;
Logger.log(customerInfo);
ws.getRange(rowNumber, 2, 1, 8).setValues([[
customerInfo.name,
customerInfo.total,
customerInfo.day1in,
customerInfo.day1out,
customerInfo.day1tot,
customerInfo.day2in,
customerInfo.day2out,
customerInfo.day2tot
// UNTIL DAY 14
]]);
return true;
To skip columns, you can subdivide your range into individual ranges and implement conditional statements
Sample:
function editCustomerByID(id,customerInfo){
...
var valueArray = [
customerInfo.name,
customerInfo.total,
customerInfo.day1in,
customerInfo.day1out,
customerInfo.day1tot,
customerInfo.day2in,
customerInfo.day2out,
customerInfo.day2tot
// UNTIL DAY 14
]
var startColumn = 2;
//loop through all values
for (var i = 0; i < valueArray; i++){
// filter out every 3rd value
if((i+1) % 3 != 0){
ws.getRange(rowNumber, (startColumn + i)).setValue(valueArray[i]);
}
}
return true;
Note that the sample code above uses the method setValue() instead of setValues()
Performing multiple requests to set values to individual ranges is less efficient that setting all values at once within a single request, however in your case it is necessary since your desired value range is not continuos
I have a set of documents in Firestore in this format. Questions array will 10 questions.
I want to get the data of questions field: one row for one question
I do I code in the appscript to perform this
This is my code so far (for one document only)
function test(){
const firestore = getFirestore();
var query = firestore.getDocument("QuestionCollection/test").fields;
var data = {};
data.subject = query.subject;
data.questions= query.questions;
const sheet = SpreadsheetApp.getActiveSheet();
for(i = 0 ; i < 10 (no. of question); i++){
const row = [data.questions[i].answer, data.questions[i].difficulty];
sheet.appendRow(row);
}
}
Error:
TypeError: Cannot read property 'answer' of undefined
Modification points:
When I saw your sample data in the image, it seems that the array length of questions is 2. But at the for loop, the end index of loop is 9. I think that by them, such error occurs.
When you want to put the value of "Serial", it is required to add the value for putting to Spreadsheet.
In your script, appendRow is used in a loop. In this case, the process cost becomes high.
When above points are reflected to your script, it becomes as follows.
Modified script:
Your for loop is modified as follows.
From:
for(i = 0 ; i < 10 (no. of question); i++){
const row = [data.questions[i].answer, data.questions[i].difficulty];
sheet.appendRow(row);
}
To:
var values = [];
for (var i = 0; i < data.questions.length; i++) {
const row = [i + 1, data.questions[i].answer, data.questions[i].difficulty];
values.push(row);
}
sheet.getRange(sheet.getLastRow() + 1, 1, values.length, values[0].length).setValues(values);
For the end index of loop, the array length is used.
Reference:
setValues(values)
You shouldn't query the .fields property directly (because your data isn't converted properly). Assuming you're using v28+ of the library, your code should look something like this:
function test(){
const firestore = getFirestore();
const query = firestore.getDocument("QuestionCollection/test").obj; // Don't use .fields here
const sheet = SpreadsheetApp.getActiveSheet();
const values = [["Serial", "Answer", "Difficulty"]]; // Init 2D array with Header row
// Loop through each question in the array and extract necessary values to construct Data rows
for (const question of query.questions){
values.push([query.questions.indexOf(question) + 1, question.answer, question.difficulty]);
}
// Replace 1, 1 below with coords of "Serial" header cell
const range = sheet.getRange(1, 1, values.length, values[0].length);
range.setValues(values);
// sheet.getRange(subjRow, subjCol).setValue(query.subject); // Add location for Subject data
}
I saw that you wanted "Serial" to represent "Question number", so I added that column to the header and data rows.
As Tanaike mentioned, there's a huge performance hit for writing to the spreadsheet in a loop, so it's better if you set up a 2D array of values to write all at once using range.setValues(array2D). Ideally, you'll want to minimize the calls to the Spreadsheet API.
Disclaimer: I'm an active contributor to the FirestoreGoogleAppsScript library.
I have generated a number and sent it to a text box. Now I want to save that number for later use. Arrays seem (to my very limited knowledge) to be the place to keep data you wish to access later on. How do I do this?
my code so far:
roll_btn.addEventListener (MouseEvent.CLICK, rollDice);
function rollDice (Event:MouseEvent):void{
var die1:uint = Math.floor (Math.random()* 6) + 1;
var die2:uint = Math.floor (Math.random()* 6) + 1;
die1_txt.text = die1.toString();
die2_txt.text = die2.toString();
sec1_txt.text = (die1 + die2).toString();
}
I want to add the result in "sec1_txt.text" to an array.
Thanks in advance.
Use this:
var myArray:Array = new Array();
myArray.push(die1 + die2)
You can also use a Vector that is a typized (of uint) array.