Excel VBA: Programmatically setting X,Y,Z values for chart generation - vba

The following code succesfully generates an XY scatter plot with dynamically changing ranges. However, the hurdle I can't get over is how to programmatically set the x,y,z values for the scatterplot to generate a bubble chart. I've made attempt at doing so(as you can see in the code) but it doesn't work.
Any helps is appreciated
dim a as long
dim b as long
dim i as long
dim m as long
dim j as long
For i = 2 To lastrow
If Cells(i, "A") = "Regression #" & m & " Output" Then
a = i 'save regression #1 row number, where it begins
For j = 2 To a
If Cells(j, "A") = "Regression #" & m + 1 & " Output" Then
b = j
End If
Next j
Set rngx = Range(Cells(b + 1, 2), Cells(a - 1, 2))
Set rngy = Range(Cells(b + 1, 7), Cells(a - 1, 7))
Set rngz = Range(Cells(b + 1, 8), Cells(a - 1, 8))
Sheets("Chart Table").Shapes.AddChart.Select
ActiveChart.ChartType = xlBubble
ActiveChart.SetSourceData Source:=Union(rngx, rngy, rngz)
With ActiveChart.SeriesCollection.NewSeries
'.Name = ActiveSheet.Range("B2:B13")
.value = rngy
.xvalues = rngx
.BubbleSizes = rngz
End With
With ActiveChart
.SetElement (msoElementChartTitleAboveChart)
.Legend.Delete
.ChartTitle.Select
.ChartTitle.Text = Cells(a, 1).Value
End With
Else
End If
Next i
For example, if I have just one row of data(one x, one y, one z) - then I want Excel to know that it means there's only one bubble. Right now it reads it as 3 separate bubbles, disregarding the fact there's a bubble sizing element

If the union of rngx, rngy, and rngz is a contiguous range, it works fine. Since these ranges are separated by several columns, your SetSourceData command is incomplete, and treats their union as a set of Y values, and uses the default (1, 2, 3) as X values and (1, 1, 1) as bubble sizes.
However, this small change fixes your code:
ActiveChart.SetSourceData Source:=Union(rngx, rngy, rngz), PlotBy:=xlColumns

Related

Excel reporting - function hlookup doesn't work in nested for loop

I've got a problem. I' m trying to match specific values by item_id using hlookup function. But this function does not return specified value.
Here is the code of my macro :
Sub create_report()
Dim itemWs As Worksheet, offerWs As Worksheet, testWs As Worksheet
Dim itemLastRow As Long, offerLastRow As Long
Dim offerLastCol As Long, itemLastCol As Long
Dim dataRng As Range
Set itemWs = ThisWorkbook.Worksheets("nn_rfx_compare_per_lot")
Set offerWs = ThisWorkbook.Worksheets("Offers")
Set testWs = ThisWorkbook.Worksheets("Testowy")
itemLastRow = itemWs.Range("A" & Rows.Count).End(xlUp).Row
offerLastRow = offerWs.Range("A" & Rows.Count).End(xlUp).Row
offerLastCol = offerWs.Cells(1, Columns.Count).End(xlToLeft).Column
itemLastCol = itemWs.Cells(1, Columns.Count).End(xlToLeft).Column
Set dataRng = testWs.Range("I3:AF" & 4)
'For x = 2 To 7
'On Error Resume Next
'itemWs.Range("I" & x).Value = Application.WorksheetFunction.VLookup(itemWs.Range("C" & x).Value & itemWs.Range("B" & x).Value, dataRng, 3, 0)
'Next x
Sheets("Testowy").Range(Sheets("Testowy").Cells(offerLastCol - 1, 1), Sheets("Testowy").Cells(itemLastRow + 4, itemLastCol)) = _
Sheets("nn_rfx_compare_per_lot").Range(Sheets("nn_rfx_compare_per_lot").Cells(1, 1), Sheets("nn_rfx_compare_per_lot").Cells(itemLastRow, itemLastCol)).Value
Sheets("Testowy").Range(Sheets("Testowy").Cells(1, itemLastCol), Sheets("Testowy").Cells(offerLastCol - 2, offerLastRow - 2)) = _
WorksheetFunction.Transpose(Sheets("Offers").Range(Sheets("Offers").Cells(1, 2), Sheets("Offers").Cells(offerLastRow, offerLastCol - 1)))
Dim lastTestCol As Long
lastTestCol = testWs.Cells(1, Columns.Count).End(xlToLeft).Column
Dim ColumnLetter As String
For Row = 6 To 11
For Col = 9 To lastTestCol
On Error Resume Next
testWs.Cells(Row, Col).Value = Application.WorksheetFunction.Index(testWs.Range( _
"I4:AF4"), WorksheetFunction.Match(testWs.Cells(Row, 3).Value, testWs.Cells(3, Col), 0))
'Match(testWs.Cells(Row, 3), dataRng, 1)
'HLookup(testWs.Cells(Row, 3), dataRng, 2, 0)
Next Col
Next Row
End Sub
In this link there is shown a report which I'd like to organise
enter image description here
The task and conditions are not completely clear (what to do with duplicates, whether they can occur, whether item_id is unique and so on).
If, for example, you need to select sup_id corresponding to item_id, it can be done by the following code:
Set item_id_rng = testWS.Range("I3:AF3")
For Row = 6 To 11
' search `item_id` in Range("I3:AF3")
find_col = Application.Match(testWS.Cells(Row, 3).Value, item_id_rng, 0)
If IsNumeric(find_col) Then ' if found, get correspondent value from correspondent row
'output to 9 column (empty area), for example
testWS.Cells(Row, 9).Value = item_id_rng(1).Offset(-1, find_col - 1)
End If
Next Row
As for the task as a whole, it would be good if you formulated the conditions of the task and placed an image of the result

vba use linest to calculate polynomial coefficients and index to output

I have two rows of data, fracture pressure and depth. I have to code in vba to generate the polynomial (quadratic for this case) equation and then output the coefficients to the worksheet. I am using Linest and Index. For this two rows of data, I don't know how many datasets I have because I need to delete some noisy data first (the definition of noisy data is randomly so the number of datasets vary each time), so I can't use something like "A17:A80" in the linest function. However, it looks like the worksheet function in vba can't work for arrays.
Dim Frac_x, Frac_y As Range
Dim X
Set Frac_x = Range(Cells(17, 1), Cells(e - 1, 1))
Set Frac_y = Range(Cells(17, 7), Cells(e - 1, 7))
X= Application.WorksheetFunction.LinEst(Frac_y,Frac_x,{1,2})
Cells(3, 8).Value = Application.WorksheetFunction.Index(X, 1, 1)
Cells(4, 8).Value = Application.WorksheetFunction.Index(X, 1, 2)
Cells(5, 8).Value = Application.WorksheetFunction.Index(X, 1, 3)
In this code, e is defined in the previous code, (e-1) represents the total number of datasets. However, I keep getting { is a invalid character for the line: X= Application.WorksheetFunction.LinEst(Frac_y,Frac_x,{1,2})
Then I did some researches and modified the code to:
Dim Frac_x, Frac_y As Range
Dim X
Set Frac_x = Range(Cells(17, 1), Cells(e - 1, 1))
Set Frac_y = Range(Cells(17, 7), Cells(e - 1, 7))
X = Application.Evaluate("=linest(" & Frac_y & "," & Frac_x & "^ {1,2}))")
Cells(3, 8).Value = Application.WorksheetFunction.Index(X, 1, 1)
Cells(4, 8).Value = Application.WorksheetFunction.Index(X, 1, 2)
Cells(5, 8).Value = Application.WorksheetFunction.Index(X, 1, 3)
Then I keep getting Type Dismatch error for the line:
X = Application.Evaluate("=linest(" & Frac_y & "," & Frac_x & "^ {1,2}))")
I am sure the two ranges frac_y and frac_x their type matches. Anyone could help?
You are right, that Excel VBA can't do things like arrVariable^{1,2}. That must be done with loops over the array items.
But the Evaluate approach should work. But your formula string is not correct. To detect and avoid such incorrectness, I will ever concatenate such formula strings within a String variable first. Then I can simply check the variable's value.
Example, Values are in A17:A26 and G17:G26:
Sub test()
Dim Frac_x As Range, Frac_y As Range
Dim X
e = 27
With ActiveSheet
Set Frac_x = .Range(.Cells(17, 1), .Cells(e - 1, 1))
Set Frac_y = .Range(.Cells(17, 7), .Cells(e - 1, 7))
arrX = Frac_x
ReDim arrX2(1 To UBound(arrX), 1 To 2) As Double
For i = LBound(arrX) To UBound(arrX)
arrX2(i, 1) = arrX(i, 1)
arrX2(i, 2) = arrX(i, 1) * arrX(i, 1)
Next
X = Application.LinEst(Frac_y, arrX2)
'sFormula = "=LINEST(" & Frac_y.Address & "," & Frac_x.Address & "^{1,2})"
'X = Application.Evaluate(sFormula)
.Range(.Cells(3, 8), .Cells(5, 8)).Value = Application.Transpose(X)
End With
End Sub
Hints: Use Application.LinEst instead of Application.WorksheetFunction.LinEst. The latter will throw an error if the function cannot work while the first will return an error value instead. So the first will not interrupt the program as the latter will do.

Run brute force on a column to identify if the values cross over a point using VBA

I am wondering how I can write a VBA code to check if my data crosses over a certain point of interest. I have a column of approx. 40,000 data points that linearly increase and decrease (i.e 0 to 10 and then back down from 10 to 0). I want to identify when the points cross over a value and perform interpolation on corresponding data values. For example, I would like to write a code that will pick every time my data set crosses 4.1, and perform interpolation on the corresponding cell values in another column.
This is what I have tried so far
'Calculate how many data points are present in worksheet
Dim lastRow As Long
lastRow = Range("B" & Rows.Count).End(xlUp).Row
'Identify the data colum as pot1 throughout code
Set pot1 = Range("N14:N" & lastRow)
Dim i As Integer
'data starts from line 14 of worksheet
For i = 14 To lastRow
'check to see if the cell above contains text, if it does, line a tells it to skip that cell and move to next one
If WorksheetFunction.IsNumber(Cells(i - 1, 2)) = False Then GoTo a
a:
i = i + 1
GoTo b
'check if two vertically adjacent cells have crossed over 4.1
b:
If Cells(i, 2) > 3.995 & Cells(i + 1, 2) < 4.01 Then
' interpolate the value if they have crossed 4.1
Range("S1")=WorksheetFunction.Forecast(4.1, Cells(i:i+1,2), Range("D" i ":D" i+1)
I am stuck at using forecast function as I currently don't know how I can tell excel to pick a block of cells inside a loop.
Here's how you would do the looping:
Sub Tester()
Dim sht As Worksheet, lastRow As Long, xvals, yvals, r As Long
Dim th As Double, y1, y2, x1, x2
Set sht = ActiveSheet
lastRow = sht.Range("B" & Rows.Count).End(xlUp).Row
'assumes y vals in "B" and x vals in "N"
'adjust as rtequired...
yvals = sht.Range(sht.Cells(14, "B"), sht.Cells(lastRow, "B"))
xvals = sht.Range(sht.Cells(14, "N"), sht.Cells(lastRow, "N"))
th = 4.1
For r = 1 To UBound(yvals) - 1
y1 = yvals(r, 1)
y2 = yvals(r + 1, 1)
'pair of points crosses the threshold?
If IsNumeric(y1) And IsNumeric(y2) Then
If (y1 < th And y2 > th) Or (y1 > th And y2 < th) Then
x1 = xvals(r, 1)
x2 = xvals(r + 1, 1)
'*************
'calculate the intercept
'*************
End If
End If
Next r
End Sub
First of all, you forgot & in your forecast formula :
Range("S1")=Worksheetfunction.Forecast(4.1, , Range("D" & i ":D" & i+1)
Secondly, Forecast function requires three arguments - you only provide two of them. Please take a look here for more info on Forecast function.
There are a few problems with this statement:
Range("S1")=WorksheetFunction.Forecast(4.1, Cells(i:i+1,2), Range("D" i ":D" i+1)
The main problem is you are calling the ranges wrong
Cells(i:i+1,2)
Should be:
Range(Cells(i,2),Cells(i+1,2))
or
Range("B" & i & ":B" & i + 1)
See above for why Range("D" i ":D" i+1) is also wrong.
You also are missing a ')' At the end of the statement.
So Adding it all together:
Range("S1")=WorksheetFunction.Forecast(4.1, Range("B" & i & ":B" & i + 1), Range("D" & i & ":D" & i+1))

Referencing worksheets to draw data

I am writing a vba macro to allow me to reference data from a worksheet and summarize some of the data rather than using a ton of formulas to do so.
I am having difficulties in referencing worksheets and have reverted to activating sheets. I'm not sure what I am doing incorrectly. For example:
Sheets("Rainfall").Activate
Set x = Range(Range("C2"), Range("C2").End(xlDown))
rather than
Set x = Sheets("Rainfall").Range(Range("C2"), Range("C2").End(xlDown))
When I attempt to reference code such as
Cells(2 + j, 3) = Application.WorksheetFunction.VLookup(Cells(2 + j, 2), Worksheets("Raw Data").Range(Range("C4"), Range("H4").End(xlDown)), 6, False)
I get a 1004 error. Below is my code and if anyone has any suggestions on the simplification of the code that would be great as well.
Sub selectall()
Dim x, y As Range
Dim nv, rd As Long
Set Wkb = Workbooks("DWH Calculations V1.xlsm")
Sheets("Rainfall").Activate
Set x = Range(Range("C2"), Range("C2").End(xlDown))
nv = x.Rows.Count
'MsgBox (nv)
Sheets("Raw Data").Activate
Set y = Range(Range("E4"), Range("E4").End(xlDown))
rd = y.Rows.Count
'MsgBox (rd)
MinD = Round(Application.WorksheetFunction.Min(y), 0)
MaxD = Round(Application.WorksheetFunction.Max(y), 0)
Ndays = MaxD - MinD
'MsgBox (Ndays)
Sheets("Rainfall").Activate
Cells(2, 2) = MinD
For j = 1 To Ndays - 1
Cells(2 + j, 2) = Cells(1 + j, 2) + 1
Cells(2 + j, 3) = Application.WorksheetFunction.VLookup(Cells(2 + j, 2), Worksheets("Raw Data").Range(Range("C4"), Range("H4").End(xlDown)), 6, False)
Next j
End Sub
Thank you all for your help
This has been asked many times before - you need to qualify all the Range calls with a worksheet object, so:
Set x = Sheets("Rainfall").Range(Sheets("Rainfall").Range("C2"), Sheets("Rainfall").Range("C2").End(xlDown))
or use a With...End With block:
With Sheets("Rainfall")
Set x = .Range(.Range("C2"), .Range("C2").End(xlDown))
End With
and note the periods before all three Range calls. You can also use a Worksheet variable:
Dim ws as Worksheet
Set ws = Sheets("Rainfall")
Set x = ws.Range(ws.Range("C2"), ws.Range("C2").End(xlDown))
The problem is the range-within-range:
replace:
Set x = Range(Range("C2"), Range("C2").End(xlDown))
with:
With Sheets("Rainfall")
Set x = .Range(.Range("C2"), .Range("C2").End(xlDown))
End With
Activate is not needed to Set ranges.

Scatter plot code outputting too many series Excel VBA

I'm VERY new to VBA. I'm trying to write a code that will output 33 series. The x-values for the first series are in column A and the y-values for the first series are in column C. Then D and F. Then G and I....and so on. (So basically the x-values and y-values are every third column starting from A and C respectively). The values are in rows 2 to 25.
Also the name for each series is in the first row, every third column starting with 2.
The first 33 data points come out OK, but it continues on to produce a bunch on unintended data points. Is there a problem with my loop? Like I said I'm pretty new so it could be something super obvious. Thanks!
Here's my code:
Sub Scatter
Dim i As Int
Dim name As String
ActiveSheet.Shapes.AddChart.Select
ActiveChart.ChartType = xlXYScatterLinesNoMarkers
For i = 1 To 33
name = Cells(1, 3 * i - 1)
ActiveChart.SeriesCollection.NewSeries
ActiveChart.SeriesCollection(i).name = name
With Worksheets("Sheet1")
ActiveSheet.SeriesCollection(i).XValues = .range(.Cells(2, 3 * i - 2), .Cells(25, 3 * i - 2))
ActiveSheet.SeriesCollection(i).Values = .range(.Cells(2, 3 * i), .Cells(25, 3 * i))
End With
Next i
End Sub
Sub Scatter()
Dim i As Integer
Dim cht As Chart, sht As Worksheet
Set sht = ActiveSheet
Set cht = sht.Shapes.AddChart().Chart
cht.ChartType = xlXYScatterLinesNoMarkers
For i = 1 To 33
With cht.SeriesCollection.NewSeries()
.Name = sht.Cells(1, (3 * i) - 1)
.XValues = sht.Range(sht.Cells(2, (3 * i) - 2), sht.Cells(25, (3 * i) - 2))
.Values = sht.Range(sht.Cells(2, 3 * i), sht.Cells(25, 3 * i))
End With
Next i
End Sub