How does the AxisName enumeration work in Windows.Forms.Charts? - vb.net

I'm using the windows forms charts in Visual Studio, and I want to write a function that, given a chart area, and an axis returns the maximum or minimum value (XValue or Yvalue, depending on the axis argument) from the points in that chart area. I want to use the AxisName enumeration for the second argument but, as per usual, the official documentation from msdn does not cover me. Does the enum name represent an index for the Axes() property of the ChartArea class or is it a direct link to an Axis object? Do i need to declare the enum in my class (that inherits DataVisualisation.Charts), or is it already known? pls help me
Public Function getAxisMinimum(ByVal area As AreaEnum, ByVal axe As AxisName) As Double
Dim min As Double = Double.NaN
For Each ser As Series In Series
If ser.ChartArea = ChartAreas(area).Name And ser.Points.Count > 0 Then
For Each p As DataPoint In ser.Points
'compare X or Y values depending on the axe argument to set the min
Next
End If
Next
'If there are no points in any series in the area, it will return NaN
Return min
End Function
AreaEnum is an integer enumeration that represents the index of the ChartArea() property that corresponds to each name.
I don't need a solution as to how to compare my points' values or how to return them, I just need an explanation on how to use the AxisName enumeration

Nevermind, I think I solved it. Visual Studio's auto-complete gave me the answer, because it recognized AxisName enumeration and corrected me in the select statement. I think this works:
Public Function getAxisMinimum(ByVal area As AreaEnum, ByVal axe As AxisName) As Double
Dim min As Double = Double.NaN
For Each ser As Series In Series
If ser.ChartArea = ChartAreas(area).Name AndAlso ser.Points.Count > 0 Then
For Each p As DataPoint In ser.Points
Select Case axe
Case AxisName.X
If Double.IsNaN(min) OrElse p.XValue < min Then
min = p.XValue
End If
Case AxisName.Y
For Each Yval As Double In p.YValues
If Double.IsNaN(min) OrElse Yval < min Then
min = Yval
End If
Next
Case Else
' Not an acceptable AxisName
Return Double.NaN
End Select
Next
End If
Next
'If there are no points in any series in the area, it will return NaN
Return min
End Function

Related

Issue with ByVal and Arrays in Functions (VB.NET)

I've ran into an issue with my code for the last week or so, and its been killing me trying to figure out what's wrong with it. I've extracted and isolated the issue from my main project, but the issue still isn't apparent.
Essentially, I have a function that usually does a lot of stuff, but in this example just changes 1 element in an array called FalseTable. Now, I have set this variable to be ByVal, meaning the original variable (ie: TrueTable) shouldn't change, however, it does! Here is the full code:
Dim TrueTable(7) As Char
Sub Main()
Dim FalseTable(7) As Char
For x = 0 To 7
TrueTable(x) = "T"
Next
For x = 0 To 7
FalseTable(x) = "F"
Next
Console.WriteLine("before")
For x = 0 To 7
Console.Write(TrueTable(x))
Next
Console.WriteLine()
Test(TrueTable)
Console.WriteLine("result")
For x = 0 To 7
Console.Write(TrueTable(x))
Next
Console.WriteLine()
Console.ReadLine()
End Sub
Function Test(ByVal FalseTable() As Char) As Char()
FalseTable(0) = "0"
Return FalseTable
End Function
Now, I used to think that it was the repetition of the name "FalseTable" in the function, however even if I change the function to:
Function Test(ByVal SomeTable() As Char) As Char()
SomeTable(0) = "0"
Return SomeTable
End Function
And not modify the rest, the issue still persists - for some reason, TrueTable is being updated when it shouldn't due to the ByVal status.
Any help with this would be greatly appreciated; it's probably something stupid that I've overlooked, but it's pulling my hair out!!
Many thanks,
Alfie :)
If you don't want to change the TrueTable, define another Array and copy TrueTable to it.
Here's the code you can refer to.
Dim TrueTable(7) As Char
Dim TrueTable2(7) As Char
Sub Main()
For x = 0 To 7
TrueTable(x) = "T"c
Next
Console.WriteLine("before")
For x = 0 To 7
Console.Write(TrueTable(x))
Next
Console.WriteLine()
TrueTable.CopyTo(TrueTable2, 0)
Test(TrueTable2)
Console.WriteLine("result")
For x = 0 To 7
Console.Write(TrueTable(x))
Next
Console.WriteLine()
Console.ReadLine()
End Sub
Result:
To understand why that happens just imagine this scenario.
You have a regular TextBox1 (this will be your TrueTable), now you want to pass the object TextBox1 to a function, something like this:
Function Test(ByVal TextBoxAnything as TextBox) As String
TextBoxAnything.Text = "0"
Return ""
End Function
Do you understand that you're passing thru TextBox1 and once inside the function Test the object TextBoxAnything is just TextBox1, anything you do to TextBoxAnything you're just doing it to TextBox1. TextBoxAnything doesn't exist, it just points to Textbox1. That's why the value of your TrueTable is also changed.

While loop generating random numbers - part of Monte Carlo Integration

I am trying to create a program that is part of Monte Carlo's Integration.
What I have managed to do is create a loop that generates x and y values a specific number of times that have been requested by the user.
Dim ninput As String
ninput = Val(Console.ReadLine())
Dim xvalue As Decimal
Dim yvalue As Decimal
Dim r As New Random()
Dim index As Integer = 0
Do
index +=1
xvalue = r.NextDouble()
yvalue = r.NextDouble()
Loop Until index = ninput
The problem I am having is that I need to generate 'pairs' of x and y values between 0 - 1. So if the user input 1, then it'd be one pair of x and y. If they input 30, then I'd need to generate 30 pairs of x and y values. In my case, I just repeat the random function n amount of times.
I don't know how to generate these pairs of x and y values depending on what the user has inputted for n.
Any help is greatly appreciated, cheers.
It looks like it would be convenient to have those X, Y pairs in the same entity, so you could create a class for them with members that store the values.
While you're creating a class, you can add methods to it to perform operations on the data, for example you might want an easy way to make a new instance of the class, or get some string representation of it.
To store a lot of instances of something, you could use an array, but a List is often more convenient as it does not need its size (capacity) to be declared in advance: you just add a new item to it and the framework takes care of the storage for you.
So you could have something like:
Option Strict On
Module Module1
Public Class PointDec
Property X As Decimal
Property Y As Decimal
Public Sub New(x As Double, y As Double)
Me.X = Convert.ToDecimal(x)
Me.Y = Convert.ToDecimal(y)
End Sub
Public Overrides Function ToString() As String
Return $"({X}, {Y})"
End Function
End Class
Sub Main()
Dim nInput As Integer
Console.Write("Enter number of points to generate: ")
nInput = Integer.Parse(Console.ReadLine())
Dim rand As New Random()
Dim points As New List(Of PointDec)
For i = 1 To nInput
points.Add(New PointDec(rand.NextDouble, rand.NextDouble))
Next
Console.WriteLine("The first point has a y-value of " & points(0).Y)
Console.WriteLine(String.Join(vbCrLf, points))
Console.ReadLine()
End Sub
End Module
Sample output:
Enter number of points to generate: 3
The first point has a y-value of 0.243760395908617
(0.390420139483372, 0.243760395908617)
(0.0321734459289226, 0.175302619661811)
(0.336522278066968, 0.0186830754478849)
It is a good idea to set Option Strict On as the default for new projects: it helps a lot because then Visual Studio can point out several programming mistakes for you.
I used the Decimal type in PointDec as I assumed you actually needed it instead of Double. The Double type is faster for calculations, and the program might be doing a lot of those with a Monte Carlo simulation.
The Val() function should usually be avoided, as it can accept some things that you'd wouldn't at first glance consider to be a number.

Find matches in a card hand turns up slightly off results around 10% of the time

This is my code which is supposed to compare the values in the array 'arrHands' which stores a hand of x cards (x = cardsDrawn) as singles where the integer part is the suit (1 to 4) and the decimal represents the card number ( .01 = 1 = Ace, etc).
However around 1 in 10 times it runs it returns values that are off by one or two pairs. I know that this will happen when the hand contains a three-of-a-kind, as i haven't written the code for that yet, but it still doesn't make sense. if the value returned is wrong it is always higher than i expected.
here's the code:
Dim numPairs As Integer = 0
Dim A As Integer = 1
Dim B As Integer = 1
'A and B represent the position in the array of the cards being compared
For A = 1 To cardsDrawn
For B = 1 To cardsDrawn
If (A <> B) And (A < B) And (arrHand(A) <> 0) And (arrHand(B) <> 0) Then
'The above line stops cards from being compared to each other, or to a card they have already been compared to.
If (arrHand(A) - (Int(arrHand(A))) = (arrHand(B) - (Int(arrHand(B))))) Then
'the code above extracts the card number from the single that each card is stored as
numPairs += 1
arrHand(A) = 0
arrHand(B) = 0
End If
End If
Next
Next
Thanks for any help or ideas you may have.
It is almost always a bad idea to glue 2 pieces of information into one variable. Classes make it easy to track the various datum for a card:
Public Class Card
Private Shared Faces() As String = {"Jack", "Queen", "King", "Ace"}
Private Shared Names() As String = {"Ace", "Deuce", ..."King"}
Public Property Value As Int32
Public Property Rank As Int32
Public Property Suit As String
Public Property Img As Image
Public Property Name As String
Public Overrides Function ToString() As String
Return String.Format("{0} of {1}", Names(Rank - 1), Suit)
End Function
End Class
There is a Value and a Rank because a card always has the same rank, but depending on the game, the Value may change (e.g. Euchre and Baccarat). A Deck class could use a Stack(Of Card) and a hand can be a List(Of Card) or an array depending on the game.
Given an array of 5 cards, ranking the hand for poker is simple with linq (and assuming Poker):
Dim pairs = cards.
GroupBy(Function(v) v.Value,
Function(key, values) New With {
Key .Rank = key,
Key .Count = values.Count()
}).
OrderByDescending(Function(o) o.Count).
ThenByDescending(Function(r) r.Rank).
ToArray()
If pairs.Count is 4, there is Four of a Kind; likewise 2pair when Count=2 and a pair when the count is one. If pairs(0).Count = 3 then you have trips.
If pairs.Count = 2 AndAlso pairs(0).Count = 3, then you have a FullHouse. It is pretty simple to also do a Group on the suit to determine a flush, and put them in order to see if it is a Straight.
Do be sure to test hands from high to low: you don't want to return 2 pair when it is really a Full House.

How do I sort objects in VB.net with custom comparer elegantly?

I want to sort a bunch of domainsdata object. I want to sort first based on countryCode then I want to sort based on revenue.
First I created a private comparer.
Private Function CompareDomainCountry(ByVal x As domainsData, ByVal y As domainsData) As Integer
If x.countryCode < y.countryCode Then
Return -1
ElseIf y.countryCode < x.countryCode Then
Return 1
ElseIf x.revenue < y.revenue Then
Return 1
ElseIf y.revenue < x.revenue Then
Return -1
Else
Return 0
End If
End Function
This has several problem.
The comparer returns 1,-1,0. I think there should be a normal enum for that.
Also I think my comparer should simply call standard vb.net comparer.
And after that, how do I sort list (of domainsdata)?
comparer?
You can use the CompareTo method to compare the values. If the first comparison is zero, then do the other comparison:
Private Function CompareDomainCountry(ByVal x As domainsData, ByVal y As domainsData) As Integer
Dim result As Integer = x.countryCode.CompareTo(y.countryCode)
If result = 0 Then
result = x.revenue.CompareTo(y.revenue)
End If
Return result
End Function
To sort the list using the comparison you use it in the Sort method call:
myList.Sort(AddressOf CompareDomainCountry)
First, note that your Revenue compare code is inconsistent: a smaller X should return -1. You also don't absolutely need that method. This gives the same result:
Dim sorted = DomainList.OrderBy(Function(x) x.CountryCode).
ThenBy(Function(y) y.Revenue).
ToList()
If you want to rely on a standard NET method, your method can be a class member:
Public Class DomainComparer
Implements IComparer(Of Domain)
Public Function Compare(x As Domain, y As Domain) As Integer _
Implements IComparer(Of Domain).Compare
' all your code
End Function
End Class
Then to use it:
Dim dSorter = New DomainComparer
DomainList.Sort(dSorter)
' or simply:
DomainList.Sort(New DomainComparer)
Mr Guffa's AddressOf method is simpler and more concise; I like the class method when there are other variables/properties such as a SortOrder.
The results are the same either way (when the revenue result is changed) unless a sort member is mixed alpha-numeric string (which seemed not to be the case based on the names and comparison).
If you were hoping to use your method with OrderBy(), I dont think you can - the signature doesn't match Func(Of T)(TKey). The return however is uniform with most all Compare() methods to indicate the larger value (DateTime indicates the lesser/earlier date; there may be others).

Randomized location isn't random [vb.net]

I made a randomization function for my regen and it just makes all the things that respawn in a diagonal line across the form... the code is this:
Public Function RandomNumber(ByVal MaxNumber As Integer, _
Optional ByVal MinNumber As Integer = 0) As Integer
'initialize random number generator
Dim r As New Random(System.DateTime.Now.Millisecond)
'if passed incorrect arguments, swap them
'can also throw exception,return 0
If MinNumber > MaxNumber Then
Dim t As Integer = MinNumber
MinNumber = MaxNumber
MaxNumber = t
End If
Return r.Next(MinNumber, MaxNumber)
End Function
and the code for 1 regen is this:
'regen coins
z = coin1
z.Location = zloc
z.Hide()
zloc = New Point(RandomNumber(playspace.Width), RandomNumber(playspace.Height))
If zloc.Y > 595 Then
zloc = New Point(RandomNumber(playspace.Width), RandomNumber(playspace.Height))
End If
z.Location = zloc
z.Show()
I do not know why it just makes a diagonal line but help would be VERY appreciated!
Your question is a bit vague, but I'm going to make a suggestion. Initialize your random number generator outside the RandomNumber function. Otherwise you create a new instance every time you make a call:
'initialize random number generator outside the function
Public _r As New Random(System.DateTime.Now.Millisecond)
Public Function RandomNumber(ByVal MaxNumber As Integer, Optional ByVal MinNumber As Integer = 0) As Integer
' ensure min is less than max
If MinNumber > MaxNumber Then
Return _r.Next(MaxNumber, MinNumber)
Else
Return _r.Next(MinNumber, MaxNumber)
End If
End Function
Your Random object, r, has function-level scope, which means that you re-initialize it upon each entry to the RandomNumber function.
A lot of people make this mistake and get the same "random" value each time*. You do get a slightly different number each time because, instead of using the default constructor, you're re-initializing it with a semi-random seed (the current millisecond count from the clock). Either way, the call to r.Next() is still not doing what you want it to do.
To fix this, ensuring that it's the same Random object that is used on each call to the function, hoist the declaration of r up a scope level (e.g., to the containing class), or mark it Static at function-level.
That will probably help enough to make you happy. If not, you're in for more education than you were probably hoping. The topic of randomness is a big philosophical one. There is no better place to start than the Wikipedia article on the subject, or perhaps this famous Stack Overflow question.
* Which is, of course, entirely allowed within the definition of "random". It's just not what people are wanting.