Tableau is giving me a hard time, trying to compare two items by percentages. I need to display the percentage different between the number (couintif) of string items based on condition.
Basically, I wrote two calculated fields like:
Calc field #1
IF [Outcome] = "Complete" Then 1 Else 0
Calc field #2
IF [Outcome] = "Pending" Then 1 Else 0
and a third field to get the percentage of pending sales to completed sales
Calc percentage
SUM(Calc field #1 / Calc field #2)
But it's not working. The first two fields work fine, validated them with dataset, but the third calculation doesn't work and always outputs 0
The formula for Calc percentage should be
SUM(Calc field #1) / SUM(Calc field #2)
As both the calculated fields are computed row-wise, it is important to aggregate while using it in a formula.
I have a google sheet where checkboxes control if a column must be included or not.
Each column represents one person, the checkbox on top of the column determines if the person must be taken into account into the computation.
The calculation consists in determining how much each person must pay (Monthly installments), according to:
a starting contribution (Input)
a percentage of the remaining amount to be repaid (Proportion of 300 000,00€-110 000,00€)
My data is structured like this:
My problem is that, when I uncheck one of the columns, the percentage associated with the person stays the same and this introduces an error in the calculation: the sum of the Input and the Monthly installments is no longer equal to the total sum 300 000,00€.
What I'd like to achieve is:
when unchecked, to automatically set to 0% the value of the Proportion cell
when checked, to allow user to enter any percentage in the Proportion cell
Do you have any idea on how to allow simultaneously user input and value based on a condition?
Thanks a lot!
EDIT
You can find here a working example
Adding this script to your Sheets can solve your task
function onEdit(e) {
let row = e.range.getRow(),
col = e.range.getColumn(),
firstCol = 2,
lastCol = 6;
if (sheet.getName() == 'MONEY' && col>=firstCol && col<=lastCol){
switch (row){
case 1:
if (!e.range.getValue()) e.range.offset(3,0).clearContent();
break;
case 4:
if (!e.range.offset(-3,0).getValue()) e.range.clearContent();
break;
}
}
}
I want a formula to generate random data of birth dates for a specific years (Example: 1995 to 2002) and make it Array like this:
Sheet URL: https://docs.google.com/spreadsheets/d/1XHoxD-hNmpUOMVm_u-cz-4ESrabodsrS0fIfaN-n4js/edit
That might not be the best approach but it will get you closer to what you want:
=DATE(RANDBETWEEN(1995,2002),RANDBETWEEN(1,12),RANDBETWEEN(1,31))
There are two issues with this approach:
you might get a day that does not exist for the particular month. For example, 2/28/2021 exists, but 2/29/2021 does not exist.
I wasn't able to generate an array but only drag down formulas. When I generate an array, the same random numbers are used and as a result the dates are the same.
For the first issue, you can use isdate to check if the random date returned is correct. For example, 2/29/2021 is a wrong date (I hardcopied that date).
but I guess you can filter out the FALSE cases.
I really hope other people can come up with a better approach.
You could try (as I demonstrated in your sheet):
=ARRAY_CONSTRAIN(SORT(SEQUENCE(DATE(1992,12,31)-DATE(1900,1,1),1,DATE(1900,1,1)),RANDARRAY(DATE(1992,12,31)-DATE(1900,1,1)),1),COUNTA(A2:A),1)
SEQUENCE(DATE(1992,12,31)-DATE(1900,1,1),1,DATE(1900,1,1)) - Is used to create an array of valid numeric representations of true dates between 1-1-1900 and 31-12-1992.
SORT(<TheAbove>,RANDARRAY(DATE(1992,12,31)-DATE(1900,1,1)),1) - Is used to sort the array we just created randomly.
ARRAY_CONSTRAIN(<TheAbove>, COUNTA(A2:A),1) - Is used to only return as many random birth-dates we need according to other data.
Note that this is volatile and will recalculate upon sheet-changes and such. Also note that this is just "slicing" a given array and may fall short when you try to use it on a dataset larger than the given array.
As Google Sheets can deal with dates as integers (~ number of days since 1900), choosing a random date between two dates can be a single call to RANDBETWEEN (with the output formatted as Date).
With your initial date written in B1 and your end date in B2, the formula is simply:
=RANDBETWEEN($B$1,$B$2)
You can paste this formula in as many cells as you want, to generate N different random dates.
Of course, as other answers involving random generators in your sheet, the formula will be recomputed at each change. My suggestion to overcome this would simply be to copy/paste the output, using the "Paste special > Values only" option (right click or "Edit" menu).
Script Solution
Just for sake of completeness, here is a solution using a script
Initial Considerations
This cannot function like a in sheet function/formula.
https://developers.google.com/apps-script/guides/sheets/functions
Custom function arguments must be deterministic. That is, built-in spreadsheet functions that return a different result each time they calculate — such as NOW() or RAND() — are not allowed as arguments to a custom function. If a custom function tries to return a value based on one of these volatile built-in functions, it will display Loading... indefinitely.
A custom function cannot affect cells other than those it returns a value to. In other words, a custom function cannot edit arbitrary cells, only the cells it is called from and their adjacent cells. To edit arbitrary cells, use a custom menu to run a function instead.
So a normal script is needed.
The Script
/**
* Sets the values of a range to random dates.
*/
function generateRandomBdays(range, start, end) {
let height = range.getHeight();
let width = range.getWidth();
let output = [];
for (let i = 0; i != height; i++) {
let row = [];
for (let j = 0; j != width; j++) {
row.push(randomBday(start, end));
}
output.push(row)
}
range.setValues(output);
}
/**
* Generates a random date beween start and end
*/
function randomBday(start, end) {
if (start < 2000) start = start - 1900
start = new Date(`${start}`);
if (end < 2000) end = end - 1900
end = new Date(`${end}`);
let bday = new Date(
start.getTime() + (Math.random() * (end.getTime() - start.getTime()))
);
return bday;
}
/**
* Gets active selection and fills with random dates
*/
function main(){
let file = SpreadsheetApp.getActive();
let sheet = file.getActiveSheet()
let range = sheet.getActiveRange();
// ============
generateRandomBdays(range, 1995, 2002); // Change these years to your liking
// ============
}
/**
* Creates menu when sheet is opened.
*/
function onOpen() {
var ui = SpreadsheetApp.getUi();
ui.createMenu('Generate Birthdays')
.addItem('Generate!', 'main')
.addToUi();
}
Which works like this:
Installation
You will have to copy it into your script editor and then run one of the functions to authorize the script with the permissions it needs. Then next time you open the sheet you should have the menu available.
Alternatively you can delete the onOpen function and just use it from the script editor.
Within the main function, customize the range of years you need.
References
Apps Script
Overview of Spreadsheet Service in Apps Script
I've found a lot of good information about the angular-ui-grid cell filters but I can't seem to locate an answer to my specific issue. Basically I have a grid set up with two columns:
Column A is a editable cell dropdown where you can pick two options, 'money' or 'percentage'. Column B is a number input displaying a value.
I have two filters in my app, 'currency' and 'percentage'. If I set up the columnDefs for either of those filters, then Column B will display all the values in that column as either a currency value or percentage.
What I need it to do though is to make it so that the filter is applied to Column B based on the setting of Column A, so I end up with this:
Value Type Value
---------------------------------------
Money $100.00
Percentage 100%
I've got some code to basically check that after the edit:
$scope.gridApi.edit.on.afterCellEdit($scope, function(rowData) {
var row = _.indexOf($scope.items, rowData);
if (rowData['valueType'] == 'percentage') {
// Apply percentage filter to the value cell for this row
} else {
// Apply currency filter to the value cell for this row
}
$scope.gridApi.core.refresh();
});
...I'm just not sure how to apply the filter to the individual cells. Any guidance would be appreciated!
If anyone else ever has the same question, I managed this by creating a filter that took the row entity as an argument, then applied the custom filters inside of that new filter based on the entity values.
I am using SpreadsheetGear to generate a excel sheet. I want to apply number formatting on a column starting from row number 10.
But when I use below code, it apply formatting for the entire column.
worksheet.Cells[10, 2].EntireColumn.NumberFormat = "#";
How can I ensure formatting is applied for the entire column starting from row number 10.
This could be accomplished any number of ways. One might be to "subtract" the top 10 rows from the entire column, which could be done using IRange.Subtract(). Example:
// First obtain a reference to all of Column C, then "subtract" the first 9 rows from it
IRange range = worksheet.Cells["C:C"].Subtract(worksheet.Cells["C1:C9"]);
// Apply your formatting...
range.NumberFormat = "#";
Another would be to use zero-based indexes to select the desired range, using the IWorkbookSet.MaxRows property to determine the maximum row (currently 1,048,576, as per Excel’s file format limitations). Example:
IRange range = worksheet.Cells[9, 2, worksheet.WorkbookSet.MaxRows - 1, 2];
Lastly, you could hard-code the range using an A1-style reference, knowing that the current file format limitation is 1,048,576 rows. Example:
IRange range = worksheet.Cells["C10:C1048576"];