I have a set of Pivot tables/charts automatically created from VBA code with custom formatting.
When I change the selection of data to be displayed from the drop down list in the chart, the custom formatting reverts back to the chart type's default display. The underlying chart data is not changed, only what's displayed on the chart. What do I have to do to retain that custom formatting everytime I change the pivot item selection in a row field?
Edit 1: The underlying data for the pivot table does not change. However, everytime I change a filter on a row, column or page field, the updated pivot chart loses the original format set by the VBA code.
Edit 2: This only pertains to Excel versions older than Excel 2007.
What it sounds like to me is that the VBA code generates the pivot table/chart and then you are trying to tweak it afterwards. Unfortunately with VBA, when you update the pivot table/chart, all your custom formatting is lost. Excel is basically creating a new one each time as well.
If you did the formatting by hand in Excel, I think Excel keeps track of that and will keep your formatting as you change the data. The example I can think of is if you accidentally delete a sheet you an Undo it, however if you delete a sheet in VBA there's no possible way to Undo.
I would try this as a solution.
Create two procedures: one that creates a PivotTable from scratch when given data, and the other that formats a pivot table when given the range of a pivot table. The code could look something like this
Sub GeneratePivotTable(rng as Range, var1 as Variant, var2 as Variant)
' Code here that makes your Pivot Table
' pass whatever you need to get the job done
End Sub
Sub FormatPivotTable(rng as Range, var1 as Variant, var2 as Variant)
' Code here to format pivot table given range and other information
' You might even be able to just directly pass a PivotTable object :D
End Sub
Then all you would have to do next to make it functional like your current code is create a wrapper function that just calls both.
Sub GenerateAndFormatPivotTable(rng as Range, var1 as Variant, var2 as Variant)
Call GeneratePivotTable(rng, var1, var2)
' Maybe some processing here to set up the next call
Call FormatPivotTable(rng, var1, var2)
End Sub
If you wanted to pass the PivotTable as an object you could do something neat like....
Function GeneratePivotTable(variables as Variant) as PivotTable
' Generate your pivot table and return it
GeneratePivotTable = myPivotTableThatIMade
End Function
Sub FormatPivotTable(aPivotTableThatYouMake as PivotTable)
' Code that formats your PivotTable
End Sub
Sub GenerateAndFormatPivotTable(rng as Range, var1 as Variant, var2 as Variant
Call FormatPivotTable(GeneratePivotTable(variables as Variant)
End Sub
You do all this so if you make a table, then have to tweak it, you can use that FormatPivotTable to format the updated table.
For extra madness, have the sheet that has the PivotTable fire it's Worksheet.Change or Worksheet.Activate event to search for a PivotTable and call your formatting function :D
Related
I tried to work a bit more with dynamic arrays in excel in combination with vba. My problem is that I cant return a table-column with vba. Here a minimal example of what I want to do:
I have two Tables TabFeb and TabMar (see image below). Each of them has a column costs which I want to sum up individually. The results shall be put into a new Table. This can be easily done in excel with =SUM(TabFeb[Costs]) and =SUM(TabMar[Costs]), respectively. My idea is now to write a VBA function which takes a string as input, in this example it will be the month, and returns the table acording to the input. After that it will be summed up and the result is given in a cell.
I tried the following:
Function Selectmon(mon As String) As Range
If mon = "Feb" Then
Set Selectmon = Worksheets("Sheet1").ListObjects("TabFeb").ListColumns("Costs").DataBodyRange
ElseIf mon = "Mar" Then
Set Selectmon = Worksheets("Sheet1").ListObjects("TabMar").ListColumns("Costs").DataBodyRange
End If
End Function
The problem of this idea is that this function just copy the table data. Hence, if I would change the input table data the sum would not change. One has to recalculate every cell by hand. Somehow I need VBA to return TabFeb[Costs] for the input "Feb". Does anyone have an idea how this can be done?
Example
It's really just a one-liner (unless you want to do some in-function error checking)
Function Selectmon(mon As String) As Range
Set Selectmon = Range("Tab" & mon & "[Costs]")
End Function
As implied by #ceci, this formula will not update with changes in the table. Depending on other particulars of your worksheet, you can have it update either by
embedding it in a worksheet change event code;
or by adding the line Application.Volatile to the function itself.
The latter method will force a recalculation when anything changes on the worksheet that might cause a recalculation.
The first method can limit the recalculation only when there has been a change in the data, but has other limitations.
One of the limitations of the Worksheet Change method is that it will only work on the relevant worksheet.
If you use the Workbook sheet change method, you won't have that limitation.
In either event you can limit your code to run only when the table has changed.
Here is one generalized method:
Option Explicit
Private Sub Workbook_SheetChange(ByVal Sh As Object, ByVal Target As Range)
Dim LOS As ListObjects
Dim LO As ListObject
Set LOS = Sh.ListObjects
For Each LO In LOS
'could select relevant tables here
'Could also select relevant worksheets, if you like
'for example
Select Case LO.Name
Case "TabFeb", "TabMar", "TabApr"
If Not Intersect(LO.DataBodyRange, Target) Is Nothing Then
Application.EnableEvents = False
Application.Calculate
End If
End Select
Next LO
Application.EnableEvents = True
End Sub
And there is other code you could use to find the relevant formula and just update that formula -- probably not worth the effort.
I am trying to find a way to display PivotTable Data Source in excel worksheet. I know we can manually view the Data source by clicking on PivotTable Tools Analyze > Change Data Source > Change Data source to display source in a separate window. I would like to know if it is possible dynamically display the source value as text in a linked cell(sample cell F4 below).
It can be one way relationship, meaning changing PivotTable Data Source, the display cell should be automatically updated, but changing the cell value in display cell does not necessary lead to change in PivotTable Data source. (**but if it change be done for both directions, would be even better.)
welcome both VBA and non-VBA solutions.
Any suggestions are much appreciated.
THANK YOU VERY MUCH!
Create this function.
Function PivotTableSource(myPivot As String) As String
Dim rawSource As String
Dim a1Source As String
Dim bracket As Long
Application.Volatile
rawSource = ActiveSheet.PivotTables(myPivot).SourceData
a1Source = Application.ConvertFormula(rawSource, xlR1C1, xlA1)
bracket = InStr(1, a1Source, "]")
PivotTableSource = "=" & Mid(a1Source, bracket + 1)
End Function
Then put =PivotTableSource("PivotTable1") in cell F4. PivotTable1 is the default name of the first Pivot Table created in a spreadsheet. Change it if your pivot table is named something else.
It would be interesting to look at the events associated to the PivotTable Data Source, in the Microsoft documentation for example.
If there is an event triggered on the Data Source change, you can create a handler to update the value in the F4 cell.
Recording a macro while changing the Data Source of the PivotTable might also give some interesting hints.
I have an excel sheet with a table and its quite large so I also have a slicer to break it up in viewable pieces. My problem is that then selecting a specific unit in the slicer sometimes there will be columns in the table that's empty. I would very much like to make a button to hide them (and then have another button to unhide so I can select other units in the slicer and view new data and so on...)
My problem is that most VBA code online hides all the columns outside the table. Im not in any way fluent in VBA. I have unsuccessfully tried to modifying code I found only. From what I can see online, most codes define an area/range within a worksheet and then loops over that range and hides all empty columns. But then I try to redefine the range as the ListObjects("Table1")the code fails.
So far i have managed to make code that unhides all columns outside the table and I have tried to make a small piece of code that hides the
Sub ShowHidden()
Rows.Hidden = False
Columns.Hidden = False
End Sub
Sub HideEmptyColumns()
ActiveSheet.ListObjects("Table1").Columns.Hidden = True
End Sub
The latter fails
Is it possible to make code that hides empty columns in a table in excel and if so, how does the code look
Kind regards
Need to use the properties of the ListObject object (Excel), in this case use the DataBodyRange to set the range to loop after.
You'll also need to use Range.SpecialCells method (Excel)
Dim lo As ListObject
Set lo = ThisWorkbook.Worksheets("DATA").ListObjects("lo.Data") 'change as required
For Each rCol In lo.DataBodyRange.Columns
'… Here goes the validation of the cells within the column (i.e. rCol)
If … Then rCol.EntireColumn.Hidden = True
Next
To unhide the columns use:
Dim lo As ListObject
Set lo = ThisWorkbook.Worksheets("DATA").ListObjects("lo.Data") 'change as required
lo.DataBodyRange.EntireColumn.Hidden = False
I have created a pivot table using vba. I need help with the understanding of below-mentioned points.
1: I want to select(copy) values with certain filters (eg: Underlying price
for Instrument Type = OPTCUR, Symbol = GBPUSD). Basically a VBA alternative for formula
GETPIVOTDATA("Underlying_price",$C$4,"Instrument Type","OPTCUR","Symbol","GBPUSD")
2: I want to set "show detail=True" without knowing cell details but the criteria as mentioned above.
3: when we set "show detail=True" a new sheet opens. i want to asign this sheet to a variable of type worksheet.
below is the SS of my pivot table. and TableName:="My_Pivot"
You get the relevant cell with PivotTable.GetPivotData
The new worksheet with details of this cell is shown by Range.ShowDetail = True.
Directly after that, the new ActiveSheet is the wanted one.
Here is a function to get the wanted worksheet with the details for a specified data field:
Private Function GetDetailSheet(pt As PivotTable, Val1 As String, Val2 As String) As Worksheet
Dim myCell As Range
With pt
Set myCell = .GetPivotData(.DataFields(1).Name, _
.RowFields(1).Name, Val1, _
.RowFields(2).Name, Val2)
End With
myCell.ShowDetail = True
Set GetDetailSheet = ActiveSheet
End Function
It can be used like this:
Private Sub Test()
Dim ws as Worksheet
Set ws = GetDetailSheet(ActiveSheet.PivotTables("My_Pivot"), "OPTCUR", "GBPUSD")
ws.Name = "Details OPTCUR GBPUSD"
End Sub
If you don't want to use the (hideos) GETPIVOTDATA there's a solution for you!
It's called CUBEVALUE. It's a bit difficult to master but once it's done you reports & Pivot Table get to a whole new level.
See here: https://www.excelcampus.com/cubevalue-formulas/
Yes, it's a long article, but it's definitely worth the effort, as it would enable you to point to a specific data point, not to a specific cell.
Once mastered, adding a VBA code to a "changed" cell event and changing the visibility status of a certain sheet is just a matter of minutes.
I have a list of items to work through and some items require deeper analysis. Essentially I have two tables. The first shows production results and through filtering column U, I get a list of outliers as in the following image.
Table of outliers
The values displayed in column S then require further analysis for which a pivot chart has been set up. In this chart I filter the particular VRTY number to take a closer look.
Pivot Chart for analysis
Both sheets are contained in the same workbook and I essentially work with two windows open, but to go through the list I have to manually enter every single VRTY value in the pivot filter.
The table of the Pivot chart and the outlier table are not related and data sources are different.
In column S of the outlier table (VRTY) I would ideally turn the values into links that automatically set the pivot filter to this value when clicked.
I am a novice at VBA but from the research I've done this will be the only option - I just haven't come by an instructions how to achieve this particular function.
Instructions/ advice would be highly appreciated.
Sambo: Make sure the orientation of the 'Number' field in the PivotChart's underlying PivotTable is a PageField, and then put the below code in the Sheet code module that corresponds to the sheet where the Outliers PivotTable is:
Private Sub Worksheet_SelectionChange(ByVal Target As Range)
Dim pf As PivotField
Dim pf_Slave As PivotField
Set pf = ActiveSheet.PivotTables("PivotTable1").PivotFields("VRTY")
Set pf_Slave = ActiveSheet.PivotTables("PivotTable2").PivotFields("number")
If Not Intersect(Target, pf.DataRange) Is Nothing Then
On Error Resume Next
pf_Slave.CurrentPage = CStr(Target)
On Error GoTo 0
End If
End Sub
Change "PivotTable1" and "PivotTable2" as appropriate.
By "Sheet code module" I mean this type of thing: