VBA Excel: Modifying Existing Graph (Errors) - vba

Using a macro, I want to modify the data series of a graph at any given time. Whenever I run the macro, I get an error. "error 438 "object doesn't support this property or method"". My code is attached below. Thanks.
Private Sub CommandButton2_Click()
Dim objChrt As ChartObject
Dim chrt As Chart
Set objChart = ActiveSheet.ChartObjects("Chart 1")
Set chrt = objChart.Chart
With objChart
.SetSourceData (ActiveSheet.Range("D2", Cells(2, N + 3))) '"N" is a user defined range
End With
End Sub

Three layers to this problem, I think.
1) Cells returns a range object, not a range address. When using this as an argument in a Range then you need to ensure that either the returned cell contains a valid address string, or that you refer directly to the .Address of that cell.
It's rare that you'd do the former, but I've seen it done before so I mention it just in case.
2) Parentheses force evaluation, so this line (even as corrected):
.SetSourceData (ActiveSheet.Range("D2", Cells(2, N + 3).Address))
Is functionally equivalent to:
.SetSourceData (ActiveSheet.Range("D2", Cells(2, N + 3).Address)).Value
Which probably raises an error because of the parentheses, since I believe the .SetSourceData requires a range address, so try:
.SetSourceData ActiveSheet.Range("D2", Cells(2, N + 3).Address)
And further:
3) The SetSourceData is a member of the Chart object, not the ChartObject object. Confusing, right?
with chrt
.SetSourceData ActiveSheet.Range("D2", Cells(2, N + 3).Address)
End With

Related

Excel macro for chart based on selection with custom name

I already found macro to create chart based on selection
Sub Charter()
Dim my_range As Range
Set my_range = Selection
ActiveSheet.Shapes.AddChart.Select
ActiveChart.ChartType = xlColumnStacked
ActiveChart.SetSourceData Source:=my_range
Cells(1, 1).Select
End Sub
but cant figure out how to give it custom name (not generic Chart <number>) so that I can build another macros around it. I found couple of ways to create chart with name but I cant figure out how to connect those two macros.
Any ideas what to do?
Thank you
You can't set the Name property of the ActiveChart. You have to go for its parent object:
ActiveChart.Parent.Name = "Bananas"
I would recommend not to use ActiveSheet, Selection, Select and ActiveChart, instead use fully qualified objects, like in the code below:
Option Explicit
Sub Charter()
Dim MyCht As Object
Dim my_range As Range
Dim ws As Worksheet
' avoid using ActiveSheet, instead use fully qualifed objects
Set ws = Worksheets("Sheet1") ' <-- change "Sheet1" to your sheet's name
Set my_range = Selection
' set the Chart
Set MyCht = ws.Shapes.AddChart2
With MyCht ' modify the chart's properties
.Chart.ChartType = xlColumnStacked
.Chart.SetSourceData Source:=my_range
.Name = "My Chart"
End With
End Sub

VBA code to select columns based on user defined variables in cells

I am trying to write a code for my macro in excel with VBA but I keep getting stuck on the user defined variable part. I currently have a spreadsheet with four sets of measured data that correspond to a single date.
What I am trying to achieve is:
-Have one cell for a start date, and another cell for an end date that is specified by the user; I want to macro to read these two cells and use these two dates, read the data between them, and create a line graph corresponding to these dates with the 4 data series I have.
The end goal is to be able to create a chart between whichever two dates the user wishes to.
I have figured out the macro to plot the line graph if I specify the entire column (i.e. I have put B3:F170 as the data range) however I am not sure how integrate a user defined range in the code.
Any help would be greatly appreciated. Many thanks in advance.
Edit: Here's what I have so far, sorry if its quite messy I am just starting out!
Dim chtChart As Chart
Set chtChart = Charts.Add
With chtChart
.Name = "Chart Name"
.ChartType = xlLine
.SetSourceData Source:=Sheets("Sheet1").Range("B3:F170"),_
PlotBy:=xlColumns
End With
Dim FromDateCell As String
Dim ToDateCell As String
Dim DateRange As Range
FromDateCell = Range("I13").Value
ToDateCell = Range("I14").Value
DateRange = Range(FromDateCell, ToDateCell)
Range(DateRange).Select
you could first set the wanted data range and then assign it as your new chart Source, like follows:
Option Explicit
Sub main()
Dim chtChart As Chart
Dim FromDateCell As Range, ToDateCell As Range, DataRange As Range
With Sheets("Sheet1") '<--| reference your relavant sheet
Set FromDateCell = .Range("B3:B170").Find(.Range("I13").Value, LookIn:=xlValues, lookat:=xlWhole) '<--| get "initial date" cell in range B3:B170
Set ToDateCell = .Range("B3:B170").Find(.Range("I14").Value, LookIn:=xlValues, lookat:=xlWhole) '<--| get "final date" cell in range B3:B170
Set DataRange = Range(FromDateCell, ToDateCell).Resize(, 5) '<--| set the "data" range as the one ranging form "initial date" to "final date" cells extended to enclose four columns to the right
End With
Set chtChart = Charts.Add
With chtChart
.Name = "Chart Name"
.ChartType = xlLine
.SetSourceData Source:=DataRange, PlotBy:=xlColumns
End With
End Sub
the same code could be rewritten (i.e. refactored) to use a specific function to get the wanted range and have your main code more readable and the whole code more maintainable
like follows:
Sub main()
Dim chtChart As Chart
Set chtChart = Charts.Add
With chtChart
.Name = "Chart Name"
.ChartType = xlLine
.SetSourceData Source:=GetDataRange, PlotBy:=xlColumns '<--| here you use GetDataRange() function to return the wanted range
End With
End Sub
Function GetDataRange() As Range
Dim FromDateCell As Range, ToDateCell As Range
With Sheets("Sheet 1")
Set FromDateCell = .Range("B3:B170").Find(.Range("I13").Value, LookIn:=xlValues, lookat:=xlWhole)
Set ToDateCell = .Range("B3:B170").Find(.Range("I14").Value, LookIn:=xlValues, lookat:=xlWhole)
Set GetDataRange = .Range(FromDateCell, ToDateCell).Resize(, 5)
End With
End Function
I think you can achieve this quite simply by using named ranges. Define a named range with the formula
=OFFSET(A8:E200,0,<column>)
Enter that as the data series as input range for the graph as
=<sheet1>! <name>
Replace all values between < and > to whatever is applicable to you. See full reference at https://support.microsoft.com/en-us/kb/183446
You can also use the offset formula in combination with index/match to find the starting/end point in order to get a subset of your data.

Why does my code work for ActiveChart but not for the chart name?

At the moment, my code reads:
Private Sub Worksheet_Activate()
' This Macro Code for this sheet updates the x axis range for the graph in 'Dashboard' automatically
Dim V_900_SPC As Worksheet
Set V_900_SPC = Sheets("AR Data 900A SPC")
Dim chart1values As String, chart1_xvalues As String
chart1values = Cells(2, 10)
chart1_xvalues = Cells(3, 10)
V_900_SPC.ChartObjects("Chart 1").Activate
ActiveChart.SeriesCollection(1).Values = "='AR Data 900A SPC'!" & chart1values
ActiveChart.SeriesCollection(1).XValues = "='AR Data 900A SPC'!" & chart1_xvalues
Cells(1, 1).Activate
End Sub
However if I replace "ActiveChart." with "V_900_SPC.ChartObjects("Chart 1")." (and obviously delete the line that activates the chart object) then the code doesn't work. What's going on??
Try:
V_900_SPC.ChartObjects("Chart 1").Chart.SeriesCollection(1).Values = "='AR Data 900A SPC'!" & chart1values
The reasoning being that ChartObject and Chart isn't the same thing. ChartObject is a container for Chart, and SeriesCollection belongs to Chart.
I recently made a post on SO that is relevant to this, that also contains more information and examples, as well as MSDN links.

Copying range of cells from one workbook to another yields 400 error

Okay, so I am relatively new to Excel VBA. I am trying to do something which seems quite simple to me and there are many, many examples of how to do it which I have read exhaustively but I cannot seem to get past this so...here goes.
I am trying to paste a range of cells from one worksheet to another in Excel Microsoft Office Professional Plus 2010. I think I have reduced the problem to the absolute simplest form possible to illustrate the problem. This is just a snippet. The VictimResults and TempWorksheet variables are set higher up. I didn't include the code because I thought it might confuse the articulation of the problem.
Dim SourceWorksheet As Worksheet
Dim TargetWorksheet As Worksheet
Dim SourceRange As Range
Dim TargetRange As Range
Set SourceWorksheet = VictimResults
Set TargetWorksheet = TempWorksheet
Set SourceRange = Cells(1, 1)
Set TargetRange = Cells(1, 1)
TargetWorksheet.Range(TargetRange) = SourceWorksheet.Range(SourceRange)
I have placed the variables SourceWorksheet, TargetWorksheet, SourceRange, and TargetRange in a watch and set a breakpoint at the last line and they are all valid objects (not null). When I step over the breakpoint I get a dialog box which simply says "400".
Any help is much appreciated.
---edit---
I have created this complete VBA file that replicates the problem. Thought that might help someone answer.
Option Explicit
Sub Main()
GetFirstWorksheetContainsName("Sheet1").Range(Cells(1, 1)).Value = GetFirstWorksheetContainsName("Sheet2").Range(Cells(1, 1)).Value
End Sub
Function GetFirstWorksheetContainsName(worksheetNameContains) As Worksheet
Dim m As Long
Dim result As Worksheet
m = 1
Do
If InStr(1, Sheets(m).Name, worksheetNameContains) Then
Set result = Sheets(m)
Exit Do
End If
m = m + 1
Loop Until m > ThisWorkbook.Worksheets.Count
Set GetFirstWorksheetContainsName = result
End Function
Here is something else I tried which yields something a little more verbose.
Option Explicit
Sub Main()
Sheets("Sheet1").Select
Range(Cells(1, 1)).Select
Selection.Copy
Sheets("Sheet2").Select
Range(Cells(1, 1)).Select
ActiveSheet.Paste
End Sub
It gives me a "Method 'Range' of object '_Global' failed" error when executing the first Range(Cells(1, 1)).Select line.
If you are trying to copy and paste why not use .copy and .pastespecial. They may slow down your code a little bit but as long as your aren't copying and pasting thousands of things it should be ok.
I'm not sure where the 400 is coming from, but the exception that is thrown is the same is in your verbose example (1004 - "Method 'Range' of object '_Worksheet' failed", and is thrown for the same reason.
The problem is how you're addressing the Range. Cells(1, 1) is implicitly set to the active worksheet, not whatever range you are passing it to as a parameter. Since you only need one cell, you can just use the .Cells property instead:
Sub Main()
GetFirstWorksheetContainsName("Sheet1").Cells(1, 1).Value = _
GetFirstWorksheetContainsName("Sheet2").Cells(1, 1).Value
End Sub
If you need to copy more than one cell, you'll have to either grab a reference to a worksheets instead of inlining the calls to GetFirstWorksheetContainsName if you use dynamic ranges:
Sub Main()
Dim source As Worksheet
Dim data As Range
Set source = GetFirstWorksheetContainsName("Sheet2")
Set data = source.Range("A1:B2")
GetFirstWorksheetContainsName("Sheet1").Range(data.Address).Value = data.Value
End Sub
Or hard code it:
Sub Main()
GetFirstWorksheetContainsName("Sheet1").Range("A1:B2").Value = _
GetFirstWorksheetContainsName("Sheet2").Range("A1:B2").Value
End Sub

excel vba chart on a different sheet using that sheet's data

I have a program that creates a new sheet, adds data to that sheet, and the last part it should do is chart that output. When I try the code below, I get "object or variable or with block variable not set"
please let me know where I am going wrong. thank you.
Dim ws As Worksheet
For Each ws In ActiveWorkbook.Worksheets
ws.Shapes.AddChart.Select
ActiveChart.SetSourceData Source:=Range("J2", Sheets(ws.Name).Range("L2").End(xlDown).Address)
ActiveChart.ChartType = xlLine
With ActiveChart.Parent
.Height = 400
.Width = 800
End With
Next
You are using a comma to create your range with strings. That only works with range objects. Try:
ActiveChart.SetSourceData Source:=ws.Range("J2:" & ws.Range("L2").End((xlDown).Address)
With ws.ChartObjects.Add(Left:=100, Width:=375, Top:=75, Height:=225)
.Chart.SetSourceData Source:=ws.Range("J2", Sheets(ws.Name).Range("L2").End(xlDown).Address)
.Chart.ChartType = xlLine
End With
A lot of object accessors in vba return variant.
If you have this issues, for example chart.parent //returns variant btw
the first thing to try is to assign it to a typed variable
At run time if variant is dealt with as if it were a different type you will almost certainly get a runtime error.
dim ws As Worksheet
set ws = ActiveChart.Parent
With ws
'ws operations here
.Name = "My worksheet!"
.Cells(1,1).Value = "cell A1"
End With
Also its worth noting that Workbook.Worksheets collection also contains the chart objects http://msdn.microsoft.com/en-us/library/microsoft.office.tools.excel.workbook.worksheets.aspx
so when you are adding a chart a worksheet you are essentially adding to the collection you are iterating over which is not advised.
Change to this:
ActiveChart.SetSourceData Source:=Range(Sheets(ws.Name).Range("J2"), Sheets(ws.Name).Range("L2").End(xlDown))