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

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.

Related

Getting invalid parameter when looping through .FullSeriesCollection if the Range has an empty cell

I am setting a dynamic single column range, then looping through that Range to build a ColumnClustered graph.
If the Range has an empty cell looping through the .FullSeriesCollection throws an invalid parameter error. Error occurs at
With .FullSeriesCollection(I).
Is there any easy way around this? I would like to show that the empty cell exists, this is a time point, but does not exist for this particular parameter getting graphed.
Appreciate any help!
With Sheets(GSheet).ChartObjects.Add _
(Left:=100, Width:=200, Top:=75, Height:=150)
With .Chart
.ChartType = xlColumnClustered
'Set data source range.
.SetSourceData Source:=MyRange, PlotBy:=xlRows
For I = 1 To MyRange.Count
With .FullSeriesCollection(I)
' Do Stuff
End With
Next I
End With
End With
You'll need to assign MyRange only cells that contain a value. One way would be to use the Union method. Another way would be to use the SpecialCells method. Here's an example using the Union method, assuming that the source data is located in the first sheet, and in A2:A10...
Dim rCell As Range
Dim MyRange As Range
For Each rCell In Sheets(1).Range("A2:A10")
If Len(rCell) > 0 Then
If MyRange Is Nothing Then
Set MyRange = rCell
Else
Set MyRange = Union(MyRange, rCell)
End If
End If
Next rCell
Also, you should test whether MyRange has been assigned any cells...
If Not MyRange Is Nothing Then
'Create your chart
'
'
Else
MsgBox "No data found.", vbExclamation
End If
Hope this helps!

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

Using charts with VBA

I'm trying to generate two charts using VBA. The problem is most examples use ActiveChart but I want multiple charts on multiple sheets. If I inserted a blank chart how do I rename that chart to reference it. I don't want a new chart to be generated each time I run the macro and I want it to be in the sheet. I'm struggling with the code but am assuming it will be something like the code below. I've attached the desired graph (I made this through excel, but I need to do it through VBA).
macro1()
lastrow2 = Sheet1.Cells(Sheet1.Rows.Count, "A").End(xlUp).Row
dim chart1 as chart
dim chart2 as chart ' ect
chart1.title = "test"
chart1.xaxis = sheet1.cell(lastrow2,1)
chart1.yaxis = "manhours"
end sub
using a the record function, i got the code commented below. I tried to change it but i'm still having issues
Sub Macro7()
Dim Chart2 As ChartObject
Dim chartb As Chart
Chart2 = Sheet1.chartb.SeriesCollection(2)
chartb.Select
Formula = "=SERIES(Master!R3C3,Master!R4C1:R18C1,Master!R4C3:R19C3,2)"
' ActiveChart.SeriesCollection(2).Select
' Selection.Formula =_
'"=SERIES(Master!R3C3,Master!R4C1:R18C1,Master!R4C3:R19C3,2)"
End Sub
I really just need this formula converted to i can reference my lastrow function and individual sheets
ActiveChart.SeriesCollection(2).Select
Selection.Formula =_
"SERIES(sheet1.cells(3,3),sheet1.cells(4,1):sheet1.cells(18,1)_
,sheet1.cells(4,3):sheet1.cells(4,19),2"
' Selection.Formula"_
' =SERIES(Master!R3C3,Master!R4C1:R18C1,Master!R4C3:R19C3,2)"
this was what i was trying to do. It declares the sheet name and references an existing chart named chart 1.
Dim cht As ChartObject
Dim rng As Range
Set cht = Sheets("Master").ChartObjects("Chart 1")
Set rng = Sheets("Master").Range("A4", Range("D4").End(xlDown).Offset(-1))
cht.Chart.SetSourceData Source:=rng
cht.Chart.HasTitle = True
cht.Chart.ChartTitle.Text = "Bird Report - By Cost Code/Activity" ' title
cht.Chart.SeriesCollection(1).Name = "=Master!$B$3"
cht.Chart.SeriesCollection(2).Name = "=Master!$C$3"
cht.Chart.SeriesCollection(3).Name = "=Master!$D$3"

Chart not generated from vba code unless another chart already exists

I have a table in excel with multiple columns and rows. I have written this simple code to generate a Line chart from my table:
Sub DrawLine()
Dim cht As ChartObject
For Each cht In Worksheets(Sheets.Count).ChartObjects
cht.Chart.Type = xlLine
Next cht
End Sub
However, when I execute this code I can't see my chart, unless if I have another chart on my worksheet generated manually. In this case, when I execute the code, the chart changes to display what my sub is doing.
Does anyone know what could be the problem ?
You're not creating any charts with your code. What you're doing is changing any chart currently there to become a line chart.
There are many things missing in your code. Pl see example below.
Sub Test()
Dim LastRow As Long
Dim Rng1 As Range
Dim ShName As String
With ActiveSheet
LastRow = .Range("A" & .Rows.Count).End(xlUp).Row
Set Rng1 = .Range("A2:A" & LastRow & ", B2:B" & LastRow)
ShName = .Name
End With
Charts.Add
With ActiveChart
.ChartType = xlLine
.SetSourceData Source:=Rng1
.Location Where:=xlLocationAsObject, Name:=ShName
End With
End Sub

Using VBA to select a dynamic range of cells and create a chart

I am attempting to use VBA to create a chart using dynamic ranges. Specifically, I have an Excel table as follows
Based on this data, I would like to create a chart, with the date ranges changed as per requirement. For example, at one instance, I would be required to produce a chart for 1st July - 6th July, and at another, from 10th July - 14th July.
The following is my attempt at generating such a chart, but I feel there would be much better ways other than mine. Hence, my question, is there any other, better way?
1- I first enter the date values in 'helper cells' for which a chart is sought. In this case, cell M24 has the value 10th July, while cell M26 has the value 14th July.
2- Then, I use the match() function to find the positions from the date column of my Table. The function is =MATCH(M24,Table1[Dates],0), and =MATCH(M26,Table1[Dates],0).
3- Given that I have the relative positions for the dates, I then use the following VBA code to generate the chart:
Private Sub CommandButton1_Click()
Dim mySheet As Worksheet
Dim myShape As Shape
Dim myChart As Chart
Dim myVal1 As String
Dim myVal2 As String
Set mySheet = ActiveWorkbook.Worksheets("dataSheet")
If myShape Is Nothing Then
Set myShape = mySheet.Shapes.AddChart(XlChartType:=xlColumnClustered, _
Left:=CommandButton1.Left + CommandButton1.Width + 2, _
Width:=370, Height:=200)
End If
'In the following, I am offsetting from the first cell
'of my Table, which contains the `value 1-Jul.
'My objective is to use the range 10-Jul to 14th Jul,
'so I also add a column offset
'Cells O24 and O26 contain the results of the match functions
myVal1 = Range("B4").Offset(Range("O24").Value, 0).Address
myVal2 = Range("B4").Offset(Range("O26").Value, 4).Address
Set myChart = myShape.Chart
myChart.ChartType = xlLine
myChart.SetSourceData Source:=Sheets("dataSheet") _
.Range(CStr(myVal1 & ":" & myVal2))
End Sub
So, now hoping that my question is clear, could somebody please educate me of a better method than this one? This seems to be more a hacking method than proper coding to me...
Many thanks in advance!
In my tutorial Chart Partial Range Between Variable Endpoints, I show a couple alternatives using defined Names, without VBA. One way simply gives the index of the first and last record to include in the chart, another uses match to find the range of records that begin and end at dates entered by the user.
As what Dave said, it is pretty solid. But you can try this one:
Private Sub CommandButton1_Click()
Dim d1 As Range, d2 As Range
Dim ws As Worksheet: Set ws = Thisworkbook.Sheets("datasheet")
'~~> Look for the dates
With ws.Range("Table1[Dates]")
Set d1 = .Find(ws.Range("M24").Value, .Cells(.Cells.Count))
Set d2 = .Find(ws.Range("M26").Value, .Cells(.Cells.Count))
End With
'~~> Handle unavailable dates, interchanged inputs
Dim i As Long, j As Long
If d1 Is Nothing Or d2 Is Nothing Then MsgBox "Invalid coverage": Exit Sub
If d2.Value > d1.Value Then i = 0: j = 4 Else i = 4: j = 0
'~~> Set the chart source
Dim chsource As Range
Set chsource = ws.ListObjects("Table1").HeaderRowRange
Set chsource = Union(chsource, ws.Range(d1.Offset(0, i), d2.Offset(0, j)))
'~~> Clean up existing chart
Dim sh As Shape
For Each sh In Me.Shapes
If sh.Type = msoChart Then sh.Delete
Next
'~~> Create the chart
With Me.Shapes.AddChart(, Me.CommandButton1.Left + _
Me.CommandButton1.Width + 2, Me.CommandButton1.Top, _
370, 200).Chart
.ChartType = xlLine
.SetSourceData chsource
.SetElement msoElementChartTitleAboveChart
.ChartTitle.Text = "Trend Chart"
End With
End Sub
You still retrieve dates on M24 and M26 respectively, but no need to use additional ranges with the formulas.
If the values aren't found, it returns a message box.
As long as the dates are found it will create the graph regardless where the user put it.
Also I did 2 ways of accessing the Table, 1 is using Range and the other is using ListObjects.
That is intentional for you to get a hang of both. Sometimes one is better than the other.
Also I am explicit in using Me (which pertains to the sheet that contain your CB).
I also think that your graph should have the correct legends instead of Series(x) names so I added the header to the source. HTH.