Error while creating error bars in Excel with VBA - excel

I want to insert error bars into a clustered column chart in excel using macros. Whenever I do, an error is thrown.
I have a much larger program that takes and sorts data into a couple column charts, and I want to add error bars to them. In an attempt to troubleshoot, I stripped the program way back to just the part that adds the error bars in a separate sheet (code below). I made a simple column chart, selected it and tried to run the program, but it threw an Application Defined error.
Then I tried recording a macro, and that also failed (with a "Method SetElement of Object _Chart Failed" error).
I've Googled around a bit, and found next to nothing (only examples of how to use my first method, close to exactly the same as mine), but also I am relatively new to VBA and might just not know the correct words to google.
Here is my code:
'The code that I had written
Sub AddErrorBars()
'Adds error bars (Standard deviation) to selected chart
ActiveChart.SeriesCollection(1).ErrorBar Direction:=xlY, _
Type:=xlErrorBarTypeStDev, Include:=xlBoth
End Sub
'The code generated by recoring a macro
Sub AddErrorBarsV2()
'Adds error bars (Standard deviation) to selected chart
ActiveChart.SetElement (msoElementLineHiLoLine)
End Sub
One odd thing, the Include enum in first sub (xlBoth) was listed as xlErrorBarIncludeBoth in the MO documentation website, but the listed value is 1, which is the value of xlBoth according to the debugger, xlErrorBarIncludeBoth is empty. Using xlNone doesn't spit out an error, but also doesn't generate error bars. Ive also tried changing the Direction, but that doesnt seem to help.
Is there something I am doing wrong, or perhaps is it the way my data is formatted? Does anyone else seem to have the same issue?

If you have the chart selected, then ActiveChart.SetElement (msoElementErrorBarStandardError) will work fine. However, you should call the chart by name, like so:
ThisWorkbook.Worksheets("Sheet1").ChartObjects("Chart 1").Chart.SetElement (msoElementErrorBarStandardError)

Related

Select headers in table - method range of object _ global failed - works when run with button? but not stepping through

When stepping through my code i get error 1004 on this line.
Range("tablename[[#Headers],[startheadername]:[lastheadername]]").Select
Now the weird thing is, I use it every month without issue via a button.
This error only pops when im stepping through the code.
this works instead
ActiveSheet.ListObjects("Tablename").HeaderRowRange(1).Resize(, 7).Select
The error code involves the words "range of object" which made me think that maybe there was a way to use the object in another manner. my original code was just a simple range reference.
I dont have particular insight into listobjects, i mainly copy pasted and tested. But headerrowrange(1) is the first column header in the tablename, resize(,7) expands it from 1 to 7 and .Select does what it does.
So this new code selects the first 7 table headers without error 1004.
This site got me there https://exceloffthegrid.com/vba-excel-tables-code/

"On Error GoTo" ignored when searching for second horizontal axis

NOTE: the code below actually works! See my own answer on the cause of the issue I was having. I decided to leave the code here since I have seen other questions regarding how to delete second horizontal axis.
THE INITIAL QUESTION/ISSUE: I'm formating a series of spreadsheets that have multiple charts on them. When applying the chosen chart style (I'm using style 209 - with a code line "ActiveChart.ChartStyle = 209), some charts come back with two horizontal axis, which I don't want (some charts have two vertical axis - but that is OK). Instead of going chart by chart and manually deleting each secondary horizontal axis, I included a piece of code on my formating subroutine. The code works most of the time. But sometimes I get the error below:
VB error image
The impression I have is that the "On Error GoTo" is being "ignored". I.e. the error above happens when I get to "ActiveChart.SetElement..." line, as the chart has no secondary axis. This means that the line where I asked for the secondary axis' maximum scale (i.e., "chart_axis = ...") must have returned an error (as the secondary axis doesn't exist). Which means that the "On Error GoTo" was ignored (or didn't jump to "No_second_axis").
Here is the part of the code I'm using that deletes the second axis (if it exists):
Dim s_name As String
Dim chart_axis As Variant
For Each Shape In ActiveSheet.Shapes
s_name = Shape.Name
If Shape.Type = msoChart Then
ActiveSheet.ChartObjects(s_name).Activate
On Error GoTo No_second_axis
'Try to get the "scale" of secondary horizontal axis - error if non-existent
chart_axis = ActiveChart.Axes(xlValue, xlSecondary).MaximumScale
'If it reached this line, there was no error when getting the second horizontal axis scale (i.e., the second horizontal axis exists. No I can delete it!
With ActiveChart
ActiveChart.SetElement (msoElementSecondaryCategoryAxisNone)
End With
No_second_axis:
End If
Next Shape
End Sub
Am I missing something? Why does the "On Error Go To" appears to work sometimes but doesn't work for some charts? I can't find a "pattern" in terms of which type of chart it works with vs. a type of chart it doesn't work with.
After an extra couple of hours struggling with this issue, I decided to inspect each chart before running the sub. Using "Go To" on Excel (shortcut = F5) and selecting "objects", I could cycle through each object (by pressing TAB). What I realized is that I had some "hidden" charts (i.e., very old charts that were somehow minimized/collapsed into a obscure place in the spreadsheet). These charts had no "series" on them. For some reason, the "chart_axis = ..." part of the code above can read a secondary horizontal axis scale, but the axis really doesn't exist (as I get an error when trying to delete such axis). Maybe this is a bug on Excel or there is a logical explanation for it - but this is beyond what I need for now. I decided to answer my own question in case this example helps someone else.
The error you are getting is a generic Office error that suggests something went wrong under the hood.
To try and avoid this error I would try the following:
Use Application.ScreenUpdating=false in the beginning of the function (and then Application.ScreenUpdating=true in the end). This helped me avoid rendering problems in the when updating a large number of objects/shapes in an Office document.
OR
Use Application.ScreenUpdating=false in the beginning of every iteration of your Shape object loop and then use Application.ScreenUpdating=true after updating it.
Hopefully you will be able to spot which of the charts creates a problem and under which circumstances (or state).

How to position a chart copied from excel into powerpoint using CommandBars?

I am trying to copy some charts (embedded) in different worksheets of an excel workbook using vbscript into different slides of a powerpoint. I would like to keep the link between the excel sheet and the powerpoint while doing so and therefore I used the below piece of code that allows me to keep formatting and link (instead of a simple paste or PasteSpeical. Is there any other way?) :
For i = 1 to TotalNumWorkSheets 'I iterated with indices.
Set pptSlide = pptPres.Slides.Add(i, 11) 'There is one opening slide before this.
set ws = wb.Worksheets(i)
ws.ChartObjects(1).Chart.ChartArea.Copy
pptApp.CommandBars.ExecuteMso("PasteExcelChartSourceFormatting")
pptApp.CommandBars.ReleaseFocus
With pptSlide
.Shapes.Title.TextFrame.TextRange.Text = objCurSheet.Name
'Adding some more textboxes here. Working fine. Position checks out in PPT.
.Shapes(.Shapes.Count).Left = 20 'Doesn't work for all slides.
End With
Next
The code works and copies all the charts, creates titles, adds new text as expected, but I am not able to position the charts on individual slides because after the ExecuteMso command, I don't know how to access the reference to the chart. I read in one of the SO posts that pasting using this method looses the chart selection but you can access the last .Shapes object since pasting always adds the object to the end of the list. Is that always the case? I tried accessing and positioning my chart by accessing the last object but it only works for the first slide of the loop (i.e. the first chart pasted is shifted to Left=20). The rest all charts in other slides are centered. Can someone explain where and how to add the formatting chart options? I ran into an even weirder problem. If I increase the number of worksheets, even the first plot looses it's Left formatting. The above code is the only place where I add formatting so I don't know what is happening. I am sure I am not formatting it correctly.
Many thanks for your suggestions.
Edit: One additional thing which I tested. I am using
WScript.Sleep 500
code before the For loop ends since it gives enough time for earlier operations to finish (at least that's what I understood from many other google searches).
So after some more searching and testing, I found a solution (for my case at least).
Moved the WScript.Sleep 1000 (500 didn't work for me) statement just below CommandBars.ReleaseFocus.
It makes some sense now since it is the Chart copying, pasting and linking from excel that needs time. Especially with source formatting. After that there is only text generation which I believe is not so heavy.
Cleared all the set Object variables when not used. Especially the ones associated with the "With" keyword.
set obj = CreateObject()
With obj
'Do something here.
End With
set obj = Nothing
Not clearing them, apparently, can also prevent you from closing the applications even after you use the .Close and .Quit method. At least that's what I observed. I found PowerPoint.exe running in the task manager when nothing was opened.
After doing the above, I am able to copy with format the charts and also able to set the position of the charts. The weird problem of larger number of worksheets also disappeared. Hopefully, it might help others. If someone thinks the observations are incorrect or troublesome, please correct.

Shape.CopyPicture fails (Error 1004) when Format:=xlBitmap

I am attempting to copy a shape group which contains some charts as a high resolution picture. To achieve the high resolution, I use the options Appearance:=xlPrinter and Format:=xlBitmap.
Run-time error '1004' Application-defined or object-defined error
The code I am using to do this is below
ws.Shapes.Range(Array("Chart 1", "Chart 2")).Group.Name = "temp_group"
With ws.Shapes("temp_group")
.CopyPicture Appearance:=xlPrinter, Format:=xlBitmap
.Ungroup
End With
If I just remove the Format:=xlBitmap or change it to Format:=xlPicture, it works fine. The MSDN help shows xlBitmap as an option and I have tried just using 2 but that gives the same error.
If I try the same thing on a single chart, it works just fine.
ws.ChartObjects("Chart 1").Chart.CopyPicture Appearance:=xlPrinter, Format:=xlBitmap
What is the best way to copy multiple charts as a high resolution picture? I would like to avoid saving them because I need to copy/paste multiple groups of up to 30 charts for exporting to OneNote.
Edit:
After some additional testing, it turns out that I can use xlBitmap if the appearance option is set to xlScreen instead of xlPrinter. However, the resolution is still pretty terrible. This is very frustrating since just copy/pasting these same charts manually gives very nice clear pictures but for some reason VBA just ruins it. VBA is required though since this would be a very time consuming process otherwise.
shape.copypicture work's fine in excel 2016. The error is in office 360.
I was facing the same problem in my app. Here is the solution:
If you want to copy an object of type MsoShapeType.msoChart or MsoShapeType.msoPicture do this trick:
shape.ScaleHeight(2.5f, MsoTriState.msoFalse);
shape.ScaleWidth(2.5f, MsoTriState.msoFalse);
shape.Copy();
shape.CopyPicture(Excel.XlPictureAppearance.xlScreen, Excel.XlCopyPictureFormat.xlPicture);
shape.ScaleHeight(0.4f, MsoTriState.msoFalse);
shape.ScaleWidth(0.4f, MsoTriState.msoFalse);
where shape is of course your object.
First, you need to scale up the object (scaling is loseless up to orginal size of the image or maximum size of the chart, which is just 400% zooming). Then, you use CopyPicture() method with mentioned parameters, preceed with Copy()*.The last thing to do is to scale down (or not, if you won't save this sheet) the object.
*Copy() is used here to eliminate common and random error
System.Runtime.InteropServices.COMException (0x800A03EC): CopyPicture method of range class failed
If you open any Excel sheet, you will see some copy configurations:
link, because I can't add images yet
Common copy is just (xlScreen, xlBitmap);
Good quality copy is xlScreen, xlPicture) and, depending on installed printer driver, (xlPrinter) and (xlPrinter, xlPicture);

Resetting Chart Axis fails

Sorry for such a simple question, I can't figure this out. I have searched several forums for ideas but none of them solved my issue.
All I want is to have the graph axis reset upon the end of some code.
Sheet1.ChartObjects("Chart 13").Chart.Axes(xlValue).MinimumScaleIsAuto = True
This is what I used along with several variations and I get the same error.
Method 'MinimumScaleIsAuto' of object 'Axis' failed.
OR Subscript out of Range
I can assure you that it is Chart 13, and on Sheet1.
Interestingly, if I record a macro doing what I want, then run the macro, I get the same error...

Resources