I have a PowerPoint presentation with ~200 slides. Each slide has one chart, with data that is updated monthly by a link to a master xlsx file.
To not show empty values (future months) in the charts, I open the data editor (chart right click > Edit data...) of every chart and select the range until the current month.
I wrote a macro for it in PowerPoint:
Sub Refresh_slides()
For i = 1 To ActivePresentation.Slides.Count
Set ObjSlide = ActivePresentation.Slides(i)
On Error Resume Next
Set mychart = ObjSlide.Shapes("Chart 3").Chart
mychart.Select
mychart.ChartData.Activate
Set wb = mychart.ChartData.Workbook
Set ws = wb.Worksheets(1)
Application.Run "Refresh_slides_AUX.xlsm!atual_slide"
wb.Close True
Next
End Sub
Refresh_slides_AUX.xlsm is an auxiliary macro worksheet to select the correct range of each chart (because PowerPoint VBA, as far as I know, don't have an option to do it):
Sub atual_slide()
Windows("Gráfico no Microsoft PowerPoint").Activate
ActiveSheet.ListObjects("Table1").Resize Range("$A$1:$I$23")
ActiveWindow.Close SaveChanges:=True
End Sub
The result is:
BEFORE:
AFTER:
It works, but after the range is resized the charts don’t change, they still looking like the BEFORE picture.
I know the process is right because if I do the resizing manually (right corner of the dotted line) the chart is updated correctly.
Add wb.Application.Update before wb.Close
See if that helps.
This is an old question but I had trouble finding an answer and this question came up as the first hit for my search.
I'd like to post a powerpoint vba routine that has an ActivateChartDataWindow method that I found was necessary to refresh the chart after I had updated the data.
Private Sub RefreshChart(slideName As String, shapeName As String, spName As String, dataRange As String)
'Add reference to Microsoft ActiveX Data Object 6.x Library
'Read data point info from SQL
Dim conn As ADODB.Connection
Dim rs As ADODB.Recordset
Dim connStr As String
Dim query As String
Dim sld As Slide
Dim shp As Shape
Dim xlWB As Excel.Workbook
Dim xlWS As Excel.Worksheet
Set sld = ActivePresentation.Slides(slideName)
Set shp = sld.Shapes(shapeName)
Set xlWB = shp.Chart.ChartData.Workbook
Set xlWS = xlWB.Sheets(1)
xlWS.Range(dataRange).Clear
Set conn = New ADODB.Connection 'CreateObject("adodb.connection")
connStr = "Provider=SQLOLEDB;Data Source='" & SQLServer & "';Initial Catalog=WVCore;Integrated Security=SSPI;"
conn.Open connStr
Set rs = New ADODB.Recordset 'CreateObject("adodb.recordset")
query = "exec " & spName 'usp_WVCRevenue
With rs
.ActiveConnection = conn
.Open query
xlWS.Range("A2").CopyFromRecordset rs 'Leave headings in tact
.Close
End With
shp.Chart.ChartData.ActivateChartDataWindow
xlWB.Close
conn.Close
Set rs = Nothing
Set conn = Nothing
End Sub
Related
I have been performing these operations through excel, but the raw data that I am dealing with is overwhelming for excel. I shifted over to access as the database but I am trying to find similar functionality. I am still using excel as my interface.
I am essintially breaking my data into samples. Taking a sample of the data, analyzing it then moving on to the next sample. I would like to do the same with the Access data. What I am looking for is how to perform operations (summation, multipication, division,max, min...) on a sample using a for loop. Also, what is the ID of max value and ID on the min value. I am also dealing with a huge amout of raw data, so the less lines of code would be optimal. Any pointers in the right direction would be appreciated.
Code in Excel:
For CoUnTer = 1 To FindRecordCount
Set Circ_Rng = WS.Range(WS.Cells(CoUnTer , 5), WS.Cells(CoUnTer + TempTimeFrame - 1, 5))
Set DataPoint_Rng = WS.Range(WS.Cells(CoUnTer , 1), WS.Cells(CoUnTer + TempTimeFrame - 1, 1))
Set DataPoint_Circ_Rng = WS.Range(WS.Cells(CoUnTer , 8), WS.Cells(CoUnTer + TempTimeFrame - 1, 8))
Set DataPoint_SQ_Rng = WS.Range(WS.Cells(CoUnTer , 9), WS.Cells(CoUnTer + TempTimeFrame - 1, 9))
'---------------------------
MaxPoint = WorksheetFunction.Max(CircPressure_Rng)
Row_At_MaxPressure = WS.Columns(5).Cells.Find(MaxPoint, After:=WS.Cells(3, 5), SearchOrder:=xlByRows, LookIn:=xlValues, SearchDirection:=xlNext).Row
Sigma_X_Sigma_Y = WorksheetFunction.Sum(Circ_Rng) * WorksheetFunction.Sum(DataPoint_Rng)
Sigma_XY = WorksheetFunction.Sum(DataPoint_Circ_Rng)
Sigma_X2 = WorksheetFunction.Sum(DataPoint_SQ_Rng)
Min_X = WorksheetFunction.Min(DataPoint_Rng)
Code for Access data:
This code gets the data sample. What I am missing how can I handle the operations on them similar to what I have done in excel.
Sub GetAccessData()
Dim DBFullName As String
Dim Connect As String, Source As String
Dim Connection As ADODB.Connection
Dim Recordset As ADODB.Recordset
Dim Col As Long
Dim x As Long
Application.ScreenUpdating = False
'DataBase Path
DBFullName = WB_Path & "\RawData - Template.accdb"
'Open the Connection
Set Connection = New ADODB.Connection
Connect = "Provider=Microsoft.ACE.OLEDB.12.0;"
Connect = Connect & "Data Source=" & DBFullName & ";"
Connection.Open ConnectionString:=Connect
'Create a RecordSet
Set Recordset = New ADODB.Recordset
' Client-side cursor
Recordset.CursorLocation = adUseClient
With Recordset
Source = "SELECT * FROM RawData WHERE [ID] BETWEEN " & StartofData & " AND " & EndofData
.Open Source:=Source, ActiveConnection:=Connection
On Error Resume Next
End With
EndofData = Recordset.RecordCount
Set Recordset = Nothing
Connection.Close
Set Connection = Nothing
'Application.ScreenUpdating = True
'Application.EnableEvents = True
End Sub
As you are seeing, Excel is better for some things and Access is better for some things. Sometimes you can literally substitute Access for Excel, and vice versa, but often each one should be used for it's intended purpose. There are probably a few ways forward here, but I would lean towards leaving your Excel stuff in Excel, and control Excel from Access. You can use Late Binding or Early Binding to control one app from another app. Here are two options for you to consider.
‘EARLY BINDING
Option Compare Database
Option Explicit ' Use this to make sure your variables are defined
' One way to be able to use these objects throughout the Module is to Declare them
' Here and not in a Sub
Private objExcel As Excel.Application
Private xlWB As Excel.Workbook
Private xlWS As Excel.Worksheet
Sub Rep()
Dim strFile As String
strFile = "C:\your_path_here\YourExcelFile.xls"
' Opens Excel and makes it Visible
Set objExcel = New Excel.Application
objExcel.Visible = True
'Opens up the Workbook
Set xlWB = objExcel.Workbooks.Open(strFile)
'Sets the Workseet to the last active sheet - Better to use the commented version and use the name of the sheet.
Set xlWS = xlWB.ActiveSheet
'Set xlWS = xlWB("Sheet2")
With xlWS ' You are now working with the Named file and the named worksheet
End With
'Do Close and Cleanup
End Sub
‘LATE BINDING
Sub ControlExcelFromAccess()
' No reference to a type library is needed to use late binding.
' As long as the object supports IDispatch, the method can
' be dynamically located and invoked at run-time.
' Declare the object as a late-bound object
Dim oExcel As Object
Dim strFile As String
strFile = "C:\your_path_here\YourExcelFile.xls"
Set oExcel = CreateObject("Excel.Application")
' The Visible property is called via IDispatch
oExcel.Visible = True
Set xlWB = oExcel.Workbooks.Open(strFile)
'Call code here . . .
Set oExcel = Nothing
End Sub
Just copy/paste your code inside this code, make a few small tweaks if necessary, and you should be good to go!
A chart was created through the Chart In Microsoft PowerPoint feature and we would like to control how the chart is updated by using a PowerPoint Userform. Is there a line of code that can point to sheet named DVPVreport located within the Chart In Microsoft PowerPoint when the routine is executed? Current code is below which does not consider that the DVPVreport is located within the Chart In Microsoft PowerPoint. We tried to execute code:
Set ws = 'Chart In MicrosoftPowerPoint!'.Worksheets(DVPVreport)
but without success.
Private Sub AddDVSetUp_Click()
Dim ws As Worksheet
Set ws = Worksheets("DVPVreport")
ws.Cells(3, 4).Value = Gate2Date.Value
Unload M
ws.Cells(3, 5).Value = Gate3Date.Value
Unload M
End Sub
Yes it is possible. Try this:
Dim sl As Slide
Set sl = ActivePresentation.Slides(1)
Dim xlWB As Object
Dim sh As Shape, ch As Chart
For Each sh In sl.Shapes
If sh.Type = msoChart Then
Set ch = sh.Chart
Set xlWB = ch.ChartData.Workbook
With xlWB.Sheets(1) '/* It has only 1 sheet so this will be fine */
'/* Do the changes you want here */
.Range("B2").Value = 4.2
End With
End If
Next
Set ch = Nothing: Set xlWB = Nothing: Set sl = Nothing '/* clean up */
Now, if you already know the index or name of your object, you can simply:
Dim sl As Slide
Set sl = ActivePresentation.Slides(1)
Dim xlWB As Object
Dim sh As Shape
Set sh = sl.Shapes("Chart 1")
Set xlWB = sh.Chart.ChartData.Workbook
With xlWB.Sheets(1)
.Range("B2").Value = 4.2
End With
Important: Be very careful not to ruin the source data layout. It de-associates the chart with the ChartData for some reason when you do this.
All I want to do is use VBA to get the results of some query into an Excel workbook instead. The main issue is that the openRecordSet method appears to not be working. Every time when I try debugging it I see that the recordset (rcset) is Nothing. When I just run the query so it is viewed in the Access viewer, it seems to work just fine (see last line of code). I get no errors when I run the code, so I'm having a very hard time understanding why my recordset would return Nothing. I've searched around the internet quite a bit, but haven't found anyone in this particular situation. Thanks in advance for any help!
Dim db As DAO.Database
Dim qdef As DAO.QueryDef
Dim rcset As DAO.Recordset
Dim i As Integer
'Identify the database and query
Set db = CurrentDb
On Error Resume Next
With db
.QueryDefs.Delete ("RealQuery")
Set qdef = .CreateQueryDef("RealQuery", strSQLRQ)
.Close
End With
'The problem child line
Set rcset = qdef.OpenRecordset()
'Clear previous contents
Dim xlApp As Object
Set xlApp = CreateObject("Excel.Application")
With xlApp
.Visible = True
.Workbooks.Add
.Sheets("Sheet1").Select
'Copy the recordset to Excel
.ActiveSheet.Range("A2").CopyFromRecordset rcset
'Add column heading names to spreadsheet
For i = 1 To rcset.Fields.Count
xlApp.ActiveSheet.Cells(1, i).Value = MyRecordset.Fields(i - 1).Name
Next i
xlApp.Cells.EntireColumn.AutoFit
End With
qdef.Close
Set qdef = Nothing
Set db = Nothing
DoCmd.OpenQuery "RealQuery", acViewNormal
Option Explicit
Public Const strQry = "insert sql select command here"
Public Const conStr = "insertconnectionstringhere";
Dim cn As ADODB.Connection
Dim rs As ADODB.Recordset
Sub sql2excell()
Set cn = New ADODB.Connection
Set rs = New ADODB.Recordset
cn.Open (conStr)
rs.Open strQry, cn
If Not rs.EOF Then
ActiveSheet.Range("A1").CopyFromRecordset rs
End If
rs.Close
cn.Close
End Sub
Simplest SQL to excel vba i can get
I'm creating automated pivottables from a pivotcache which imports its recordset form an adodb connection.
I need to group the date field and found a way online to do it with the .pivotselect method. The code works fine, however excel does not seem to select the worksheet where the pivottables are somehow, even though the pivottable data is selected. This leads to an error if one select another sheet and then runs the procedure.
Shouldn't pivottable.pivotselect select the sheet also automatically? I have solved it temporarily by having sheets("Pivot").select just before the date grouping code. How may one come around this problem? The current code is based on code generated from macro recorder.
Code
Private Sub PivotAccessADODB()
' Link Pivottable to access database, successfull!
Const ConnectionPath As String = "Provider=Microsoft.ACE.OLEDB.12.0;Data Source=C:\Users\name\Desktop\DataBase.accdb;Persist Security Info=False;"
Dim DataConnection As ADODB.Connection: Set DataConnection = New ADODB.Connection
Dim RecordSet As ADODB.RecordSet: Set RecordSet = New ADODB.RecordSet
DataConnection.ConnectionString = ConnectionPath
DataConnection.Open
Dim SQLString As String: SQLString = "SELECT * FROM ALFA"
With RecordSet
.ActiveConnection = DataConnection
.Source = SQLString
.LockType = adLockReadOnly
.CursorType = adOpenForwardOnly
.Open
End With
' Initiate accept of external data
Dim PTCache As PivotCache
Set PTCache = ActiveWorkbook.PivotCaches.Create(xlExternal)
Set PTCache.RecordSet = RecordSet
'----------------------------------'
'First Pivot Table export procedure
Dim PT As PivotTable: Set PT = PTCache.CreatePivotTable(Sheets("Pivot").Range("A1"), "PivotTable#1")
With PT
.PivotFields("Date").Orientation = xlRowField
.PivotFields("Date").Position = 1
Sheets("pivot").Select ' Bypass selection grouping error, temporary solution as of 2014-12-26
PT.PivotSelect "Date[All]", xlLabelOnly + xlFirstRow, True
Selection.Group Start:=True, End:=True, Periods:=Array(False, False, False, False, True, False, False)
.PivotFields("Adj Close").Orientation = xlDataField
.PivotFields("Sum of Adj Close").Calculation = xlPercentDifferenceFrom
.PivotFields("Sum of Adj Close").BaseItem = "(previous)"
.PivotFields("Volume").Orientation = xlDataField
.PivotFields("Sum of Volume").Calculation = xlPercentDifferenceFrom
.PivotFields("Sum of Volume").BaseItem = "(previous)"
End With
Dim wst As Worksheet: Set wst = Sheets("Mainwindow")
Dim wshape As Shape
Set wshape = wst.Shapes.AddChart2(286, xl3DColumnClustered, wst.Range("A24").Left, wst.Range("A24").Top, _
wst.Range("A24:Q24").Width, wst.Range("A24:A39").Height)
With wshape.Chart
.SetSourceData Source:=PT.TableRange1
.ClearToMatchStyle
.ChartStyle = 291
.ApplyLayout (1)
.ChartTitle.Text = "Difference from previous month in percentage"
.ChartTitle.Format.TextFrame2.TextRange.Font.Size = 14
End With
'-----------------------------------'
'Second Pivot Table export procedure'
'Cleanup
RecordSet.Close
DataConnection.Close
Set RecordSet = Nothing
Set DataConnection = Nothing
End Sub
Be sure to dimension a Worksheet object and set it to the whatever worksheet has the pivot tables:
Dim wkb As Excel.Workheet
Set wkb = ActiveWorkbook.Worksheet("Me")
wkb.Activate 'wkb.Select may give focus but doesn't register as the active worksheet object.
<PT Code>
Set wkb = Nothing
I am trying to extract the source data from a PivotTable that uses a PivotTable cache and place it into a blank spreadsheet. I tried the following but it returns an application-defined or object defined error.
ThisWorkbook.Sheets.Add.Cells(1,1).CopyFromRecordset ThisWorkbook.PivotCaches(1).Recordset
Documentation indicates that PivotCache.Recordset is an ADO type, so this ought to work. I do have the ADO library enabled in references.
Any suggestions on how to achieve this?
Unfortunately, there appears to be no way to directly manipulate PivotCache in Excel.
I did find a work around. The following code extracts the the pivot cache for every pivot table found in a workbook, puts it into a new pivot table and creates only one pivot field (to ensure that all rows from the pivot cache are incorporated in the total), and then fires ShowDetail, which creates a new sheet with all of the pivot table's data in.
I would still like to find a way to work directly with PivotCache but this gets the job done.
Public Sub ExtractPivotTableData()
Dim objActiveBook As Workbook
Dim objSheet As Worksheet
Dim objPivotTable As PivotTable
Dim objTempSheet As Worksheet
Dim objTempPivot As PivotTable
If TypeName(Application.Selection) <> "Range" Then
Beep
Exit Sub
ElseIf WorksheetFunction.CountA(Cells) = 0 Then
Beep
Exit Sub
Else
Set objActiveBook = ActiveWorkbook
End If
With Application
.ScreenUpdating = False
.DisplayAlerts = False
End With
For Each objSheet In objActiveBook.Sheets
For Each objPivotTable In objSheet.PivotTables
With objActiveBook.Sheets.Add(, objSheet)
With objPivotTable.PivotCache.CreatePivotTable(.Range("A1"))
.AddDataField .PivotFields(1)
End With
.Range("B2").ShowDetail = True
objActiveBook.Sheets(.Index - 1).Name = "SOURCE DATA FOR SHEET " & objSheet.Index
objActiveBook.Sheets(.Index - 1).Tab.Color = 255
.Delete
End With
Next
Next
With Application
.ScreenUpdating = True
.DisplayAlerts = True
End With
End Sub
Go to the Immediate Window and type
?thisworkbook.PivotCaches(1).QueryType
If you get something other than 7 (xlADORecordset), then the Recordset property does not apply to this type of PivotCache and will return that error.
If you get an error on that line, then your PivotCache is not based on external data at all.
If your source data comes from ThisWorkbook (i.e. Excel data), then you can use
?thisworkbook.PivotCaches(1).SourceData
To create a range object and loop through it.
If your QueryType is 1 (xlODBCQuery), then SourceData will contain the connection string and commandtext for you to create and ADO recordset, like this:
Sub DumpODBCPivotCache()
Dim pc As PivotCache
Dim cn As ADODB.Connection
Dim rs As ADODB.Recordset
Set pc = ThisWorkbook.PivotCaches(1)
Set cn = New ADODB.Connection
cn.Open pc.SourceData(1)
Set rs = cn.Execute(pc.SourceData(2))
Sheet2.Range("a1").CopyFromRecordset rs
rs.Close
cn.Close
Set rs = Nothing
Set cn = Nothing
End Sub
You need the ADO reference, but you said you already have that set.
I found myself having the same problem, needing to scrape programmatically data coming different Excels with cached Pivot data.
Although the topic is a bit old, still looks there is no direct way to access the data.
Below you can find my code, which is a more generalized refinement of the already-posted solution.
The major difference is the filter removal from fields, as sometimes pivot comes with filters on, and if you call .Showdetail it will miss filtered data.
I use it to scrape from different file format without having to open them, it is serving me quite well thus far.
Hope it is useful.
Credit to spreadsheetguru.com on the filter cleaning routine (although I don't remember how much is original and how much is mine to be honest)
Option Explicit
Sub ExtractPivotData(wbFullName As String, Optional wbSheetName As_
String, Optional wbPivotName As String, Optional sOutputName As String, _
Optional sSheetOutputName As String)
' This routine extracts full data from an Excel workbook and saves it to an .xls file.
Dim iPivotSheetCount As Integer
Dim wbPIVOT As Workbook, wbNEW As Workbook, wsPIVOT As Worksheet
Dim wsh As Worksheet, piv As PivotTable, pf As PivotField
Dim sSaveTo As String
Application.DisplayAlerts = False
calcOFF
Set wbPIVOT = Workbooks.Open(wbFullName)
' loop through sheets
For Each wsh In wbPIVOT.Worksheets
' if it is the sheet we want, OR if no sheet specified (in which case loop through all)
If (wsh.name = wbSheetName) Or (wbSheetName = "") Then
For Each piv In wsh.PivotTables
' remove all filters and fields
PivotFieldHandle piv, True, True
' make sure there's at least one (numeric) data field
For Each pf In piv.PivotFields
If pf.DataType = xlNumber Then
piv.AddDataField pf
Exit For
End If
Next pf
' make sure grand totals are in
piv.ColumnGrand = True
piv.RowGrand = True
' get da data
piv.DataBodyRange.Cells(piv.DataBodyRange.Cells.count).ShowDetail = True
' rename data sheet
If sSheetOutputName = "" Then sSheetOutputName = "datadump"
wbPIVOT.Sheets(wsh.Index - 1).name = sSheetOutputName
' move it to new sheet
Set wbNEW = Workbooks.Add
wbPIVOT.Sheets(sSheetOutputName).Move Before:=wbNEW.Sheets(1)
' clean new file
wbNEW.Sheets("Sheet1").Delete
wbNEW.Sheets("Sheet2").Delete
wbNEW.Sheets("Sheet3").Delete
' save it
If sOutputName = "" Then sOutputName = wbFullName
sSaveTo = PathWithSlash(wbPIVOT.path) & FilenameNoExtension(sOutputName) & "_data_" & piv.name & ".xls"
wbNEW.SaveAs sSaveTo
wbNEW.Close
Set wbNEW = Nothing
Next piv
End If
Next wsh
wbPIVOT.Close False
Set wbPIVOT = Nothing
calcON
Application.DisplayAlerts = True
End Sub
Sub PivotFieldHandle(pTable As PivotTable, Optional filterClear As Boolean, Optional fieldRemove As Boolean, Optional field As String)
'PURPOSE: How to clear the Report Filter field
'SOURCE: www.TheSpreadsheetGuru.com
Dim pf As PivotField
Select Case field
Case ""
' no field specified - clear all!
For Each pf In pTable.PivotFields
Debug.Print pf.name
If fieldRemove Then pf.Orientation = xlHidden
If filterClear Then pf.ClearAllFilters
Next pf
Case Else
'Option 1: Clear Out Any Previous Filtering
Set pf = pTable.PivotFields(field)
pf.ClearAllFilters
' Option 2: Show All (remove filtering)
' pf.CurrentPage = "(All)"
End Select
End Sub