Create and Update a Chart Using Only Part of a Pivot Table’s Data

In Referencing Pivot Table Ranges in VBA I showed how to identify certain sections of a pivot table using VBA. In Dynamic Chart using Pivot Table and VBA I showed how to update a non-pivot chart when a pivot table updates.

How about some code that makes a chart based on only part of a pivot table, and updates it on demand?

The Pivot Table

The data we’re using shows causes of failure in a system, broken down by categories and types of failure. It’s the same data used in the dynamic chart article cited above.

Pivot Table Source Data

Here’s the pivot table from the dynamic chart article. The duplicate columns Main Category and Category were needed in order to have the categories (electrical, mechanical, etc.) in both the row area and column area of the pivot table. Doing this plots each category’s defect data in a different series, so each category is shown in a different format.

Pivot Table

If we just make a chart from the pivot table, here is the result. Not bad, but our objective is to show only one category, say, Environmental.

Pivot Chart

One of the limitations of a pivot chart is that we can’t plot a subset of the data. Well, we could, but we’d have to filter the pivot table so only the information we wanted to chart was visible.

Even if we selected only the data we wanted to plot, Excel would automatically expand the data range to the extent of the pivot table, and hand us a pivot chart.

We can still plot only part of the pivot table in a regular chart, but we need to take some special measures, as described in Making Regular Charts from Pivot Tables. For example, the selected range has to be nowhere near the pivot table when we insert the chart. Then we need to add the chart data one series at a time. Any attempt to enter a portion of the pivot table in the top portion of the Select Data Source dialog will convert the chart to a pivot chart and convert the source data range to the entire pivot table.

Chart Source Data in the Pivot Table

Basically, we need the subcategories of the environmental category for our X axis labels, we want the corresponding defect totals for our Y values, and we need the environmental category label for the series name.

I’ll use the approach I described in Referencing Pivot Table Ranges in VBA to identify these ranges.

The code to select the environmental category label (series name) is

ActiveSheet.PivotTables(1).PivotFields("Category").PivotItems("Environmental")
    .LabelRange.Select

Series Name: Environmental Pivot Item Label

Very good, the label is selected. One part done, the easy part.

If we use

ActiveSheet.PivotTables(1).PivotFields("Category").PivotItems("Environmental")
    .DataRange.Select

we would select the entire column of environmental defect data, including the blank cells for the other categories.

Category Pivot Field - Environmental Data Range

Likewise, if we try

ActiveSheet.PivotTables(1).PivotFields("Main Category").PivotItems("Environmental")
    .DataRange.Select

we end up with the entire row of data, including those blank cells.

Main Category Pivot Field - Environmental Data Range

What we need is the intersection of those two ranges, or

Intersect(ActiveSheet.PivotTables(1).PivotFields("Category")
    .PivotItems("Environmental").DataRange,
    ActiveSheet.PivotTables(1).PivotFields("Main Category")
    .PivotItems("Environmental").DataRange).Select

Y Values: Intersection of Environmental Data Ranges

Perfect. Now for the category labels. Trying

ActiveSheet.PivotTables(1).PivotFields("Category").PivotItems("Environmental")
    .DataRange.Select

gives us all of the subcategories.

Subcategory Data Range

We only want some of those, so let’s poke around a little deeper.

ActiveSheet.PivotTables(1).PivotFields("Main Category").PivotItems("Environmental")
    .LabelRange.Select

gives us the four cells we want, but not in the right column.

Main Category Pivot Field - Environmental Label Range

So let’s use the interesection of the column of subcategory labels and the entire row of environmental data:

Intersect(ActiveSheet.PivotTables(1).PivotFields("Subcategory").DataRange,
    ActiveSheet.PivotTables(1).PivotFields("Main Category")
    .PivotItems("Environmental").DataRange.EntireRow).Select

Category Labels (X Values): Intersection of Main Category Environmental Ranges (entire row) with Subcategory Data Range

Good, so we’ve figured out the ranges we’ll need.

Let’s Write Some Code

Now that we know what we’re starting with (a pivot table), how much of it we’ll need (the chart data ranges we divined above), and the output (a chart), it’s time to write some code.

I’ll do this in two parts. I’ll use a routine that updates a specified chart based on the ranges within the pivot table. I’ll write a routine that makes sure that the selected range doesn’t overlap with a pivot table and insert a new chart, then call the first routine to populate the chart. Finally I’ll write a short routine that calls the update chart routine, specifying the active chart.

The following routine accepts a chart from whatever code calls it, defines the various ranges it needs, uses the addresses of these ranges to construct the series formula, then clears the data out of the specified chart and replaces it with a series that uses this formula.

Sub UpdateChart(cht As Chart)
  Dim rXVals As Range
  Dim rYVals As Range
  Dim rName As Range
  Dim sSrsFmla As String
  Dim PT1 As PivotTable

  On Error GoTo LeaveThisMess

  ' define chart data ranges

  Set PT1 = ActiveSheet.PivotTables(1)

  Set rName = PT1.PivotFields("Category").PivotItems("Environmental").LabelRange

  Set rXVals = Intersect(PT1.PivotFields("Subcategory").DataRange, _
      PT1.PivotFields("Main Category").PivotItems("Environmental") _
      .DataRange.EntireRow)

  Set rYVals = Intersect(PT1.PivotFields("Category").PivotItems("Environmental") _
      .DataRange, PT1.PivotFields("Main Category").PivotItems("Environmental") _
      .DataRange)

  ' write series formula

  sSrsFmla = "=series(" & rName.Address(, , , True) & "," & _
      rXVals.Address(, , , True) & "," & rYVals.Address(, , , True) & ",1)"

  With cht
    ' clear out chart data
    Do
      If .SeriesCollection.Count = 0 Then Exit Do
      .SeriesCollection(1).Delete
    Loop

    ' add brand new series with data we've defined
    With .SeriesCollection.NewSeries
      .Formula = sSrsFmla
    End With
  End With

LeaveThisMess:

End Sub

The following routine moves the active cell to the bottom right cell of the sheet, where hopefully there won’t be any pivot tables. I could do more checking, but I won’t. Then the sheet is scrolled up to the top left cell.

It disables screen updating while it does this, so the user doesn’t get a case of vertigo.

The routine inserts a chart in the default position (centered in the window), makes it a clustered column chart, then sends the chart to the routine above to be populated for the first time.

Sub CreateChartFromPartialPivotTable()
  Dim cht As Chart

  Application.ScreenUpdating = False

  On Error GoTo BailOut

  ' make sure active cell isn't in pivot table
  ' if it were, the chart would be a pivot chart
  With ActiveSheet
    .Cells(.Rows.Count, .Columns.Count).Select
  End With
  With ActiveWindow
    .ScrollColumn = 1
    .ScrollRow = 1
  End With

  ActiveSheet.Shapes.AddChart
  Set cht = ActiveSheet.ChartObjects(1).Chart
  cht.ChartType = xlColumnClustered

  UpdateChart cht

  ActiveSheet.Cells(1, 1).Select

BailOut:
  Application.ScreenUpdating = True

End Sub

This last routine makes sure a chart is selected, and if so, calls the first routine to repopulate it.

Sub UpdateActiveChart()
  If Not ActiveChart Is Nothing Then
    UpdateChart ActiveChart
  End If
End Sub

Fairly elegant for something so quick and dirty.

Finally, The Chart

And oh yeah, here’s the chart. I’ve shown it next to the pivot table with the plotted series selected, so you can see the highlighted ranges used to plot the data. Environmental defect totals as Y values (blue highlights), environmental subcategories as X values (purple highlights), and Environmental label as series name (red highlight).

Chart and Pivot Table, with Source Data Highlighted

 

Peltier Tech Charts for Excel

Comments

  1. Thank you so much. This is just what I was looking for! Just wondering, can you please post a sample worksheet of this for better understanding.

  2. Couldn’t you have done this by filtering the table so that only rows with Main Category=’Electric’ are used in the table. Ah, yes, but this would change the shape of the pivot table, which the user may not want…..

  3. Michael –

    There are many methods to skin a cat, and each method has pros and cons in a given situation. The easiest thing to do might be to have a pivot table showing everything, then a second one showing only the category of interest, with a pivot chart based on the second pivot table.

  4. I am getting an error as
    “1004:Unable to get the PivotFields property of the PivotTable class” when I use following code:

    ActiveSheet.PivotTables(1).PivotFields(“Category”).PivotItems(“Environmental”).DataRange.Select

    Note:
    My data is exactly as shown in the example.

  5. Make sure the pivot field and pivot item names are exactly as shown. “Category”, not “Categories” or “Category “. And make sure the pivot fields items are visible in the pivot table, and not filtered out.

    Also make sure you’re using the Tabular report layout.

Trackbacks

  1. […] Create and Update a Chart Using Only Part of a Pivot Table’s Data | Peltier Tech Blog […]

  2. […] Peltier shows how to create and update a chart, using only part of a pivot table’s […]

Speak Your Mind

*

Peltier Tech Charts for Excel 3.0