VBA to Use Inputs to - excel

So I'm new to VBA and it has been a long time since I had to program something like this. I'm trying to use six different inputs to format cells. Right now, if I could just get the inputs in x, y, z to format the corresponding cell, that would be great! I'm trying to avoid writing over 125 different if statements or cases and need a way to copy whatever color is in the B column to the appropriate x, y, z box. How can I do this iteratively?
Example
Edit: Basically what I'm trying to do is locate a cell that corresponds to an x, y, z input. Right now, the l, w, h don't matter. I'm just trying to go through all the cells in the z-planes and to find the one that matches the three input conditions (x,y,z).

Unfinished but, this should get you started in the right direction.
This will add your 3d object to an array.
AddValue will insert a value in the array at the appropriate locations
PostArray will display the array at a given location.
Note: There is no error checking in either function.
Your example Height (named depth in mine) is incorrect for sub_3. If height 0 shows on a single depth, then 3 should show on 4 depths (the starting depth extended 3 depth layers). Much like length and width values of 1 extend one past the original position.
Sub Test()
Dim oArr(1 To 5, 1 To 5, 1 To 5) As String
Call AddValue(oArr, 4, 4, 1, 0, 0, 0, "s1")
Call AddValue(oArr, 1, 3, 2, 0, 0, 0, "s2")
Call AddValue(oArr, 2, 2, 1, 1, 1, 3, "s3")
Call PostArray(oArr, Sheet1.Range("I4"))
End Sub
Private Sub AddValue(ByRef Arr() As String, ByVal iX As Integer, ByVal iY As Integer, ByVal iZ As Integer, _
ByVal iLength As Integer, ByVal iWidth As Integer, iDepth As Integer, _
ByVal Value As String)
Dim oLength As Integer
Dim oWidth As Integer
Dim oDepth As Integer
For oLength = iX To iX + iLength
For oWidth = iY To iY + iWidth
For oDepth = iZ To iZ + iDepth
Arr(oLength, oWidth, oDepth) = Value
Next
Next
Next
End Sub
Private Sub PostArray(ByRef Arr() As String, ByVal PostRange As Range)
Dim oX As Integer
Dim oY As Integer
Dim oZ As Integer
For oX = 1 To 5
For oY = 1 To 5
For oZ = 1 To 5
PostRange.Offset(oX - 1, (oY - 1) + ((oZ - 1) * 6)).Value = Arr(oX, oY, oZ)
Next
Next
Next
End Sub
Additional work
PostArray values from are going left to right, rather than your example of Right to left. If you read from right to left in your grids why arn't the depths also listed in the same direction? If you need it in that order, you'll likely want to separate the math to get the cooridinate of the 1,1 position for each depth, and a separate calculation for the offsets within that grid.
PostArray listed values instead of color, but if you enter the color as your value for each position you could set the color instead of posting the value.
Will need a loop to call AddValue using values from your worksheet rather than manually entering them into an array.

Related

Excel VBA Redim of variables giving odd and empty values

I am having trouble with some loops in some code that I have inherited but that I can't get to run. I have passed what I assume are the correct values into the function (see my previous question), but now I am struggling to have the initial loops work.
The function works fine when called in a cell. However, when it runs in this macro, it is giving me a few errors, which I have chased back to the ReDim of the Lambda and v variables.
When I check it in the debugger, Lambda has the value of 0.33, but the value of the variable Splines is 1, and there is no variable with the value 0.33 that it could be picking up nearby.
Meanwhile I would expect V to pick up the value of 2, i.e. 1+1, but instead it has the value of 0.
I cannot work out why this is happening. Here is the code.
Function Spline(form As String, Splines As Integer, params As Variant, knots As Variant, coef As Variant, tstar As Range) 'form is type of spline, splines is number of knots, params is gammas, knots as knot posititions, coef as 0, tstar as cycle length in days
Dim Lambda As Variant
Dim v As Variant
Dim kmin, kmax As Double
Dim vtstar As Variant
Dim vspline As Variant
Dim a As Long
vtstar = tstar.Value2 'set vtstar as second value of the array of the cycle length
ReDim vspline(1 To UBound(vtstar), 1 To 1) 'set vspline to be cycle lengths without the 0
For a = 1 To UBound(vtstar) 'for each cycle to the max cycle
If vtstar(a, 1) = 0 Then 'for each cycle
vspline(a, 1) = 1 'recoding the days cycles into cycle number
'Exit Function
GoTo Avert 'unsure of this functionality, i think its just part of the loop syntax, by the 'exit function notation
End If
timeS = Log(vtstar(a, 1)) 'set timeS as the log of the cycle length
ReDim Lambda(Splines, 0) 'set lambda to number of knots
ReDim v(Splines + 1, 0) 'recode v to number of knots plus 1
v(0, 0) = 1
v(1, 0) = timeS 'unsure about this part
This is causing errors when the lambda and v variables are used in calculations further down in the function, first causing the lambda calculations to give "subscript out of range" error when called in this loop, I assume because 0.33 isn't a cycle number:
For i = 1 To Splines 'loop for each variable in splines (number of knots)
Lambda(i, 0) = (kmax - knots(i + 1)) / ulamb 'calculate lambda as kmax - knots+1 divided by difference between max and min knot values
Next i
(kmax, knots and ulamb appear to be calculating correctly)
And then I am getting a Error2015 error on the following loop which uses v
s = Application.SumProduct(params, v) 'set s as multiply gammas by v
Thanks in advance
Unclear what your previous question was.
Struggle a bit with your description.
the value of the variable Splines is 1
Is Splines a constant = 1? You do not show how Splines is a variable but you state it is equal to the number of knots...
ReDim Lambda(Splines, 0) 'set lambda to number of knots
If Splines = 1, you are re-dimensioning Lambda to an array of size 2x1. So your array will hold two values.
For i = 1 To Splines 'loop for each variable in splines (number of knots)
Lambda(i, 0) = (kmax - knots(i + 1)) / ulamb 'calculate lambda as kmax - knots+1 divided by difference between max and min knot values
Next i
If Splines = 1 you are starting your loop at 1 and ending at 1... So your array Lambda(0, 0) is empty. You will have a value in Lambda(1, 0).

How to fix "Sub or Function not defined" when using HSL Function

I'm trying to set the interior color of some cells using HSL instead of RGB.
Judging by this documentation from Microsoft, it's very simple:
https://learn.microsoft.com/en-us/office/client-developer/visio/hsl-function
The syntax is simply HSL(** hue **, ** saturation **, ** luminosity ** )
Why, then, is my VBA telling me the sub or function is not defined?
The same error occurs for both of these lines of code:
Range("A1").Interior.Color = HSL(160, 240, 120)
Range("A1").Interior.ColorIndex = HSL(160, 240, 120)
Here's an alternative method for converting between RGB → HSL in VBA, using a Windows API. Since it's a "Classic Windows" function it has a couple idiosyncrasies.
RGB to HSL with ColorRGBToHLS
ColorRGBToHLS is an Windows API function which therefore uses an outdated color range that's been carried forward since the 1980's (originally used in a long-defunct program called MS Chart). You may be familiar with converting R/G/B values between percentages and values out of 255.
However in this case the conversion must be to/from values out of 240, not 255.
Just to further confuse us here in the future, they used notation of HLS instead of more-common HSL (and hex color strings are 0xBBGGRR instead of #RRGGBB).
tl;dr
Option Explicit
Public Declare PtrSafe Sub ColorRGBToHLS Lib "shlwapi.dll" (ByVal clrRGB As Long, _
wHue As Integer, wLuminance As Integer, wSaturation As Integer)
Function rgb_to_hsl(r As Integer, g As Integer, b As Integer)
Dim h As Integer, s As Integer, l As Integer
ColorRGBToHLS RGB(r, g, b), h, l, s
h = 360 * (h / 239)
s = 100 * (s / 240)
l = 100 * (l / 240)
rgb_to_hsl = "hsl(" & h & "," & s & "%," & l & "%)"
End Function
...and a demo:
Sub test()
Debug.Print rgb_to_hsl(255, 180, 63) 'returns "hsl(36,100%,62%)"
End Sub
By the way the API also has a ColorHLSToRGB function.
The 80's was a crazy (often confusing) time for computer nerds. Fun fact: Bill Gates married the first female programmer he hired.

Generating random colors with a bias to one color using Excel VBA

I am trying to generate random colors (2,6) using the following code below; however, my end goal is to generate white color (2) more than the rest of the colors. Would appreciate if someone could help. Thank you.
GenerateColor = Int(Rnd() * 5) + 2
It is a probably a good idea to separate the randomization logic and the logic, which forces a given color to be created more often. E.g., this one works quite ok, giving equal chances to each number:
randomColor = CLng(rnd() * 5) + 2
However, once you obtain the randomColor, it could be changed based on some percentage, named priorityPercentage in the function:
Public Sub TestMe()
Dim counter As Long
Dim randomColor As Long
With Worksheets(1)
.Cells.Clear
For counter = 1 To 1000000
randomColor = CLng(rnd() * 5) + 2
.Cells(counter, 1) = GenerateColor(randomColor, 2, (0.4 - 0.4 * 1 / 6))
Next
.Cells(1, 2).Formula = "=COUNTIF(A:A,2)"
End With
End Sub
Public Function GenerateColor(randomColor As Long, _
priorityColor As Long, _
priorityPercentage As Double) As Long
If rnd() <= priorityPercentage Then
GenerateColor = priorityColor
Exit Function
End If
GenerateColor = CLng(rnd() * 5) + 2
End Function
This example runs 1 million times and it writes in B2 the count of the 2. The reason to pass 0.4 - 0.4 * 1.6 in the parameter, is to make sure, that the chance for 2 is exactly 40%. We have 1/6 for each of the possible 6 numbers - [2,3,4,5,6,7]. Thus, the times when we do not enter in If rnd() <= priorityPercentage are also taken into account.

Is there an Excel VBA function to resize text to fit a shape?

I am drawing circles in excel with a number in them, but as soon as that number hits a double digit, the second digit is not visible.
I would like the textsize to fit the shape.
I cannot change the size of the circle, because this is based on the opportunity value.
I am working on a business funnel, the relevant input of the funnel is:
- ticket number
- value of opportunity (potential revenue): used to size the circle
The circles are drawn in the funnel, which exists of four stages that are depicted as four shapes.
I have tried:
Public Function DrawCircle(x As Integer, y As Integer, tickets As Collection, ticketIndex As Integer)
Dim myCircle As Shape
Dim circleSize As Integer
circleSize = GetTicketSize(tickets, ticketIndex)
Dim name As String
name = "" & tickets.Item(ticketIndex).id
Set myCircle = ThisWorkbook.Sheets("Graphic funnel").Shapes.AddShape(msoShapeOval, x, y, circleSize, circleSize)
myCircle.Select
Selection.ShapeRange.Fill.Visible = msoTrue
Selection.ShapeRange.TextFrame.Characters.Text = name
Selection.ShapeRange.Left = Selection.ShapeRange.Left
Selection.ShapeRange.Top = Selection.ShapeRange.Top - circleSize / 2
With myCircle
.DeleteText
.wrapformat = msoWrapFormat
.WordWrap = True
.AutoSize = msoAutoSizeTextToFitShape
End With
But it returns: "object doesn't support this property or method"

Value Error when using UBound for ParamArray

I am trying to write a function that calculates the minimum distance of one zip code to the other. The function should take in the longitude and latitude of one zip code, and then a 2-D array with all longitude and latitude info of zip codes. Here is the function I wrote:
Public Function PassArray(Longitude As Double, Latitude As Double, ParamArray varValues() As Variant) As Double
Dim arr() As Variant
Dim x As Long
For x = 1 To UBound(varValues(0), 1)
ReDim Preserve arr(x)
arr(UBound(arr)) = Sqr((Longitude - varValues(0)(x, 1)) ^ 2 + (Latitude - varValues(0)(x, 2)) ^ 2)
Next x
PassArray = WorksheetFunction.Min(arr)
I got #Value! error when I tried to use this function. I checked every step and it seems that the UBound(varValues(0), 1) is causing the problem. When I try UBound(varValues) it returns 0, which I guess it is the first dimension upper bound of the parameter array?
I cannot get why UBound(varValues(0), 1) would not work. I thought it should return my longitude & latitude array's last row number.
Consider #Mathieu Guindon's comment and go along those lines:
Option Explicit
'ASSUMPTION: coordinatesArray is a 2D array with rows in dimension 1 and columns in dimension 2.
Public Function PassArray(longitude As Double, latitude As Double, coordinatesArray As Variant) As Double
Dim rowLowerBound As Long
Dim rowUpperBound As Long
Dim x As Long
'We're looking at coordinatesArray's first dimension (rows).
'Let's consider both the lower and upper bounds, so as to adapt to the
'configuration of coordinatesArray.
rowLowerBound = LBound(coordinatesArray, 1)
rowUpperBound = UBound(coordinatesArray, 1)
'Dim arr upfront; this will be way faster than redimming within the loop.
ReDim arr(rowLowerBound To rowUpperBound) As Double
For x = rowLowerBound To rowUpperBound
'Your calculations go here.
'You can access coordinatesArray elements like so:
'coordinatesArray(x, 1) for row x, column 1, and
'coordinatesArray(x, 2) for row x, column 2.
arr(x) = Sqr((longitude - coordinatesArray(x, 1)) ^ 2 + (latitude - coordinatesArray(x, 2)) ^ 2)
Next x
'Note that Application.WorksheetFunction.Min doesn't seem to care
'whether arr is zero, one or n-based.
PassArray = Application.WorksheetFunction.Min(arr)
End Function
Note that I can't vouch for your distance calculation; might work for cartesian coordinates, but for not for longitude/latitude.

Resources