Get odd rows in a range using VBA - vba

I need to get every odd row in a range (in my case, the range is RngList) using VBA in Excel.
Here is my code, it comes out a blank chart:
Sub Chart()
Dim myData As String, sh As String
Dim LastRow As Long
Dim Rng As Range
Dim RngList As Range
With ActiveSheet
LastRow = .Range("C" & .Rows.count).End(xlUp).Row - 2
Set RngList = .Range("D1:U" & LastRow & ", C2:C" & LastRow)
Set Rng = RngList(1)
For CurRow = 3 To LastRow - 1 Step 2
Set Rng = Union(Rng, RngList(CurRow))
Next CurRow
End With
sh = ActiveSheet.Name
Charts.Add
ActiveChart.ChartType = xlLine
ActiveChart.SetSourceData Source:=Rng, PlotBy:=xlColumns
ActiveChart.Location Where:=xlLocationAsObject, Name:=sh
ActiveChart.SeriesCollection(1).XValues = Range("C2:C" & LastRow)
With ActiveChart
.HasTitle = True
.ChartTitle.Characters.Text = "PVC MIXER"
.Axes(xlCategory, xlPrimary).HasTitle = True
.Axes(xlCategory, xlPrimary).AxisTitle.Characters.Text = "BATCH NUMBER"
.Axes(xlValue, xlPrimary).HasTitle = True
.Axes(xlValue, xlPrimary).AxisTitle.Characters.Text = "WEIGHT"
End With
ActiveChart.ChartArea.Select
Set Rng = Nothing
Set RngList = Nothing
End Sub

Try this out which worked for me.
Sub marine()
Dim sh As Worksheet: Set sh = ActiveSheet
Dim lr As Long, RngList As Range, rng As Range
With sh
lr = .Range("C" & .Rows.Count).End(xlUp).Row - 2
Set RngList = .Range("C2:C" & lr)
Set rng = RngList(1).Resize(, 19) 'resize until Column U
Dim c As Range
For Each c In RngList
If c.Row Mod 2 = 1 Then
Set rng = Union(rng, c.Resize(, 19))
End If
Next
Dim ch As Chart
Set ch = .Shapes.AddChart2(, xlLine).Chart
With ch
.SetSourceData rng
.HasTitle = True
.ChartTitle.Characters.Text = "PVC MIXER"
.Axes(xlCategory, xlPrimary).HasTitle = True
.Axes(xlCategory, xlPrimary).AxisTitle.Characters.Text = "BATCH NUMBER"
.Axes(xlValue, xlPrimary).HasTitle = True
.Axes(xlValue, xlPrimary).AxisTitle.Characters.Text = "WEIGHT"
End With
End With
End Sub

I think you need to allow for a null range to begin with:
With ActiveSheet
LastRow = .Range("C" & .Rows.Count).End(xlUp).Row - 2
Set RngList = .Range("D1:U" & LastRow & ", C2:C" & LastRow)
Set rng = RngList(1)
For CurRow = 3 To LastRow - 1 Step 2
If Not rng Is Nothing Then
Set rng = Union(rng, RngList(CurRow))
Else
Set rng = RngList(CurRow)
End If
Next CurRow
End With

Related

Ways to improve macros execution time

I have created a macro, which runs fine but, for no reason I can explain, takes so long to finish. I have tried running the macro line to line and cannot figure out which part of the process takes so long. I can only imagine that it is the part where I delete rows based on backround color. I have built several macros with similar lines of code and the performance was way better.
Sub Pharma_Stock_Report()
Application.ScreenUpdating = False
Application.EnableEvents = False
Application.DisplayAlerts = False
Application.Calculation = xlCalculationManual
Dim ws1 As Worksheet
Dim ws2 As Worksheet
Dim ws3 As Worksheet
Dim lastrow1 As Long
Dim lastrow2 As Long
Dim lastrow3 As Long
Dim cell As Range
Dim DeleteRange As Range
spath1 = Application.ThisWorkbook.Path & "\Pharma replenishment.xlsm"
spath2 = Application.ThisWorkbook.Path & "\NOT OK.xlsx"
Workbooks.Open spath1
Workbooks.Open spath2
Set ws1 = Workbooks("Pharma Stock Report.xlsm").Worksheets("Pharma Stock Report")
Set ws2 = Workbooks("Pharma replenishment.xlsm").Worksheets("Replenishment")
Set ws3 = Workbooks("NOT OK.xlsx").Worksheets("Sheet1")
ws1.Cells.Clear
lastrow1 = ws2.Range("A" & Rows.Count).End(xlUp).Row
ws2.Range("A4:G" & lastrow1).Copy
With ws1.Range("A1")
.PasteSpecial xlPasteColumnWidths
.PasteSpecial xlPasteValues, , False, False
.PasteSpecial xlPasteFormats, , False, False
End With
Application.CutCopyMode = False
Workbooks("Pharma replenishment.xlsm").Close
lastrow2 = ws1.Range("A" & Rows.Count).End(xlUp).Row
For Each cell In ws1.Range("D2:D" & lastrow2)
If Not cell.Interior.ColorIndex = 2 Or cell.Interior.ColorIndex = -4142 Then
If DeleteRange Is Nothing Then
Set DeleteRange = cell
Else
Set DeleteRange = Union(DeleteRange, cell)
End If
End If
Next cell
If Not DeleteRange Is Nothing Then DeleteRange.EntireRow.Delete
ws3.Range("H1:J1").Copy
With ws1.Range("H1")
.PasteSpecial xlPasteColumnWidths
.PasteSpecial xlPasteValues, , False, False
.PasteSpecial xlPasteFormats, , False, False
End With
lastrow3 = ws1.Range("D" & Rows.Count).End(xlUp).Row
ws1.Range("H2:H" & lastrow3).Formula = "=IFERROR(VLOOKUP(C2,'[NOT OK.xlsx]Sheet1'!F:H,3,FALSE),"""")"
With Range("H2:H" & lastrow3)
.Value = .Value
.NumberFormat = "dd/mm/yyyy"
End With
ws1.Range("I2:I" & lastrow3).Formula = "=IFERROR(VLOOKUP(C2,'[NOT OK.xlsx]Sheet1'!F:I,4,FALSE),"""")"
With Range("I2:I" & lastrow3)
.Value = .Value
.NumberFormat = "dd/mm/yyyy"
End With
ws1.Range("J2:J" & lastrow3).Formula = "=IFERROR(VLOOKUP(C2,'[NOT OK.xlsx]Sheet1'!F:J,5,FALSE),"""")"
With Range("J2:J" & lastrow3)
.Value = .Value
.NumberFormat = "dd/mm/yyyy"
End With
Application.CutCopyMode = False
Workbooks("NOT OK.xlsx").Close
Application.ScreenUpdating = True
Application.EnableEvents = True
Application.DisplayAlerts = True
Application.Calculation = xlCalculationAutomatic
End Sub

Exclude certain columns form range

Having trouble coding a macro in vba to exclude certain columns from being included in a chart. I want to exclude Column F from being included. Here is my code from a recoreded macro that I tweaked a bit:
Sub Macro4()
Dim ws As Worksheet
Dim wb As Workbook
Set wb = ThisWorkbook
Set ws = wb.Sheets("Sheet1")
ActiveSheet.Shapes.AddChart2(251, xlBarClustered).Select
ActiveChart.SetSourceData Source:=ws.Range("E" & ActiveCell.Row & ":F" & ActiveCell.Row & ":G" & ActiveCell.Row & ":H" & ActiveCell.Row)
ActiveChart.FullSeriesCollection(1).XValues = "=Sheet1!$E$9:$H$9"
ActiveChart.SetElement (msoElementDataLabelOutSideEnd)
ActiveChart.SetElement (msoElementPrimaryCategoryGridLinesNone)
ActiveChart.Axes(xlValue).MajorGridlines.Format.Line.Visible = msoFalse
ActiveChart.FullSeriesCollection(1).DataLabels.ShowCategoryName = False
With ActiveChart
.HasTitle = True
.ChartTitle.Characters.Text = "Analysis for " & ws.Range("C" & ActiveCell.Row)
ActiveChart.HasAxis(xlValue) = False
ActiveChart.HasLegend = False
End With
End Sub
Try the following, you use "," to delimit non-consecutive ranges:
ActiveChart.SetSourceData Source:=ws.Range("Sheet1!$E$" & ActiveCell.Row & ",Sheet1!$G$" & ActiveCell.Row & ",Sheet1!$H$" & ActiveCell.Row)
ActiveChart.FullSeriesCollection(1).XValues = "=Sheet1!$E$9,Sheet1!$G$9,Sheet1!$H$9"
This should exclude F from your chart.
Edit:
To create your chart only using data from the active row, you can try:
Sub Macro4()
Dim wb As Workbook: Set wb = ThisWorkbook
Dim ws As Worksheet: Set ws = wb.Sheets("Sheet1")
ws.Activate
Dim MyRange1 As Range: Set MyRange1 = Range("E" & ActiveCell.Row)
Dim MyRange2 As Range: Set MyRange2 = Range(Cells(ActiveCell.Row, "G"), Cells(ActiveCell.Row, "H"))
Dim MyChartRange As Range: Set MyChartRange = Union(MyRange1, MyRange2)
ActiveSheet.Shapes.AddChart2(251, xlBarClustered).Select
ActiveChart.SetSourceData Source:=MyChartRange
ActiveChart.FullSeriesCollection(1).XValues = "=Sheet1!$E$9:$H$9"
ActiveChart.SetElement (msoElementDataLabelOutSideEnd)
ActiveChart.SetElement (msoElementPrimaryCategoryGridLinesNone)
ActiveChart.Axes(xlValue).MajorGridlines.Format.Line.Visible = msoFalse
ActiveChart.FullSeriesCollection(1).DataLabels.ShowCategoryName = False
With ActiveChart
.HasTitle = True
.ChartTitle.Characters.Text = "Analysis for " & ws.Range("C" & ActiveCell.Row)
ActiveChart.HasAxis(xlValue) = False
ActiveChart.HasLegend = False
End With
End Sub

Adding a pivot table to a new sheet with data on the same sheet

My code creates a new sheet as per below code which is ws2 where I have a table extracted from ws1. I want to place a pivot table on the same sheet ws2 in cell "L4" as per bottom part of the code, but it would not work.
Sub ClickThisMacro()
Dim i As Long
Dim y As Long
Dim n As Long
Dim ws1 As Worksheet: Set ws1 = ThisWorkbook.Sheets("Report")
Dim ws2 As Worksheet: Set ws2 = Sheets.Add
Set rng1 = ws1.Range("A:A").Find("Name")
fr = rng1.Row
lr = ws1.Range("B" & Rows.Count).End(xlUp).Row
y = 2
For i = fr + 1 To lr
ws2.Cells(y, 1) = ws1.Cells(i, 1)
ws2.Cells(y, 2) = ws1.Cells(i, 2)
ws2.Cells(y, 3) = ws1.Cells(i, 3)
ws2.Cells(y, 4) = ws1.Cells(i, 4)
ws2.Cells(y, 5) = ws1.Cells(i, 18)
y = y + 1
Next i
ws2.Cells(1, 1) = "Cost centre name"
ws2.Cells(1, 2) = "Cost centre code"
ws2.Cells(1, 3) = "Phone number"
ws2.Cells(1, 4) = "User name"
ws2.Cells(1, 5) = "Amount"
LastRow = ws2.Range("A1").End(xlDown).Row
' making columns C and F numbers
ws2.Range("C2:C" & LastRow).Select
For Each xCell In Selection
xCell.Value = xCell.Value
Next xCell
With ws2.UsedRange.Columns(5)
.Replace "£", "", xlPart
.NumberFormat = "#,##0.00"
.Formula = .Value
End With
With ws2.UsedRange.Columns(8)
.Replace "£", "", xlPart
.NumberFormat = "#,##0.00"
.Formula = .Value
End With
'Pivot table
Dim mypivot As PivotTable
Dim mycache As PivotCache
Set mycache = ws2.PivotCaches.Create(xlDatabase, Range("a1").CurrentRegion)
Set mypivot = ws2.PivotTables.Add(mycache.Range("l4"), "Mypivot1")
mypivot.PivotFields("Cost centre name").Orientation = xlRowField
mypivot.PivotFields("Cost centre code").Orientation = xlColumnField
mypivot.PivotFields("Amount").Orientation = xlDataField
End Sub
You have a few syntax errors in your code at the section where you set your PivotCache and PivotTable objects.
Modified code (Pivot-Table section)
' set the Pivot-Cache
Set mycache = ThisWorkbook.PivotCaches.Create(SourceType:=xlDatabase, SourceData:=ws2.Range("A1").CurrentRegion.Address(False, False, xlA1, xlExternal))
' set the Pivot-Table object
Set mypivot = ws2.PivotTables.Add(PivotCache:=mycache, TableDestination:=ws2.Range("L4"), TableName:="Mypivot1")
With mypivot
.PivotFields("Cost centre name").Orientation = xlRowField
.PivotFields("Cost centre code").Orientation = xlColumnField
.PivotFields("Amount").Orientation = xlDataField
End With
Some Other modifications/suggestions you should add to your code:
Using Find you should handle a scenario (even though unlikely) that you won't find the term you are looking for, in that case if Rng1 = Nothing then fr = Rng1.Row will result with a run-time error.
Dealing with Find code:
Set Rng1 = ws1.Range("A:A").Find("Name")
If Not Rng1 Is Nothing Then ' confirm Find was successfull
fr = Rng1.Row
Else ' if Find fails
MsgBox "Critical Error, couldn't find 'Name' in column A", vbCritical
Exit Sub
End If
You should avoid using Select and Selection, you can use fully qualified Range object instead:
Looping through a Range:
For Each xCell In ws2.Range("C2:C" & lr)
xCell.Value = xCell.Value
Next xCell

Excel-VBA: Error 438 on Adding Values to Series in Chart Sheet, Excel 2010

I'm trying to put together some code that collects a set of data from a worksheet and then generates an XY Scatter plot. Whenever it reaches the line for inputting values into the series, it produces a "Runtime Error 438: Object doesn't support this property or method."
xDataRng.Address has a value of "$C$8:$C$11"
I'm using Excel 2010 on Win 7.
I've looked up every article and help thread I could find about this issue. Am I using .SeriesCollection.XValues incorrectly? How can I fix it?
Thanks,
Eeshwar
Sub createChart()
Set wb = ThisWorkbook
Dim sheetName As Variant, chartName As Variant
sheetName = ActiveSheet.Name
'Find x-axis data
Dim xnameRng As Range, xdataRng As Range
Dim lastCol As Long, lastRow As Long
Dim i As Integer
With ActiveSheet
lastCol = .Cells(7, .Columns.Count).End(xlToLeft).Column
Set xnameRng = .Range(Cells(7, 2), Cells(7, lastCol)).Find("Horizontal Position (", lookat:=xlPart)
lastRow = .Cells(.Rows.Count, xnameRng.Column).End(xlUp).Row
Set xdataRng = .Range(xnameRng.Offset(1, 0).Address, Cells(lastRow, xnameRng.Column))
End With
'Find y-axis data
Dim ynameRng As Range, ydataRng As Range
With ActiveSheet
Set ynameRng = .Range(.Cells(7, 2), .Cells(7, lastCol)).Find("Pressure (", lookat:=xlPart)
Set ydataRng = .Range(ynameRng.Offset(1, 0).Address, .Cells(lastRow, ynameRng.Column))
End With
'Create chart
With wb.Sheets("Chart_Template")
.Copy After:=Sheets(sheetName)
chartName = ActiveChart.Name
'Update chart details
With wb.Sheets(chartName)
.SeriesCollection.NewSeries
.SeriesCollection.XValues(1) = wb.Sheets(sheetName).Range(xdataRng.Address) FAILS HERE
.SeriesCollection.Values(1) = wb.Sheets(sheetName).Range(ydataRng.Address)
.Axes(xlCategory, xlPrimary).HasTitle = True
.Axes(xlCategory, xlPrimary).Character.Text = xnameRng.Value
.Axes(xlValue, xlPrimary).HasTitle = True
.Axes(xlValue, xlPrimary).Character.Text = ynameRng.Value
End With
End With
End Sub
Try the section of code below to replace yours:
With wb.Sheets(chartName)
Dim Ser As Series
Set Ser = .SeriesCollection.NewSeries
With Ser
.XValues = "=" & xDataRng.Address(True, True, xlA1, xlExternal)
.Values = "=" & yDataRng.Address(True, True, xlA1, xlExternal)
End With
.Axes(xlCategory, xlPrimary).HasTitle = True
.Axes(xlCategory, xlPrimary).Character.Text = xnameRng.Value
.Axes(xlValue, xlPrimary).HasTitle = True
.Axes(xlValue, xlPrimary).Character.Text = ynameRng.Value
End With

Can not stop the loop of importing rows from a sheet to another

I have a problem in the loop. I want to import lines that contain "X" in their first cell but :
It doesn't paste them from the first row
It pastes them too many times
Can someone help me ?
Sub refresh()
'
' refresh Macro
'
' Touche de raccourci du clavier: Ctrl+y
'
Dim LastRow As Integer, i As Integer
Dim wksSrc As Worksheet, wksDest As Worksheet
Dim lngRow As Long
Set wksSrc = ThisWorkbook.Worksheets("Scénarios de menace")
Set wksDest = ThisWorkbook.Worksheets("Analyse de risque S")
Application.Calculation = xlAutomatic
Application.DisplayAlerts = False
wksDest.Range("A6:AP1000").Delete
Application.DisplayAlerts = True
wksDest.Range("A6:AP1000").ClearContents 'Works directly, without selection
lngRow = wksDest.Cells(wksDest.Rows.Count, 2).End(xlUp).Row + 1
For i = 2 To wksSrc.Range("A" & wksSrc.Rows.Count).End(xlUp).Row
If wksSrc.Cells(i, 1) = "X" Then
wksSrc.Range(wksSrc.Cells(i, 2), wksSrc.Cells(i, 20)).Copy
wksDest.Range("B" & lngRow).PasteSpecial xlPasteValuesAndNumberFormats
Application.CutCopyMode = False
lngRow = lngRow + 1
End If
Next i
End Sub
sub refresh()
Dim LastRow As Integer, i As Integer
Dim wksSrc As Worksheet, wksDest As Worksheet
Dim lngRow As Long
Set wksSrc = ThisWorkbook.Worksheets("Scénarios de menace")
Set wksDest = ThisWorkbook.Worksheets("Analyse de risque S")
wksDest.Range("A6:AP1000").Delete
wksDest.Range("A6:AP1000").ClearContents 'Works directly, without selection
lngRow = 6
LastRow = wksSrc.Range("A" & wksSrc.Rows.Count).End(xlUp).Row
For i = 2 To LastRow
If wksSrc.Cells(i, 1) = "X" Then
wksSrc.Range(wksSrc.Cells(i, 2), wksSrc.Cells(i, 20)).Copy
wksDest.Range("B" & lngRow).PasteSpecial xlPasteValuesAndNumberFormats
Application.CutCopyMode = False
lngRow = lngRow + 1
End If
Next i
end sub
This version is optimized (not using a For loop)
Option Explicit
Public Sub refreshAnalyse()
Dim ws1 As Worksheet, ws2 As Worksheet, lr1 As Long
Set ws1 = ThisWorkbook.Worksheets("Scénarios de menace")
Set ws2 = ThisWorkbook.Worksheets("Analyse de risque S")
ws2.Range("B6:AP" & ws2.Cells(ws2.Rows.Count, 2).End(xlUp).Row).Clear
lr1 = ws1.Cells(ws1.Rows.Count, 2).End(xlUp).Row
Application.ScreenUpdating = False
ws1.Range("A1:A" & lr1).AutoFilter Field:=1, Criteria1:="x"
ws1.Range("B2:AP" & lr1).SpecialCells(xlCellTypeVisible).Copy
ws2.Range("B6").PasteSpecial Paste:=xlPasteValuesAndNumberFormats
ws1.Range("A6:A" & lr1).AutoFilter
ws2.Activate: ws2.Cells(1, 1).Activate
Application.ScreenUpdating = True
End Sub