Assigning ColumnWidths with textbox data - excel

I want to control the different column widths of a listbox with the use of textbox input. This is my code:
Sub code()
Dim x1 as integer
Dim x2 as integer
x1 = Me.TB1.value ‘x1 is assigned the number 40
x2 = Me.TB2.value ‘x2 is assigned the number 40
With Me.listbox1
.Clear
.ColumnCount = 2
.ColumnWidths = ‘’x1;x2’’
.list = getArray(SQLinput)
End with
End sub
Thanks for any help!
Edit:
The question, to be more precise, is that the code does not work. I am not allowed to write: .ColumnWidths = «x1;x2» So how can I write the code so that is it possible to control these variables from a textbox?

aListBox.ColumnWidths = newStringValue
or
StringValue = aListBox.ColumnWidths
A list of comma-separated values, with each value controlling the width of the associated column. A value can be an absolute value (in pixels), a percentage, a relative length expressed as i* where i is an integer, or an "*" that indicates "fill in the remaining width." If you use percentages, you can use non-integer values to specify fractions of a percent, e.g., 43.52%. The percentage value can be greater than 100%.
Notes
If you use pixels, the last column doesn't grow to the size of the rest of the ListBox. You should set the width of the last column to "" and it will automatically take up the remaining width of the ListBox.
Without any column width specifications, the headers will be divided evenly. If there are fewer column widths specified than the total number of columns, the remaining columns will divide up the remaining width equally.
An element with a length of "3" will be allotted three times the space of an element with length "1*". The value "" is equivalent to "1" and can be used to mean "fill the remaining space."

Related

How to round a list of decimals in Excel, so that the sum of the whole numbers equal a defined total?

Having difficulty developing an excel function that will round a list of decimals, so that the sum of the whole numbers equals the original or a defined total.
Edit
I guess one way to do it is writing a function that first searches for the largest numbers and rounds them to the nearest whole number. That whole number is then counted and the function moves on to the next, until the total count equals the target total.
The problem that I am running into is that if there are too many numbers that are closer to 0, then the function will never equal the target total. So what the function then needs to do is identify the largest decimals, round them up, count, and then move on to the next until the sum of the count is equal to the target total. The left over data can then round to 0.
Sorry, I hope this is clearer....
I am dealing with larger data sets where the totals of the rounded whole numbers have much larger deviations to the original total.
It would preferable if this could be accomplished with an excel function, otherwise I am also open to doing in VBA.
Thanks!
Edit 3: Here is an example data set:
Please study my project VBA.Round.
Browse to paragraph Rounding a series of numbers to a sum
Code is way too much to post here, but an example workbook is included for download.
Example:
This function will read the range of distribution values, round the sum, and fill the two ranges with rounded values of 2 and zero decimals, totalling to the requested total (confirmed, as seen, by the formula):
' Practical example for using Excel ranges for RoundSum
'
' Source URL:
' https://stackoverflow.com/questions/63715043/how-to-round-a-list-of-decimals-in-excel-so-that-the-sum-of-the-whole-numbers-e
'
' 2020-09-14. Gustav Brock, Cactus Data ApS, CPH.
'
Public Sub RoundDistribution()
' Named ranges. These should pairwise match in row size.
Const VolumeName As String = "Volume"
Const PercentValuesName As String = "Percent_Distribution"
Const ValuesName As String = "Distribution"
Const RoundedValuesName As String = "Rounded_Distribution"
Dim Range As Excel.Range
Dim Values() As Currency
Dim Results() As Currency
Dim Total As Integer
Dim Index As Integer
' Read percent distribution values from the named range.
Set Range = ThisWorkbook.Names(PercentValuesName).RefersToRange
' Read original volume value.
Total = ThisWorkbook.Names(VolumeName).RefersToRange(1, 1)
' Dim input and output arrays.
ReDim Values(1 To Range.Rows.Count)
ReDim Results(1 To Range.Rows.Count)
' Fill input array.
For Index = LBound(Values) To UBound(Values)
Values(Index) = Range(Index, 1)
Next
' Round total and retrieve array with distribution values.
Results = RoundSum(Values, RoundMid(Total), 2)
' Fill named range with distribution values.
For Index = LBound(Results) To UBound(Results)
ThisWorkbook.Names(ValuesName).RefersToRange(Index, 1) = Results(Index)
Next
' Round total and retrieve array with rounded distribution values.
Results = RoundSum(Values, RoundMid(Total))
' Fill named range with rounded distribution values.
For Index = LBound(Results) To UBound(Results)
ThisWorkbook.Names(RoundedValuesName).RefersToRange(Index, 1) = Results(Index)
Next
End Sub
Output:
Note please, that the function is capable of rounding to any number of decimals, and to select one instance only of the values 0.34 to obtain a match.
The full demo (Excel workbook) and code is still for download on GitHub.
I'd agree with #pghcpa this is rather an arithmetic problem.
One idea for solution:
order the numbers descending on their fraction part
take the floor of each (i.e ignoring the fractions)
take the sum of those floors
compare that sum to the desired sum, take the difference
This way you'd probably have a positive difference, so you can start from the top and add 1 to each number downwards, all until the difference is gone.

Zoom couple of columns to fit page with VBA

I'm having trouble fitting my columns in Excel on a sheet.
I have a sheet with columns from A to CK (can be different per project).
I don't need to print column A, but column B has to be on all pages and next to column B has to be 3 columns. So that will make column "B,C:E" on first page, next page "B,F:H", and so on... Column B is set as title, so it will be printed on every page.
My problem is to set the scale. What I'm doing:
Take pagesize and translate to points, take off margin left and margin right = my printable area
Get the width of range("B:E") = my range to fit the page
Divide my printable area by my range to fit, multiply that with 100%, and extract 1% to make sure it will fit
The outcome in my situation is 83, but is has to be 77 to fit the page. I'll have to find other numbers I think, but I don't know how and which...
My code:
If ActiveSheet.Name = "Meterkastlijst" Then
Dim lngZoom As Long
Dim lngKolB As Long
Dim lngPagB As Long
lngKolB = ActiveSheet.Range("B:E").Width
If ActiveSheet.PageSetup.PaperSize = xlPaperA4 Then
lngPagB = CLng(Application.CentimetersToPoints(21)) - CLng((ActiveSheet.PageSetup.LeftMargin + ActiveSheet.PageSetup.RightMargin))
ElseIf ActiveSheet.PageSetup.PaperSize = xlPaperA3 Then
lngPagB = CLng(Application.CentimetersToPoints(29.7)) - CLng((ActiveSheet.PageSetup.LeftMargin + ActiveSheet.PageSetup.RightMargin))
End If
If lngPagB <> 0 And lngKolB <> 0 Then
lngZoom = ((lngPagB / lngKolB) * 100) - 1
With ActiveSheet.PageSetup
.Zoom = lngZoom
End With
End If
End If
Different widths:
Column B: 45 (319 pixels) -> in Excel, set with VBA
Column C: 15 (109 pixels) -> in Excel, set with VBA
Column D: 30 (214 pixels) -> in Excel, set with VBA
Column E: 20 (144 pixels) -> in Excel, set with VBA
Column B-E: 589 points -> with VBA
Page: 21 centimeters (595 points)
Margins (left & right): 1.8 centimeters (50.4 points)
Print area: 595 - 101 (100.8) = 494 points
With numbers above it calculates 83%, but then it doesn't fit, when I set it manually to 77% it does fit, but how can I get this number with VBA? I don't understand the column widths, what I see in Excel and how I set it in VBA (45+15+30+20) is different from what VBA tells me it should be (589)...
Column Width Units
Column width is measured in Characters, Points, Centimeters / Inches, Pixels, ...
Column width in Characters
If you set a column width by manual value input or by mouse, you see the "amount of standard font number characters". Please refer to Microsoft support for details.
This value can be read and written in VBA: .Range.ColumnWidth = 10.78.
The maximum value is 255.
Column width in Points
This is an internal value not shown in GUI during manual resize of a column.
It corresponds to 72 points per inch.
In VBA it can only be read: .Range.Width
Column width in Pixels
Excel shows the column width in pixels (in parentheses) during manual resize of a column width in normal view. This value can not be read or written directly in VBA.
Column width in Centimeters or Inches
During manual resize within the page layout view Excel shows column width in centimeters (or inches) instead of pixels.
Only this value depends on print zoom level!
The measurement unit itself can be read in VBA:
Application.MeasurementUnit ' 0 = xlInches, 1 = xlCentimeters, 2 = xlMillimeters
Conversion Formulas
By this you may check or verify all values in your environment:
Dim ScreenResolution As Double
Dim ColumnWidthChars As Double
Dim ColumnWidthPoints As Double
Dim ColumnWidthPixels As Double
Dim ColumnWidthInches As Double
Dim ColumnWidthCentimeters As Double
ScreenResolution = 120 ' normal (96 dpi) or large (120 dpi)
ColumnWidthChars = ActiveSheet.Columns(1).ColumnWidth
ColumnWidthPoints = ActiveSheet.Columns(1).Width
ColumnWidthPixels = (ColumnWidthPoints / 72) * ScreenResolution
ColumnWidthInches = ColumnWidthPoints / 72 * ActiveSheet.PageSetup.Zoom / 100
ColumnWidthCentimeters = ColumnWidthInches * 2.54
Debug.Print ColumnWidthChars, ColumnWidthPoints, ColumnWidthInches, _
ColumnWidthCentimeters, ColumnWidthPixels
ScreenResolution may be retrieved with API function GetDeviceCaps(hDC, 88)
Rounding Effects
Excel stores the character-based .Range.ColumnWidth with decimals for each relevant column in the workbook file. If you set it to 100, it is stored as e. g.
<cols><col min="1" max="1" width="100.77734375" customWidth="1"/></cols>
After reopening this file, the reported .ColumnWidth is 100 without decimals.
If you set a large column width and switch between normal view and page layout view, then you may register difference of about 2% between the measures (.Range.Width and pixels suddenly change) - but all values still correspond to each other according to above formulas.
Display Scaling Dependency
All different column width values are independent of Excel's view zoom level and/or Windows 10 display scaling.
Print Zoom Dependency
Only the inch- and centimeter values change, if you change the print zoom level.
But you get more or less columns i. e. amount of points on your paper.
Excel measures .PageSetup.Leftmargin in points (with a scale of 72 points per inch). This corresponds to .Range.Width which is also measured in points.
Example: If I set both paper margins to 5.5 cm, then the resulting A4 paper width of 10 cm holds e. g. two columns with a total .Width of appr. 283 points which corresponds to 72 points/inch.
If I set the print zoom to 83 percent a .Width of appr. 340 points is maximum, and at a print zoom of 30 % it's almost 943 points.
Print Scaling
The calculation of a print zoom factor is
WorkSheet.PageSetup.Zoom = (PageWidthInPoints / AllColumnsWidthInPoints) * 100
Your calculation seems to be correct, but I would subtract at least 2 % (see rounding effects above).

How to set Excel column widths to a certain number of pixels?

I have the following data set on a worksheet:
SheetName|ColumnIndex|Pixels
---------+-----------+------
abc |1 |50
abc |2 |150
def |1 |125
For each sheet, I'd like to set the column width to the appropriate number of pixels, using something like:
Sub setColumn (sheetName As string, columnIndex As long, pixels As long)
width=getWidthInCharacters(pixels)
ThisWorkbook.Sheets(sheetName).Cells(1, columnIndex).EntireColumn.ColumnWidth = width
End Sub
I haven't been able to figure out how to write the getWidthInCharacters() function. How do I convert pixels to characters, or possibly set .ColumnWidth to pixels directly?
I'm sorry to tell you, but in my experience, you can't. Column width is measured in points, and whilst you can - in theory - convert points to pixels, Excel won't listen very precisely when you assign them. They also seem to vary somewhat from monitor to monitor. Basically, points are fractions of inches, pixels are dots on the screen. Windows has a notion (right or wrong) of how many pixels there are to a point given a particular output device.
You can write a function that tweaks column width, but usually the approach has to be
Find the smallest contextual value that excel is willing to increment a column width by (say, store the original value, then assign .ColumnWidth = dblOriginal + 0.01. Check if columnwidth has changed - if it has, you just made a 1-pixel adjustment. If it hasn't, you need a bigger number than 0.01.
Find a final column width in pixels that you want, and repeat this first step until you've incremented the column width that many times.
Check the result, and see if it looks OK.
Word of warning: this is horrible, slow, and not good code, and if they've fixed column widths in versions of Excel after 2010, then you might be lucky and just be able to use a pixels-to-points function, convert and assign. There are some around, just in my experience they didn't give me consistent results on different screens on the same machine. Really weird that one.
.ColumnWidth does not depend on theme font selection, but pixel width does: https://support.microsoft.com/en-us/kb/214123
'pixel width of column A
Debug.Print (Columns("A").Width / 72) * ThisWorkbook.WebOptions.PixelsPerInch
After some reading and thinking, my solution:
Sub setColumnWidth(rColumnWidth As Range, iPixelWidth As Integer)
' set column width by pixels
' check status ScreenUpdating
Dim bScreenUpdatingState As Boolean
bScreenUpdatingState = Application.ScreenUpdating
' set status ScreenUpdating
If bScreenUpdatingState = True Then Application.ScreenUpdating = False
Dim iPointsPerInch As Byte
iPointsPerInch = 72
Dim iPixelsPerInch As Byte
iPixelsPerInch = ThisWorkbook.WebOptions.PixelsPerInch
' check 2 column widths: get iPointDelta
Dim rColumn As Range
Set rColumn = rColumnWidth.EntireColumn
rColumn.ColumnWidth = 1
Dim iPoint_1 As Single
iPoint_1 = rColumn.Width
rColumn.ColumnWidth = 2
Dim iPoint_2 As Single
iPoint_2 = rColumn.Width
Dim iPointDelta As Single
iPointDelta = iPoint_2 - iPoint_1
' set column width to iPixelWidth
Dim iPoint_New As Single
iPoint_New = iPixelWidth / iPixelsPerInch * iPointsPerInch
Dim iChar_New As Single
iChar_New = (iPoint_New - (iPointDelta - 1.5)) / iPointDelta
rColumn.ColumnWidth = iChar_New
' reset status ScreenUpdating
If bScreenUpdatingState = True Then Application.ScreenUpdating = True
End Sub
To run the sub setColumnWidth:
Sub call_setColumnWidth()
Dim r As Range
Set r = ActiveSheet.Range("C1")
setColumnWidth r, 70
End Sub

Color cells by absolute value in a range in Excel 2010

I'm looking to color a table of values in Excel 2010 by their absolute value. Basically, if I have the table:
...the cells are colored by the cell's raw value. What I would like to do is color by the cell's absolute value, so with the cell coloring of this table:
...but with the values of the first table (the real values). Any ideas on how one might do this? Through the GUI or with VBA?
I don't think that there is any way to do this with three colors (red, yellow, green), but you can do it with two colors (for example yellow and green). Simply make the color for the low value and the color for the high value the same. That way, the cells with the lower absolute value will have the middle color and cells with the higher absolute value will have the other color.
Select Your data
Conditional Formatting
Color Scale
More Rules
Select "3-Point Scale" under Format Style
Change the colors so that the Maximum and Minimum colors are the same
Here is my solution to this problem. The conditional format formula reads
=AND(ABS(B3)>0,ABS(B3)<=500)
for the darkest green, the scale changes to 500 to 1000, 1000 to 1500, and finally 1500 to 2000 for the red band.
Conditional Formats
Color Scale Values
Here is a picture of the dataset that I used to test these conditional formats:
A variation on this simple conditional formatting illustration may work for you.
Highlight the whole of the data range (you need the top LH cell to be the anchor for relative addressing) and enter the Formula: in 'relative notation' i.e. cell references without the dollar signs. You also have to consider the order of the rules.
The uppermost formula is obscured but reads =(ABS(B3)>39) * (ABS(B3)<41) Note that the * symbol applies an AND operation.
Ok, I have a solution that works with 3 color conditioning. Basically you supply a region to my code. It then creates two ranges, one of neg numbers and one of positive ones. It then applies conditional formatting
red-low yellow-mid green-high to the positive range and
red-high yellow-mid green-low to the negative range.
It was a quick solution so its sloppy and not robust (for instance it only works in columns A-Z because of a lazy ascii conversion for column numbers), but it works. (i'd post a pic but I don't have enough points)
---------------------edit-------------------------------
#pnuts is right, unless the data is symmetric this solution wont work as is. so with that in mind I came up with a new solution. First I will explain the general idea, then basically just dump the code, if you understand the logic the code should be fairly clear. It is a rather involved solution for such a seemingly simple problem, but isn't that always the way? :-P
We are still using the basic idea of the original code, create a negative range and apply colorscale to it, then create a positive range and apply the inverted color scale to it. As seen below
Negative ........... 0 ................ positive
green yellow red | red yellow green
So with our skewed data data_set={-1,-1,-2,-2,-2,-2,-3,-4,1,5,8,13} what I do is mirror the the extreme value. In this case 13, so now data_set={-13,-1,-1,-2,-2,-2,-2,-3,-4,1,5,8,13} Notice the additional -13 element. I assume you have a button to enact this macro so I store the extra -13 in a cell that is underneath the button so even though its there it isn't visible (yeah I know they can move the button etc, but it was the easiest thing I could think of)
Well that's all well and good green maps to 13 AND -13 but the color gradient is based on percentiles (in fact the color bar code uses the 50th percentile to determine the midpoint, or in our case where the yellow section is)
Selection.FormatConditions(1).ColorScaleCriteria(2).Value = 50
so with our distribution {-13,-1,-1,-2,-2,-2,-2,-3,-4,1,5,8,13} we could start seeing the yellow in the positive range around the number 8.5 Since 8.5 is 50th percentile. but in the neg range (even if we add a mirrored -13) the 50th percentile is -2, so our yellow in the negative range would start at 2!! Hardly ideal. just like pnuts mentioned, but we are getting closer. if you have fairly symmetric data this issue won't be present, but again we are looking at worst case of skewed datasets
What I did next is statistically match the midpoints....or at least their colors. So since our extreme value (13) is in the positive range we leave the yellow at the 50th percentile and try to mirror it to the negative range by changing what percentile the yellow color appears at (if the negative range had the extreme value we would leave the yellow at that 50th percentile and try to mirror it to the positive range). That means in our negative range we want to shift our yellow (50th percentile) from -2 to a number around -8.5 so it matches the positive range. I wrote a function called
Function iGetPercentileFromNumber(my_range As Range, num_to_find As Double) That does just that! More Specifically it takes a range and reads the values into an array. It then adds num_to_find to the array and figures out what percentile num_to_find belongs to as an integer 0-100 (hence the i in the function name). Again using our example data we would call something like
imidcolorpercentile = iGetPercentileFromNumber(negrange with extra element -13, -8.5)
Where the -8.5 is the negative(50th percentile number of positive range = 8.5). Don't worry the code automatically supplies the ranges and the numbers, this is just for your understanding. The function would add -8.5 to our array of negative values {-13,-1,-1,-2,-2,-2,-2,-3,-4,-8.5} then figure out what percentile it is.
Now we take that percentile and pass it in as the midpoint for our negrange conditional formatting. so we changed the yellow from 50th percentile
Selection.FormatConditions(1).ColorScaleCriteria(2).Value = 50
to our new value
Selection.FormatConditions(1).ColorScaleCriteria(2).Value = imidcolorpercentile 'was 50
which now deskewed the colors!! we have basically created a symmetric in appearance color bar. Even if our numbers are far from symmetric.
Ok, I know that was a TON to read and digest. but here are the main takeaways this code
- uses full 3-color conditional formatting (not simply setting the two extreme colors the same to look like abs value)
- creates symmetric color ranges by using a obstructed cell (say under a button) to hold the extreme values
- uses statistical analysis to match the color gradients even in skewed data sets
both steps are necessary and neither one on its own is sufficient to create a true mirror color scale
Since this solution requires statistical analysis of the data set, you would need to run it again any time you changed a number (which was actually the case before, I just never said it)
and now the code. Put it in vba or some other highlighting program. It is nearly impossible to read as is ..... takes deep breath
Sub main()
Dim Rng As Range
Dim Cell_under_button As String
Set Rng = Range("A1:H10") 'change me!!!!!!!
Cell_under_button = "A15"
Call AbsoluteValColorBars(Rng, Cell_under_button)
End Sub
Function iGetPercentileFromNumber(my_range As Range, num_to_find As Double)
If (my_range.Count <= 0) Then
Exit Function
End If
Dim dval_arr() As Double
'this is one bigger than the range becasue we will add "num_to_find" to it
ReDim dval_arr(my_range.Count + 1)
Dim icurr_idx As Integer
Dim ipos_num As Integer
icurr_idx = 0
'creates array of all the numbers in your range
For Each cell In my_range
dval_arr(icurr_idx) = cell.Value
icurr_idx = icurr_idx + 1
Next
'adds the number we are searching for to the array
dval_arr(icurr_idx) = num_to_find
'sorts array in descending order
dval_arr = BubbleSrt(dval_arr, False)
'if match_type is 0, MATCH finds an exact match
ipos_exact = Application.Match(CLng(num_to_find), dval_arr, 0)
'there is a runtime error that can crop up when num_to_find isn't formated as long
'so we converted it, if it was a double we may not find an exact match so ipos_Exact
'may fail. now we have to find the closest numbers below or above clong(num_to_find)
'If match_type is -1, MATCH finds the value <= num_to_find
ipos_small = Application.Match(CLng(num_to_find), dval_arr, -1)
If (IsError(ipos_small)) Then
Exit Function
End If
'sorts array in ascending order
dval_arr = BubbleSrt(dval_arr, True)
'now we find the index of our mid color point
'If match_type is 1, MATCH finds the value >= num_to_find
ipos_large = Application.Match(CLng(num_to_find), dval_arr, 1)
If (IsError(ipos_large)) Then
Exit Function
End If
'barring any crazy errors descending order = reverse order (ascending) so
ipos_small = UBound(dval_arr) - ipos_small
'to minimize color error we pick the value closest to num_to_find
If Not (IsError(ipos_exact)) Then
'barring any crazy errors descending order = reverse order (ascending) so
'since the index was WRT descending subtract that from the length to get ascending
ipos_num = UBound(dval_arr) - ipos_exact
Else
If (Abs(dval_arr(ipos_large) - num_to_find) < Abs(dval_arr(ipos_small) - num_to_find)) Then
ipos_num = ipos_large
Else
ipos_num = ipos_small
End If
End If
'gets the percentile as an integer value 0-100
iGetPercentileFromNumber = Round(CDbl(ipos_num) / my_range.Count * 100)
End Function
'fairly well known algorithm doesn't need muxh explanation
Public Function BubbleSrt(ArrayIn, Ascending As Boolean)
Dim SrtTemp As Variant
Dim i As Long
Dim j As Long
If Ascending = True Then
For i = LBound(ArrayIn) To UBound(ArrayIn)
For j = i + 1 To UBound(ArrayIn)
If ArrayIn(i) > ArrayIn(j) Then
SrtTemp = ArrayIn(j)
ArrayIn(j) = ArrayIn(i)
ArrayIn(i) = SrtTemp
End If
Next j
Next i
Else
For i = LBound(ArrayIn) To UBound(ArrayIn)
For j = i + 1 To UBound(ArrayIn)
If ArrayIn(i) < ArrayIn(j) Then
SrtTemp = ArrayIn(j)
ArrayIn(j) = ArrayIn(i)
ArrayIn(i) = SrtTemp
End If
Next j
Next i
End If
BubbleSrt = ArrayIn
End Function
Sub AbsoluteValColorBars(Rng As Range, Cell_under_button As String)
negrange = ""
posrange = ""
'deletes existing rules
Rng.FormatConditions.Delete
'makes a negative and positive range
For Each cell In Rng
If cell.Value < 0 Then
' im certain there is a better way to get the column character
negrange = negrange & Chr(cell.Column + 64) & cell.Row & ","
Else
' im certain there is a better way to get the column character
posrange = posrange & Chr(cell.Column + 64) & cell.Row & ","
End If
Next cell
'removes trailing comma
If Len(negrange) > 0 Then
negrange = Left(negrange, Len(negrange) - 1)
End If
If Len(posrange) > 0 Then
posrange = Left(posrange, Len(posrange) - 1)
End If
'finds the data extrema
most_pos = WorksheetFunction.Max(Range(posrange))
most_neg = WorksheetFunction.Min(Range(negrange))
'initial values
neg_range_percentile = 50
pos_range_percentile = 50
'if the negative range has the most extreme value
If (most_pos + most_neg < 0) Then
'put the corresponding positive number in our obstructed cell
Range(Cell_under_button).Value = -1 * most_neg
'and add it to the positive range, to reskew the data
posrange = posrange & "," & Cell_under_button
'gets the 50th percentile number from neg range and tries to mirror it in pos range
'this should statistically skew the data
the_num = WorksheetFunction.Percentile_Inc(Range(negrange), 0.5)
pos_range_percentile = iGetPercentileFromNumber(Range(posrange), -1 * the_num)
Else
'put the corresponding negative number in our obstructed cell
Range(Cell_under_button).Value = -1 * most_pos
'and add it to the positive range, to reskew the data
negrange = negrange & "," & Cell_under_button
'gets the 50th percentile number from pos range and tries to mirror it in neg range
'this should statistically skew the data
the_num = WorksheetFunction.Percentile_Inc(Range(posrange), 0.5)
neg_range_percentile = iGetPercentileFromNumber(Range(negrange), -1 * the_num)
End If
'low red high green for positive range
Call addColorBar(posrange, False, pos_range_percentile)
'high red low green for negative range
Call addColorBar(negrange, True, neg_range_percentile)
End Sub
Sub addColorBar(my_range, binverted, imidcolorpercentile)
If (binverted) Then
'ai -> array ints
adcolor = Array(8109667, 8711167, 7039480)
' green , yellow , red
Else
adcolor = Array(7039480, 8711167, 8109667)
' red , yellow , greeb
End If
Range(my_range).Select
'these were just found using the record macro feature
Selection.FormatConditions.AddColorScale ColorScaleType:=3
Selection.FormatConditions(Selection.FormatConditions.Count).SetFirstPriority
'assigns a color for the lowest values in the range
Selection.FormatConditions(1).ColorScaleCriteria(1).Type = _
xlConditionValueLowestValue
With Selection.FormatConditions(1).ColorScaleCriteria(1).FormatColor
.Color = adcolor(0)
.TintAndShade = 0
End With
'assigns color to... midpoint of range
Selection.FormatConditions(1).ColorScaleCriteria(2).Type = _
xlConditionValuePercentile
Selection.FormatConditions(1).ColorScaleCriteria(2).Value = imidcolorpercentile 'originally 50
With Selection.FormatConditions(1).ColorScaleCriteria(2).FormatColor
.Color = adcolor(1)
.TintAndShade = 0
End With
'assigns colors to highest values in the range
Selection.FormatConditions(1).ColorScaleCriteria(3).Type = _
xlConditionValueHighestValue
With Selection.FormatConditions(1).ColorScaleCriteria(3).FormatColor
.Color = adcolor(2)
.TintAndShade = 0
End With
End Sub
I am going to borrow heavily from the answer of #barryleajo (won't hurt my feelings if you select that answer). As was stated in that answer the order of the conditional formatting is the key, start with the smallest absolute values and work your way up. The difference between that answer and this one is that there is no need to use an "and" statement, since the OP seems to indicate that all values within a certain range of absolute value should receive the same color format. Here is a small example:

Display Value Does Not Match Data Value After Split Function

I'm writing a macro that parses a string in a cell from my excel sheet and should return the three coordinates in that string. I can get the script to parse the string fine and create a "coordinateHolder" array to hold the three coordinates. My issue is that when I update cells to show the coordinates excel shows does not show the entire coordinate.
For example, if the coordinates string is originally "1234.1324123, 12345.23521, 2384.1234253", my code will update my x, y, and z coordinate cells as "1234.132", "12345", "2384.1234"
Image of what I mean:
(This one shows scientific notation in the cell and a shortened double in the formula builder bar)
My Code:
Dim i, j As Integer
Dim coordinates As String
Dim coordHolder As Variant
i = 2
j = 1
Range("I2:K2").Value = Range("E2:G2").Value
Do While Cells(i, j) <> ""
coordinates = Cells(i, j)
coordinates = Replace(coordinates, ",", "")
coordHolder = Split(coordinates, " ")
For a = 0 To UBound(coordHolder)
Cells(i, 7 + a) = coordHolder(a)
Next a
i = i + 1
Loop
Excel has a limit of 15 digits for numbers. Any number with more digits will lose precision in the lower magnitudes to enable the number display. Your data has values that go beyond the limit and will be truncated.
513402938412.123 shows just 15 digits. The remaining decimal places have been removed. The significance of 4 or more decimals pales in comparison with the magnitude of the value, therefore Excel considers the digits after the third deicmal as dispensable.
If you want to retain all digits in the value, you need to convert it to text and make sure it remains text and is not converted to a number again. To do that, you can precede any number with the apostrophe sign.
If a cell contains the value 5134029388412.12341234 it will be truncated. A cell containing the value '5134029388412.12341234 will be treated as text and remain intact.

Resources