Error i n creating chart (Double Creation) - vba

I am trying to create a chart on my sheet Monthprepare.
I am using the below code.
I have the code , behind the button with several other calling functions.
The problem is, whenever I am creating the chart, it is creating them twice.
I am left confused what would be the reason.
Could someone help to figure it out.
Sub chartmonthprep()
Dim cht As Chart
Dim stable As PivotTable
Dim pt, sh
If ActiveSheet.PivotTables.count = 0 Then Exit Sub
Set stable = ActiveSheet.PivotTables(2)
Set pt = stable.TableRange1
Set sh = ActiveSheet.ChartObjects.Add(Left:=250, _
Width:=400, Top:=20, Height:=250)
sh.Select
Set cht = ActiveChart
With cht
.SetSourceData pt
.ChartType = xlColumnStacked
End With
cht.FullSeriesCollection(1).Name = "Average of Red"
cht.SeriesCollection(1).HasDataLabels = True
cht.SeriesCollection(2).HasDataLabels = True
cht.SeriesCollection(1).Format.Fill.ForeColor.RGB = RGB(0, 255, 0)
cht.SeriesCollection(2).Format.Fill.ForeColor.RGB = RGB(255, 0, 0)
cht.HasTitle = True
cht.ChartTitle.Text = " Result"
End Sub

Try like this:
Sub chartmonthprep()
If ActiveSheet.ChartObjects.Count > 1 Then Exit Sub
'the rest of your code here --v
Dim cht As Chart
Dim stable As PivotTable
End Sub
It will make sure that it is only 1 chart.

You can loop for each Pivot Table in a sheet with this:
Sub PivotTable()
Dim sh As Worksheet
Dim pvt As PivotTable
Set sh = ThisWorkbook.Sheets("Sheet1")
For Each pvt In sh.PivotTables
MsgBox pvt.Name
'do something
Next pvt
End Sub

Related

Naming a chart created with .shapes.chart

I've been trying to figure out what i'm doing wrong but I can't find the answer. I've got the following code:
Sub CreatePivotChart()
Dim sh As Shape
Dim ws As Worksheet
Dim ch As Chart
Dim pt As PivotTable
DeleteAllChartObjects
'setting ws and sh will be done alot here. It's basically making it easy for yourself by making a new (short name):
Set ws = Worksheets("Analysis")
Set sh = ws.Shapes.AddChart(XlChartType:=xlColumn, Width:=400, Height:=200)
'This part to make sure that when there's no cell selected when running the code) within the pivottable, it still works
Set ch = sh.Chart
'Acipivot is created as title for the pivottable in sbCreativpivot:
Set pt = Worksheets("PivotTable").PivotTables("Acpivot")
ch.SetSourceData pt.TableRange1
'align the chart with the table:
sh.Top = pt.TableRange1.Top
sh.Left = pt.TableRange1.Left + pt.TableRange1.Width + 10
End Sub
Everything works fine, except I can't name the chart. I've tried several methods that I found online, but none of them seem to work.
Here's my latest attempt:
'This part to make sure that when there's no cell selected when running the code) within the pivottable, it still works
Set ch = sh.Chart
With ch
With .Parent.Name = "test"
End With
End With
But if I then try to reference it like here:
Sub EditPivotChart()
Dim pt As PivotTable
Dim ch As Chart
Dim pf As PivotField
Set ch = Charts("test")
Set pt = ch.PivotLayout.PivotTable
For Each pf In pt.VisibleFields
pf.Orientation = xlHidden
Next pf
End Sub
I get an error
vba ran out of memory
Does anyone see what wrong I am doing?
Thanks!
You can remove all of the following segment
With ch
With .Parent.Name = "test"
End With
End With
and simply replace it with
sh.Name = "test"
That should do the trick.

Customzing the Charts using VBA

I have a sheet with Pivot table and I am creating an Column stacked chart from the table.
I would like to change the colours of Legend entries in chart and would like to have an title for the chart every time I create the chart.
I tried the below code and I'm getting
Object variable or with block variable not set
I get the error in the line
cht.SeriesCollection(1).Format.Fill.ForeColor.RGB = RGB(155, 213, 91)
Could anyone, tell me how I could create chart for my requirements. I have added an image of my current chart and required chart.
Sub chart11()
Dim sh As Shape
Dim cht As Chart
If ActiveSheet.PivotTables.Count = 0 Then Exit Sub
Set ptable = ActiveSheet.PivotTables(1)
Set ptr = ptable.TableRange1
Set sh = ActiveSheet.Shapes.AddChart
sh.Select
With ActiveChart
.SetSourceData ptr
.ChartType = xlColumnStacked
End With
cht.SeriesCollection(1).Format.Fill.ForeColor.RGB = RGB(155, 213, 91)
cht.Axes(xlCategory).MinimumScale = 5
cht.Axes(xlCategory).MaximumScale = 40
cht.HasTitle = True
cht.ChartTitle.Text = "Default Chart"
End Sub
This is the chart generated by my code now, if I comment the error line:
I would like to have a chart of this type with change in colour legends and chart title:
You can't use cht.Axes(xlCategory).MinimumScale = 5 and MaximumScale.
Because Pivot chart do not assist Scatterchart.
Only in scatter chart, you can set xlCategory Scale.
Sub chart11()
Dim sh As Shape
Dim cht As Chart
If ActiveSheet.PivotTables.Count = 0 Then Exit Sub
Set ptable = ActiveSheet.PivotTables(1)
Set ptr = ptable.TableRange1
Set sh = ActiveSheet.Shapes.AddChart
sh.Select
Set cht = ActiveChart
With cht
.SetSourceData ptr
.ChartType = xlColumnStacked
End With
cht.SeriesCollection(1).Format.Fill.ForeColor.RGB = RGB(255, 0, 0) '<~~ Red
cht.SeriesCollection(2).Format.Fill.ForeColor.RGB = RGB(0, 255, 0) '<~~ green
'cht.Axes(xlCategory).MinimumScale = 5
'cht.Axes(xlCategory).MaximumScale = 40
cht.HasTitle = True
cht.ChartTitle.Text = "Default Chart"
End Sub

How to make a range bar chart

Hey I'm new to forums and this is my first post. I am new to vba in excel, but have written thinkscript in ThinkorSwim.
If anyone is familiar with a range stock chart, thats what Im going after.
I found code for a line chart, and am using it, but it is based on where price is at any given time. I want to modify this line chart to only plot values when they are above or below a range so that it resembles a candlestick chart with no wicks. Once data enters that range, I only want it to update whenever a new high or low is made in that range. The ranges need to be preset (ex. 50 ticks) Once the range is exceeded, I want the data plotted in the next range up, and repeat the process. Time and dates should be ignored, and only plot based on price action.
Does anyone have any ideas?
Option Explicit
'Update the values between the quotes here:
Private Const sChartWSName = "Chart"
Private Const sSourceWSName = "Sheet1"
Private Const sTableName = "tblValues"
Public RunTime As Double
Private Sub Chart_Setup()
'Create the structure needed to preserve and chart data
Dim wsChart As Worksheet
Dim lstObject As ListObject
Dim cht As Chart
Dim shp As Button
'Create sheet if necessary
Set wsChart = Worksheets.Add
wsChart.Name = sChartWSName
'Set up listobject to hold data
With wsChart
.Range("A1").Value = "Time"
.Range("B1").Value = "Value"
Set lstObject = .ListObjects.Add( _
SourceType:=xlSrcRange, _
Source:=.Range("A1:B1"), _
xllistobjecthasheaders:=xlYes)
lstObject.Name = sTableName
.Range("A2").NumberFormat = "h:mm:ss AM/PM (mmm-d)"
.Columns("A:A").ColumnWidth = 25
.Select
End With
'Create the chart
With ActiveSheet
.Shapes.AddChart.Select
Set cht = ActiveChart
With cht
.ChartType = xlLine
.SetSourceData Source:=Range(sTableName)
.PlotBy = xlColumns
.Legend.Delete
.Axes(xlCategory).CategoryType = xlCategoryScale
With .SeriesCollection(1).Format.Range
.Visible = msoTrue
.Weight = 1.25
End With
End With
End With
'Add buttons to start/stop the routine
Set shp = ActiveSheet.Buttons.Add(242.25, 0, 83.75, 33.75)
With shp
.OnAction = "Chart_Initialize"
.Characters.Text = "Restart Plotting"
End With
Set shp = ActiveSheet.Buttons.Add(326.25, 0, 83.75, 33.75)
With shp
.OnAction = "Chart_Stop"
.Characters.Text = "Stop Plotting"
End With
End Sub
Public Sub Chart_Initialize()
'Initialize the routine
Dim wsTarget As Worksheet
Dim lstObject As ListObject
'Make sure worksheet exists
On Error Resume Next
Set wsTarget = Worksheets(sChartWSName)
If Err.Number <> 0 Then
Call Chart_Setup
Set wsTarget = Worksheets(sChartWSName)
End If
On Error GoTo 0
'Check if chart data exists
With Worksheets(sChartWSName)
Set lstObject = .ListObjects(sTableName)
If lstObject.ListRows.Count > 0 Then
Select Case MsgBox("You already have data. Do you want to clear it and start fresh?", vbYesNoCancel, "Clear out old data?")
Case Is = vbYes
'User wants to clear the data
lstObject.DataBodyRange.Delete
Case Is = vbCancel
'User cancelled so exit routine
Exit Sub
Case Is = vbNo
'User just wants to append to existing table
End Select
End If
'Begin appending
Call Chart_AppendData
End With
End Sub
Private Sub Chart_AppendData()
'Append data to the chart table
Dim lstObject As ListObject
Dim lRow As Long
With Worksheets(sChartWSName)
Set lstObject = .ListObjects(sTableName)
If lstObject.ListRows.Count = 0 Then
lRow = .Range("A1").End(xlDown).Row
End If
If lRow = 0 Then
lRow = .Range("A" & .Rows.Count).End(xlUp).Offset(1, 0).Row
End If
If lRow > 2 Then
If .Range("B" & lRow - 1).Value = Worksheets(sSourceWSName).Range("C10").Value Then
'Data is a match, so do nothing
Else
'Data needs appending
.Range("A" & lRow).Value = CDate(Now)
.Range("B" & lRow).Value = Worksheets(sSourceWSName).Range("C10").Value
End If
Else
'Data needs appending
.Range("A" & lRow).Value = CDate(Now)
.Range("B" & lRow).Value = Worksheets(sSourceWSName).Range("C10").Value
End If
End With
RunTime = Now + TimeValue("00:00:01")
Application.OnTime RunTime, "Chart_AppendData"
End Sub
Public Sub Chart_Stop()
'Stop capturing data
On Error Resume Next
Application.OnTime EarliestTime:=RunTime, Procedure:="Chart_AppendData", Schedule:=False
End Sub
Take your sheet of data and filter... example would be:
Columns("A:C").Sort key1:=Range("C2"), _
order1:=xlAscending, header:=xlYes
Sort info: https://msdn.microsoft.com/en-us/library/office/ff840646.aspx
You then can define to select your desired range. Assuming column A is x-axis and B is y-axis (where your parameters for modifying need to be assessed):
Dim High1 as integer
Dim Low1 as integer
High1 = Match(Max(B:B),B:B) 'This isn't tested, just an idea
Low1 = Match(Max(B:B)+50,B:B) 'Again, not tested
and using those defined parameters:
.Range(Cells(High1,1),Cells(Low1,2).Select
This should give an idea for High1/Low1, where you can work through how you want to define the row that the max value occurs.
You then CreateObject for the Chart you want, having selected the data range you are going to use.

Strip Specific Word in VBA for each chart

So I loop through each chart using the following code:
Sub LoopThroughCharts()
Dim sht As Worksheet
Dim CurrentSheet As Worksheet
Dim cht As ChartObject
Application.ScreenUpdating = False
Application.EnableEvents = False
Set CurrentSheet = ActiveSheet
For Each sht In ActiveWorkbook.Worksheets
For Each cht In sht.ChartObjects
cht.Activate
'Do something with the chart...
ActiveChart.Legend.Select
Selection.Left = 108.499
Selection.Width = 405.5
Selection.Height = 36.248
Selection.Top = 201.85
Selection.Left = 63.499
Selection.Top = 330.85
ActiveChart.PlotArea.Select
Selection.Height = 246.69
Selection.Width = 445.028
Next cht
Next sht
CurrentSheet.Activate
Application.EnableEvents = True
This makes each chart a specific size and I was thinking that I can modify the following vba code to strip the word "Test: out of Test: abc the legend and then the resulting legend would be abc. I think that I can modify the following code, but I am not sure how to to do this. :
For i = ActiveChart.SeriesCollection.Count To 1 Step -1
If ActiveChart.Legend(i)= "Test: *" Then
ActiveChart.Legend(i) **what I think needs to be modified**
End If
Next i
In order to strip a specific word, you can
Replace the prefix using the function Replace()
Take the sub string using the function Mid()
Here's the demo code
Sub stripDemo()
Dim str As String
str = "Test: my legend"
Debug.Print Replace(str, "Test: ", "")
Debug.Print Mid(str, 7, Len(str) - 6)
End Sub
EDIT
So when the code is applied to chart, it becomes :
For Each sht In ActiveWorkbook.Worksheets
For Each cht In sht.ChartObjects
cht.Activate
' iterate the series collection
' replace the prefixe "Tests: " with ""
For Each sr In ActiveChart.SeriesCollection
If Len(sr.Name) > 6 And Left(sr.Name, 6) = "Test: " Then
sr.Name = Replace(sr.Name, "Test: ", "")
End If
Next sr
Next cht
Next sht

How can I adapt my VBA to include a second series of data

When I use the below macro it only works for one series data set. How can I adapt it so that I can include multiple series?
Currently if I try and use it to label a second set it will delete the first one and so on...
Thanks in advance
Sub AddXYLabels()
If Left(TypeName(Selection), 5) <> "Chart" Then
MsgBox "Please select the chart first."
Exit Sub
End If
Set StartLabel = _
Application.InputBox("Click on the cell containing the first(top) label", Type:=8)
Application.ScreenUpdating = False
For Each pt In ActiveChart.SeriesCollection(1).Points
pt.ApplyDataLabels xlDataLabelsShowValue
pt.DataLabel.Caption = StartLabel.Value
Set StartLabel = StartLabel.Offset(1)
Next
End Sub
Your code is not working for rest of the series since you have hard coded the range for only one series
For Each pt In ActiveChart.SeriesCollection(1).Points
Please try this
Sub AddXYLabels()
If Left(TypeName(Selection), 5) <> "Chart" Then
MsgBox "Please select the chart first."
Exit Sub
End If
Dim mySeries As Series
Dim seriesCol As SeriesCollection
Dim I As Integer
I = 1
Set seriesCol = ActiveChart.SeriesCollection
For Each mySeries In seriesCol
Set mySeries = ActiveChart.SeriesCollection(I)
With mySeries
.ApplyDataLabels xlDataLabelsShowValue
End With
I = I + 1
Next
End Sub