Excel VBA inline IF statement makes variable 0 - vba

I am trying to reduce the amount of code from If... Then... Else statements and trying to use IIf(expression, true, false) for setting variables. I am having a problem where somehow the variable gets set to 0 and it's quite annoying.
For example:
'Declarations for testing (changing currenty to work for bot and top)
xval = 15
currenty = 20
largebot = 5
largecen = 5
largetop = 5
This one works:
largebot = IIf(xval > largebot, IIf(currenty >= -1 And currenty <= 21, xval, largebot), largebot)
But this one does not:
largetop = IIf(xval > largetop, IIf(Range("B2").Value = "RED or BLUE", IIf(material = 18, IIf(currenty >= 41 And currenty <= 64, xval, largetop), IIf(currenty >= 26 And currenty <= 64, xval, largetop)), IIf(currenty >= 22 And currenty <= 49, largetop = xval, largetop)), largetop)
'----------COMMENTS TO EXPLAIN DESIRED OUTCOME-------
'If the xval is greater than the highest x value (largetop),
'And if this is for RED or BLUE machines,
'And if on 18 in. material,
'And within the correct range on the material, xval. (largetop should be the value of xval)
'If on 24 in. material (not 18 in.),
'And within the correct range for 24 in. material, xval. (largetop should be the value of xval)
'If not for RED or BLUE machines (GREEN machine, then),
'If within the correct range, (both 18 in. and 24 in. are in the same range)
'largetop should be the value of xval.
'The remaining false statements keep current value.

Alright, so as I was posting this question, I figured it out. The first one worked fine and this one did not, so I was beginning to question if it was my problem, which it was. The error is that I essentially made a statement that was
largetop = largetop = xval
Shown in bold (If in code, bold doesn't show):
largetop = IIf(xval > largetop, IIf(Range("B2").Value = "RED or BLUE", IIf(material = 18, IIf(currenty >= 41 And currenty <= 64, xval, largetop), IIf(currenty >= 26 And currenty <= 64, xval, largetop)), IIf(currenty >= 22 And currenty <= 49, largetop = xval, largetop)), largetop)
Changing that to just xval fixed the problem! Hopefully someone will find this useful...

Related

VB.NET - How to find all modes (most frequent occurring numbers) in an array

So a Mode is the most frequent number in a dataset.
I've already managed to solve it, but it can only get 1 mode.
Here's my code:
Dim mode = inputX.GroupBy(Function(n) n).Select(Function(g) New With {.Number = g.Key, .Quantity = g.Count}).OrderByDescending(Function(o) o.Quantity).FirstOrDefault
If mode.Quantity > 1 Then
result = mode.Number.ToString() + " Quantity: " + mode.Quantity.ToString()
Else
result = "None."
End If
Now even though I inputted 29 29 35 30 30, which has 2 modes, it only shows 29, which is the first mode that it got. I want to get two modes or more.
I've been racking my brains and kept searching for answers, but I couldn't make it work.
I just started learning this language 2 days ago.
Quoting myself from a comment in LINQ: Mean, Median, and Mode:
Dim inputX = {29, 29, 35, 30, 30}
Dim modes = From a In
(From n In inputX
Group n By n Into g = Count()
Select g, n)
Where a.g =
(From n In inputX
Group n By n Into g = Count() Select g).Max
Select a.n
Console.WriteLine(String.Join(", ", modes))
Outputs:
29, 30

Power BI Report Builder Indicator Formula

I am adding in an indicator to a PBI Report Builder Report. The indicator is based off multiple fields from the dataset so I need to use a formula, to create the three up/down/side arrows.
Previously in Crystal Reports this could be implemented using a series of IF statements as follows. The below example is what is required for the down arrow. (the other 2 arrows also have multiple calculations)
IF (({spScorecard_SLView;1.CATEGORY_ID} = 4) OR
({spScorecard_SLView;1.CATEGORY_ID} = 25)) THEN
IF ({spScorecard_SLView;1.PM_3MM_NC_CNT}-{spScorecard_SLView;1.3MM_NC_CNT}) <
0 THEN 'Down Arrow'
ELSE IF (({spScorecard_SLView;1.CATEGORY_ID} = 21)
OR({spScorecard_SLView;1.CATEGORY_ID} = 26) OR
({spScorecard_SLView;1.CATEGORY_ID} = 41)) THEN
IF ({spScorecard_SLView;1.CM_TOTAL_CNT}> 0) AND
(({spScorecard_SLView;1.PM_3MM_TOTAL_CNT} = 0) OR
({spScorecard_SLView;1.3MM_TOTAL_CNT} = 0)) AND
({spScorecard_SLView;1.3MM_NC_CNT} > 0) AND
(((({spScorecard_SLView;1.3MM_TOTAL_CNT} - {spScorecard_SLView;1.3MM_NC_CNT})
/ {spScorecard_SLView;1.3MM_TOTAL_CNT}) * 100) >= 0.00) THEN 'Down Arrow' //
ELSE IF ((((({spScorecard_SLView;1.3MM_TOTAL_CNT} -
{spScorecard_SLView;1.3MM_NC_CNT}) / {spScorecard_SLView;1.3MM_TOTAL_CNT}) *
100) -((({spScorecard_SLView;1.PM_3MM_TOTAL_CNT} -
{spScorecard_SLView;1.PM_3MM_NC_CNT}) /
{spScorecard_SLView;1.PM_3MM_TOTAL_CNT}) * 100))/100) < 0.00 THEN
'Down Arrow'
I am stuck as to how to do something similar in PBI Report builder. Should I create a formula in the Value field under Value and States, and then delete any arrow settings under the Indicator States?
Can you create a formula using 'Down Arrow' etc in an IIf statement? I can only get indicator data returned when selecting 1 field under Value, but I need multiple fields & conditions.
SSRS Reports are similar to PBI Report builder so if there are any examples using it that may be of help. I am connecting to a SQL Server stored proc to pull back the data.
Thanks
Blowers
I would approach it like this...
Set a formula in the Indicator Value so that you return a number that corresponds to the arrow you want to show (e.g. return 1, 2 or 3)
You can use whatever format you feel comfotable with but I would suggest using the SWITCH() function rather than nested IIFs.
For example this checks two fields and returns one of three values, (this is just a random example to illustrate the point)
=SWITCH(
SUM(Fields!Amount.Value) >5000 AND Fields!Year.Value >2019, 1
, SUM(Fields!Amount.Value) >10000 AND Fields!Year.Value <2019, 2
, True, 3
)
Switch takes pairs of expressions and return values. It returns the value when it hits the first expression that evaluates to True. So this reads...
If the aggregated Amount is greater than 5000 and the Year >2019 then return 1
If the aggregated Amount is greater than 10000 and the Year <2019
then return 12
Else return 3
The final 'True', as it will always return true acts like an ELSE
Anyway, this will return a value of either 1, 2 or 3
Then in the Indicator Properties, just set the range for each indicator to 1, 2 or 3 like this
I ended up using IIF Logic to solve this, some of the calculations were too awkward in the end and it was easier for me to use IIF.
Using the 1,2,3 indicator values works well.
Here is the expression that i ended up using:
=IIF(Fields!CATEGORY_ID.Value = 4 AND Sum(Fields!PM_3MM_NC_CNT.Value -
Fields!Q3MM_NC_CNT.Value) < 0,1,
IIF(Fields!CATEGORY_ID.Value = 25 AND Sum(Fields!PM_3MM_NC_CNT.Value -
Fields!Q3MM_NC_CNT.Value) < 0,1,
IIF(Fields!CATEGORY_ID.Value = 4 AND Fields!PM_3MM_NC_CNT.Value <> 0
AND Fields!Q3MM_NC_CNT.Value <> 0 AND Fields!PM_3MM_NC_CNT.Value =
Fields!Q3MM_NC_CNT.Value ,2,
IIF(Fields!CATEGORY_ID.Value = 25 AND Fields!PM_3MM_NC_CNT.Value <> 0
AND Fields!Q3MM_NC_CNT.Value <> 0 AND Fields!PM_3MM_NC_CNT.Value =
Fields!Q3MM_NC_CNT.Value ,2,
IIF(Fields!CATEGORY_ID.Value = 4 AND Sum(Fields!PM_3MM_NC_CNT.Value -
Fields!Q3MM_NC_CNT.Value) > 0, 3,
IIF(Fields!CATEGORY_ID.Value = 25 AND Sum(Fields!PM_3MM_NC_CNT.Value -
Fields!Q3MM_NC_CNT.Value) > 0, 3,
IIF(Fields!CATEGORY_ID.Value = 4 AND Fields!PM_3MM_NC_CNT.Value = 0 AND
Fields!Q3MM_NC_CNT.Value = 0,4,
IIF(Fields!CATEGORY_ID.Value = 25 AND Fields!PM_3MM_NC_CNT.Value = 0
AND Fields!Q3MM_NC_CNT.Value = 0,4,
IIF(Fields!CATEGORY_ID.Value = 21 AND Fields!CM_TOTAL_CNT.Value > 0 AND
Fields!PM_3MM_TOTAL_CNT.Value =0,1,
IIF(Fields!CATEGORY_ID.Value = 26 AND Fields!CM_TOTAL_CNT.Value > 0 AND
Fields!PM_3MM_TOTAL_CNT.Value =0,1,
IIF(Fields!CATEGORY_ID.Value = 41 AND Fields!CM_TOTAL_CNT.Value > 0 AND
Fields!PM_3MM_TOTAL_CNT.Value =0,1,
IIF(Fields!CATEGORY_ID.Value = 21 AND Fields!Q3MM_TOTAL_CNT.Value = 0
AND Fields!Q3MM_NC_CNT.Value > 0 AND Fields!TrendCalculation1.Value -
Fields!TrendCalculation2.Value > 0.00,1,
IIF(Fields!CATEGORY_ID.Value = 26 AND Fields!Q3MM_TOTAL_CNT.Value = 0
AND Fields!Q3MM_NC_CNT.Value > 0 AND Fields!TrendCalculation1.Value -
Fields!TrendCalculation2.Value > 0.00,1,
IIF(Fields!CATEGORY_ID.Value = 41 AND Fields!Q3MM_TOTAL_CNT.Value = 0
AND Fields!Q3MM_NC_CNT.Value > 0 AND Fields!TrendCalculation1.Value -
Fields!TrendCalculation2.Value > 0.00,1,
IIF(Fields!CATEGORY_ID.Value <> 12 AND Fields!CATEGORY_ID.Value <> 30
AND Fields!PM_3MM_TOTAL_CNT.Value = 0,3,
IIF(Fields!CATEGORY_ID.Value <> 12 AND Fields!CATEGORY_ID.Value <> 30
AND Fields!Q3MM_TOTAL_CNT.Value = 0,3,
IIF(Fields!CATEGORY_ID.Value <> 12 AND Fields!CATEGORY_ID.Value <> 30
AND Fields!TrendCalculation1.Value - Fields!TrendCalculation2.Value <
0.00,1,
IIF(Fields!CATEGORY_ID.Value <> 12 AND Fields!CATEGORY_ID.Value <> 30
AND Fields!TrendCalculation1.Value - Fields!TrendCalculation2.Value >
0.00,3,
IIF(Fields!CATEGORY_ID.Value <> 12 AND Fields!CATEGORY_ID.Value <> 30
AND Fields!TrendCalculation1.Value - Fields!TrendCalculation2.Value =
0.00,2,
5)))))))))))))))))))

SSRS Color Gradient

I've been able to figure out how to make certain values the certain colors I would like. However, I'd really like to be able to create a color gradient so that it's more of a gradual change between each value.
0 = white
from white to green between 1 and 15,
gradient from green to yellow between 16 and 25,
and gradient from yellow to red between 26 and 35,
anything above 35 is red.
This is the code I have in the background fill expression:
=SWITCH(
(Sum(Fields!Total_Transaction_Count.Value) / CountDistinct(Fields!TransUserNumber.Value)) = 0, "White",
((Sum(Fields!Total_Transaction_Count.Value) / CountDistinct(Fields!TransUserNumber.Value)) >= 1 and
(Sum(Fields!Total_Transaction_Count.Value) / CountDistinct(Fields!TransUserNumber.Value)) <= 15), "Green",
((Sum(Fields!Total_Transaction_Count.Value) / CountDistinct(Fields!TransUserNumber.Value)) >= 16 and
(Sum(Fields!Total_Transaction_Count.Value) / CountDistinct(Fields!TransUserNumber.Value)) <= 25), "Yellow",
((Sum(Fields!Total_Transaction_Count.Value) / CountDistinct(Fields!TransUserNumber.Value)) >= 26 and
(Sum(Fields!Total_Transaction_Count.Value) / CountDistinct(Fields!TransUserNumber.Value))) <= 35, "Orange",
(Sum(Fields!Total_Transaction_Count.Value) / CountDistinct(Fields!TransUserNumber.Value)) > 35, "Red")
This is the matrix I have so far
Take a look at this answer I wrote a while back. It's for a chart but the principle should be the same.
the basic idea is to calculate the colour in SQL and then use that to set the color properties in SSRS
Applying Custom Gradient to Chart Based on Count of Value
Keeping it all in SSRS
If you want to keep this within the report you could write a function to do the calculation.
For a very simple red gradient, it might look something like this..
Public Function CalcRGB (minVal as double, maxVal as double, actualVal as double) as String
Dim RedValue as integer
Dim GreenValue as integer
Dim BlueValue as integer
RedValue = ((actualVal - minVal) / (maxVal - minVal)) * 256
GreenValue = 0
BlueValue = 0
dim result as string
result = "#" & RedValue.ToString("X2") & greenValue.ToString("X2") & BlueValue.ToString("X2")
Return result
End Function
In this function I have set green and blue to 0 but these could be calculated too based on requirements.
To use this function as a background colour, set the Background Color property to something like
=Code.CalcRGB(
MIN(Fields!myColumn.Value),
MAX(Fields!myColumn.Value),
Fields!myColumn.Value
)

Looking for specific label properties in VB.net

Image of the problem
Sub DrawGraph()
'Used to draw the current state.
G = Me.CreateGraphics
'G.Clear(Color.White) 'Sets entire background to white
G.clear(transparent)
Dim placeholder As Integer = 0 'Used to store the current point being checked.
If UsedLocations > 0 Then 'This part will only run if any points have been made
For i = 0 To 19
If Locations(i).Name <> "unused" Then 'only draws points that aren't unused.
If Locations(i).StartPoint = True Then 'only draws light blue outline if the point is selected as the start.
'the -3 on the end is to correct positions.
G.FillEllipse(Brushes.LightBlue, Locations(i).Xcoord - 3, Locations(i).Ycoord - 3, 16, 16)
End If
If Locations(i).Selected = True Then 'only draws the light green outline if the point is currently selected.
G.FillEllipse(Brushes.LightGreen, Locations(i).Xcoord - 3, Locations(i).Ycoord - 3, 16, 16)
End If
G.FillEllipse(Brushes.Black, Locations(i).Xcoord, Locations(i).Ycoord, 10, 10)
End If
Next
For i = 0 To UsedConnections - 1
'draws connections
If Connections(i).PartOfSolution = True Then
G.DrawLine(Pens.Red, Locations(Connections(i).PointOne).Xcoord + 5, Locations(Connections(i).PointOne).Ycoord + 5, Locations(Connections(i).PointTwo).Xcoord + 5, Locations(Connections(i).PointTwo).Ycoord + 5)
Else
G.DrawLine(Pens.Black, Locations(Connections(i).PointOne).Xcoord + 5, Locations(Connections(i).PointOne).Ycoord + 5, Locations(Connections(i).PointTwo).Xcoord + 5, Locations(Connections(i).PointTwo).Ycoord + 5)
End If
Next
'creating labels
Controls.Clear()
Dim NumberToMake As Integer = (39 + UsedConnections)
Dim infolabels(NumberToMake) As Label
For i = 0 To NumberToMake
infolabels(i) = New Label
infolabels(i).Height = 13
infolabels(i).BackColor = Color.Red
If i < 20 Then
infolabels(i).Text = Locations(i).Name
infolabels(i).Top = Locations(i).Ycoord - 15
infolabels(i).Left = Locations(i).Xcoord
If Locations(i).Name <> "unused" Then
Me.Controls.Add(infolabels(i))
End If
ElseIf i > 19 And i < 40 Then
'dijkstra labels
Else
Console.WriteLine(i)
Console.WriteLine(Connections(i - 40).Length)
infolabels(i).Text = CStr(Connections(i - 40).Length)
infolabels(i).Top = 0
infolabels(i).Top = (Locations(Connections(i - 40).PointOne).Ycoord + Locations(Connections(i - 40).PointTwo).Ycoord) * 0.5
'infolabels(i).Left = (Locations(Connections(i - 40).PointOne).Xcoord + Locations(Connections(i - 40).PointTwo).Xcoord) * 0.5
Me.Controls.Add(infolabels(i))
End If
infolabels(i).Width = infolabels(i).Text.Length * 15
Next
End If
End Sub
So while trying to add labels to a form to display information above points & connections, i found that they were covering them. I've already set width & height to proper conenctions, without changing anything.
I've tried setting the backcolour to red to find the problem, that did nothing.
After playing with the background colour of the form, I've found that the label has some white part added on to the sides (as pictured above), and i can't find any way to control it so that it doesn't cover up the draw objects.
Thanks in advance for help.
Edit: after investigating a little more, it seems the white space is the space the labels would normally take up before i resize them.
I had to resize the labels before adding controls to the form, like so:
If i < 20 Then
infolabels(i).Text = Locations(i).Name
infolabels(i).Top = Locations(i).Ycoord - 15
infolabels(i).Left = Locations(i).Xcoord
If Locations(i).Name <> "unused" Then
infolabels(i).Width = infolabels(i).Text.Length * 10
Me.Controls.Add(infolabels(i))
End If
ElseIf i > 19 And i < 40 Then
'dijkstra labels
Else
Console.WriteLine(i)
Console.WriteLine(Connections(i - 40).Length)
infolabels(i).Text = CStr(Connections(i - 40).Length)
'infolabels(i).Top = 0
infolabels(i).Top = (Locations(Connections(i - 40).PointOne).Ycoord + Locations(Connections(i - 40).PointTwo).Ycoord) * 0.5
infolabels(i).Left = (Locations(Connections(i - 40).PointOne).Xcoord + Locations(Connections(i - 40).PointTwo).Xcoord) * 0.5
infolabels(i).Width = infolabels(i).Text.Length * 10
Me.Controls.Add(infolabels(i))
End If

Verify Gamefield VB.NET

So I'm developing a minesweeper game and im assigning the mines, but I've got to check where are the mines now, in order to generate the numbers. The problem is that when I'm verifying the columns and lines I need the program not to get out of the game field.
Here's how my code looks like now:
Public Sub avisinhos(ByVal line, ByVal column)
If mat(line, column) = 0 Then
mat(line, column) = -1
numbandeiras = numbandeiras + 1
End If
For auxlinha = -1 To 1
For auxcolumn = -1 To 1
Next
Next
End Sub
How do I create a IF function to verify that I don't get out of the game field?
Best regards, joao.
pseudo code
int linestart = -1;
int lineend = 1;
int colstart = -1;
int colend = 1;
Assuming a 10 x 10 grid (zero based)
if line < 2 linestart = 0
if line > 8 lineend = 0
if column < 2 colstart = 0
if column > 8 colend = 0
For auxlinha = linestart To lineend
For auxcolumn = colstart To colend
// check
Next
Next
Personally though I wouldn't bother with the loops, they add very little to nothing
HasMineAbove = (line > 1) and (gamefield[line -1,column] = MinePresentValue
would be my approach, do it all in one.
Not to mention the huge potential confusion when auxlinha and auxcolumn are both zero...
I'm not sure exactly what your code is saying. It's a bit cryptic since you're using abbreviations and all lowercase names. You might want to try camelCasing and spelling out the words more completely, intellisense is your friend. =)
But coding style aside, if you are trying to loop through a limited range of values, you can keep your values bounded by using the modulus operator (%). For example, if you need to keep you values between 0-7 and you end up with a value of 12, just take the modulus of 8 to loop back to within range with a value of 4:
12 % 8 = 4
9 % 8 = 1
15 % 8 = 7
24 % 8 = 0
I realize this doesn't answer your specific question, but it's a handy technique might find useful.