Google Spreadsheets API - Conditional Formatting based on range and adjacent values - asp.net-core

I have the following very streamlined version of a spreadsheet:
Sect | Lbl | A | B | C | D | E
==========================================================
Sec1 | Lbl1 | 1 | 8 | 6 | 10 |
----------------------------------------------------------
Sec2 | Lbl2 | 2 | 1 | 1 | >100 |
----------------------------------------------------------
etc...
I want to apply a rule/rules across all values to say:
Bg Color = Green if:
- the cell to the right is not blank and higher than this value
Bg Color = Red if:
- the cell to the right is not blank and less than this value
Bg Color = white (no action) if:
- the cell to the right has the same value
In addition, if the value is set to the non-numeric ">100" I need to convert it to 100 as part of this formatting.
I'm using C# to do this with the Spreadsheets v4 API.
So far I have the code below but I'm unsure as to how I could apply multiple conditions to a formatting rule.
Update
Please note updated table example above before reading below
Thanks to TheMaster I've got something up and running but it's not quite right yet. I've got an additional factor of:
the first row should be excluded from the conditional formatting
the first two columns are labels and should also be ignored/excluded
all other columns and rows of data need to be compared to the column to their right (if available) and coloured accordingly.
Here is my code so far for the Red rule (where cell value > cell value to the right).
In addition to this I have a Green rule (where cell value < cell value to the right) and a White rule (where cell value = cell value to the right)
They are indexed as below in a batchupdate request:
0 = red
1 = green
2 = white
The Code for the Red rule:
formatRequest.Requests.Add(new Google.Apis.Sheets.v4.Data.Request()
{
AddConditionalFormatRule = new AddConditionalFormatRuleRequest()
{
Rule = new ConditionalFormatRule()
{
BooleanRule = new BooleanRule()
{
Condition = new BooleanCondition()
{
Type = "CUSTOM_FORMULA",
Values = new List<ConditionValue>() {
new ConditionValue()
{
UserEnteredValue = "=AND(NOT(ISBLANK(A2)),(1*REGEXEXTRACT(A2,\"\\d+\"))>(1*REGEXEXTRACT(B2,\"\\d+\")))"
}
}
},
Format = new CellFormat()
{
BackgroundColor = new Color()
{
Red = 0.8f,
Green = 0f,
Blue = 0f,
Alpha = 1f
}
}
},
Ranges = new List<GridRange>()
{
new GridRange()
{
SheetId = Convert.ToInt32(sheetId)
,StartRowIndex = 1
},
}
},
Index = 0
}
});
The problem is it doesn't apply the conditional formatting to the whole sheet...only the first column of data.

You should use CUSTOM_FORMULA as Boolean condition Type
You'll need to add two conditional formatting rules with index 0 and 1
Range will be open-ended and cover the full sheet.
Snippet(for A1:Z;Bg:red):
Boolean Condition JSON:
{
"type": "CUSTOM_FORMULA",
"values": [
{
userEnteredValue: "=AND(NOT(ISBLANK(A1)),A1>(IF(ISNUMBER(B1),B1,1*REGEXEXTRACT(B1,\"\d+\"))))"
}
]
}
BooleanRule/Format/BackgroundColor JSON:
{
"red": 1,
"green": 0,
"blue": 0,
"alpha": 1
}

Related

How to check user name and last name length in one textfield in android jetpack compose?

There is an outlinedtextfield where the user enters his/her name and surname, and this outlinetextfield enters the user name and surname, but if the user's name and surname are less than 3 characters, I want to make the border of the outlinetextfield red, but I couldn't figure out how to do this control because space intervened.
for example :
a(space)b wrong
jac(space)jac correct
tony(space)stark correct
this is my example code:
OutlinedTextField(
value = state.name,
onValueChange = { onChangeName(it) },
modifier = Modifier
.fillMaxWidth(),
shape = RoundedCornerShape(25.dp),
label = {
Text(
text = "name and lastname",
fontSize = 14.sp,
color = Color.White
)
},
colors = TextFieldDefaults.outlinedTextFieldColors(
focusedBorderColor = if (state.name.length < 7) Color.Red else DefaultDYTColor,
unfocusedBorderColor = Color.Transparent
)
)
When I do it this way, it accepts it as correct even if I type 7 characters without spaces, but it should not be like this.
for example:
tonystark
According to the code I wrote, this is correct because it is greater than 7 characters
How to achieve this issue ? Do you have any suggestion or solve ?
This is just an algorithmic problem, you can solve it like this:
fun isValidName(name: String): Boolean {
// split name on each space and filter out those that are blank (consecutive spaces)
val splits = name.split(" ").filter { it.isNotBlank() }
// we need at least 2 strings (name and surname)
// you can also use != 2 if you want exactly 2
if (splits.size < 2) return false
// if any name is less than 3 chars, return false
for (split in splits) {
if (split.trim().length < 3) {
return false
}
}
// now we have at least 2 names and all of them have 3 or more chars
return true
}

how do i update a Google Charts pie chart to reflect filtered data but retain filtered out segments as a diff colour

I'm new to Google Charts and I'm struggling to solve this.
I have a datatable (called "result" in the code)
Name Liquidity percent
a 1.3 20%
b 2.0 20%
c 3.4 20%
d 4 20%
e 5 20%
My pie chart is set to show 5 segments of equal size - 20% - and each segment is blue
I have set a 'Number Range Filter' control wrapper to filter the liquidity - when i set the control to the range 1 to 4 the pie moves to 4 equal sized segments.
BUT... I don't want it to do this. Instead of 1 segment disappearing I want the 5 segments to remain visible and the colour of the filtered segment to change to be a different colour.
The aim being that I can see visually a total percentage that falls within the number filter.
EDIT:
So I've had a mess about and this is as far as I've got incorporating dlaliberte's comment below.
function drawChart3(chartData3) {
var result = google.visualization.arrayToDataTable(chartData3,false); // 'false' means that the first row contains labels, not data.
var chart3 = new google.visualization.ChartWrapper({
'chartType': 'PieChart',
'containerId': 'chart3_div',
'dataTable': result,
'options': {
'width': 500,
'height': 500,
'legend': {position: 'none'},
'pieSliceText': 'none',
'colors': ['blue']
},
'view': {'columns': [0 , 1]}
});
var liquidityDT = new google.visualization.DataTable();
// Declare columns
liquidityDT.addColumn('number', 'Liquidity');
// Add data.
liquidityDT.addRows([
[1],
[2],
[3],
[4],
[5],
]);
// Create a range slider, passing some options
var liquidityRangeSlider = new google.visualization.ControlWrapper({
'controlType': 'NumberRangeFilter',
'containerId': 'filter3_div',
'dataTable': liquidityDT,
'options': {
'filterColumnLabel': 'Liquidity',
'minValue': 0,
'maxValue': 5
}
});
liquidityRangeSlider.draw();
chart3.draw();
google.visualization.events.addListener(liquidityRangeSlider, 'statechange', setChartColor);
function setChartColor(){
var state = liquidityRangeSlider.getState();
var stateLowValue = state.lowValue;
var stateHighValue = state.highValue;
for (var i = 0; i < result.getNumberOfRows(); i++) {
var testValue = result.getValue(i,2);
if (testValue < stateLowValue || testValue > stateHighValue){
alert("attempting to set colors")
//this bit I have no clue how to change the color of the table row currently being iterated on
chart3.setOption({'colors' : ['red']});
}
}
chart3.draw();
}
}
so it produces the pie chart with 5 blue segments. I can move the number filter and it fires the listener event but I can't get it to affect anything on the piechart (Chart3) - The code currently attempts just to change the whole chart to RED but that isn't even working never mind the just colouring the filtered segments
So how do I effect the changes into Chart3 and how do I only effect the filtered segments?.
any clues welcome?
thanks
You can (and must, for your application) use a NumberRangeFilter outside of a Dashboard because it will otherwise always do the data filtering. Instead, just listen for the change events on the NumberRangeFilter, get its current state, and then iterate through the colors array for your chart to set the appropriate colors. You'll have to draw the chart again with the updated colors. Here is the loop to set the colors and redraw.
var colors = [];
for (var i = 0; i < result.getNumberOfRows(); i++) {
var color = (testValue < stateLowValue || testValue > stateHighValue) ? 'red' : 'blue';
colors.push(color);
}
chart3.setOption('colors', colors);
chart3.draw();

How to calculate a field based on two columns while looping through a spreadsheet

I have a table with two columns, and I want to calculate the third.
Column 1 | Column 2 | Calculated Column
1 | 1 | 1
1 | 1.5 | 2
1 | 2 | 3
2 | 2 | 1
I am trying to add the third column to my sheet and then in ascending order increment the calculate value.. Once the value in column 1 changes, the incrementing should start over. I was good at this once.. but rusty :) Any help would be awesome
//name the datasets
var ss=SpreadsheetApp.getActiveSpreadsheet();
//add a new column and name it
ss.insertColumnAfter(2);
ss.getRange("C1").setValue("Tier");
//Get the first store number and result space number
var atvStr = ss.getRange("A2").getValue();
var strNbrR = ss.getRange("A2:A9000").getValues();
var rslt = ss.getRange("C2:C9000").getValues();
//get the last filled row and +1 to go on to the next
var line=ss.getLastRow()+1;
for (i in strNbrR) {
if (strNbrR[i] = atvStr) {
ss.getRange(line).setValue("1");
}
}
}
If I understand you correctly, try this:
function testMe(){
//name the datasets
var ss=SpreadsheetApp.getActiveSpreadsheet();
//add a new column and name it
ss.insertColumnAfter(2);
//Get the first store number and result space number
var strNbrR = ss.getRange("A2:A").getValues();
var rsltRng = ss.getRange("C2:C");
var rsltVals = rsltRng.getValues();
var newValue = 1;
for ( i in strNbrR) {
if (i >1 ){
if (strNbrR[i][0] !== strNbrR[i - 1][0]) {
++newValue;
}
}
rsltVals[i][0] = newValue;
}
rsltRng.setValues(rsltVals);
}
It will increment the value placed in Column C if the value in A is not the same as the value in cell A in the previous row.

Finding index using switch case statement in javascript

I'm using Pentaho(ETL) tool to achieve the output using a javascript component which accepts javascript code to achieve the desired transformation.The following table is imported into pentaho from a .csv file(source file).
For example this is my table structure
+--------+--------+--------+
| RLD | MD | INC |
+--------+--------+--------+
| 0 | 3868 | 302024 |
| 53454 | 7699 | 203719 |
| 154508 | 932 | 47694 |
| 107547 | 36168 | 83592 |
I want to use a script which would give me the max_value and its index number, such that my output would look like
Output Table
+--------+--------+--------+-----------+-----------+
| RQD | MT | IZC | max_value | max_index |
+--------+--------+--------+-----------+-----------+
| 0 | 3868 | 302024 | 302024 | 3 |
| 53454 | 7699 | 203719 | 203719 | 3 |
| 154508 | 932 | 47694 | 154508 | 1 |
| 456 | 107547| 83592 | 107547 | 2 |
To get the max value from rows I have used
var max_value = Math.max(RQD,MT,IZC);
println(max_value);
I tried to get their index using the following script
var max_index = switch (Math.max(RQD,MT,IZC))
{
case "RQD":document.write("1")
case "MT":document.write("2")
case "MT":document.write("3")
default:document.write("0")
}
How can I get the desired result in the form of javascript data structure? Any help would be much appreciated.Thanks
var list = [
{RLD:0,
MD:3868,
INC:302024
},
{RLD:53454,
MD:7699,
INC:203719
},
{RLD:154508,
MD:932,
INC:47694
},
{RLD:107547,
MD:36168,
INC:83592
},
];
list = list.map(function(item){
var keys = Object.keys(item);
item.max_value = item[keys[0]];
item.max_index = '';
for(var i = 1, l = keys.length; i < l; i++) {
var key = keys[i];
var keyValue = item[key];
if (item.max_value < keyValue){
item.max_value = keyValue;
item.max_index = key;
}
}
return item;
})
There are several issues with your code, lets solve them!
Use breaks: you must use breaks in order to avoid the switch moving to cases below its match.
switch cases do not return a value like functions, you cannot use a switch return to define a variable, you need to define the variable inside the switch case.
Math.max does not return the name of its maximum variable, instead it returns the maximum number from its given parameters.
to solve this issue, i would not use a switch case with math.max to be honest, however to answer your question:
var tableArray = [RQD,MT,IZC];
var maxIndex = tableArray.indexOf(Math.max.apply(null, arr));
if(maxIndex > -1) document.write(maxIndex+1);
i used +1 because you have your index in the example table starting from 1 instead of 0.
the way the array is sorted should match the way the table is sorted per raw.
First of all you could not solve this problem with a switch statement.
In a javascript switch you should provide a value that is one of the followed case(s), otherwise the switch will go to the default if defined.
Your problem seems to be to find out the higher value of 3 columns and print out, the colums row by row adding a column with the max value and the index of the column where you found it.
So for example on the row:
1, RLD : 0
2, MD : 3868
3, INC : 302024
In this case the higher value is INC with the column index 3.
If you have just the variables with the number values, you could do nothing more than something like this:
function getMaxValueRow (RLD, MD, INC) {
var max_value = RLD;
var max_index = 1;
if (MD > max_value) {
max_value = MD;
max_index = 2;
}
if (INC > max_value) {
max_value = INC;
max_index = 3;
}
return [RLD, MD, INC, max_value, max_index];
}
You could return an object too like this:
retrun {
'RQD': RLD,
'MT': MD,
'IZC': INC,
'max_value': max_value,
'max_index': max_index
}

Rowspan or nested? Create a table itextsharp

I've been searching about how to merge two cells and I've found two answers Rowspan and Nested. I can't make my table with those two functions because I don't know how to merge cells at the begining and at the end. I've been trying many ways but this is driving me crazy.
The table I want to make has 9 columns and 3 rows. So, I want the table looks like:
| Header 1 | Header 2 | Header 3 | Header 4 | Header 5 |
| | | H1 | H2 | H3 | H4 | H5 | | |
| D1 | D2 | D3 | D4 | D5 | D6 | D7 | D8 | D9 |
Header 1: cs=1, rs=2.
Header 2: cs=1, rs=2.
Header 3: cs=5, rs=1.
H1: cs=1, rs=1.
H2: cs=1, rs=1.
H3: cs=1, rs=1.
H4: cs=1, rs=1.
H5: cs=1, rs=1.
Header 4: cs=1, rs=2.
Header 5: cs=1, rs=2.
cs:colspan, rs:rowspan.
Header 3 contains H1, H2, H3, H4, H5.
I think the solution is pretty easy but I can't find it. I hope you can understand Which the problem is because I can't upload images yet.
There are a couple ways to do what you want to do. Since your table structure isn't overly complex perhaps the easiest approach is to create your PdfPTable with nine columns and add your cells one at a time using each cell's Rowspan and Colspan properties as you create rows.
The code below will create a table laid out exactly as you described:
private void CreatePdf() {
using (FileStream fs = new FileStream("TableTest.pdf", FileMode.Create)) {
Document doc = new Document(new iTextSharp.text.Rectangle(800f, 800f));
PdfWriter.GetInstance(doc, fs);
doc.Open();
PdfPTable table = new PdfPTable(9);
// Hdeaer row.
table.AddCell(GetCell("Header 1", 1, 2));
table.AddCell(GetCell("Header 2", 1, 2));
table.AddCell(GetCell("Header 3", 5, 1));
table.AddCell(GetCell("Header 4", 1, 2));
table.AddCell(GetCell("Header 5", 1, 2));
// Inner middle row.
table.AddCell(GetCell("H1"));
table.AddCell(GetCell("H2"));
table.AddCell(GetCell("H3"));
table.AddCell(GetCell("H4"));
table.AddCell(GetCell("H5"));
// Bottom row.
table.AddCell(GetCell("D1"));
table.AddCell(GetCell("D2"));
table.AddCell(GetCell("D3"));
table.AddCell(GetCell("D4"));
table.AddCell(GetCell("D5"));
table.AddCell(GetCell("D6"));
table.AddCell(GetCell("D7"));
table.AddCell(GetCell("D8"));
table.AddCell(GetCell("D9"));
doc.Add(table);
doc.Close();
}
}
private PdfPCell GetCell(string text) {
return GetCell(text, 1, 1);
}
private PdfPCell GetCell(string text, int colSpan, int rowSpan ) {
PdfPCell cell = new PdfPCell(new Phrase(text));
cell.HorizontalAlignment = 1;
cell.Rowspan = rowSpan;
cell.Colspan = colSpan;
return cell;
}
As you can see I've wrapped the construction of PdfPCells in helper methods that allow you to set each cell's text content and Rowspan and Colspan properties.
If you haven't already done so, I suggest you check out this tutorial on iTextSharp tables:
iTextSharp - Introducing Tables
Robert (below) is right! Rowspan is not supported in the latest versions of iTextSharp. Only colspan is supported. The URL provided above does state that it has been supported since v 2.1.6, but looks like that hasn't been updated in a while as there is no more setRowSpan() method in any of the new versions (above v5) and the RowSpan property setting is just ignored.
You're better off adding a empty cells for rowspanned cells.
Rowspan isn't a answer, because there is no rowspan in iTextSharp. You have to use nested tables.
Colspan is posible but not rowspan.
For your table, i would only use one colspan and use empty Cells between Header 1 and D1