Loop Through a Specific Set of Charts in Excel VBA - vba

I want to loop though only a specific set of charts in one sheet and then apply to those a set of formating (title font size, title position, axis size, grid lines formating etc.)
The problem ist that there are already 66 charts on that sheet that were manually created (1 to 66). I will now add more charts but automatically generated, and only for those ones I would like to apply the formating needed.
For now I managed to create the charts and apply the formating separately. But in order to make it more fluid I would require a loop that I have not figured out yet. My idea was/is to count all Charts on the sheet and then do something like "If cnt > 66 Then "put here the code starting from the cht.Activate line".
My problem is counting all the charts. I am guessing using something like
with For -> For i to .CharObjects(i). But maybe you can suggest a different way.
Public Sub TEST()
Dim rng As Range, rng1 As Range, rng2 As Range, rng3 As Range
Dim cht As ChartObject, cht1 As ChartObject, cht2 As ChartObject, cht3 As ChartObject
Dim LastRow As Long
Dim wsG As Worksheet: Set wsG = ThisWorkbook.Worksheets("Charts")
Dim wsS As Worksheet: Set wsS = ThisWorkbook.Worksheets("Scatter Raw")
LastRow = wsS.Cells(wsS.Rows.count, "A").End(xlUp).Row
Set rng1 = wsS.Range("A4:B" & LastRow)
Set rng2 = wsS.Range("H4:I" & LastRow)
Set rng3 = wsS.Range("O4:P" & LastRow)
Set cht1 = wsG.ChartObjects.Add(Range("A595").Left, Range("A595").Top, Width:=518.5, Height:=296.7)
Set cht2 = wsG.ChartObjects.Add(Range("M595").Left, Range("M595").Top, Width:=518.5, Height:=296.7)
Set cht3 = wsG.ChartObjects.Add(Range("Y595").Left, Range("Y595").Top, Width:=518.5, Height:=296.7)
cht1.Chart.SetSourceData Source:=rng1
cht1.Chart.ChartType = xlXYScatter
cht1.ShapeRange.LockAspectRatio = msoTrue
cht1.Activate
With ActiveChart
.FullSeriesCollection(1).Name = "=""NAME 1"""
.ChartTitle.Text = "TITLE 1"
End With
cht2.Chart.SetSourceData Source:=rng2
cht2.Chart.ChartType = xlXYScatter
cht2.ShapeRange.LockAspectRatio = msoTrue
cht2.Activate
With ActiveChart
.FullSeriesCollection(1).Name = "=""NAME 2"""
.ChartTitle.Text = "TITLE 2"
End With
cht3.Chart.SetSourceData Source:=rng3
cht3.Chart.ChartType = xlXYScatter
cht3.ShapeRange.LockAspectRatio = msoTrue
cht3.Activate
With ActiveChart
.FullSeriesCollection(1).Name = "=""NAME 3"""
.ChartTitle.Text = "TITLE 3"
End With
For Each cht In wsG.ChartObjects
cht.Activate
With ActiveChart
.Legend.Delete
.ChartTitle.Font.Size = 14
.ChartTitle.Select
With Selection.Format.TextFrame2.TextRange.Font.Fill
.Visible = msoTrue
.ForeColor.ObjectThemeColor = msoThemeColorText1
.ForeColor.TintAndShade = 0
.ForeColor.Brightness = 0.150000006
.Transparency = 0
.Solid
End With
Selection.Left = 27.536
Selection.Top = 5
.ChartArea.Select
With Selection.Format.Line
.Visible = msoFalse
End With
With .Axes(xlValue).TickLabels.Font
.Size = 11
End With
.Axes(xlValue).Select
Selection.Format.Line.Visible = msoFalse
.Axes(xlValue).MajorGridlines.Select
With Selection.Format.Line
.Visible = msoTrue
.ForeColor.ObjectThemeColor = msoThemeColorBackground1
.ForeColor.TintAndShade = 0
.ForeColor.Brightness = -0.25
.Transparency = 0
.Visible = msoTrue
.DashStyle = msoLineDash
End With
End With
Next cht
End Sub

If you want to ignore Chart 3 and Chart 2, add these two names to an array. Then check whether the chart object has name from this array and act accordingly:
Public Sub TestMe()
Dim myChart As ChartObject
Dim chartCount As Long
Dim cnt As Long
Dim chartNamesToExclude As Variant
chartNamesToExclude = Array("Chart 3", "Chart 2")
For Each myChart In Worksheets(1).ChartObjects
If Not valueInArray(myChart.Name, chartNamesToExclude) Then
cnt = cnt + 1
myChart.Chart.ChartTitle.Text = "Title" & cnt
End If
Next myChart
End Sub
Public Function valueInArray(myValue As Variant, myArray As Variant) As Boolean
Dim cnt As Long
For cnt = LBound(myArray) To UBound(myArray)
If CStr(myValue) = CStr(myArray(cnt)) Then
valueInArray = True
Exit Function
End If
Next cnt
End Function
The code above loops through all the charts in Worksheets(1) and changes their titles accordingly to Title N. It ignores the charts with names Chart 3 and Chart 2, by seeing that these are in chartNamesToExclude array.

Thanks Vityata. You solution worked but I think I have found what I was looking for in the beginning. I am not sure if it is better, but it does the job also. Here it is. Cheers, Daniel
Private Sub newtest()
Dim rng As Range, rng1 As Range, rng2 As Range, rng3 As Range
Dim cht As ChartObject, cht1 As ChartObject, cht2 As ChartObject, cht3 As ChartObject
Dim LastRow As Long
Dim wsG As Worksheet: Set wsG = ThisWorkbook.Worksheets("Charts Radio")
Dim wsS As Worksheet: Set wsS = ThisWorkbook.Worksheets("Scatter Raw")
Dim i As Long
For i = 67 To wsG.ChartObjects.count
wsG.ChartObjects(i).Activate
With ActiveChart
.Legend.Delete
.ChartTitle.Font.Size = 14
.ChartTitle.Select
With Selection.Format.TextFrame2.TextRange.Font.Fill
.Visible = msoTrue
.ForeColor.ObjectThemeColor = msoThemeColorText1
.ForeColor.TintAndShade = 0
.ForeColor.Brightness = 0.150000006
.Transparency = 0
.Solid
End With
Selection.Left = 27.536
Selection.Top = 5
'Added more formating / code here
End With
Next
End Sub

Related

Unable to take screenshot (JPEG) of a defined range

I am trying to take a screenshot of a range with a button and put the JPEG in the same folder. The defined range is 'header'
It runs fine for some time then all of sudden I get one of the following errors.
Vba code:
Sub CommandB_Click()
dt = Format(CStr(Now), "yy_mm_dd_hh_mm")
Const FName As String = "Screenshotzx.jpg"
Dim pic_rng As Range
Dim ShTemp As Worksheet
Dim ChTemp As Chart
Dim PicTemp As Picture
Application.ScreenUpdating = False
Set pic_rng = ActiveSheet.Range("header")
Set ShTemp = Worksheets.Add
Charts.Add
ActiveChart.Location Where:=xlLocationAsObject, Name:=ShTemp.Name
Set ChTemp = ActiveChart
pic_rng.CopyPicture Appearance:=xlScreen, Format:=xlPicture
ChTemp.Paste
Set PicTemp = Selection
With ChTemp.Parent
.Width = 1400
.Height = 720
End With
ChTemp.Export Filename:=ThisWorkbook.Path & "\" & "Scrnsht.jpg", FilterName:="jpg"
Application.DisplayAlerts = False
ShTemp.Delete
Application.DisplayAlerts = True
Application.ScreenUpdating = True
End Sub
Error Code 13 Type Mismatch on the following line
Set PicTemp = Selection
Error Code 1004 on the following line
pic_rng.CopyPicture Appearance:=xlScreen, Format:=xlPicture
What about something like this (gets rid of unused variables dt and Fname and avoids ActiveSheet, ActiveChart and Selection)? Note that this uses AddChart2, which is only available in Excel 2013 and later.
Sub SaveRangeAsJPEG()
Dim pic_rng As Range
Dim ChTemp As Chart
Dim ShTemp As Worksheet
Application.ScreenUpdating = False
Set pic_rng = Sheets("YourSheetName").Range("header") 'change to your sheet name
Set ShTemp = Worksheets.Add
Set ChTemp = ShTemp.Shapes.AddChart2.Chart
pic_rng.CopyPicture xlScreen, xlPicture
ChTemp.Paste
With ChTemp.ChartArea
.Width = 1400
.Height = 720
End With
ChTemp.Export Filename:=ThisWorkbook.Path & "\" & "Scrnsht.jpg", FilterName:="jpg"
Application.DisplayAlerts = False
ShTemp.Delete
Application.DisplayAlerts = True
Application.ScreenUpdating = True
End Sub

How to combine shapes using vba-excel?

I want to combine shapes based on range selection. Like this picture. Is it possible?
Here I attached the images:
Here I attached my code
Sub cohabitationButton_Click()
'''''split range
Dim s() As String
Dim txt As String
Dim i As Long
s = Split(Selection.Address(False, False), ",")
For i = LBound(s) To UBound(s)
Dim r As range: Set r = range(s(i))
With r
l = .Left - 5
t = .Top - 5
w = .Width + 10
h = .Height + 10
End With
ShapeName = "ex"
With ActiveSheet.Shapes.AddShape(msoShapeFlowchartTerminator, l, t, w, h)
.Fill.Visible = msoFalse
.Line.Weight = 1
.Line.DashStyle = msoLineDash
.Line.ForeColor.RGB = BASICCOLOR
.Name = ShapeName
End With
Next i
End Sub
There is no possibility to combine shapes in Excel. But here is an example how you can draw combined borders around your selections. This might be an option for you.
So with the selection of your example we end up with this:
Sub DrawCombinedBordersOnly()
'''''split range
Dim s() As String
Dim txt As String
Dim i As Long
Dim rngOverlappings As Range
'Draw borders around all selected ranges
Selection.BorderAround LineStyle:=xlDot, Weight:=xlThin
s = Split(Selection.Address(False, False), ",")
For i = LBound(s) To UBound(s)
Dim r As Range: Set r = Range(s(i))
Dim j As Long
For j = LBound(s) To UBound(s)
'find overlapping areas
If i <> j And Not Application.Intersect(r, Range(s(j))) Is Nothing Then
If rngOverlappings Is Nothing Then
Set rngOverlappings = Application.Intersect(r, Range(s(j)))
Else
Set rngOverlappings = Union(rngOverlappings, Application.Intersect(r, Range(s(j))))
End If
End If
Next j
Next i
' remove borders from overlappings
If Not rngOverlappings Is Nothing Then
rngOverlappings.Borders.LineStyle = xlNone
End If
End Sub
Try This and remove apostrophe ' before ' Range("D5:F9,F8:H12,H11:J15").Select 'for test
Sub cohabitationButton_Click()
'''''split range
Dim WB As Workbook
Dim WS As Worksheet
Dim s() As String
Dim txt As String
Dim i As Long
Dim Shp As Shape
Dim L As Single, T As Single, Lft As Single, Tp As Single
Set WB = ThisWorkbook 'Set WB = Workbooks("WorkbookName")
Set WS = WB.ActiveSheet 'Set WS = WB.WorkSheets("WorkSheetName")
With WS
For Each Shp In .Shapes
If Shp.Type = 5 Then Shp.Delete
Next
' Range("D5:F9,F8:H12,H11:J15").Select 'for test***
MyRange = Selection.Address
s = Split(Selection.Address(False, False), ",")
Dim Names(1 To 100) As Variant
For i = LBound(s) To UBound(s)
Dim r As Range: Set r = Range(s(i))
With r
L = .Left - 5
T = .Top - 5
w = .Width + 10
h = .Height + 10
If i = LBound(s) Then
Lft = L
Tp = T
End If
If Lft > L Then Lft = L
If Tp > T Then Tp = T
End With
ShapeName = "ex"
With .Shapes.AddShape(msoShapeFlowchartTerminator, L, T, w, h)
.Fill.Visible = msoFalse
.Line.Weight = 1
.Line.DashStyle = msoLineDash
.Line.ForeColor.RGB = BASICCOLOR
.Name = Replace(.Name, "Flowchart: Terminator", ShapeName)
Names(i + 1) = .Name
End With
Next i
.Activate
.Shapes.Range(Names).Select
Selection.Cut
Call MangeCombinePPTFromExcel(WS, Lft, Tp)
.Range(MyRange).Select
End With 'WS
End Sub
Public Sub MangeCombinePPTFromExcel(WS As Worksheet, Lft As Single, Tp As Single)
Dim PPT As Object
Dim Pres As Object
Dim Sld As Object
Dim Shp As Shape, Rctangl As Shape, Rctangll As Shape, MergeShape As Shape
Set PPT = CreateObject("Powerpoint.Application")
Set Pres = PPT.Presentations.Add
Set Sld = Pres.Slides.Add(1, 12)
PPT.Activate
ShapeName = "ex"
With Sld
.Shapes.Paste.Select
On Error Resume Next
PPT.CommandBars.ExecuteMso ("ShapesUnion")
On Error GoTo 0
.Shapes(.Shapes.Count).Cut
End With
With WS 'back to Excel
.Paste
With .Shapes(.Shapes.Count)
.Name = ShapeName
.Left = Lft
.Top = Tp
End With
End With
PPT.Quit
End Sub
Click to see Picture
enter image description here

Copy tables from different worksheet in excel and paste it in existing presentation

I have a specific excel workbook which has tables in different worksheets in different range.I want tables should be automatically copied from all the worksheet of my excel workbook and should be pasted in different slides of my existing ppt template.
I have created a code but giving error on range which I want to copy:
Sub newpp()
Dim pptapp As PowerPoint.Application
Dim pres As PowerPoint.Presentation
Dim preslide As PowerPoint.Slide
Dim shapepp As PowerPoint.Shape
Dim exappli As Excel.Application
Dim exworkb As Workbook
Dim xlwksht As Worksheet
Dim rng As Range
Dim myshape As Object
Dim mychart As ChartObject
Dim lastrow1 As Long
Dim lastcolumn1 As Long
Dim slidecount As Long
'Open powerpoint application
Set exappli = New Excel.Application
exappli.Visible = True
'activate powerpoint application
Set pptapp = New PowerPoint.Application
pptapp.Visible = True
pptapp.Activate
'open the excel you wish to use
Set exworkb = exappli.Workbooks.Open("C:\Users\ap\Desktop\Macro\Reference Sheet.xlsm")
'open the presentation you wish to use
Set pres = pptapp.Presentations.Open("C:\Users\ap\Desktop\Macro\new template.pptx")
'Add title to the first slide
With pres.Slides(1)
If Not .Shapes.HasTitle Then
Set shapepp = .Shapes.AddTitle
Else: Set shapepp = .Shapes.Title
End If
With shapepp
.TextFrame.TextRange.Text = "Gulf+ Market Segment Analysis Report" & vbNewLine & "P5 Week 04 FY17"
.TextFrame.TextRange.Font.Name = "Arial Black"
.TextFrame.TextRange.Font.Size = 24
.TextEffect.FontBold = msoTrue
.TextFrame.TextRange.Paragraphs.ParagraphFormat.Alignment = ppAlignLeft
End With
End With
'set the range
lastrow1 = exworkb.ActiveSheet.Cells(Rows.Count, "A").End(xlUp).Row
lastcolumn1 = exworkb.ActiveSheet.Cells(1, Columns.Count).End(xlToLeft).Column
For Each xlwksht In exworkb.Worksheets
xlwksht.Select Application.Wait(Now + TimeValue("0.00:1"))
**'getting error in this line-------**
exworkb.ActiveSheet.Range(Cells(1, 1), Cells(lastrow1, lastcolumn1)).CopyPicture appearance:=xlScreen, Format:=xlPicture
slidecount = pres.Slides.Count
Set preslide = pres.Slides.Add(slidecount + 1, 12)
preslide.Select
preslide.Shapes.Paste.Select
pptapp.ActiveWindow.Selection.ShapeRange.Align msoAlignTops, msoTrue
pptapp.ActiveWindow.Selection.ShapeRange.Top = 65
pptapp.ActiveWindow.Selection.ShapeRange.Left = 72
pptapp.ActiveWindow.Selection.ShapeRange.Width = 700
Next xlwksht
End Sub
Replace your For Each xlwksht In exworkb.Worksheets loop with the modified loop below.
I made the following modifications to your code (so it will work):
Instead of Selecting the worksheet and then use ActiveSheet, use xlwksht, I've added the With xlwksht.
You need to search for the last row and column for each worksheet, so I've moved it inside the With statement.
There is no need to Select the slide every time in order to paste.
Some other modifications...
Modified For loop Code
For Each xlwksht In exworkb.Worksheets
With xlwksht
lastrow1 = .Cells(.Rows.Count, "A").End(xlUp).Row
lastcolumn1 = .Cells(1, .Columns.Count).End(xlToLeft).Column
' set the range
.Range(.Cells(1, 1), .Cells(lastrow1, lastcolumn1)).CopyPicture appearance:=xlScreen, Format:=xlPicture
Set preslide = pres.Slides.Add(pres.Slides.Count + 1, 12) ' <-- set the Slide
preslide.Shapes.Paste
With preslide.Shapes(preslide.Shapes.Count) '<-- modify the pasted shape properties
.Top = 65
.Left = 72
' etc...
End With
End With
Next xlwksht

Setting a Trendline as Variable Throws Error

I'm working witht he following code:
Sub AddTrendLinesBoth()
Dim myCht As ChartObject
Dim oTren As Trendline
Dim oWb As Workbook
Dim oWS As Worksheet
Set oWb = ThisWorkbook
Set oWS = oWb.Sheets("Summary")
Set myCht = oWS.ChartObjects("Chart 1")
On Error GoTo GetOut
With myCht.Chart
.SeriesCollection(1).Trendlines.Add
.SeriesCollection(2).Trendlines.Add
End With
Set oTren = myCht.SeriesCollection(1).Trendlines(1)
With oTren.Format.Line
.Visible = msoTrue
.Weight = 3
.ForeColor.RGB = RGB(112, 48, 160)
.Transparency = 0
End With
Set oTren = myCht.SeriesCollection(2).Trendlines(1)
With oTren.Format.Line
.Visible = msoTrue
.Weight = 3
.ForeColor.RGB = RGB(255, 0, 0)
.Transparency = 0
End With
GetOut:
End Sub
On each instance of set oTren = the code errors out on establishing the variable. What am I missing to adequately establish that line?
The reason I'm using with statements as set variables, is because using ActiveChart and ActiveSheet was throwing method errors with older versions of Excel.
The problem is that myCht is a ChartObject object rather than a Chart object. You thus need to go through the chart object's chart method to get to the elements of the chart, such as trendlines associated to series:
Set oTren = myCht.Chart.SeriesCollection(1).Trendlines(1)

How to set picture aspect ratio?

Sub ExampleUsage()
Dim myPicture As String, myRange As Range
myPicture = Application.GetOpenFilename _
("Pictures (*.gif; *.jpg; *.bmp; *.tif),*.gif; *.jpg; *.bmp; *.tif", _
, "Select Picture to Import")
Set myRange = Selection
InsertAndSizePic myRange, myPicture
End Sub
Sub InsertAndSizePic(Target As Range, PicPath As String)
Dim p As Object
Application.ScreenUpdating = False
Set p = ActiveSheet.Pictures.Insert(PicPath)
If Target.Cells.Count = 1 Then Set Target = Target.MergeArea
With Target
p.Top = .Top
p.Left = .Left
p.Width = .Width
p.Height = .Height
End With
End Sub
This is my code for Microsoft Excel. I want to have the aspect ratio unlock so that I can fill the entire merged cell. Thanks in advance.
This is how you'll set the Aspect Ratio. It is a Property of the Shape Object. p is of Picture Object Type. You can use it's name to access it via Shapes which has the Aspect Ratio property:
Sub InsertAndSizePic(Target As Range, PicPath As String)
Dim p As Object
Application.ScreenUpdating = False
Dim sh As Worksheet: Set sh = ActiveSheet
Set p = sh.Pictures.Insert(PicPath)
sh.Shapes(p.Name).LockAspectRatio = False
If Target.Cells.Count = 1 Then Set Target = Target.MergeArea
With Target
p.Top = .Top
p.Left = .Left
p.Width = .Width
p.Height = .Height
End With
Application.ScreenUpdating = True
End Sub
I declared and set variable for Worksheet Object just to have Intellisense kick in to get the arguments.
Another way is to use Shape Object AddPicture Method like below.
Sub InsertAndSizePic(Target As Range, PicPath As String)
Dim s As Shape
Application.ScreenUpdating = False
Dim sh As Worksheet: Set sh = ActiveSheet
If Target.Cells.Count = 1 Then Set Target = Target.MergeArea
With Target
Set s = sh.Shapes.AddPicture(PicPath, True, True, .Left, .Top, .Width, .Height)
End With
Application.ScreenUpdating = True
End Sub
This code will also accomplish what the first code does. HTH.