Repeated calls of Chart.SetSourceData give error 1004 - vba

I have a problem with an application that was created in Excel 2003 in my company. The application retrieves data from a source and updates a Chart using the SetSourceData in a VBA routine passing a Range containing the cells where the relevant data is written.
The application runs just fine in Office 2003, but when the application is executed in Office 2010 it gives this error:
Run-time error '1004': Method 'SetSourceData' of object'_Chart' failed.
I have created a For loop in a simple Excel file in Office 2010 and depending on the number of columns passed in the Range to the Chart the error will come up sooner or later. The more columns passed in the Range the sooner it will come up. I guess this has to be related with the number of series in the Chart(more columns more series).
Is this some sort of mechanism/buffer in the Chart Object or Series implemented in Office 2010 that did not exist in Office 2003? The same For loop never shows a problem when it is run in Office 2003 and I am not sure how to solve this problem.
So far I have only been able to delete all the Series controlling the Error with a Goto instruction to delete all the series in the SeriesCollection using a For Each loop to select all the objects in the SeriesCollection of the Chart. If I do this and resume the execution of the application when I pass the Range again all the data is painted in the Chart Object properly.
Example to reproduce the error. The following code is to be put in a VBA module in a new Excel 2010 workbook. Run the Sub setDataChart and the application will run until the error message is displayed.
Sub setDataChart()
Call createAColValues
ActiveSheet.Shapes.AddChart.Select
ActiveChart.ChartType = xlXYScatterSmoothNoMarkers
ActiveChart.SetSourceData Source:=Range("A1:FA6"), PlotBy:=xlColumns
ActiveSheet.ChartObjects(1).Activate
With ActiveChart.Parent
.Height = 325
.Width = 900
.Top = 120
.Left = 10
End With
Call updateValues
Call sendData
End Sub
Sub sendData()
Dim cht As ChartObject
Set cht = ActiveSheet.ChartObjects(1)
'On Error GoTo delSeries:
For i = 0 To 1000
cht.Chart.SetSourceData Source:=ActiveSheet.Range("A1:FA6"), PlotBy:=xlColumns
Next i
End Sub
Sub createAColValues()
Range("A1").Select
ActiveCell.FormulaR1C1 = "1"
Range("A2").Select
ActiveCell.FormulaR1C1 = "2"
Range("A1:A2").Select
Selection.AutoFill Destination:=Range("A1:A6"), Type:=xlFillDefault
Range("A1:A6").Select
End Sub
Sub updateValues()
Range("B1").Select
ActiveCell.FormulaR1C1 = "=RANDBETWEEN(0,10)"
Range("B1").Select
Selection.AutoFill Destination:=Range("B1:B6"), Type:=xlFillDefault
Range("B1:B6").Select
Selection.AutoFill Destination:=Range("B1:FA6"), Type:=xlFillDefault
Range("B1:FA6").Select
End Sub

This doesn't address why the error occurs. This is a workaround.
Before calling SetSourceData, delete all the existing series currently in the chart, and the code will run as expected.
For j = cht.Chart.SeriesCollection.Count To 1 Step -1
cht.Chart.SeriesCollection(j).Delete
Next j
I'm not sure why the error occurs in the first place, but this makes it go away.

Another possibility is to define a named range for the data that's defined using the Offset formula and appropriate reference cells. This requires the data to be contiguous, not change the initial row & column it begins in, and for you to setup at least one reference formula (=COUNTA() on the column/row containing the data) that can be used to set the height/width of the offset range.
Otherwise a very handy little work around to take this out of macros and put it in worksheet logic.

Related

Run-time error 1004 with Range.Autofilter in Excel VBA 2016

My code is
With ActiveSheet
.AutoFilterMode = False
.Range("23:23").AutoFilter
End With
This works fine in Excel 2010, but with Excel 2016 I get:-
Run-time error '1004'
AutoFilter method of Range class failed
Also, I can manually click the filter icon in the Ribbon (Under Data > Filter) but cannot do this with VBA code
Any ideas much appreciated.
The AutoFilter gives 1004 error, when you are trying to filter by an empty row. Try to put something on row 23 and to filter it again like this:
Public Sub TestMe()
With ActiveSheet
.AutoFilterMode = False
.Range("23:23").Cells(1) = 1
.Range("23:23").Cells(2) = 2
.Range("23:23").AutoFilter
End With
End Sub
If it works, then you simply do not have values in row 23, thus it cannot apply an autofilter.
In general, the AutoFilter in Excel has some strange behaviour. E.g., if you open a new Excel file and you run the following code:
Public Sub TestMe()
With ActiveSheet
.AutoFilterMode = False
'.Range("23:23").Cells(1) = 1
'.Range("23:23").Cells(2) = 2
.Range("23:23").AutoFilter
End With
End Sub
It will give you the 1004 error. Let's call this time momentum FirstTime.
Then, if you uncomment the two ranges and run it, the AutoFilter would appear.
Now the strange part - delete all cells from the sheet, comment back the two ranges and it really looks like the way it was, at the FirstTime. But if you run the code it will put an AutoFilter on the empty 23rd row without a problem.
Remove the Existing filer and Run it again

VBA deleting a duplicate copy of chart object fails in Excel 2013

I have a VBA code that is intended to copy the contents of a range into a chart, to be able to export it to a PNG file (+some post-processing using an external command). Here is the relevant part:
Sub GenererImage() ' Entry point
getparams ' Collect parameters and define global variables
MiseEnPage.Range(ZoneImage).CopyPicture Appearance:=xlScreen,Format:=xlPicture
Application.DisplayAlerts = False
With ObjetGraphique.Duplicate
.Chart.Paste
.Chart.Export Filename:=CheminImage, Filtername:="PNG"
.Select
.Delete
End With
Application.DisplayAlerts = True
End Sub
The getparams procedure called in there is just collecting some parameters from another worksheet to define:
"MiseEnPage": reference to the worksheet object where the range I want to copy exists,
"ZoneImage" is set to the "B4:F11" string (refers to the range address),
"ObjetGraphique" is a reference to a ChartObject inside the "MiseEnPage" sheet. This ChartObject is an empty container (I am mainly using it to easily set the width and height).
"CheminImage" is a string containing the path to the picture filename on disk.
This code used to work perfectly in Excel 2010. Now my company has deployed Excel 2013 and my code now fails on the .Delete line, leaving the copy of the ChartObject (with the range picture pasted inside it) on the sheet and stopping macro execution.
I have tried activating the worksheet first, selecting the duplicate prior to deleting it and other things, to no avail. When tracing the execution in the debugger it chokes on the delete line with error 1004.
I am frustratingly stuck. Any clue?
If this works
With ObjetGraphique.Duplicate
.Chart.Paste
.Chart.Export Filename:=CheminImage, Filtername:="PNG"
.Select
End With
Selection.Delete
we have to assume that either the With is holding a reference and preventing the delete, or that the delete routine called by the selection object is not the same delete that's called by ObjetGraphique.Duplicate.delete, or that it's a subtle timing bug and that the extra time it takes to retrieve the selected object is enough to fix it.
OK after fiddling a lot with the object model, here is (the relevant part of) my final solution. Many thanks to HarassedDad for the clues.
Sub GenererImage() ' Point d'entrée
getparams
MiseEnPage.Range(ZoneImage).CopyPicture Appearance:=xlScreen, Format:=xlPicture
Application.DisplayAlerts = False
With ObjetGraphique
.Chart.Paste
.Chart.Export filename:=CheminImage, Filtername:="PNG"
.Chart.Shapes(1).Delete
End With
Application.DisplayAlerts = True
End Sub
What seems to happen is that the .Paste method of the Chart object creates a Shape in the .Shapes collection of this object. I can delete this Shape, but not the Chart itself or the ChartObject. Excel 2010 would allow that, but not Excel 2013.
I still do not understand the reasons, but at least I have something that works (until the next excel update probably...).

VBA Runtime Error 1004 “Application-defined or Object-defined error” when setting Range in macro

I'm going to preface this by saying that I am very new to VBA and this is my first project with it however, I'm trying quite hard because otherwise it is manual copy paste ~200 times.
Unfortunately, for a first project it has been difficult.
EDITED FOR CLARITY (HOPEFULLY): The main idea is that I need to start at the beginning of a drop down list, copy the first string listed, then paste that string down the column. This changes the numerical data adjacent to the right. I then want to select this newly changed numerical data and copy and paste it to a different sheet in the same workbook in the first blank space in column F. I then want the code to iterate through the drop down list and do this for all 51 strings in the drop down. However it needs to paste offset by 3 columns for each iteration to copy the data to the correct column in the other sheet.
Here is my code thus far
Option Explicit
Sub PtComp()
'
' PtComp Macro
'
'
Dim List1 As String
Dim Range1 As Range
Dim Line1 As Range
Dim i As Integer
Dim Begin As Range
ActiveWorkbook.Sheets("Sample Data Summary").Activate
List1 = Selection
Set Range1 = Evaluate(ActiveSheet.Range(List1).Validation.Formula1)
For Each Line1 In Range1
Selection.Copy
ActiveSheet.Range(Selection, Selection.End(xlDown)).Select
ActiveSheet.Paste
ActiveCell.Offset(0, 1).Select
ActiveSheet.Range(Selection, Selection.End(xlDown)).Select
Application.CutCopyMode = False
ActiveSheet.Selection.Copy
ActiveWorkbook.Sheets("Pt Comparison").Activate
Begin = ActiveSheet.Range("F1").End(xlDown).Offset(-1, 0)
For i = 0 To 148 Step 3
Begin.Offset(0, i).Select
ActiveSheet.PasteSpecial Paste:=xlPasteValues
Next i
Next Line1
End Sub
It is highlighting this line
Set Range1 = Evaluate(ActiveSheet.Range(List1).Validation.Formula1)
Any help would be greatly appreciated. Sorry if my code is trash, like I said, first timer hoping to get better.
EDIT: Also, I looked back at older questions with the same error and thought that it was maybe because it wasn't clear what worksheet I was trying to define the range in, hence why my code is full of 'ActiveSheet' but still no luck.
Your code assumes List1 contains a valid range address, and thus that the active cell on that "Sample Data Summary" worksheet, contains a valid range address.
Apparently that isn't always the case. Search for more details on the On Error statement for ideas about how you could go about handling that situation.
You need to read up on How to avoid using Select in Excel VBA macros, and know that clipboard operations in a tight loop is pretty much the single slowest thing you can do in Excel-VBA.
Seems you want something like this:
Set Range1 = Evaluate(Selection.Validation.Formula1)
Your code blows up on Range(List1) because List1 does not contain a valid range address.

Excel VBA: Update chart button when new row of data is added to datasheet

I'm working on an Excel VBA macro that will create a timeline for a list of projects. I would like the macro to be dynamic and have an update command button that will refresh the chart when new information is added to the data sheet.
However, anytime I add a new row to the data sheet, the chart format goes haywire. Here is my code:
Private Sub CommandButton1_Click()
Application.ScreenUpdating = False
On Error Resume Next
ThisWorkbook.Charts.Delete
On Error GoTo 0
Dim ChartSheet1 As Chart
Set ChartSheet1 = Charts.Add
With ChartSheet1
.SetSourceData Source:=Sheets("Sheet1").Range("A2:A61,F2:F61,I2:I61")
.ChartType = xlBarStacked
End With
Application.ScreenUpdating = True
End Sub
The "ThisWorkbook.Charts.Delete" is to delete the existing chart and have it replaced with the new, updated chart.
Column A contains the project titles. Column F contains the date that the project starts on. Column I contains the number of days that the project will last for.
I have 59 rows of data in my data sheet. I made the range to 61 so that I could add another row or two of data to see if my code works. But it doesn't. I used the record macro function to make most of my code. I understand this isn't the best technique but I have no background in VBA and was looking for a quick solution. I've been trying to learn the basics but can't find a solution for the problem I'm having.
I'm thinking that the problem is with "61" and that I should change that to a variable like "lastRow". Or maybe I'm completely off due to my lack of experience with programming. Thanks for any insight.
You can make the data source dynamic by calculating the last row of the data in VBA like this:
Private Sub CommandButton1_Click()
' declare variables for last row and worksheet
Dim lastRow
Dim sh As Worksheet
Set sh = ActiveWorkbook.Worksheets("Sheet1")
' get last populated cell in column A
lastRow = sh.Cells(Rows.Count, "A").End(xlUp).Row
Application.ScreenUpdating = False
On Error Resume Next
ThisWorkbook.Charts.Delete
On Error GoTo 0
Dim ChartSheet1 As Chart
Set ChartSheet1 = Charts.Add
With ChartSheet1
.SetSourceData Source:=Sheets("Sheet1").Range("A2:A" & lastRow & ",F2:F" & lastRow & ",I2:I" & lastRow)
.ChartType = xlBarStacked
End With
Application.ScreenUpdating = True
End Sub
Your code completely deletes the chart sheet and then creates a new one. I'm not sure what "the chart format goes haywire" means in your world, but without any formatting you'll get the Excel default horizontal bar chart with that code.
Turn the data in the worksheet into a Table (Insert tab > Table). Make the chart using this table.
Now whenever a row is added to or deleted from the table, the chart automatically updates to reflect the current contents of the table.
No need for VBA, no need to delete and recreate the chart, and lose then try to restore its formatting.
Look at the numbers. The Range goes from Row 2 to Row 61, which covers 59 rows of data. If you want to add another 2 more rows of data, you need to change it to "63".

Excel 2010 VBA: .Names.Add does not work after .Hyperlinks.Add

I have run into a problem in Excel 2010 VBA on Windows 7 64-bit version which I have not been able to solve. The issue can easily be recreated by pasting the code below in a module in a new workbook and run it.
What I want to do is to loop through a number of sheets and add a defined name and a hyperlink on each sheet.
Sub Test()
Dim i As Integer
Dim ws As Worksheet
Dim defName As String
For i = 1 To 2
Set ws = Sheets(i)
defName = "Name_" & ws.Name
ws.Names.Add Name:=defName, RefersToR1C1:="=OFFSET(Sheet3!R1C1,0,0,1)"
ws.Hyperlinks.Add Anchor:=ws.Range("A1"), _
Address:="", SubAddress:="=Sheet3!A1"
Next i
End Sub
Running the code gives the following error on the second iteration, on the ws.Names.Add call: Run-time error '1004: The formula you typed contains an error.
Doing any of the following makes the error disappear:
Change the for iteration to "i = 1 To 1" or "i = 2 To 2"
Put a debug breakpoint inside the for loop and pressing F5 when it has stopped
Change the cell reference to
ws.Names.Add Name:=defName, RefersToR1C1:="=Sheet3!R1C1", i.e. removing the OFFSET command
Adding DoEvents to the first line of the for loop or setting Application.EnableEvents = False does not solve the problem.
Does anyone know the cause of this error or how to get around it? I am thankful for any help.
Edit: The issue occurs no matter what the hyperlink links to. Changing the hyperlink to the following does not solve the issue
ws.Hyperlinks.Add Anchor:=ws.Range("A1"), Address:="http://www.google.com"
Edit2: Managed to recreate the issue with an even simpler code:
Sub Test()
With Sheets(1)
.Hyperlinks.Add Anchor:=.Range("A1"), Address:="http://www.google.com"
.Names.Add Name:="myDefName", RefersToR1C1:="=OFFSET(Sheet1!R1C1,0,0,1)"
End With
End Sub
I solved this by separating the for loops into two loops, one for the .names.add calls and one for the hyperlinks.add calls. This way all the names get defined before the first hyperlink is created.
Sorry if it is not correct of me to post this as an answer.