I am using Google Sheets.
I have a spreadsheet with a column 'B' containing data which is conditionally formatted with background colors.
I need to place the hex code corresponding to the color in each cell of 'B' into the neighboring cell in 'C'.
I have the following code, which works:
function GetBackColorCode(cell)
{
return (SpreadsheetApp.getActiveSheet().getRange(cell).getBackground());
}
As you can see, however, this code requires manually inserting the proper column and row number in each and every cell. Thus, if I want the hex. code for the color in B14, I insert the following in C14:
=GetBackColorCode("b14")
This method would require me to manually imput about three hundred cells. Is there no way to automatically pick up the cell reference, with, for example, a 'this.someFunction()' call? Such that I can paste the call '=GetBackColorCode(this.someFunction())' into all the cells in column 'C' and each will automatically furnish the necessary reference to the cell to its immediate left?
Change your script to
function getHexCodes(range) {
return SpreadsheetApp.getActiveSheet()
.getRange(range).getBackgrounds();
}
then enter in C2 (or whatever your 'start row' will be)
=getHexCodes("B2:B")
Related
I am trying to figure out how to get the A1 Notation of a Cell calling a Custom Function.
I found this but this is for active cell. https://webapps.stackexchange.com/questions/54414/in-google-script-get-the-spreadsheet-cell-calling-a-custom-function
Essentially if I want Cell A5 to Call =TEST(). I want the function to return the text value A5.
I want to use this as a cache identifier for an API Call.
There are subtle differences in different range returning method names- active,current,selection:
The term "active range" refers to the range that a user has selected in the active sheet, but in a custom function it refers to the cell being "active"ly recalculated.
The current cell is the cell that has focus in the Google Sheets UI, and is highlighted by a dark border.
A selection is the set of cells the user has highlighted in the sheet, which can be non-adjacent ranges. One cell in the selection is the current cell, where the user's current focus is.
The first two are still range objects,while the latter is not. To reiterate, getActiveRange()
in a custom function it refers to the cell being "active"ly recalculated.
I want the function to return the text value A5.
Without Custom Functions,We can use:
=ADDRESS(ROW(),COLUMN())
With Custom function,We can use:
function test() {
return SpreadsheetApp.getActiveRange().getA1Notation();
}
I am trying to apply conditional formatting to more than one range. The formatting is always the same but the cell that contains the condition is not.
For example:
`=OR($B$11="金",$B$11="木")` //this custom formula applies to range C5:Q14
'=OR($B$22="金",$B$22="木") //this custom formula applies to range C16:Q25
The first formula checks the cell B11 for condition
The second formula checks the cell B22 for the condition
It works as intended. However I have to set up many such ranges and if I copy or paste, the formatting ranges just get added to the ones already in the formula and they all check the same cell for the condition. I can achieve what I need if I set the condition for every range manually but I would like to know if there is a better way via sheets formula or a script if formulas are not viable.
Please see the sheet for the example
https://docs.google.com/spreadsheets/d/1G0eUibjNKlZ1fDm9id5SPFNlF392cuEPzNDMB8E5jyU/edit?usp=sharing
I see 3 possible abstractions of your problem.
1) Conditional formatting by groups of rows of known length. 2) How to identify the row index of the top of a section in a copy-paste friendly way if helper column is permitted. 3) Detect the top most non-blank cell in a column above a particular row.
Of course, 3) is most general. But if you only need 1) or 2), it's better to use simpler solutions. So I'll comment on each.
Conditional formatting by groups of rows of known length
Use a combination of index and match. (If the requirement grows more complicated, also consider using indirect.)
For example, if you need rows in groups of 11 to refer to the head row, you can do
=match(index($A:$A,floor(row(B1)/11)*11+1,1),{"金";"木"},0)
in B1:C11; given that you have weekday character in A:A every 11 rows.
Recall that in Conditional Formatting, we specify a (fixed) range and a formula that refers to relative ranges. Google Sheet will then iterate the cell indices over the (fixed) range -- meaning, starting with the top-left most cell, when you move down 1 row, the (relative) ranges in the formula will all have row index adds +1; when you move right 1 column, the (relative) ranges in the formula will all have column index adds +1. $ sign functions normally.
The only (relative) range in the formula that is free to iterate is B1. Thus what happens here is that: as you move along (fixed) range B1:C11, for example when you reach C10, the (relative) range in the formula becomes C10 (coincidentally) because C10 is 9 rows down and 1 column right from the top-left most cell in range B1:C11.
Test:
Input
Result
Identify/Designate row index of the top of a section
If you can use a helper column, there is an easy way to designate a row index as a function of the position of a section.
For example, let's say your section spans B1:D10. You want to be able to copy-paste this section to B21:D21 and you want everything else to keep.
It's simple if you can tolerate using A:A just for labeling the top of the section.
You do not need to know the number of rows per section ahead of time.
In A1, input =row(A1). In A2, input =A1. Now drag the formula across your section, ie. to A10.
Now you can put conditional formatting in C1:D10 as simply
=match(index($B:$B,A1,1),{"金";"木"},0)
and of course you can use simpler formulas for string comparison.
Detect the top most non-blank cell in a column above a particular row
If you don't have a fixed template for your section with known number of rows, and you need to keep your sheet clean of helper columns, then the only way is to detect the last non-empty cell above a given row in the column you have your weekday characters.
A number of variations are possible here. You can detect non-empty cell. Or you can detect the presence of a string from a list of string. You can retrieve the content of the cell or you can get the row index. etc. We are going to do the simplest thing here.
Suppose you have your weekday characters in A:A and you need conditional formatting in B:C. Then, in Conditional Formatting tab, put range as B:C, and formula as follows.
=match(+SORT($A$1:$A1,$A$1:$A1<>"",,ROW($A$1:$A1),),{"金";"木"},0)
What happens here is that +SORT($A$1:$A1,$A$1:$A1<>"",,ROW($A$1:$A1),) will pick out the content of the last non-empty cell in column A relative to the row in question.
Here is how SORT achieves the result for us:
The 2nd input of SORT will evaluate into a column of boolean with TRUE meaning non-empty. $A$1:$A1 relative to B1:C means to pick out cells in A1:A above and including the cell in question. Leaving the 3rd input empty means descending, which in turn means TRUE comes before FALSE. + tells Google Sheet to output the first element in an array output. Up to this point, +SORT($A$1:$A1,$A$1:$A1<>"",) will output the top-most non-empty cell. Within all the non-empty cells, you want the last one. Hence, the 4th input for row index and 5th input for descending. The non-empty cell with the highest row index in A1:A is the cell you want.
It is up to you as the Asker to identify the exact requirements for your task at hand.
I would say it is important that the Asker abstracts the requirements and state them in the question --- as opposed to seeking how to assess the task at hand in answers.
That is what often distinguishes a programming question that everyone else can search easily, thus learn and adapt from vs an outsourcing query.
Apps Script Solution
AFAIK the best way is with Apps Script
With a script like this:
function createRule() {
// Get Ranges
var sheet = SpreadsheetApp.getActiveSheet();
var cellToWatch = sheet.getActiveCell()
var rangeForRule = cellToWatch.offset(-6, 1, 10, 15)
// Create absolute Cell reference
var cellNotation = cellToWatch.getA1Notation()
var patt = /([a-zA-Z]+)([\d]+)/
var result = patt.exec(cellNotation)
var absoluteRef = "$" + result[1] + "$" + result[2]
// Create Conditional Formatting rule
var rule = SpreadsheetApp.newConditionalFormatRule()
.whenFormulaSatisfied('=OR('+ absoluteRef +'="金",'+ absoluteRef +'="木")')
.setBackground("#00FF00")
.setRanges([rangeForRule, cellToWatch])
.build();
var rules = sheet.getConditionalFormatRules();
rules.push(rule);
sheet.setConditionalFormatRules(rules);
}
This script
Assumes that your sheet will always have exactly the same format
Needs you to select the cell with the criteria, like this:
At the moment you need to run from the script editor
It chooses a range to apply the formatting rule based on the position of the selected cell. var rangeForRule = cellToWatch.offset(-6, 1, 10, 15)
It gets the A1 notation of the selected cell and using RegEx, makes an absolute version of the A1 notation. A1 => $A$1
It creates a conditional formatting rule using the references it has just built.
You will need to modify the HEX value of the color to suit your needs "#00FF00"
You could make this a custom sidebar on your spreadsheet, so that creating this rule is just a couple mouse clicks.
References
Apps Script Main Page
RegEx
Sheets Range Object
Conditional Format Rule Builder
Conditional Format Rule Class
I would like to write my own function in Google Script that I can use in Google Sheets to get the background color of a cell. Let's call the function GETBACKGROUNDCOLOR.
I want to be able to pass a cell reference (in A1 notation) as parameter, e.g. if I call =GETBACKGROUNDCOLOR(B2), it should return the background color of cell B2. If I call the function without parameter, I want it to return the background color of the same cell in which it is called, e.g. calling =GETBACKGROUNDCOLOR() in C3 should return the background color of C3.
I have tried this:
function GETBACKGROUNDCOLOR(cell){
return SpreadsheetApp.getActiveSheet().getRange(cell).getBackground();
}
But when I call GETBACKGROUNDCOLOR(A1), the parameter is not the cell reference of A1, but the cell content of A1.
How can I solve this?
Bulletproof script below:
1. Paste to AppsScript:
function bgHex(cellAddress) {
var mycell = SpreadsheetApp.getActiveSheet().getRange(cellAddress);
var bghex = mycell.getBackground();
return bghex;
}
2. Back in sheets call it with =bgHex(CELL("address"; B4)) or =bgHex(CELL("address", B4)), depending on your locale. Look closely and note the difference: delimiters. Some countries like Poland use comma as decimal delimiter and we use semicolons for separating arguments. Others use dots as delimieters so they can use comma for separating args.
With that function you'll get the hex code for specified cell's background. Call any cell, no range errors, no mismatched data formats.
Now you can play with getting other stuff out of these cells, for example check cell values. Here's a test sheet so You can see how it works.
You will find a second function there, for extracting cell's value – the principle is the same.
function cellValue(cellAddress) {
var mycell = SpreadsheetApp.getActiveSheet().getRange(cellAddress);
var value = mycell.getValue();
return value;
}
Now go to https://developers.google.com/apps-script/reference/spreadsheet/range and play with other methods.
You could try something like
=GETBACKGROUNDCOLOR("A"&row(A1))
or
=GETBACKGROUNDCOLOR(cell("address", A1))
and see if that works?
(Note: depening on your locale you may have to use a semi-colon instead of a comma).
You can use =address to resolve name
=GETBACKGROUNDCOLOR(address(row(A1),column(A1)))
for relative cells or
=GETBACKGROUNDCOLOR(address(row(),column()))
for cell with formula
However, the big problem would be that then you'll change cell backround color, formula won't recalculate(function re-eval won't trigger), so it might not be exactly a way.
Example sheet:
https://docs.google.com/spreadsheets/d/1lfFRLVqhns0AJCbZd6ikgcDtvktcgpNWfNomMASWemE/edit#gid=0
I'm trying to use a function to get the hexadecimal code of the cell background and concatenate it with the text contained in the same cell.
i.e. in sht1.cell(A1) I type "Hello" with red background, I would have in sht2.cell(A1) the following text: "[#FF0000]Hello"
I was trying this:
function getHexValue(range) {
return SpreadsheetApp.getActiveSheet().getRange(range).getBackground();
}
but it doesn't always work, especially if I share the file. I tried to setup some triggers using edit, change or open events but id keeps not updating
this is what i tried to do.
Any suggestion?
If I type: =gethexvalue("A5") I get the color code, if I type the formula to another cell or another sheet and I update the values or reload the sheet it doesn't work.
In your formula =gethexvalue("A5"), "A5" is text, not a dynamic range.
Read How to pass a range into a custom function in Google Spreadsheets? for a full discussion and 11 different answers. This is itself a possible duplicate of passing cell references to spreadsheet functions.
This =getHexValue(ADDRESS(ROW(A1), COLUMN(A1)))&A1 is dynamic. It will return:
"#ff0000Hello"
. If you want the hex in Uppercase, then use UPPER with getHexvalue.
I was sure to find that on StackOverflow but finally no. Maybe it's not possible?
I'd like to get the cell where my function is running.
If for example I have the function that is repeated in column D for line 1 to 10, I'd like that function to know that the current "processing" is D4 (for example).
I want this in order to be able to change the color of the cell based on the computation the function does. This, of course, changes based on the data input.
Is this possible? How? I wasn't able to find it.
Here's an applicable example code :
function ALERT_IF_NEGATIVE(input) {
if (input < 0) {
// Set that cell's color to red
}
}
Thank you.
Conditional formatting will solve this.
https://support.google.com/docs/answer/78413?hl=en
This is an example I have from a spreadsheet I use:
In my code it adds the row values:
ss.appendRow([account,sAccount.name,sAccount.id,response.access_token,d,expTime,'=if(E'+lastRow+'<NOW(), "EXPIRED","VALID")',]);`
In this case the formula in column 'G' looks at a timestamp in Column 'E' and sets the value in 'G'. The conditional format looks at the values in 'G' and changes the cells background color based on the value.
The formatting is recalculated when there is a change to the sheet, or can be set-up to recalculate on a timer in File->Spreadsheet settings.