Find 2 cells' values based on max value found in range - excel

I have a multiplication style table with values inside x and y axis'. After the initial macro is run, I want to search for the max value, then find the corresponding x and y cells. Example...
enter image description here
In this example, the red text is the highest value, so it should find the 1 and the .015. But, there are some tables that might return multiple numbers, so I just want to pick the first cell found. Here is the full code.
Private Sub CommandButton6_Click()
Dim c As Range
Dim rng As Range
Dim balanceValue As Range
Dim dayValue As Range
Dim multValue As Range
Dim lCol As Long
Dim lRow As Long
Dim whereRow As Long
Dim AddressOfMaxH As Variant
'Dim AddressOfMaxV As Range
'Set rng = Sheets("MacroTesting").Range("B91:CD110")
Set rng = Sheets("MacroTesting").Range("B91:C92")
Set balanceValue = Sheets("Header").Range("B4")
Set dayValue = Sheets("Header").Range("E17")
Set multValue = Sheets("Header").Range("F17")
getRow = Sheets("MacroTesting").Range("B91").Row
getCol = Sheets("MacroTesting").Range("B91").Column
whereRow = 90
lCol = Cells(whereRow, Columns.Count).End(xlToLeft).Column
rng.Clear
For Each c In rng
If ActiveCell.Column = lCol Then
getRow = getRow + 1
getCol = 2
End If
getRow = Sheets("MacroTesting").Cells(getRow, 1)
dayValue = getRow
getCol = Sheets("MacroTesting").Cells(whereRow, getCol)
multValue = getCol
c = balanceValue.Copy
c.Select
c = FormatCurrency(c, 0)
Selection.PasteSpecial Paste:=xlPasteValues
getCol = ActiveCell.Column + 1
getRow = ActiveCell.Row
Next
With rng.FormatConditions.AddTop10
.TopBottom = xlTop10Top
.Rank = 1
.Percent = False
With .Font
.Bold = True
.ColorIndex = 3
End With
End With
Set AddressOfMaxH = rng.Cells(WorksheetFunction.Match(WorksheetFunction.Max(rng), rng, 0))
Set AddressOfMaxV = rng.Cells(WorksheetFunction.Match(WorksheetFunction.Max(rng), rng, 0))
AddressOfMaxHoriz = Cells(whereRow, AddressOfMaxH.Column)
AddressOfMaxVerti = Cells(AddressOfMaxV.Row, 1)
dayValue = AddressOfMaxVerti
multValue = AddressOfMaxHoriz
Application.CutCopyMode = False
End Sub
Here is the part where I'm trying to find the relevant cell.
Set AddressOfMaxH = rng.Cells(WorksheetFunction.Match(WorksheetFunction.Max(rng), rng, 0))
Set AddressOfMaxV = rng.Cells(WorksheetFunction.Match(WorksheetFunction.Max(rng), rng, 0))
AddressOfMaxHoriz = Cells(whereRow, AddressOfMaxH.Column)
AddressOfMaxVerti = Cells(AddressOfMaxV.Row, 1)
dayValue = AddressOfMaxVerti
multValue = AddressOfMaxHoriz

Dim rng As Range, f As Range
Set rng = Range("C6:G13")
Set f = rng.Find(Application.Max(rng), lookat:=xlWhole)
Debug.Print Cells(rng(1).Row - 1, f.Column).Value 'column header
Debug.Print Cells(f.Row, rng(1).Column - 1).Value 'row header

Related

Excel VBA: Range Compare, For Each Loops, Nested IF Statements

Looking for assistance with the following:
Goal:
Compare cells in 2 defined ranges (same size) one by one. If they are the same then move on to the next set of cells. If not:
Input an integer (between 1 to 2000) in a corresponding cell within a 3rd range (same size as the other 2). Run this in a For loop until the cells in the first 2 ranges equal each other.
Once achieved, then move on to the next set of cells and so forth.
The code I've written up so far is outlined below but its not producing the right results. From what I can tell, the hCell value loops while the rest don't which is putting the If comparison conditions off...
Thank you for any help with this!
Sub Update()
Range("A1").Select
ActiveWindow.ScrollColumn = 1
ActiveWindow.ScrollRow = 1
Sheets("Funds").Select
Range("A1").Select
ActiveWindow.ScrollColumn = 1
ActiveWindow.ScrollRow = 1
'resets the "looping cells" from NR8 to PF207.
'Dim d As Integer
For d = 8 To 207
Range(Cells(d, 382), Cells(d, 422)) = ""
Next
Dim e As Integer
e = 1
Dim fRng As Range: Set fRng = Range("RB8:SP207")
Dim fCell As Range
Dim gRng As Range: Set gRng = Range("SU8:UI207")
Dim gCell As Range
Dim hRng As Range: Set hRng = Range("NR8:PF207")
Dim hCell As Range
Dim i As Integer
i = i
For e = 8 To 207
For Each fCell In fRng.Cells
For Each gCell In gRng.Cells
For Each hCell In hRng.Cells
If Cells(e, 191).Value = 0 Then
Exit For
Else
If (fCell.Value >= gCell.Value Or gCell.Value = "N/A") Then
Exit For
Else
For i = 0 To 2000
If fCell.Value >= gCell.Value Then
Exit For
Else
hCell.Value = i
If fCell.Value >= gCell.Value Then
Exit For
End If
End If
Next i
End If
End If
Next hCell, gCell, fCell
End If
Next e
Range("A1").Select
End Sub
I assume the values in the first two ranges are in some way dependent on the values in the third.
Option Explicit
Sub Update()
Const NCOLS = 41 ' 41
Const NROWS = 200 ' 200
Const LOOPMAX = 2000 ' 2000
Dim wb As Workbook, ws As Worksheet
Dim rng1 As Range, rng2 As Range, rng3 As Range
Dim cell1 As Range, cell2 As Range
Dim i As Long, r As Long, c As Integer, t0 As Double
t0 = Timer
Set wb = ThisWorkbook
Set ws = wb.Sheets(1)
Set rng1 = ws.Range("RB8")
Set rng2 = ws.Range("SU8")
Set rng3 = ws.Range("NR8")
'resets NR8 to PF207.
rng3.Resize(NROWS, NCOLS).Value = ""
Application.ScreenUpdating = False
For r = 1 To NROWS
Application.StatusBar = "Row " & r & " of " & NROWS
For c = 1 To NCOLS
Set cell1 = rng1.Offset(r - 1, c - 1)
Set cell2 = rng2.Offset(r - 1, c - 1)
If (cell1.Value <> cell2.Value) Or (cell2.Value = "N/A") Then
i = 0
Do
rng3.Offset(r - 1, c - 1) = i
i = i + 1
Loop Until cell1.Value = cell2.Value Or i > LOOPMAX
End If
Next c
Next r
Application.ScreenUpdating = True
MsgBox "Done", vbInformation, Int(Timer - t0) & " seconds"
rng3.Select
End Sub

How to turn a column of data into an 8x12 grid?

I'm trying to put values from 1 column into an 8x12 grid.
With the first value starting in the top left of the grid, moving to the right 12 cells, then offsetting 1 row from starting cell and having the data continue filling cells in this format.
I'm trying to replace
roneWS.Range("E6:N6") = Application.Transpose(ptWS.Range("B4:B13"))
roneWS.Range("C7:N7") = Application.Transpose(ptWS.Range("B14:B25"))
roneWS.Range("C8:N8") = Application.Transpose(ptWS.Range("B26:B37"))
roneWS.Range("C9:N9") = Application.Transpose(ptWS.Range("B38:B49"))
roneWS.Range("C10:N10") = Application.Transpose(ptWS.Range("B50:B61"))
roneWS.Range("C11:N11") = Application.Transpose(ptWS.Range("B62:B73"))
roneWS.Range("C12:N12") = Application.Transpose(ptWS.Range("B74:B85"))
roneWS.Range("C13:N13") = Application.Transpose(ptWS.Range("B86:B97"))
with an array/loop.
I came up with:
Dim ptWS As Worksheet, roneWS As Worksheet, rtwoWS As Worksheet, rthreeWS As Worksheet, rfourWS As Worksheet
Dim ptRng As Range, destRng As Range
Dim i As Integer
Dim ptArr() As Variant
Set ptWS = ThisWorkbook.Worksheets("PT")
Set roneWS = ThisWorkbook.Worksheets("WS1")
Set rtwoWS = ThisWorkbook.Worksheets("WS2")
Set rthreeWS = ThisWorkbook.Worksheets("WS3")
Set rfourWS = ThisWorkbook.Worksheets("WS4")
i = 4
Set ptRng = ptWS.Range("B4:B97") 'data that needs to be moved to other worksheets B4:B97 = 1st WS, C4:C97 = 2nd WS, D4:D97 = 3rd WS, E4:E97 = 4th WS
Set destRng = roneWS.Range("E6") 'destination range for WS1-WS4 starts at E6
ptArr = ptRng.Value 'setting all values for the WS1 to ptArr
For i = LBound(ptArr) To UBound(ptArr)
If ptArr(i, 1) = ptWS.Cells(14, 2) Then 'move my way across the columns until I hit Col O then, offset back to Col C and repeat until the end (N13) is reached
Set destRng = destRng.Offset(1, -12)
destRng = ptArr(i, 1)
Set destRng = destRng.Offset(0, 1)
ElseIf ptArr(i, 1) = ptWS.Cells(26, 2) Then
Set destRng = destRng.Offset(1, -12)
destRng = ptArr(i, 1)
Set destRng = destRng.Offset(0, 1)
ElseIf ptArr(i, 1) = ptWS.Cells(38, 2) Then
Set destRng = destRng.Offset(1, -12)
destRng = ptArr(i, 1)
Set destRng = destRng.Offset(0, 1)
ElseIf ptArr(i, 1) = ptWS.Cells(50, 2) Then
Set destRng = destRng.Offset(1, -12)
destRng = ptArr(i, 1)
Set destRng = destRng.Offset(0, 1)
ElseIf ptArr(i, 1) = ptWS.Cells(62, 2) Then
Set destRng = destRng.Offset(1, -12)
destRng = ptArr(i, 1)
Set destRng = destRng.Offset(0, 1)
ElseIf ptArr(i, 1) = ptWS.Cells(74, 2) Then
Set destRng = destRng.Offset(1, -12)
destRng = ptArr(i, 1)
Set destRng = destRng.Offset(0, 1)
ElseIf ptArr(i, 1) = ptWS.Cells(86, 2) Then
Set destRng = destRng.Offset(1, -12)
destRng = ptArr(i, 1)
Set destRng = destRng.Offset(0, 1)
Else: destRng = ptArr(i, 1)
Set destRng = destRng.Offset(0, 1)
End If
Next i
It gives me what I want for WS1. However I have to repeat this for the 3 other worksheets.
For the other 3 worksheets, the total range is the same as posted above, just offset by 1 column.
WS1 = ptWS.Range("B4:B97")
WS2 = ptWS.Range("C4:C97")
WS3 = ptWS.Range("D4:D97")
WS4 = ptWS.Range("E4:E97")
The destination starting point on all 4 worksheets are the same Range(E6").
How do I add a loop through the worksheets once all cells on WS1 have been set, while also offsetting the column by 1 from ptWS. I'm wondering if this can be done without copy/pasting the existing array code 3 more times and just changing the ranges.
I achieved the same result by looping through the data on ptWS by using a series of Do Until loops but then eventually ran into the same issue.
Here's one appraoch:
Sub Tester()
Dim i As Long
For i = 1 To 4
ColToMatrix ThisWorkbook.Worksheets("PT").Range("B4:B97").Offset(0, i - 1), _
ThisWorkbook.Worksheets("WS" & i).Range("C6")
Next i
End Sub
'pass in the column to be mapped and the top-left destination cell for the matrix
Sub ColToMatrix(rngCol As Range, rngTL As Range)
Dim arr, mtx(1 To 8, 1 To 12), i As Long, r As Long, c As Long, n As Long
arr = rngCol.Value
For i = 1 To UBound(arr, 1)
n = i + 2 'account for starting 3 cells in
r = 1 + ((n - 1) \ 12)
c = ((n - 1) Mod 12) + 1
mtx(r, c) = arr(i, 1)
Next i
rngTL.Resize(8, 12).Value = mtx
End Sub
To do this, better way is doing a sub to transpose data, and then call it for every worksheet.
I'm excluding roneWS.Range("E6:N6") = Application.Transpose(ptWS.Range("B4:B13")) because it's not part of the 7x12 array, due to different size (it's 10 values, not 12).
So we focus on 7x12, this part of your code:
roneWS.Range("C7:N7") = Application.Transpose(ptWS.Range("B14:B25"))
roneWS.Range("C8:N8") = Application.Transpose(ptWS.Range("B26:B37"))
roneWS.Range("C9:N9") = Application.Transpose(ptWS.Range("B38:B49"))
roneWS.Range("C10:N10") = Application.Transpose(ptWS.Range("B50:B61"))
roneWS.Range("C11:N11") = Application.Transpose(ptWS.Range("B62:B73"))
roneWS.Range("C12:N12") = Application.Transpose(ptWS.Range("B74:B85"))
roneWS.Range("C13:N13") = Application.Transpose(ptWS.Range("B86:B97"))
This sub will as for:
A source range like ptWS.Range("B14:B97"), 84 values (7x12)
A destiny range like roneWS.Range("C7:N13"), a 7x12 grid
The code is:
Sub GET_VALUES(ByVal vRngSource As Range, ByVal vRngDestiny As Range)
Dim vMatriz As Variant
Dim ZZ As Long
Dim ThisColumn As Long, ThisRow As Long
ThisColumn = 1
ThisRow = 1
vMatriz = vRngSource.Value
For ZZ = 1 To UBound(vMatriz) Step 1
vRngDestiny.Cells(ThisRow, ThisColumn).Value = vMatriz(ZZ, 1)
If ThisColumn = 12 Then
ThisColumn = 1
ThisRow = ThisRow + 1
Else
ThisColumn = ThisColumn + 1
End If
Next ZZ
Erase vMatriz
End Sub
To call it, you can just do:
Sub test()
GET_VALUES Range("B14:B97"), Range("C7:N13")
End Sub
Now you just need to call it once for every worksheet. I would use a For each loop combined with Select Case, so you can choose for every worksheet what to do, like this:
Sub TEST()
Application.ScreenUpdating = False
Dim WK As Worksheet
Dim ptWS As Worksheet
Set ptWS = ThisWorkbook.Worksheets("PT")
For Each WK In ThisWorkbook.Worksheets
Select Case WK.Name
Case "WS1"
GET_VALUES ptWS.Range("B14:B97"), WK.Range("C7:N13")
WK.Range("E6:N6") = Application.Transpose(ptWS.Range("B4:B13"))
Case "WS2"
GET_VALUES ptWS.Range("C14:C97"), WK.Range("C7:N13")
WK.Range("E6:N6") = Application.Transpose(ptWS.Range("C4:C13"))
Case "WS3"
GET_VALUES ptWS.Range("D14:D97"), WK.Range("C7:N13")
WK.Range("E6:N6") = Application.Transpose(ptWS.Range("D4:D13"))
Case "WS4"
GET_VALUES ptWS.Range("E14:E97"), WK.Range("C7:N13")
WK.Range("E6:N6") = Application.Transpose(ptWS.Range("E4:E13"))
Case Else
'we do nothing
End Select
Next WK
Application.ScreenUpdating = True
End Sub
Hope you can adapt this to your needs.

VBA Code to add multiple series to a scatter graph - run time 1004 error

I am writing a code to add multiple series to a line graph. I have also put in a counter to make two separate graphs when a minimum value corresponding to a row is met. My VBA skills are very basic and I get a run time 1004 error at the asterisked line:
Dim xrng As Range
Dim yrng As Range
Dim x2rng As Range
Dim y2rng As Range
Dim i As Integer
Dim Rng As Range
Dim l As Integer
Dim k As Integer
Dim i2 As Integer
Worksheets("Template").Activate
Dim lv As String
lv = Worksheets("Template").Range(Worksheets("Template").Range("B11"), Worksheets("Template").Range("B11").End(xlDown)).Find(WorksheetFunction.Small(Worksheets("Template").Range(Worksheets("Template").Range("B11"), Worksheets("Template").Range("B11").End(xlDown)), 1), , , 1).Address
Range(lv).Select
l = ActiveCell.Row
k = Worksheets("Template").Range(Worksheets("Template").Range("B11"), Worksheets("Template").Range("B11").End(xlDown)).Rows.Count
i = 1
i2 = 1
Set xrng = Worksheets("Template").Range("C11:CP11")
Set yrng = Worksheets("Template").Range("C201:CP201")
Set x2rng = xrng.Offset(1, 0)
Set y2rng = xrng.Offset(1, 0)
Dim Chart1 As Chart
Set Chart1 = Charts.Add
With Chart1
Chart1.ChartType = xlXYScatter
Chart1.SeriesCollection.NewSeries
Chart1.SeriesCollection(1).XValues = xrng
Chart1.SeriesCollection(1).Values = yrng
End With
i = i + 1
ITERATE:
If i < l Then
With Chart1
Chart1.SeriesCollection.NewSeries
Chart1.SeriesCollection(i).XValues = x2rng
' pretend the next line is bold
Chart1.SeriesCollection(i).Values = y2rng
x2rng = x2rng.Offset(1, 0)
y2rng = y2rng.Offset(1, 0)
i = i + 1
GoTo ITERATE
End With
End If
If i < k Then
Dim Chart2 As Chart
Set Chart2 = Charts.Add
With Chart2
Chart2.ChartType = xlXYScatter
Chart2.SeriesCollection.NewSeries
Chart2.SeriesCollection(1).XValues = x2rng
Chart2.SeriesCollection(1).Values = y2rng
End With
End If
i2 = i2 + 1
ITERATE2:
If i < k Then
Chart1.SeriesCollection.NewSeries
Chart1.SeriesCollection(i2).XValues = x2rng
Chart1.SeriesCollection(i2).Values = y2rng
x2rng = x2rng.Offset(1, 0)
y2rng = y2rng.Offset(1, 0)
i2 = i2 + 1
GoTo ITERATE2
End If
I am not sure why I am getting this error.
Any help would be appreciated.
Thanks,
Judoo

Excel VBA Code pastes result into wrong range

A script that copies a range into another range. However, when I try to copy the range from Sheet1 to Sheet2 the result won't be pasted into column J, it get pasted with an offset of 8 columns (column R). I cant understand why? Both RowCountSummary and ColumnCountSummary are set to 0, i.e. first index of the range?
Sub InsertForecastData()
Dim ColumnsCount As Integer
Dim ColCounter As Integer
Dim RowsCount As Integer
Dim ForeCastRange As Range
Dim ForecastWS As Worksheet
Dim SummaryWs As Worksheet
Dim PasteRange As Range
Dim ColumnCountSummary As Integer
Dim RowCountSummary As Integer
ColumnsCount = 300
ColCounter = 0
RowsCount1 = 0
RowsCount2 = 47
ColumnCountSummary = 0
RowCountSummary = 0
Do While ColCounter <= ColumnsCount
Worksheets("Sheet1").Select
Set ForeCastRange = Worksheets("Sheet1").Range("B2:KN49")
With ForeCastRange
.Range(.Cells(RowsCount1, ColCounter), .Cells(RowsCount2, ColCounter)).Copy
End With
Worksheets("Sheet2").Select
Set PasteRange = Worksheets("Sheet2").Range("J2:J13915")
With PasteRange
.Range(.Cells(RowCountSummary, ColumnCountSummary), .Cells(RowCountSummary + RowsCount2, ColumnCountSummary)).PasteSpecial
End With
RowCountSummary = RowCountSummary + 48
ColCounter = ColCounter + 1
Loop
End Sub
This behaviour has been encountered before and can seen with this simple demo
Sub test()
With Sheet1.Range("J3:J100")
Debug.Print .Range(.Cells(0, 0), .Cells(47, 0)).Address
End With
End Sub
which results in $R$4:$R$51. If you repeat run for the columns B to J the results are B,D,F,H,J,L,N,P showing the doubling effect. B is OK I think because of the zero column number.
You can probably fix your code by setting RowCountSummary = 1 and ColumnCountSummary = 1 and adding .parent
With PasteRange
.Parent.Range(.Cells(RowCountSummary, ColumnCountSummary), _
.Cells(RowCountSummary + RowsCount2, ColumnCountSummary)).PasteSpecial
End With
or you could try this
Sub InsertForecastData1()
Const columnCount As Integer = 3
Const rowCount As Integer = 48
Const sourceCol As String = "B"
Const targetCol As String = "J"
Const startRow As Integer = 2
Const records As Integer = 300
Dim rngSource as Range, rngTarget As Range
Dim start as Single, finish as Single
Set rngSource = Worksheets("Sheet1").Range(sourceCol & startRow)
Set rngSource = rngSource.Resize(rowCount, columnCount)
Set rngTarget = Worksheets("Sheet2").Range(targetCol & startRow)
start = Timer
Application.ScreenUpdating = False
Dim i As Integer
For i = 1 To records
'Debug.Print rngSource.Address, rngTarget.Address
rngSource.Copy rngTarget
Set rngSource = rngSource.Offset(rowCount, 0)
Set rngTarget = rngTarget.Offset(rowCount, 0)
Next i
Application.ScreenUpdating = True
finish = Timer
MsgBox "Completed " & records & " records in " & finish - start & " secs"
End Sub
See Remarks section the docs

Retrieve Column header depending on values present in an excel worksheet

I have two worksheets ( sheet 1 and sheet 2) . Sheet 1 has 500X500 table. I want to
- Loop through each row ( each cell )
- Identify the cells which have a value ' X' in it
- Pick the respective column header value and store it in a cell in worksheet 2
For example
AA BB CC DD EE FF GG HH
GHS X
FSJ X
FSA X
MSD
SKD
SFJ X X
SFJ
SFM X
MSF X
Is there a way of writing a macro which will pull values in the form of
GHS -> GG
FSJ->DD
.
.
SFJ->BB HH
I have tried looping algorithms but does not seem to work. Could anyone please help me as I am very new to macros.
Try this .. Assumed that GHS, FSJ ... in column A
Sub ColnItem()
Dim x, y, z As Integer
Dim sItem, sCol As String
Dim r As Range
z = 1
For y = 1 To 500
sItem = Cells(y, 1)
sCol = ""
For x = 2 To 500
If UCase(Cells(y, x)) = "X" Then
If Len(sCol) > 0 Then sCol = sCol & " "
sCol = sCol & ColumnName(x)
End If
Next
If Len(sCol) > 0 Then
Sheets("Sheet2").Cells(z, 1) = sItem & " -> " & sCol
z = z + 1
End If
Next
End Sub
Function ColumnName(ByVal nCol As Single) As String
Dim sC As String
Dim nC, nRest, nDivRes As Integer
sC = "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
nC = Len(sC)
nRest = nCol Mod nC
nDivRes = (nCol - nRest) / nC
If nDivRes > 0 Then ColumnName = Mid(sC, nDivRes, 1)
ColumnName = ColumnName & Mid(sC, nRest, 1)
End Function
I have placed the values GG, etc., in separate columns of Sheet2, but the code could be modified to put all the information (for a row) in a single cell.
Sub GetColumnHeadings()
Dim ws1 As Worksheet, ws2 As Worksheet
Dim rng1 As Range, rng2 As Range, rng As Range
Dim off As Integer
Set ws1 = Worksheets("Sheet1")
Set ws2 = Worksheets("Sheet2")
Set rng1 = ws1.Range("A1").CurrentRegion
'CurrentRegion is the Range highlighted when we press Ctrl-A from A1
Set rng2 = ws2.Range("A1")
Application.ScreenUpdating = False
For Each rng In rng1
If rng.Column = 1 Then off = 0
If rng.Value = "X" Then
rng2.Value = rng.EntireRow.Cells(1, 1).Value
off = off + 1
rng2.Offset(0, off).Value = rng.EntireColumn.Cells(1, 1).Value
End If
'if we are looking at the last column of the Sheet1 data, and
'we have put something into the current row of Sheet2, move to
'the next row down (in Sheet2)
If rng.Column = rng1.Column And rng2.Value <> "" Then
Set rng2 = rng2.Offset(1, 0)
End If
Next rng
Application.ScreenUpdating = True
Set rng = Nothing
Set rng2 = Nothing
Set rng1 = Nothing
Set ws2 = Nothing
Set ws1 = Nothing
End Sub
I've also based in on the spreadsheet sample from the original post, where AA appears to be in cell A1.

Resources