i am getting an out of memory error only when i try to add the name to this chart - excel

i have a sub which will create a chart onto a sheet, when i try to add the name to the chart with .name it gives me an error "out of memory". i have tried to add it inside the with block but the same error and i also tried with different name instead of hi but still the same thing.
Option Explicit
Sub addchartv4()
Dim chart As chart
Dim xRg As Range
Dim chartdatarange As Range, chartExists As Boolean
Set chartdatarange = Worksheets("count_issue").Range("a3:c17")
' chartexists = False
' For Each Chart In ActiveSheet.ChartObjects
' If Chart.Name = "issue_count" Then
' chartexists = True
' Exit For
' End If
'
' Next Chart
'
Set chart = Nothing
On Error Resume Next
Set chart = Worksheets("chart11").ChartObjects
On Error GoTo 0
If chart Is Nothing Then
Set chart = Worksheets("chart11").ChartObjects.Add(Left:=Range("a1").Left, Top:=Range("a1").Top, Width:=400, Height:=300).chart
chart.Name = "hi"
With chart
.ChartType = xlColumnClustered
.SetSourceData Source:=chartdatarange
', PlotBy:=xlColumns
.SeriesCollection(1).XValues = chartdatarange.Columns(1)
.HasTitle = True
.ChartTitle.Text = "issue_count"
.HasLegend = False
.SetElement msoElementDataLabelOutSideEnd
.SetElement msoElementPrimaryCategoryGridLinesNone
.SetElement msoElementPrimaryValueAxisNone
End With
End If
End Sub

You shouldn't name the chart, but the chartObject.
The ChartObject is the container for the chart (and is part of the Shapes-collection of a worksheet. Inside the ChartObject you have the Chart-property which defines the real chart. You cannot name the chart, you can only name the ChartObject. The chart has automatic generated name (containing sheet + chartObject name). Trying to set the name manually leads to this "Out of Memory" error (which is just a symptom that something failed).
Now the fix is simple, but you have another issue in your code: When you check if the sheet contains already a chart(object), with the command Set chart = Worksheets("chart11").ChartObjects you try to assign a chartObjects-collection to a chart variable. This will fail in any case with a "Type mismatch". As you enclosed the command with On Error Resume Next, it will look as if there is never a chart on that worksheet and every time a new chart is created.
If you always have only one chart on the sheet, you could change the code to
' Check if there is already a chart on the sheet
If Worksheets("chart11").ChartObjects.Count > 0 then Exit Sub
Dim co as ChartObject
With Worksheets("chart11")
' Create a new Chart
Set co = .ChartObjects.Add(Left:=.Range("a1").Left, Top:=.Range("a1").Top, Width:=400, Height:=300)
co.Name = "hi"
Debug.Print co.Name, co.Chart.Name ' <-- You will see "Hi chart11 Hi"
End With
With co.Chart
...(Do your chart magic here)
End With
If you want to check if the chart "Hi" already exists, use
Dim co As ChartObject
On Error Resume Next
' Check if Chart "Hi" already exists
Set co = Worksheets("chart11").ChartObjects("Hi")
If Not co Is Nothing Then Exit Sub
On Error Resume Next

Related

Create one chart which can will plot values from another sheet into a chart named as "countChart". i want only one chart in my workbook

i am trying to plot values from another sheet, but each time i run the macros it creates a chart everytime i run it. is there a way where i can create only one chart (like we do in sheets, create one sheet if its not already exits, and then add values to it) and the plot the values as the values changes in another sheet.
Option Explicit
Sub chartAdd_v2()
Dim chartSheet As ChartObject
Set chartSheet= Charts.Add
chartSheet.SetSourceData Worksheets("count_issue").Range("A2:c17")
End Sub
Option Explicit
Sub chartAdd_v2()
With Charts
If .Count = 0 Then
.Add
End If
.Item(1).SetSourceData Sheets("count_issue").Range("A2:C17")
End With
End Sub
Create if not existing
Sub mycharts()
Const CHART_NAME = "issues"
Dim wb As Workbook, ws As Worksheet
Dim cht As Chart, bHasChart As Boolean
Set wb = ThisWorkbook
Set ws = wb.Sheets("Count_issue")
For Each cht In wb.Charts
If cht.Name = CHART_NAME Then bHasChart = True
Exit For
Next
If bHasChart Then
Set cht = wb.Charts.Item(CHART_NAME)
Else
Set cht = wb.Charts.Add
cht.Name = CHART_NAME
End If
cht.SetSourceData ws.Range("A2:C17")
End Sub

Saving excel range as a picture

I have an Excel sheet that has several charts and images which is used as a dashboard. I need to save the content in the area as an image. I found this code to save the area as an image:
Set sht = ActiveWorkbook.Sheets("Graphical Dashboard")
Set strRng = sht.Range("I1:AC124") ' range to be copied
strRng.CopyPicture xlScreen, xlPicture
lWidth = strRng.Width
lHeight = strRng.Height
Set Cht = sht.ChartObjects.Add(Left:=0, Top:=0, Width:=lWidth, Height:=lHeight)
Cht.Activate
Set oCht = Charts.Add
With oCht
.Paste
.Export Filename:=ThisWorkbook.Path & "\SavedRange.jpg", Filtername:="JPG"
End With
Cht.Delete
But, the problem is, although it saves an image which matches the area of the selected range, the image is blank. Additionally, it adds another sheet named 'Chart' and pastes the blank image to sheet.
As you mentioned, excel file already contains the charts in specified range, So there is no need to add chart object Set Cht = sht.ChartObjects.Add(Left:=0, Top:=0, Width:=lWidth, Height:=lHeight).
I have Tested the following code and it is working.
Private Sub Test()
Set sht = ActiveWorkbook.Sheets("Sheet1")
Set strRng = sht.Range("A1:B2") ' range to be copied
Dim oCht As Chart
strRng.CopyPicture xlScreen, xlPicture
lWidth = strRng.Width
lHeight = strRng.Height
Set oCht = Charts.Add
With oCht
.Paste
.Export Filename:="D:\SavedRange.jpg", Filtername:="JPG"
End With
End Sub
And if chart is not there in excel and you want to draw in VBA then you will have to set source data in Chart.
.SetSourceData Source:=Sheets("Sheet1").Range("A1:B2")
Well doing whole thing VBA didn't work for me. Therefore, I have used below approach.
Select and copy the range from macro.
ActiveWorkbook.Sheets("Graphical Dashboard").Activate
Range("H80:AB121").Select
Selection.Copy
Save the content from clipboard as an image.
# invoke the macro
xlapp.Application.Run("SelectRangeMacro")
# save the area as a image
im = ImageGrab.grabclipboard()
im.save('somefile.png','PNG')
First I select the range I need to copy and use the method .CopyPicture, then I clear all current pictures out of the workbook if the type is msoPicture, then I paste the image into the worksheet in order to add it to the chart, I then add the copied picture to the chart, export it, and remove the chart when I'm finished.
Dim oCht, oChtArea, pic
Range("B2:AI5").CopyPicture
'On Error Resume Next
For Each pic In ThisWorkbook.Sheets("MonthlyRevenue").Shapes 'Deleting pics before copying next one in
If pic.Type = msoPicture Then
Debug.Print pic.Name
pic.Delete
End If
Next
With ThisWorkbook.Sheets("MonthlyRevenue").Pictures.Paste
.Left = Range("C15").Left
.Top = Range("C15").Top
.Name = "monthRevPic"
End With
For Each pic In ThisWorkbook.Sheets("MonthlyRevenue").Shapes
If pic.Type = msoPicture Then
Debug.Print pic.Name
pic.Copy
'SavePicture pic, "C:\temp\tempchart.jpg"
Set oCht = ActiveSheet.ChartObjects.Add(0, 0, pic.Width, pic.Height)
Set oChtArea = oCht.Chart
With oChtArea
.Paste
.Export ("C:\temp\tempchart.jpg")
End With
oCht.Delete
End If
Next

Unable to move Boxplot chart successfully

I have been looking around the web and have since gathered some codes that will create a box plot and move it to another worksheet. However, the following code is able to create the box plot but unable to move it to a new sheet and when it tried, this error pops up
Run-time error '1004' Method 'Location' of object '_Chart' failed
on this line
Set c = c.Location(where:=xlLocationAsNewSheet, Name:="newChartSheetName")
and when i tried to run it again, my excel file will just close itself without saving. I have tried to create a boxplot at the worksheet i wanted it to be but the data is from another worksheet which makes the chart empty which is why i changed to this method. The following is my current attempt to this problem. Appreciate any help given.
Sub test_boxplot()
Dim chart_title As String
Dim RngToCover As Range
Dim ChtOb As ChartObject, c As Chart
With Sheets("Data")
.Select
.Range("E6:E425").Select ' I understand this is not an efficient way to go about it.
chart_title = .Range("E2")
.Shapes.AddChart2(408, xlBoxwhisker).Select
ActiveChart.ChartTitle.Text = chart_title
End With
With Sheets("Graphs")
Set RngToCover = .Range("L6:O23")
End With
Set ChtOb = ActiveChart.Parent
Set c = ChtOb.Chart
Set c = c.Location(where:=xlLocationAsNewSheet, Name:="newChartSheetName") 'Error here
c.Move After:=ThisWorkbook.Worksheets(ThisWorkbook.Worksheets.Count)
With ChtOb
.Height = RngToCover.Height ' resize
.Width = RngToCover.Width ' resize
.Top = RngToCover.Top ' reposition
.Left = RngToCover.Left ' reposition
End With
End Sub
If I'm not wrong then .Location where:=xlLocationAsNewSheet gives an error for BoxPlot but successfully moves the chart. You can use On Error Resume Next | On Error Go To 0 to tackle this error.
There is also one more issue. The name successfuly will change to newChartSheetName but will not reflect in the VBE Project Properties. It'll show as ChartXXX as shown in the image below. The name will only display in the VBE once the file is saved, closed and re-opened. The name does get updated in the Properties window though. Couldn't find any MS KB to support my above statement. You can try & test it your self.
In case you try & create a columnclustered chart & then move it as a chart sheet, it'll let you but then it'll not let you use .ChartType to change it to xlBoxwhisker. It will give you The specified dimension is not valid for the current chart type error. This is usually when Excel is unable to create/convert to complex chart types.
There was an alternative but that is a definite bug. Charts.Add has a 4th parameter which is Type:= where you could have specified xlBoxwhisker but fails with Runtime Error 1004. This is a bug since Excel 2007. You cannot use this for any other type as well.
Also avoid using .Select/Activechart. Use objects and work with them. It will make your life easier.
Here is an example
Option Explicit
Sub Sample()
Dim ws As Worksheet, wsChrt As Chart
Dim objChart As ChartObject
Dim chrt As Chart
Dim shp As Shape
'~~> Change this to the relevant sheet
Set ws = Sheet1
'~~> Delete existing chart if any
Application.DisplayAlerts = False
On Error Resume Next
ThisWorkbook.Sheets("test").Delete
On Error GoTo 0
Application.DisplayAlerts = True
'~~> Create new chart and move
With ws
Set shp = .Shapes.AddChart2(408, xlBoxwhisker, 200, 100, 350, 200, True) '
Set objChart = .ChartObjects(shp.Name)
Set chrt = objChart.Chart
With chrt
'~~> Set your source data here
.SetSourceData Source:=ws.Range("E6:E11")
On Error Resume Next
.Location where:=xlLocationAsNewSheet, Name:="test"
Set wsChrt = ThisWorkbook.Sheets("test")
On Error GoTo 0
End With
If Not wsChrt Is Nothing Then
MsgBox "Chart Moved"
With wsChrt
'
'~~> Do what you want with the chart
'
End With
Else
MsgBox "Error in creating a chart"
End If
End With
End Sub

vba -How to place a chart below/down a different location when there exists a chart at the current location

I select a range for the chart to create. When created I place at a different sheet called "charts". I first check the existence of this sheet-"charts" and then place it in location. But what I want to achieve is if there exists a chart in that location already say I1 then I want the new chart that I created to go to I16. If that also has a chart then it should move to location I31 until it finds an empty spot.
Dim blnFound As Boolean
blnFound = False
'
'
ActiveChart.Parent.Cut
End With
For i = 1 To ActiveWorkbook.Sheets.Count
If ActiveWorkbook.Sheets(i).Name = "Charts" Then
Sheets("Charts").Select
Range("I1").Select
ActiveSheet.Paste
blnFound = True
Exit For
End If
Next i
If blnFound = False Then
Sheets.Add(After:=Sheets(Sheets.Count)).Name = "Charts"
Sheets("Charts").Select
Range("I1").Select
ActiveSheet.Paste
End If
The above image shows how the charts are overlaping.
I am using
.Parent.Cut
and then pasting as in the code
how do I achieve that in vba code?
One way is to recursively call the same procedure that checks if a chart exists in your range and move the range down before checking again.
This code will check if a chart already covers the exact same range as the one you're trying to place. If the second chart overlaps the first then it will happily create the new chart, only if both charts are trying to cover the exact same range will it try and move the new chart down.
Note - this sample code only creates the chart container, not the chart itself.
Any code to create the chart within the chartobject would go after the ChartObjects.Add line.
Sub Test()
Add_Chart Sheet1.Range("C2:F5")
End Sub
Public Sub Add_Chart(Target As Range)
Dim oCht As ChartObject 'The chart container.
Dim bExists As Boolean 'Will be False when first created.
'Look at each chart container on the sheet.
For Each oCht In Target.Parent.ChartObjects
If oCht.TopLeftCell.Address = Target.Cells(1, 1).Address And _
oCht.BottomRightCell.Address = Target.Cells(Target.Rows.Count + 1, Target.Columns.Count + 1).Address Then
bExists = True 'The chart does exist.
Exit For 'No need to keep searching.
End If
Next oCht
If bExists Then
'Call this procedure again, but move the Target range down.
Add_Chart Target.Offset(oCht.BottomRightCell.Row - oCht.TopLeftCell.Row)
Else
Target.Parent.ChartObjects.Add _
Target.Left, Target.Top, Target.Width, Target.Height
End If
End Sub
I'd keep it simple and position the next chart just under the previous one by looking at its top and height properties. Assuming you've assigned your worksheet to a variable called ws:
Dim nextPosition as double
Dim cObj as ChartObject
If ws.ChartObjects.Count = 0 then
nextPosition = 1 ' there are no charts, paste the new one one point from the top of the window
Else
set cObj= ws.ChartObjects(ws.ChartObjects.Count) ' get the most recently added chart...
' work out where to move the new chart by summing position & height of the previous chart
nextPosition = cObj.Top + cObj.Height + 10 ' 10, or whatever padding you want between charts
End if
myChart.Copy
ws.Range("A1").select
ws.Paste
Set cObj= ws.ChartObjects(ws.ChartObjects.Count)
cObj.Top = nextPosition

Excel VBA chart, show data label on last point only

I want to add data labels to only the final point on my line graph, at the moment I am using the below, which works fine but only if I know what number the final point is.
I've done a lot of searching and found the points(points.count) object in excel help but I can't seem to make it work for me.
Please can you suggest a way of only showing the last point on my chart or (ideally) all charts on a worksheet.
Sub Data_Labels()
'
' Data_Labels Macro
ActiveSheet.ChartObjects("Menck Chart").Activate
ActiveChart.SeriesCollection(1).DataLabels.Select
Selection.Delete
ActiveSheet.ChartObjects("Menck Chart").Activate
ActiveChart.SeriesCollection(1).Select
ActiveChart.SeriesCollection(1).Points(59).Select
ActiveChart.SeriesCollection(1).Points(59).ApplyDataLabels
ActiveChart.SeriesCollection(1).DataLabels.Select
Selection.Format.TextFrame2.TextRange.Font.Size = 9
End Sub
Short Answer
Dim NumPoints as Long
NumPoints = ActiveChart.SeriesCollection(1).Count
ActiveChart.SeriesCollection(1).Points(NumPoints).ApplyDataLabels
Long Answer
The use of ActiveChart is vague, and requires the additional step of selecting the chart of interest. If you specify the chart you are interested in explicitly, your macro will be much more robust and easier to read. I also recommend either using a With block, or creating intermediate variables, since reading ActiveChart.SeriesCollection(1).Points over and over is painful and clutters your code. Try the later method as follows:
Dim chartMenck As Chart, menckPoints as Points, menckDataLabel as DataLabel
Set chartMenck = Sheet1.ChartObjects("Menck Chart").Chart
Set menckPoints = chartMenck SeriesCollection(1).Points
menckPoints(menckPoints.Count).ApplyDataLabels
Set menckDataLabel = menckPoints(menckPoints.Count).DataLabel
menckDataLabel.Font.Size = 9
This is nearly half as long as the original and far easier to read, in my opinion.
Try this. First it applies datalabels to ALL points, and then removes them from each point except the last one.
I use the Points.Count - 1 that way the For/Next loop stops before the last point.
Sub Data_Labels()
'
Data_Labels Macro
Dim ws As Worksheet
Dim cht as Chart
Dim srs as Series
Dim pt as Point
Dim p as Integer
Set ws = ActiveSheet
Set cht = ws.ChartObjects("Menck Chart")
Set srs = cht.SeriesCollection(1)
'## Turn on the data labels
srs.ApplyDataLabels
'## Iterate the points in this series
For p = 1 to srs.Points.Count - 1
Set pt = srs.Points(p)
'## remove the datalabel for this point
p.Datalabel.Text = ""
Next
'## Format the last datalabel to font.size = 9
srs.Points(srs.Points.Count).DataLabel.Format.TextFrame2.TextRange.Font.Size = 9
End Sub
Yet another way in VBA (e.g. paste as a new hotkey macro in PERSONAL workbook): https://peltiertech.com/Excel/Charts/LabelLastPoint.html
For impatient, with ShowValue:=True:
Option Explicit
Sub LastPointLabel()
Dim mySrs As Series
Dim iPts As Long
Dim bLabeled As Boolean
If ActiveChart Is Nothing Then
MsgBox "Select a chart and try again.", vbExclamation, "No Chart Selected"
Else
For Each mySrs In ActiveChart.SeriesCollection
bLabeled = False
With mySrs
For iPts = .Points.count To 1 Step -1
If bLabeled Then
' handle error if point isn't plotted
On Error Resume Next
' remove existing label if it's not the last point
mySrs.Points(iPts).HasDataLabel = False
On Error GoTo 0
Else
' handle error if point isn't plotted
On Error Resume Next
' add label
mySrs.Points(iPts).ApplyDataLabels _
ShowSeriesName:=True, _
ShowCategoryName:=False, _
ShowValue:=True, _
AutoText:=True, LegendKey:=False
bLabeled = (Err.Number = 0)
On Error GoTo 0
End If
Next
End With
Next
End If
End Sub

Resources