5
votes

I am experiencing an error in a subroutine attempting to set the plotarea.width property of a chart.

enter image description here

The other dimensions also cause this error if I comment out the preceding line(s). There is no ActiveChart, no selection, etc. The specific error message is this: "-2147467259 (80004005) Method 'Width' of object 'PlotArea' failed"

This is stumping me for several reasons:

  • In debug mode, F8 to step through the code the error does NOT occur.
  • AFAIK "width" is not a "method" but a "property" of the chart's plotarea, so even the error message is rather ambiguous.

Any thoughts? Here's as much code as I can share, the ChartSizeMedium subroutine in its entirety, and a dummy snippet to show you how I am establishing the chart and passing it to that sub which sets the size & some other properties prior to passing to another function which adds the series data to the chart.

    Option Explicit
    Private Sub EstablishChartObject()
    Dim cObj as ChartObject
    Set cObj = ActiveSheet.ChartObjects.Add(Left:=30, Top:30, Width:=740, Height:=300)
        ChartSizeMedium cObj.Chart, "Integer", "Example Chart Title"
    End Sub
    Private Sub ChartSizeMedium(cht As Chart, NumType As String, Optional chtTitle As String)
    'Subroutine to make a consistent size chart
    Dim s As Long
    With cht
    'Add a chart title if one exists.
        If Len(chtTitle) > 0 Then
        .HasTitle = True
        .chartTitle.Characters.Text = chtTitle
        End If
    'Create the default chart Legend
        .HasLegend = True
        With .Legend
        .Position = xlTop
        .Font.Size = 11
        .Font.Bold = True
        End With
    'Format the axes
        .Axes(xlValue).MajorGridlines.Format.Line.Visible = msoFalse
        .Axes(xlValue).MinorGridlines.Format.Line.Visible = msoFalse

    'Format the size of the chart
        With .Parent
        .Width = 740
        .Height = 396
        End With

        With .PlotArea
        .Width = 640    '<---- THIS LINE TRIGGERS THE ERROR
        .Height = 280
        .Left = 30
        .Top = 30
        End With
    End With
    'Some charts start with more than one series container, so make sure they're gone:
    With cht
    Do Until .SeriesCollection.Count = 0
    s = .SeriesCollection.Count
    .SeriesCollection(s).Delete
    Loop
    End With
    End Sub

UPDATE Dec 12, 2012

I remove all non-problematic code and use only the PlotArea with block, in the same routine, I have also tried setting the chart type (several values) and as shown in this example, manually adding one series of data prior to attempting to set the PlotArea dimensions, but the error persists:

Option Explicit
Private Sub EstablishChartObject2()
    Dim cObj As ChartObject
    Dim sh As Worksheet

    Set sh = ActiveSheet
    Dim srs As Series
    Set cObj = sh.ChartObjects.Add(Left:=30, Top:=30, Width:=740, Height:=300)
    Set srs = cObj.Chart.SeriesCollection.NewSeries

    srs.Values = "={1,3,5,7,4}"
    cObj.Chart.ChartType = 57

    With cObj.Chart.PlotArea
        .Width = 100   '<---- THIS LINE TRIGGERS THE ERROR
        .Height = 280
        .Left = 30
        .Top = 30
    End With

End Sub
6
just throwing this out there, does it occur for certain chart types? maybe 1 that does not have a plot area (if that even exists... ) - Scott Holtzman
@ScottHoltzman thanks for the suggestion but by default, ChartType is 57 (xlBarClustered) which definitely does have a PlotArea :) Debug.Print cObj.Chart.PlotArea.Width returns a plotarea.width of 718. - David Zemens
This thread discusses a similar problem and a refresh timing issue: excelforum.com/excel-programming-vba-macros/…. You have to log in to see Andy Pope's solution, so I don't know what it is, but since it Andy's I'm sure it works. This thread says that they solved it by turning ScreenUpdating back on: vbaexpress.com/forum/archive/index.php/t-17251.html. Don't know if that applies to you. - Doug Glancy
can you comment this width line to see if error jumps any other line? - bonCodigo
@DougGlancy ScreenUpdating=True in this sub already, so it's not an issue of turning it back on (temporarily) although I had seen that suggestion when trying to google the error, and tried playing with ScreenUpdating to no avail. - David Zemens

6 Answers

4
votes

i had a similar problem . And its definitely an excel issue (having 2013).

With .PlotArea 
    .Select 'err if delete this line of code
    .Top = 0
    .Left = 0
    .width = 40
    .Height = 40 
End With

if you remove the .selectline, it will result in error on the next line. note that i am not working with a <with selectiondo stuff>. the .selectmakes it work, without using the selection, wich is obviously an excel bug (from previous versions?)

3
votes

Two solutions that seem to be working, neither is really as "elegant" as I'd prefer (I was hoping there would be a way to do this with selecting the chart or any part of it).

Option 1 - Select the plot area and then deselect it. This seems to be the most reliable/efficient solution.

With .PlotArea
    Application.ScreenUpdating = False
   .Select
    With Selection
        .Width = paWidth
        .Height = paHeight
        .Left = paLeft
        .Top = paTop
        ActiveSheet.Range("A1").Activate
    End With
    Application.ScreenUpdating = True
End With

Option 2 - disable error-handling in loop (this followed from Doug's link). This doesn't seem to be a very reliable or efficient method, and although it seems to work, I know that within that loop it is failing once on each of the properties before it successfully sets them on a subsequent pass.

With .PlotArea
    For pLoop = 1 To 5
        On Error Resume Next
        .Width = paWidth
        .Height = paHeight
        .Left = paLeft
        .Top = paTop
        On Error GoTo 0
    Next
End With
1
votes

Hope your sheet and chart has the ability to get a width up to 640. If so try the explicit reference. Also suggest you to change width, height values to lower values and see how programme responds. Since you said, when you select it works,

  • that also means, your cht is wrapping the correct chart object - unless otherwise you selected the chart using ActiveChart.PlotArea.Width . Hence I guess explicit reference could do be a potential try out.

,

cht.PlotArea.Width = 640
cht.PlotArea.Height = 280
cht.PlotArea.Left = 30
cht.PlotArea.Top = 30

Further, check on Aspect Ratio lock or unlock. If none of these works, then add a chart into your sheet and use most simple chart formatting code to check on widht, height, left, top changes.


Update two

Let's try specifing chart type and setting up chart object in the second sub as well. I tried out in my end and it's working. Try the code with following changes.

Code: Calling this sub from the button showed in the sheet.

Option Explicit

  Public Sub EstablishChartObject()
  Dim mySheet As Worksheet
  Dim cObj As ChartObject

    Application.ScreenUpdating = False
    Application.StatusBar = "Chart is coming soon..."

    Set mySheet = Sheets(2) '-- set according to yours
    '-- create chart with some source data first, which you can change later
    Set cObj = mySheet.ChartObjects.Add(Left:=30, Top:=30, Width:=400, Height:=200)
    ChartSizeMedium cObj, "Integer", "Example Chart Title"
        
  End Sub


  'Subroutine to make a consistent size chart
  Private Sub ChartSizeMedium(chtObj As ChartObject, NumType As String, _
                                  Optional chtTitle As String)
    
  Dim myChart As Chart
  Dim s As Long
    
     Set myChart = chtObj.Chart '-- specify chart type
     myChart.SetSourceData Source:=Sheets(2).Range("B3:C12")  '-- set to what you have
     myChart.ChartType = xlXYScatterLines  '-- set to the type you want 
                                          'and make sure to **use correct properties**

        With myChart
            If .HasTitle Then
                .ChartTitle.Characters.Text = chtTitle
            End If
        
            'Create the default chart Legend
            If .HasLegend Then
                With .Legend
                    .Position = xlTop
                    .Font.Size = 11
                    .Font.Bold = True
                End With
            End If
            
            'Format the axes
            With .Axes(xlValue)
                .HasMajorGridlines = False
            End With
                    
            'Format the size of the chart
            With .Parent
                .Width = 400 '-- change to yours
                .Height = 250 '-- change to yours
            End With
    
            With .PlotArea
                .Width = 300 '-- change to yours
                .Height = 180 '-- change to yours
                .Left = 30
                .Top = 30
            End With
    End With

    Application.ScreenUpdating = True
    Application.StatusBar = "Chart is Here!"

End Sub

Otput:

enter image description here

Make sure to use correct properties for each chart type. Note that above code doesn't delete any left over, old charts from your sheet.

.MajoreGridlines.Format.Lines.Visible fails. So set the .MajorGridlines = False to make sure you do not want to show the gridlines. Anything else you want to do can be done later. Just try with the changes to dimension initially.

Reference from : MSDN Gridlines property

1
votes

I know this is old, and this solution seems bad, but it works. I only thought to do it as you mention that stepping through works.

Option Explicit

Sub chart()

Dim cObj As ChartObject
Dim sh As Worksheet

Set sh = ActiveSheet
Dim srs As Series
Set cObj = sh.ChartObjects.Add(Left:=30, Top:=30, Width:=740, Height:=300)
cObj.chart.ChartType = 57
Set srs = cObj.chart.SeriesCollection.NewSeries
    srs.Values = "={1,3,5,7,4}"
Application.Wait Now + TimeValue("00:00:01") '<~~ Added This line
With cObj.chart.PlotArea
    .Width = 100
    .Height = 280
    .Left = 30
    .Top = 30
End With
End Sub
1
votes

EDIT: This seems to work for some chart types, but it was still failing for other chart types. I have continued to use the 5x loop with On Error Resume Next and that seems to be -- unfortunately -- the most "reliable" solution to-date.

Original: This is based on User2140261's suggested answer, above:

https://stackoverflow.com/a/16041640/1467082

Since the question was initially posted, the application now resides in PowerPoint, so I cannot use the Applicaiton.Wait. I had some intermittent errors with a 1-second pause, and 3-seconds was too much of a pause, so I built the following error trap. The same idea could be used in Excel in conjunction with Application.Wait.

It was this block of code that was giving me fits, so I added this error handling in Powerpoint to mimic the Application.Wait.

RetryChartDimensions:
On Error GoTo ErrChartDimensions
With .PlotArea
    .Width = paWidth
    .Height = paHeight
    .Left = paLeft
    .Top = paTop
End With
On Error GoTo 0

' More code
' more code

Exit Sub 'gracefully exit this subroutine before the error-handling.'

ErrChartDimensions:
Err.Clear
'Pause before setting the PlotArea dimensions:'
Dim wtTime As Double
Dim startTime As Long

'A maximum 3 second delay should be more than enough time.
If wtTime < 3 Then
    wtTime = wtTime + 0.5
    startTime = Timer
    While Timer < startTime + wtTime
        DoEvents
    Wend
End If
Resume RetryChartDimensions

End Sub
0
votes

I don't have enough reputation to add a comment, so using the above solutions I have fixed my problem with Pie Charts in VB.Net 2010 and Excel 2013. xlLine charts never caused a problem, but my code would crash when the same code was ran against an xlPie chart on Excel 2013 (All was fine on Excel 2007).

My now working code:

    appExcel.Visible = False
    xlchart_for_96_Well_Plate_Source = appExcel.Charts.Add(After:=wkbExperiment_Details.Sheets(wkbExperiment_Details.Sheets.Count))
    appExcel.ScreenUpdating = False

    With xlchart_for_96_Well_Plate_Source
            .SetSourceData(Source:=wksData.Range(wksData.Cells(2, byteCharts_added), wksData.Cells(intUsed_Rows, byteCharts_added)), PlotBy:=Microsoft.Office.Interop.Excel.XlRowCol.xlColumns)
            .ChartType = objChart_Type
            .PlotArea.Select() 
            .PlotArea.Top = 2
            .PlotArea.Select()
            .PlotArea.Left = 2
            .SeriesCollection(.SeriesCollection.count).xvalues = wksData.Range(wksData.Cells(2, 1), wksData.Cells(intUsed_Rows, 1)).Value ' Scale - wavelength for line chart
            .SeriesCollection(.SeriesCollection.count).Values = wksData.Range(wksData.Cells(2, byteCharts_added + 1), wksData.Cells(intUsed_Rows, byteCharts_added + 1)).Value
            .SeriesCollection(.SeriesCollection.count).Name = wksData.Cells(1, .SeriesCollection.count + 1).value
    End With
appExcel.ScreenUpdating = True