Peak over treshold method - VBA - Excel - vba

I really hope you can help me with the following question.
I have a dataset and I need to filter for some values. This is a dataset for wave analysis, and I need to filter out for the higstest values. The so called peak over treshold method. I want to filter out the storms in de wave dataset.
I can do this with the following: A storm is defined when the waveheight is above a certain value, for example 2.5 meters. The waveheight is measured every 3 hours.
So in the dataset I can do an If(B3>$A$1; B3;0). A1 = 2,5 m. Now I have filtered for waveheights. So now I can see in my dataset rows straight after each other with values higher than 2,5 meters, because a storm last serveral hours. See picture 1 as example:
[Picture 1][1]
So if a certain value is above X, then return that value, otherwise return zero. Now comes the hard part:
Now I need the highest value of that strip for values above 2,5 meters. As this is a big(!) dataset, I have a lot of datapoints. So I have several 'storms', which don't always last as long. So the values that are higher than 2,5 meters aren't always 3 rows, sometimes more. See picture 2picture 2
I need to compute the highst value in Column i, for each storm. Because each storm doens't last as long, I probally need to write code in VBA. Could anybody help me with this? I've been stuck for 6 days, but my VBA code doens't work and I do not have much experience with VBA. If anybody could help me that would be very much appreciated!
Kind regards,
Jeroen
EDIT as a reply on -Excel Developers-
I think I'm almost there, thank u very much for replying!! I am probably misreading the code, but a I have still a slight difficulty in computing the highstest value for each storm I think it should look something like this, as seen in picture 3.Picture 3
The highest value of each storm should be printed in the next column, as seen in picture 3. It probably says it all in the code, but I am misreading it.
Thank u very much for you answer! I really hope you can help me with the last part :-)
Kind regards,
Jeroen

You will have to iterate over all the values in column i. For every storm, find the highest value. A storm starts when a 0 is followed by a positive value, and ends when a positive value is followed by a 0. So something like this:
Sub FindHighestValue()
Dim vData As Variant
Dim Storms As Collection
Dim ndx As Long
Dim ndxStorm As Long
Dim MaxValue As Double
Dim Previous As Double
Dim InStorm As Boolean
vData = Sheet1.Range("I8:I21").Value 'Change this to whatever range your wave heights are in
Set Storms = New Collection
Previous = 0
InStorm = False
For ndx = LBound(vData, 1) To UBound(vData, 1)
If vData(ndx, 1) > 0 And Previous = 0 Then
'A storm has started
MaxValue = vData(ndx, 1)
InStorm = True
End If
If InStorm And vData(ndx, 1) > MaxValue Then
MaxValue = vData(ndx, 1)
End If
If (vData(ndx, 1) = 0 And Previous > 0) Or (ndx = UBound(vData, 1)) Then
'A storm has ended
InStorm = False
Storms.Add MaxValue
End If
Previous = vData(ndx, 1)
Next
If Storms.Count > 0 Then
For ndx = 1 To Storms.Count
Debug.Print ndx & ": " & Storms(ndx)
Next
End If
End Sub

Related

Format number in datagridview- If integer then F0, if decimal then F

I need to format all numbers in a datagridview.
If the number is a whole number then do not show the decimal point and if the number has a fraction then do show the decimal point.
I have achieved this by looping through each column and checking if the content is a double/single/decimal and then looping through each row in those columns to check each value whether the number is whole or has a fraction.
But this takes a long time for the application to process since i might have 2000 rows or more with 5 or more columns being double/single/decimal.
I can't find a standard format which does this.
Can anybody help?
dgv.SuspendLayout()
For i = 0 To dgv.Columns.Count - 1
If dgv.Columns(i).ValueType = GetType(Double) Or dgv.Columns(i).ValueType = GetType(Single) Or dgv.Columns(i).ValueType = GetType(Decimal) Then
'check If the number has a fraction
For u = 0 To dgv.Rows.Count - 1
If Not IsDBNull(dgv.Rows(u).Cells(i).Value) Then
If dgv.Rows(u).Cells(i).Value Mod 1 <> 0 Then
'number has a fraction
dgv.Rows(u).Cells(i).Style.Format = "F"
Else
'number is an integer
dgv.Rows(u).Cells(i).Style.Format = "F0"
End If
End If
Next
End If
Next
dgv.ResumeLayout()
Using the Datagridview.CellFormatting event seemed to solve the issue - Thanks Jimi. I just can't understand the difference between using the event and setting the format in a loop after populating the datagridview

Finding max value of a loop with VBA

I am trying to find max value of a loop. First, I have two random arrays and I want to find these two arrays correlation coefficient. Then, I want to calculate it multiple times as much as "I3" cell. After that, I want to write a code which finds max correlation coefficient from this calculation. I wrote the code below but it didn't work.
Sub Macro1()
Dim i As Long
For i = 1 To Range("I3")
Calculate
Next
DMax = Application.WorksheetFunction.Max("A2")
Range("I4").Value = DMax
End Sub
Any help is appreciated.
Your Max-Function needs a proper argument. Just typing "A2" doesn't work in VBA. Try:
DMax = Application.WorksheetFunction.Max(Range("A2"))
This will give you the max-Value of the Array A2. But keep in mind that the max-Value of a range consisting of a single cell is always the cell value.
If you want to calculate the maximum value of all iterations, you should use the max-function in each iteration (inside for-loop) and store it's value. In each following iteration you should then overwrite the max-Value if your new max value is larger than the old one. Just like this:
Sub Macro1()
Dim i As Long
DMax = 0
For i = 1 To Range("I3")
Calculate
DMax2 = Application.WorksheetFunction.Max(Range(...))
If DMax2 > DMax Then DMax = DMax2
Next i
Range("I4").Value = DMax
This will give you the max-Value of Range(...) of all iterations.
I barely understand your code, but the solution will be nasted loop. Suppose you have two sets of numbers: A2 (Cells(2, 1)) through I2 (Cells(2, 7)) and A3 (Cells(3, 1)) through I3 (Cells(3, 7)). You want to calculate partial correlation and find what was the maximum value of it.
For i = 1 To 7
For j = 1 To i
'Calculate the correlation
Next j
'here you have partial coefficient and you can compare it,
'if it is greater than previous one then save it and store
Next i
For i = 1 To Range("I3").value 'to calculate from 1 to the value in that cell
what i would recommend for your question.
For i = 1 To 10 ' loop 10 times
For j = 1 To i ' here it will allow you to check your stuff multiple times before moving on to the next value
arr1(i) = arr2(j) ' see if your array match
Next j
Next i

Count Number of Rows based on Parameter. (Excel VBA)

I need to count the number of rows depending on the week and type of the data. I have the excel formula but I want to make it as a VB code yet I don't have that much idea and it is not working.
=IF(AND($N$4="All",$N$5="All"),SUM(('SD'!$I$2:$I$99538='Source'!$B6)*('SD'!$A$2:$A$99538='Source'!C$5)),IF(AND($N$4="All",$N$5<>"All"),SUM(('SD'!$I$2:$I$99538='Source'!$B6)*('SD'!$A$2:$A$99538='Source'!C$5)*('SD'!$B$2:$B$99538='Source'!$N$5)),IF(AND($N$4<>"All",$N$5="All"),SUM(('SD'!$I$2:$I$99538='Source'!$B6)*('SD'!$A$2:$A$99538='Source'!C$5)*('SD'!$K$2:$K$99538='Source'!$N$4)),IF(AND($N$4<>"All",$N$5<>"All"),SUM(('SD'!$I$2:$I$99538='Source'!$B6)*('SD'!$A$2:$A$99538='Source'!C$5)*('SD Raised'!$B$2:$B$99538='Source'!$N$5)*('SD'!$K$2:$K$1048576='Source'!$N$4))))))
I have a sheet where in all datas are captured (SD) and the second one will be the sheet(Source) where i need to count the number of rows available based on the parameter as follow; The week where data belongs and the category of the data.
Edit:
This formula* does not count the data i needed to count. And if possible I want to make it as a VBA code.
This is where the counted data should go. "Weeks are changing depending on the dropdown iput (Max of 4 weeks below from the selected week)"
This image shows the data where i need to capture and count the number of category based on the weeks and category. (Sample only)
I guess, if it's the right point you're hitting DoktorOSwaldo, better use the Range().Rows.Count property rather than scrolling through allRows.
Hope this helps.
Hadi
so i have to guess a bit what you want, but if you want to Count specific rows in Excel vba you can use something like this:
Dim allRows As Variant
Dim i As Long
Dim count as Long
count = 0
allRows = Tabelle5.Range("A" & start_row, end_column & last_row)
For i = 1 To UBound(allRows)
If allRows(i, 1) = *category* and allRows(i,2) = *week* Then
count = count + 1
End If
Next
To find right range, there are multiple possible solution. I use this, maybe it is not the best, but works fine for me:
Private Function last_row() As Integer
Dim rangeObj As Range
Set rangeObj = Tabelle5.Cells.Find("*", SearchOrder:=xlByRows, SearchDirection:=xlPrevious)
If rangeObj Is Nothing Then
last_row = start_row
Else
last_row = rangeObj.row
End If
End Function
Public Function start_row() As Integer
start_row = 2
End Function

If/Else statement for chart

So, I've been stuck in this problem for so many days now. I'm trying to loop the system.array from the data in Excel. I use the if statement that read if the data value from the excel is numeric or not. After that I put elseif statement that change the chart marker style to none if the value is equal to zero. However, no matter what kind of methods that I try, the markers still show on the chart. Here's my code:
Dim A_GTRng As Excel.Range
Dim A_GTArry As System.Array
'Set the range
A_GTRng = excelWS.Range("I2", excelWS.Range("I2").End(Excel.XlDirection.xlDown))
'Read in the values of a range of cells
A_GTArry = CType(A_GTRng.Value, System.Array)
'Looping through the A_GTArry
For x As Integer = 1 To A_GTArry.GetUpperBound(0)
For y As Integer = 1 To A_GTArry.GetUpperBound(1)
Dim A_GT As Object = A_GTArry(x, y)
If IsNumeric(y).Equals(0) Then
'Chart1.Series("A_GT").MarkerSize = 0
'Chart1.Series("A_GT").MarkerColor = Color.Transparent
Chart1.Series("A_GT").MarkerStyle = MarkerStyle.None
ElseIf IsNumeric(y) Then
'Chart1.Series("A_GT").Points.Dispose()
Chart1.Series("A_GT").Points.AddY(A_GT)
Chart1.Series("A_GT").MarkerStyle = MarkerStyle.Diamond
Chart1.Series("A_GT").MarkerColor = Color.Red
Chart1.Series("A_GT").MarkerSize = 7
End If
Next y
Next x
Result from the program above:
Can anyone check if I make some mistake somewhere? I try to solve this problem since the past few days, but did got the result that I want. My brain pretty much fried now. I really need help to solve this. Thank you!
Since y is an Integer by definition in your For loop it will always be numeric.
Therefore this statement will never succeed:
If IsNumeric(y).Equals(0) Then
What exactly are you trying to do? Seems like you've gotten a little bit off course.
Z

Excel VBA Length-1 In a Range

I recently got into Excel macro development after a long time of not having the need to.
I have one column with two-hundred rows where each row has a value. I wrote a loop to iterate to each row value, read the current value and then write the value back minus the last character.
Here is some actual (and pseudo) code of what I wrote.
Dim theRow as Long
Dim totRow as Long
Dim fooStr as String
theRow = 2 'we begin on the second row of the colummn
totRow = 201 'there are 200 values
For theRow = 2 to totRow
fooStr = WorkSheets(DestSheet).Cells(theRow,"A").Formula 'read the cell value
fooStr = Left(fooStr,Len(fooStr)-1 'subtract the last character from the value
Cells(theRow,1).Value = fooStr 'write the value back
Next theRow
After I did some reading I learned that it is best practice to read and write values using a Range. Is it possible to rewrite what I am doing using a Range so it willl go faster.
Here is what I came up with so far.
Range("A2:A201").Value = Len(Range.Left("A2:A201").Value)-1
However, this doesn't work.
Any clues on how to do this if this is indeed possible?
Thanks for any tips.
If you want maximum performance (you don't need it for 200 rows, but...) you have to minimize the number of reads and writes (mostly writes) to ranges. That means reading the whole range into an array, manipulating the array, then writing it back to the range. That's one read and one write compared to 200 in a loop. Here's an example.
Sub RemoveLastChar()
Dim vaValues As Variant
Dim i As Long
vaValues = Sheet1.Range("A2").Resize(200).Value
For i = LBound(vaValues, 1) To UBound(vaValues, 1)
vaValues(i, 1) = Left$(vaValues(i, 1), Len(vaValues(i, 1)) - 1)
Next i
Sheet1.Range("A2").Resize(UBound(vaValues, 1), UBound(vaValues, 2)).Value = vaValues
End Sub
You could do something like
Sub StringTrim()
Dim xCell as Range
Range("A1:A201").Select
For Each xCell in Selection
xCell.Value = Left(xCell.Value, Len(xCell.Value) - 1)
Next
End Sub
I don't know what kind of speed improvements you are seeking, but that would also do the job.
You might know this already but putting Application.ScreenUpdating = False at the top of your code can speed it up significantly (unless you like to watch everything flash by as the script works). You should reset the value to True at the end of your code.