PTS Blog

Custom Solutions | Commercial Utilities | Training | Charts and Tutorials | PTS Blog

 

Main menu:

 
Peltier Tech
Chart Utilities

PTS Waterfall Chart Utility
PTS Cluster-Stack Column Chart Utility
PTS Box and Whisker Chart Utility
PTS Marimekko Chart Utility

Subscribe

Site search

Subscribe

Site search


Recent Posts

Recently Commented

Popular Posts

Archive


 

Categories


 

Buy me a coffee

If this topic or the whole blog has been helpful, support further development by treating me to a cup of coffee.


Privacy Policy

Creative Commons License
Licensed under a Creative Commons Attribution-Noncommercial-Share Alike 3.0 Unported License.

Dynamic Chart using Pivot Table and VBA

by Jon Peltier
Peltier Technical Services, Inc., Copyright © 2009.
Licensed under a Creative Commons Attribution-Noncommercial-Share Alike 3.0 Unported License.


In Using Pivot Table Data for a Chart with a Dual Category Axis, I showed how to make a Chart with a Dual Category Axis using a pivot table to properly arrange the source data. I generally prefer using a regular chart, because pivot charts are pretty inflexible when it comes to formatting. Unfortunately, a regular chart doesn’t know when the pivot table has been resized by a refresh. In Dynamic Chart using Pivot Table and Range Names I showed how to use dynamic ranges to allow a regular chart to update when the pivot table changes. However, that technique only accommodates a change in the number of points in a series, not the number of series in the chart. To allow for changing height and width of a pivot table, you either need to revert to a pivot chart, or use a VBA procedure, which I describe below.

This example begins with the same data range, pivot table, and chart as the previous ones.


A B C D
1 Main Category Category Sub Category Defects
2 Mechanical Mechanical Gear 11
3 Mechanical Mechanical Bearing 8
4 Mechanical Mechanical Motor 3
5 Electrical Electrical Switch 19
6 Electrical Electrical Plug 12
7 Electrical Electrical Cord 11
8 Electrical Electrical Fuse 3
9 Electrical Electrical Bulb 2
10 Hydraulic Hydraulic Pump 4
11 Hydraulic Hydraulic Leak 3
12 Hydraulic Hydraulic Seals 1



Regular Dual Cat Axis Chart from Pivot Table Data

I’ve highlighted some sections of the pivot table above to correlate them with pivot table ranges in the VBA object model.


Color Range
Blue DataBodyRange
Green ColumnRange
Purple RowRange
Yellow DataLabelRange


The VBA procedure is not too complicated. It should be run whenever the pivot table has been refreshed. It can be called from a button, or from a Worksheet_Calculate event procedure. Whatever works best in a particular application. Paste this code into a regular code module:


Sub UpdateChartFromPivot()
    Dim rCategories As Range
    Dim rValues As Range
    Dim rSeriesNames As Range
    Dim pt As PivotTable
    Dim cht As Chart
    Dim iSeries As Long
    Dim nSeries As Long

    ' Define the Pivot Table
    'Set pt = ActiveSheet.PivotTables(1)
    Set pt = ActiveSheet.PivotTables("PT_ChartSource")

    ' Define the Ranges
    Set rValues = pt.DataBodyRange
    With pt.RowRange
        Set rCategories = .Offset(1).Resize(.Rows.Count - 1)
    End With
    Set rSeriesNames = pt.ColumnRange.Rows(2)

    ' Define the Chart
    'Set cht = ActiveSheet.ChartObjects(1).Chart
    Set cht = ActiveSheet.ChartObjects("chtPivotData").Chart

    ' How Many Series?
    nSeries = rSeriesNames.Columns.Count

    ' Remove or Add Series until Chart Has Correct Number
    Select Case cht.SeriesCollection.Count - nSeries
        Case Is > 0
            ' too many: remove excess series
            For iSeries = nSeries To cht.SeriesCollection.Count + 1
                cht.SeriesCollection(iSeries).Delete
            Next
        Case Is < 0
            ' too few: add sufficient series
            For iSeries = cht.SeriesCollection.Count + 1 To nSeries
                cht.SeriesCollection.NewSeries
            Next
        Case Else
            ' just right
    End Select

    ' Populate Each Series
    For iSeries = 1 To nSeries
        With cht.SeriesCollection(iSeries)
            .Name = rSeriesNames.Columns(iSeries)
            .Values = rValues.Columns(iSeries)
            .XValues = rCategories
            .Border.LineStyle = xlNone
        End With
    Next

End Sub
 

Let’s add some rows to the pivot table source data:


A B C D
1 Main Category Category Sub Category Defects
2 Mechanical Mechanical Gear 11
3 Mechanical Mechanical Bearing 8
4 Mechanical Mechanical Motor 3
5 Electrical Electrical Switch 19
6 Electrical Electrical Plug 12
7 Electrical Electrical Cord 11
8 Electrical Electrical Fuse 3
9 Electrical Electrical Bulb 2
10 Hydraulic Hydraulic Pump 4
11 Hydraulic Hydraulic Leak 3
12 Hydraulic Hydraulic Seals 1
13 Environmental Environmental Emissions 5
14 Environmental Environmental Noise 6
15 Environmental Environmental Thermal 2


Now update the pivot table:


Updated Pivot Table

And finally, run the VBA procedure to update the chart:

The VBA procedure can be run from the Macros dialog (press Alt+F8 or navigate the menu/ribbon), from a button you’ve placed on the sheet (see Assign a Macro to a Button or Shape and Assign a Macro to an ActiveX Control), from a menu item (see Assign a Macro to a Toolbar or Menu), or from a worksheet event procedure.

In Excel 2003 (and maybe 2002) you can use the Worksheet_PivotTableUpdate event procedure. Select the sheet with the pivot table and chart, right click on the sheet tab, and choose View Code. This opens the code module for the active worksheet. From the left dropdown in the module window, choose Worksheet, and from the right dropdown, choose PivotTableUpdate. The shell for the event procedure is entered into the module for you. Insert the procedure name as shown below, and you’re ready to go:

Private Sub Worksheet_PivotTableUpdate(ByVal Target As PivotTable)
    UpdateChartFromPivot
End Sub
 

If you’re using an older version of Excel, there is no PivotTableUpdate event. What I do in this case is place a formula in a cell outside the pivot table (say, M1) with a formula like:

=SUM(A1:J20)

where the range A1:J20 includes the pivot table. This formula ensures that a calculation occurs when the pivot table refreshes. Then I use the Worksheet_Calculate event procedure to kick off the chart update procedure. As above, select the sheet with the pivot table and chart, right click on the sheet tab, and choose View Code. This opens the code module for the active worksheet. From the left dropdown in the module window, choose Worksheet, and from the right dropdown, choose Calculate. The shell for the event procedure is entered into the module for you. Insert the procedure name as shown below, and you’re ready to go:

Private Sub Worksheet_Calculate()
    UpdateChartFromPivot
End Sub
 

Fourth in a series

Possibly Related Posts:

Bookmark and share this entry:
  • Digg
  • del.icio.us
  • Facebook
  • Technorati
  • TwitThis
  • StumbleUpon
  • Google Bookmarks
  • Reddit
  • MySpace
  • Slashdot
  • LinkedIn
  • Yahoo! Buzz

Learn how to create Excel dashboards.

Comments


Comment from Peder Schmedling
Time: Saturday, April 26, 2008, 9:42 am

Hey!
Way to go, very nice solution.
I love this blog, keep up the good work.


Comment from Jon Peltier
Time: Saturday, April 26, 2008, 12:29 pm

Peder -

I told you it was on the way! Actually I was writing it as your previous comment came in. The nice thing about the blog is I can write about smaller parts of a problem, and post a bit at a time, like chapters in a serial novel. With the regular web site, I felt I had to write the whole novel at once, so I often just never got around to it.


Comment from Subhash Tiwari
Time: Friday, June 6, 2008, 11:29 am

Hi Team,

It’s nice to see the effort you people doing to help the other person as well a new comer.

I have a query…I’m working on a data range where pivot item value need to change dynamically. Once I record the Marco. It’s given a static value..

Code is: -

With ActiveSheet.PivotTables(”PivotTable2″).PivotFields(”CLOSED_DTTM”)
.PivotItems(”6/4/2008″).Visible = False
End With

Here “6/4/2008″ is a current date & every day this value gets changes.

Please help me how can I change it dynamically in the VBA code


Comment from Jon Peltier
Time: Friday, June 6, 2008, 12:12 pm

Subhash -

This might be as easy as using today’s data in the proper format:

.PivotItems(Format(Now, “m/d/yyyy”)).Visible = False


Comment from Subhash Tiwari
Time: Monday, June 9, 2008, 9:20 am

Hi Jon ,

Thank for your advice. However it’s not working :-(
Even I tried Today & Date function as well…but in all cases curser stop at this line of codes & every time I need to put the values manually :-(


Comment from Jon Peltier
Time: Monday, June 9, 2008, 9:41 am

1. Note that the straight quotes in my line of code have been converted by WordPress into curly quotes.

2. Make sure that Format(Now, “m/d/yyyy”) exactly matches the pivot item label you need to hide. In the Immediate Window, type this and press Enter:

?Format(Now, “m/d/yyyy”)


Comment from Subhash Tiwari
Time: Monday, June 9, 2008, 11:52 am

Thanks a lot Jon :-)..now code is working fine


Comment from Felix Marusic
Time: Friday, January 16, 2009, 10:25 am

John,

I’m trying apply a dynamic chart title which will should change when the data is either filtered or sorted, but have been unable to do so using a macro or via the interface. Not sure of the VBA syntax needed to pull this off.


Comment from Jon Peltier
Time: Friday, January 16, 2009, 10:44 am

Have you tried the Worksheet_Calculate and Worksheet_PivotTableUpdate event procedures? These are on the worksheet’s code module. Easiest way to get there is to right click on the worksheet tab and select View Code.


Comment from Felix Marusic
Time: Friday, January 16, 2009, 5:30 pm

Jon,

Thanks I’ll look into it.

Felix


Comment from Doug Glancy
Time: Tuesday, March 3, 2009, 8:10 pm

Jon, I’m doing something similar with an addin that updates a workbook on its Worksheet_PivotTableUpdate event. It works great except that some, to all, of my charts (pie charts!) keep reverting to Pivot Charts. It seems like this didn’t happen when my code was in the workbook itself instead of in an addin. Also, the workbooks are actually created from templates if that makes any difference, and the pivot tables are based on external queries to Access. I can kind of prevent it if I put a Stop in the code and select a sheet, but only kind of, and putting in code to activate sheets doesn’t help. I can’t really see a pattern to which charts revert and which don’t.

I know, from you, that you can accidentally turn a regular chart into a pivot chart by hand, so I assume this is related.


Comment from Doug Glancy
Time: Tuesday, March 3, 2009, 9:54 pm

I got it. Looked at your code in this post some more and that gave me the answer. I was using the SetSourceData method (I think I got that from the macro recorder, but can’t swear to it). When I switched to SeriesCollection.XValues and .Values my charts started behaving. Thanks for your most helpful site!


Comment from Jon Peltier
Time: Tuesday, March 3, 2009, 10:06 pm

Doug -

Glad you got it sorted out. When SetSourceData overlaps with a pivot table, the chart is converted to a pivot chart. Inconvenient, but setting the X and Y values of each series maintains the independence of the chart. I’m working on a replacement chart source data dialog which bypasses SetSourceData in favor of series-by-series definitions.


Comment from Doug Glancy
Time: Tuesday, March 3, 2009, 10:32 pm

Jon, that sounds like a good project. I’ve got a nice pivot chart class that passes back references to items in a field and the like. It’s been a lot of fun to put together. Thanks again.


Comment from NMullis
Time: Tuesday, May 12, 2009, 4:07 pm

Jon, I have a workbook with several pivot charts. The charts are all Line chart types where each of the series lines represents a retailer and each of the 8 retailers may or may not be in the resulting pivot chart. On each chart I need there to be consistency among each of the retailer colors, that is, to see Retailer A always in yellow, Retailer B always in blue, Retailer C always in green, etc. If Retailer A is not represented on a given chart then another retailer should not be yellow.

To add to the complexity, I would like a way to update all pivot charts (12) at one time. Is this possible?

Thank you,
N


Comment from Jon Peltier
Time: Tuesday, May 12, 2009, 4:40 pm

For the consistent formatting, you could run a macro like that in VBA Conditional Formatting of Charts by Series Name after refreshing the pivot tables.

To refresh all of the pivot tables:

Sub RefreshAllPivots()
  Dim pt As PivotTable
  For Each pt In ActiveSheet.PivotTables
    pt.RefreshTable
  Next
End Sub

&nbsp:


Comment from NMullis
Time: Wednesday, May 13, 2009, 11:05 am

That is awesome, thank you! I had to adjust for having a line chart style and then all worked perfectly.

Thanks again! N

Write a comment

I welcome comments from my readers. If you have an opinion on this post, if you have a question or if there is anything to add, I want to hear from you. Whether you agree or disagree, please join the discussion.

If you want to include an image in your comment, post it on your own site or on one of the many free image sharing sites, and include a link in your comment. I'll download your image and insert the necessary html to display the image inline.

Read the PTS Blog Comment Policy.





Subscribe without commenting

PTS Waterfall Chart Utility PTS Cluster-Stack Column Chart Utility PTS Box and Whisker Chart Utility PTS Marimekko Chart Utility

Create Excel dashboards quickly with Plug-N-Play reports.