Is there a way to have google sheets read imperial height as a number? - google-sheets

I'm making a sheet with details about a bunch of fictional characters, and one column I want to have is their height. I would also really like to use Conditional Formatting with a Color Scale to color-code the tallest and shortest characters, and everything in between.
Unfortunately, I live in the US, and am used to height expressed in feet and inches (e.g. 5'10''), which Google Sheets of course does not recognize as a number. Is there any way to remedy this, besides writing everything in terms of just inches (e.g. 60), such that I could apply conditional formatting directly to the column?
I've tried different formats (e.g. 5'10), and I considered having a hidden column with just the inch value and have conditional formatting work off of that row (doesn't work with Color Scale as far as I can tell, since you can't input a custom formula). One thought I had is somehow formatting things as an improper fraction with a denominator of 12, but hiding the denominator? But I have no idea how that would work. I've Googled as best I can, but I haven't found anything (everything's just about changing row height, which makes sense in hindsight).

I understand that you have two goals in mind. First of all, you should decide which unit length to use for managing heights. I have chosen inches, but you could work with feet if you need. This will simplify the scenario and will allow you to work easily with the data, but you could always create a function that translates inches to the foot/inches combo in order to show the data to a third party. This is the example table that I will use:
And this is my code, I will explain it at the bottom:
function main() {
var sheet = SpreadsheetApp.getActiveSheet();
var data = sheet.getDataRange().getValues();
data = sortTable(data);
sheet.getDataRange().setValues(data);
for (var i = 1; i < data.length; i++) {
data[i][2] = gradient(data.length, i);
}
for (var i = 1; i < data.length; i++) {
sheet.getRange(i, 2).setBackground("#" + data[i][2][0] + data[i][2][1] +
data[i][2][2]);
}
}
function sortTable(data) {
data.sort(function(a, b) {
return b[1] - a[1];
})
return data;
}
function gradient(arraySize, position) {
var relativePosition = position / arraySize;
var topColor = [parseInt("00", 16), parseInt("7A", 16), parseInt("33",
16)]; // Green
var bottomColor = [parseInt("FF", 16), parseInt("FF", 16), parseInt("FF",
16)]; // White
var positionColor = [0, 0, 0];
for (var i = 0; i < 3; i++) {
positionColor[i] = Math.floor(topColor[i] * (1 - relativePosition) +
bottomColor[i] * relativePosition).toString(16);
}
return positionColor;
}
First of all you have to read the data with a combination of getValues()/setValues(), and once you do that you can sort the table based on height so you can create the gradient later. Please notice how I separated the sorting function for better clarity.
After that you need the gradient color for setBackground(). To do so I developed a simple linear gradient function that calculates the RGB code from the top to the bottom. In my example the gradient fades from green to white, but you can change it. I also separated the gradient script into its own function. At this point you already have the sorted table and its gradient colors, so you only have to use setValues() and you are done. Feel free to leave any comment if you have doubts about this approach. This would be the final result:
UPDATE
Based in your comments I get that you need an imperial height format. For that case, you could use =INT(B2)&"' "&TRIM(TEXT(ROUND(MOD(B2,1)*12*16,0)/16,"# ??/??")&"""") (assuming that B2 contains the height). This approach will use Sheets Formulas to calculate the remainder part of the height, and its expression as an irreducible fraction. This is the final result:

Related

Cohort table conditional formatting

I'm looking for a way to conditionally format a cohort table in Google Sheets so that the colors will change from red (low values) through yellow (medium values) to green (high values) based on the values in each row. Anyone knows if this is possible?
Also, choosing the "Color scale" option in conditional formatting menu doesn't work because it colors the table based on the values of the full table, not each row individually.
I can use that option only if I apply it to each row individually, but my dataset has thousands of entries so that doesn't work for me.
Example table: https://docs.google.com/spreadsheets/d/1gpLMdgfs10Flt-VTtsc68E3Feju2H8UQhnai-R_9b3k/copy
Thanks in advance you guys are the greatest!
I wrote a simple script in Apps Script to apply the formatting to every row. It achieves the gradient per row that you want.
Example:
function applyColorGradientConditionalFormat(min = '#FF0000', mid = '#FF9900', max = '#00FF00') {
const sheet = SpreadsheetApp.getActiveSheet();
const lastCol = sheet.getLastColumn();
const conditionalFormatRules = sheet.getConditionalFormatRules();
// Build this conditional rule for all rows in sheet
for (let i = 2; i <= sheet.getLastRow(); i++) {
let range = sheet.getRange('R' + i + 'C2:R' + i + 'C' + lastCol);
let rule = SpreadsheetApp.newConditionalFormatRule()
.setRanges([range])
.setGradientMinpoint(min)
.setGradientMidpointWithValue(mid, SpreadsheetApp.InterpolationType.PERCENT, '50')
.setGradientMaxpoint(max)
.build()
conditionalFormatRules.push(rule);
}
// Apply all conditional rules built to the sheet
sheet.setConditionalFormatRules(conditionalFormatRules);
};
// Easy improvements: Create a menu to build all conditional formats manually
// or setup triggers to do it automatically
For your sample sheet this results in the following table:
Useful documentation:
Class ConditionalFormatRuleBuilder
getConditionalFormatRules()
non scripted:
=(B2:M2=MAX($B2:$M2))*($B2:$M2<>"")
=(B2:M2=MIN($B2:$M2))*($B2:$M2<>"")

Can't calculate the right Volume RSI in MQL4 with a functioning Pine-Script Example

I want to "translate" a Pine-Script to MQL4 but I get the wrong output in MQL4 compared to the Pine-Script in Trading-view.
I wrote the Indicator in Pine-Script since it seems fairly easy to do so.
After I got the result that I was looking for I shortened the Pine-Script.
Here the working Pine-Script:
// Pinescript - whole Code to recreate the Indicator
study( "Volume RSI", shorttitle = "VoRSI" )
periode = input( 3, title = "Periode", minval = 1 )
VoRSI = rsi( volume, periode )
plot( VoRSI, color = #000000, linewidth = 2 )
Now I want to translate that code to MQL4 but I keep getting different outputs.
Here is the MQL4 code I wrote so far:
// MQL4 Code
input int InpRSIPeriod = 3; // RSI Period
double sumn = 0.0;
double sump = 0.0;
double VoRSI = 0.0;
int i = 0;
void OnTick() {
for ( i; i < InpRSIPeriod; i++ ) {
// Check if the Volume is buy or sell
double close = iClose( Symbol(), 0, i );
double old_close = iClose( Symbol(), 0, i + 1 );
if ( close - old_close < 0 )
{
// If the Volume is positive, add it up to the positive sum "sump"
sump = sump + iVolume( Symbol(), 0, i + 1 );
}
else
{
// If the Volume is negative, add it up to the negative sum "sumn"
sumn = sumn + iVolume( Symbol(), 0, i + 1 );
}
}
// Get the MA of the sump and sumn for the Input Period
double Volume_p = sump / InpRSIPeriod;
double Volume_n = sumn / InpRSIPeriod;
// Calculate the RSI for the Volume
VoRSI = 100 - 100 / ( 1 + Volume_p / Volume_n );
// Print Volume RSI for comparison with Tradingview
Print( VoRSI );
// Reset the Variables for the next "OnTick" Event
i = 0;
sumn = 0;
sump = 0;
}
I already checked if the Period, Symbol and timeframe are the same and also have a Screenshoot of the different outputs.
I already tried to follow the function-explanations in the pine-script for the rsi, max, rma and sma function but I cant get any results that seem to be halfway running.
I expect to translate the Pine-Script into MQL4.
I do not want to draw the whole Volume RSI as a Indicator in the Chart.
I just want to calculate the value of the Volume RSI of the last whole periode (when new candel opens) to check if it reaches higher than 80.
After that I want to check when it comes back below 80 again and use that as a threshold wether a trade should be opened or not.
I want a simple function that gets the Period as an input and takes the current pair and Timeframe to return the desired value between 0 and 100.
Up to now my translation persists to provide the wrong output value.
What am I missing in the Calculation? Can someone tell me what is the right way to calculate my Tradingview-Indicator with MQL4?
Q : Can someone tell me what is the right way to calculate my Tradingview-Indicator with MQL4?
Your main miss of the target is in putting the code into a wrong type of MQL4-code. MetaTrader Terminal can place an indicator via a Custom Indicator-type of MQL4-code.
There you have to declare so called IndicatorBuffer(s), that contain pre-computed values of the said indicator and these buffers are separately mapped onto indicator-lines ( depending on the type of the GUI-presentation style - lines, area-between-lines, etc ).
In case you insist on having a Custom-Indicator-less indicator, which is pretty legal and needed in some use-cases, than you need to implement you own "mechanisation" of drawing lines into a separate sub-window of the GUI in the Expert-Advisor-code, where you will manage all the settings and plotting "manually" as you wish, segment by segment ( we use this for many reasons during prototyping, so as to avoid all the Custom-Indicator dependencies and calling-interface gritty-nitties during the complex trading exosystem integration - so pretty well sure about doability and performance benefits & costs of going this way ).
The decision is yours, MQL4 can do it either way.
Q : What am I missing in the Calculation?
BONUS PART : A hidden gem for improving The Performance ...
In either way of going via Custom-Indicator-type-of-MQL4-code or an Expert-Advisor-type-of-MQL4-code a decision it is possible to avoid a per-QUOTE-arrival re-calculation of the whole "depth" of the RSI. There is a frozen-part and a one, hot-end of the indicator line and performance-wise it is more than wise to keep static records of "old" and frozen data and just update the "live"-hot-end of the indicator-line. That saves a lot of the response-latency your GUI consumes from any real-time response-loop...

How to hide value labels when zooming out in MPAndroidChart?

I'm using Swift version of MPAndroidChart and trying to figure out how to hide value labels when a few of them are located too close together and start to overlap on a line chart.
Hiding all the value labels when zoomed out to a certain point works too(still don't know how to do it), but hiding only the ones that are overlapping would be the best.
I know that I can manually call setDrawValues = false, but I want it to be called automatically on zoom.
enter image description here
In Android, I use the same as iOS
1: Find the difference between 1st and 2nd index y-axis label(YAxisRenderer)
for (int i = from; i < to; i++)
{
String text = mYAxis.getFormattedLabel(i);
double value1=Double.parseDouble(mYAxis.getFormattedLabel(1).replace(",",""));
double value2=Double.parseDouble(mYAxis.getFormattedLabel(2).replace(",",""));
result=(value2-value1)-40;
//POPreferences.setDifference(String.valueOf(result));
c.drawText(text, fixedPosition, positions[i * 2 + 1] + offset, mAxisLabelPaint);
}
2: Use result variable when text draws on bar or line(BarChartRenderer.java):
if (result >= vals[k / 2])
{
drawValue(c,dataSet.getValueFormatter(),vals[k / 2], entry, i, x, y,color);
}

Structure Data timeintervals in Highcharts

I'd like to visualize the amount of steps taken over a day. Each datapoint looks simplified like this:
{
startDate: 1481029440000,
endDate: 1481029920000,
steps: 31
}
I'd like to plot it over an entire day and illustrate the duration but also the grow of step increase. Each datapoint is a separate series as I didn't want to have points connected to each other.
The result looks like what I want except for the styling which I have change. However the performance and zoom into the chart is extremely slow. Might there be a better way to use it?
Highcharts is optimised for managing many points, not many series (the work has been start on optimising series, though - as far as I know).
You can use one series with the null points as separators. By default connecting nulls is disabled.
data: (function (data) {
var d = [], i = 0, len = data.length, point;
for (; i < len; i++) {
point = data[i];
d.push([point.startDate, point.steps], [point.endDate, point.steps]);
if (i < len - 1) {d.push([point.endDate, null]);}
}
return d;
})(data)
example: http://jsfiddle.net/7vtd4fzm/

What is the correct way to apply filter to a image

I was wondering what the correct way would be to apply filter to a image. The image processing textbook that I am reading only talks about the mathematical and theoretical aspect of filters but doesn't talk much the programming part of it !
I came up with this pseudo code could some one tell me if it is correct cause I applied the sobel edge filter to a image and I am not satisfied with the output. I think it detected many unnecessary points as edges and missed out on several points along the edge.
int filter[][] = {{0d,-1d,0d},{-1d,8d,-1d},{0d,-1d,0d}};// I dont exactly remember the //sobel filter
int total = 0;
for(int i = 2;i<image.getWidth()-2;i++)
for(int j = 2;j<image.getHeight()-2;j++)
{
total = 0;
for(int k = 0;k<3;k++)
for(int l = 0;l<3;l++)
{
total += intensity(image.getRGB(i,j)) * filter[i+k][j+l];
}
if(total >= threshold){
image.setRGB(i,j,WHITE);
}
}
int intensity(int color)
{
return (((color >> 16) & 0xFF) + ((color >> 8) & 0xFF) + color)/3;
}
Two issues:
(1) The sober operator includes x-direction and y-direction, they are
int filter[][] = {{1d,0d,-1d},{2d,0d,-2d},{1d,0d,-1d}}; and
int filter[][] = {{1d,2d,1d},{0d,0d,0d},{-1d,-2d,-1d}};
(2) The convolution part:
total += intensity(image.getRGB(i+k,j+l)) * filter[k][l];
Your code doesn't look quiet right to me. In order to apply the filter to the image you must apply the discrete time convolution algorithm http://en.wikipedia.org/wiki/Convolution.
When you do convolution you want to slide the 3x3 filter over the image, moving it one pixel at a time. At each step you multiply the value of the filter 'pixel' by the corresponding value of the image pixel which is under that particular filter 'pixel' (the 9 pixels under the filter are all affected). The values that result should be added up onto a new resulting image as you go.
Thresholding is optional...
The following is your code modified with some notes:
int filter[][] = {{0d,-1d,0d},{-1d,8d,-1d},{0d,-1d,0d}};
//create a new array for the result image on the heap
int newImage[][][3] = ...
//initialize every element in the newImage to 0
for(int i = 0;i<image.getWidth()-1;i++)
for(int j = 0;j<image.getHeight()-1;j++)
for (int k = 0; k<3; k++)
{
newImage[i][j][k] = 0;
}
//Convolve the filter and the image
for(int i = 1;i<image.getWidth()-2;i++)
for(int j = 1;j<image.getHeight()-2;j++)
{
for(int k = -1;k<2;k++)
for(int l = -1;l<2;l++)
{
newImage[i+k][j+l][1] += getRed(image.getRGB(i+k ,j+l)) * filter[k+1][l+1];
newImage[i+k][j+l][2] += getGreen(image.getRGB(i+k ,j+l)) * filter[k+1][l+1];
newImage[i+k][j+l][3] += getBlue(image.getRGB(i+k ,j+l)) * filter[k+1][l+1];
}
}
int getRed(int color)
{
...
}
int getBlue(int color)
{
...
}
int getGreen(int color)
{
...
}
Please note that the code above does not handle the edges of the image exactly right. If you wanted to make it absolutely perfect you'd start by sliding the filter mostly off screen (so the first position would apply the lower right corner of the filter to the image 0,0 pixel of the image. Doing this is really a pain though, so usually its easier just to ignore the 2 pixel border around the edges.
Once you've got that working you can experiment by sliding the Sobel filter in the horizontal and then the vertical directions. You will notice that the filter acts most strongly on lines which are perpendicular to the direction of travel (to the filter). So for the best results apply the filter in the horizontal and then the vertical direction (using the same newImage). That way you will detect vertical as well as horizontal lines equally well. :)
You have some serious undefined behavior going on here. The array filter is 3x3 but the subscripts you're using i+k and j+l are up to the size of the image. It looks like you've misplaced this addition:
total += intensity(image.getRGB(i+k,j+l)) * filter[k][l];
Use GPUImage, it's quite good for you.

Resources