how to annotate pivot tables?

miconian

Well-known Member
Joined
Aug 18, 2004
Messages
769
My users spend a lot of time in large pivot tables that are set up in compact view, expanding and collapsing fields by clicking on the plus and minus symbols. As they do this, they want to make notes about individual line items.

However, this is difficult because a) there is nowhere that allows the user to make notes inside the pivot table, and b) if they make notes outside the table, the row their note corresponds to will change when fields are collapsed and expanded. Also, it seems that Excel does not allow comments to be added to cells within pivot tables.

Surely others have had this problem. Is there some obvious workaround I'm missing?

thanks!
 
Unreal

Hi again,

Well, this turned out to be harder than I anticipated, but I finally have some code for you to try. :)

The code allows the user to write notes in the first column of cells to the right of the PivotTable.

As notes are added, revised or deleted, Worksheet_Change event code maintains a data table of the notes on an added sheet.

Each note is indexed by its associated RowField PivotItems... this added sheet can be hidden if you prefer.

Whenever the PivotTable is updated (expanded, collapsed, sorted, refreshed), the notes are cleared and then rewritten to correct positions for the revised PivotTable display.

Because this is fairly complex, I'd encourage you to extensively test this prior to using it for a real world application (and even then make sure to have a back up of your file).

At this point, I'm hopeful this will work for the basic parameters you described.

It assumes you have:
- No more than 1 PivotTable per sheet
- Compact Report layout
- No Page/Report Fields

There's so many options and scenarios for PivotTables, that I expect you'll find some glitches through your testing.

To try it out, paste this code into a Standard Code Module
Rich (BB code):
Option Explicit
 
Public Const sRngName = "PT_Notes"
 
Public Function Check_Setup(ws As Worksheet) As Boolean
    Dim rNotes As Range, i As Long
    Dim PT As PivotTable, ptField As PivotField
    Dim tblNotes As ListObject
    Dim wsSave As Worksheet
 
'---Check if not exactly one PT on Worksheet- exit
    If ws.PivotTables.Count <> 1 Then GoTo StopNotes
    Set PT = ws.PivotTables(1)
 
'---Check if not Compact Report layout- exit
    For Each ptField In PT.RowFields
        If Not ptField.LayoutCompactRow Then GoTo StopNotes
    Next ptField
 
'---Check if Named Range "PT_Notes" doesn't exist- define it
    If Not NameExists(sRngName, ws.Name) Then
        With PT.TableRange1
            Set rNotes = Intersect(PT.DataBodyRange.EntireRow, _
                    .Resize(, 1).Offset(0, .Columns.Count))
        End With
        Set rNotes = rNotes.Resize(rNotes.Rows.Count _
            + PT.ColumnGrand)
        ws.Names.Add Name:=sRngName, RefersTo:=rNotes
        Call Format_NoteRange(rNotes)
    End If
 
'---Check if "|Notes" Worksheet doesn't exist- add it
    If Not SheetExists(ws.Name & "|Notes") Then
        Set wsSave = ActiveSheet
        Sheets.Add
        ActiveSheet.Name = ws.Name & "|Notes"
        wsSave.Activate
    End If
 
'---Check if Notes DataTable doesn't exist- add it
    With Sheets(ws.Name & "|Notes")
        On Error Resume Next
        Set tblNotes = .ListObjects(1)
        If tblNotes Is Nothing Then
            .Cells(1) = "KeyPhrase"
            .Cells(1, 2) = "Note"
            Set tblNotes = .ListObjects.Add(xlSrcRange, _
                .Range("A1:B2"), , xlYes)
        End If
    End With
 
'---Check if any PT fields are not Table Headers - add
    With tblNotes
        For Each ptField In PT.RowFields
            If IsError(Application.Match(ptField.Name, .HeaderRowRange, 0)) Then
                .ListColumns.Add Position:=2
                .HeaderRowRange(1, 2) = ptField.Name
            End If
        Next ptField
    End With
    Check_Setup = True
    Exit Function
 
StopNotes:
    If NameExists(sRngName, ws.Name) Then
        Application.EnableEvents = False
        Call Clear_Notes_Range(ws)
        ws.Names(sRngName).Delete
        Application.EnableEvents = True
        Check_Setup = False
        Exit Function
    End If
End Function
 
Private Function Format_NoteRange(rNotes As Range)
'---Format body
    With rNotes
        .Interior.Color = 16316664
        .Font.Italic = True
        .HorizontalAlignment = xlLeft
        .IndentLevel = 1
        .Borders(xlInsideHorizontal).LineStyle = xlDot
        .Borders(xlBottom).LineStyle = xlDot
    End With
 
'---Format optional header
    With rNotes.Resize(1)(0)
        .Value = "Notes"
        .Interior.Color = 16316664
        .Font.Italic = True
        .Font.Bold = True
        .HorizontalAlignment = xlCenter
        .Borders(xlBottom).LineStyle = xlContinuous
    End With
End Function
 
Private Function Clear_Notes_Range(ws As Worksheet)
'---Clear existing notes range
    On Error Resume Next
    Dim c As Range
    With ws.Range(sRngName)
        With .Offset(-1).Resize(.Rows.Count + 1)
            If Intersect(ws.PivotTables(1).TableRange2, _
                    .Cells) Is Nothing Then
                .ClearContents
                .ClearFormats
            Else 'PT overlaps notes
                For Each c In .Cells
                    c.ClearContents
                    c.ClearFormats
                Next c
                On Error GoTo 0
            End If
        End With
    End With
End Function
 
Public Function Refresh_Notes(PT As PivotTable)
    Dim sField As String, sKey As String, sFormula As String
    Dim ptField As PivotField
    Dim tblNotes As ListObject
    Dim rNotes As Range, c As Range
    Dim rLabels As Range, rLabelsAll As Range
    Dim vFields As Variant, vReturn As Variant
    Dim lPosition As Long, lOffset As Long
    Dim i As Long, lIdx As Long, lCol As Long
 
'---Clear existing notes range
    Call Clear_Notes_Range(ws:=PT.Parent)
'---Redefine and format notes range
    With PT.TableRange1
        Set rNotes = Intersect(PT.DataBodyRange.EntireRow, _
            .Resize(, 1).Offset(0, .Columns.Count))
    End With
    Set rNotes = rNotes.Resize(rNotes.Rows.Count + PT.ColumnGrand)
    PT.Parent.Names(sRngName).RefersTo = rNotes
    Call Format_NoteRange(rNotes)
 
'---Make array of rowfields by position to trace each row in hierarchy
     With PT.RowFields
        ReDim vFields(1 To .Count)
        For lIdx = 1 To .Count
            vFields(PT.RowFields(lIdx).Position) = PT.RowFields(lIdx).Name
        Next lIdx
    End With
 
'---Build formula to use as Match KeyPhrase
    Set tblNotes = Sheets(PT.Parent.Name & "|Notes").ListObjects(1)
    With tblNotes
        On Error Resume Next
        sFormula = "="
        For lIdx = LBound(vFields) To UBound(vFields)
            lCol = Application.Match(vFields(lIdx), .HeaderRowRange, 0)
            sFormula = sFormula & "RC" & lCol & "&""|""&"
        Next lIdx
        sFormula = Left(sFormula, Len(sFormula) - 1)
        Intersect(.DataBodyRange, .ListColumns(1).Range).FormulaR1C1 = sFormula
    End With
 
'---Match KeyPhrases for each visible row of PT
    Application.EnableEvents = False
    With PT.RowRange
        Set rLabelsAll = .Offset(1).Resize(.Rows.Count - 1)
        lOffset = PT.TableRange1.Columns.Count + 1
        For Each c In rLabelsAll
            lIdx = UBound(vFields) + 1
            sKey = ""
            Set rLabels = .Offset(1).Resize(c.Row - .Row)
            For i = rLabels.Rows.Count To 1 Step -1
                sField = rLabels(i).PivotField.Name
                lPosition = Application.Match(sField, vFields, 0)
                Do While lIdx > lPosition + 1
                    sKey = "|" & sKey
                    lIdx = lIdx - 1
                Loop
                If lPosition < lIdx Then
                    sKey = rLabels(i).PivotItem.Name & "|" & sKey
                    lIdx = lPosition
                    If lIdx = 1 Then Exit For
                End If
            Next i
            vReturn = Evaluate("=INDEX(" & tblNotes.Name & "[Note],MATCH(""" & _
                sKey & """," & tblNotes.Name & "[KeyPhrase],0))")
            If (Not IsError(vReturn)) Then c(1, lOffset) = CStr(vReturn)
        Next c
    End With
    Application.EnableEvents = True
End Function
 
Public Function Update_Note_Database(PT As PivotTable, rNote As Range)
    Dim rLabels As Range
    Dim sField As String, sItem As String
    Dim vFields As Variant, tblNotes As ListObject
    Dim lPosition As Long, lIdx As Long
    Dim iArray As Variant, i As Integer
 
'---Make array of rowfields by position to trace each row in hierarchy
     With PT.RowFields
        ReDim vFields(1 To .Count)
        For lIdx = 1 To .Count
            vFields(PT.RowFields(lIdx).Position) = PT.RowFields(lIdx).Name
        Next lIdx
    End With
 
'---Make new record of note at top of database table
    lIdx = lIdx + 1
    Set tblNotes = Sheets(PT.Parent.Name & "|Notes").ListObjects(1)
    tblNotes.ListRows.Add (1)
    tblNotes.ListColumns("Note").Range(2) = rNote.Value
    With PT.RowRange
        Set rLabels = .Offset(1).Resize(rNote.Row - .Row)
        For i = rLabels.Rows.Count To 1 Step -1
            sField = rLabels(i).PivotField.Name
            lPosition = Application.Match(sField, vFields, 0)
            If lPosition < lIdx Then
                sItem = rLabels(i).PivotItem.Name
                tblNotes.ListColumns(sField).Range(2) = sItem
                lIdx = lPosition
                If lIdx = 1 Then Exit For
            End If
        Next i
    End With
 
'---Remove any previous notes with matching rowfield values
    With tblNotes.Range
        ReDim iArray(0 To .Columns.Count - 3)
        For i = 0 To UBound(iArray)
            iArray(i) = i + 2
        Next i
        .RemoveDuplicates Columns:=(iArray), Header:=xlYes
        If rNote = vbNullString Then tblNotes.ListRows(1).Delete
    End With
End Function
 
Private Function NameExists(sRngName As String, _
        sSheetName As String) As Boolean
    Dim rTest As Range
    On Error Resume Next
    Set rTest = Sheets(sSheetName).Range(sRngName)
    NameExists = Not rTest Is Nothing
End Function
 
Private Function SheetExists(sSheetName As String) As Boolean
    Dim sTest As String
    On Error Resume Next
    sTest = Worksheets(sSheetName).Name
    SheetExists = LCase(sTest) = LCase(sSheetName)
End Function

Then paste this code into the Sheet Code Module of the Worksheet that has the PivotTable to be annotated.
Rich (BB code):
Private Sub Worksheet_Change(ByVal Target As Range)
'----When changes are made in the named range displaying
'--    PivotTable Notes, the Note database table
'--    will be updated with each New or Revised note.
 
    Dim rNotesChanged As Range, c As Range
 
    Application.ScreenUpdating = False
    If Check_Setup(Me) = False Then GoTo CleanUp
    Set rNotesChanged = Intersect(Target, _
        Range(sRngName))
    If rNotesChanged Is Nothing Then Exit Sub
    For Each c In rNotesChanged
        Call Update_Note_Database( _
            PT:=Me.PivotTables(1), _
            rNote:=c)
    Next c
CleanUp:
    Set rNotesChanged = Nothing
    Application.EnableEvents = True
    Application.ScreenUpdating = True
End Sub
 
Private Sub Worksheet_PivotTableUpdate(ByVal Target As PivotTable)
'----Refreshes display of PivotTable Notes from the Note database
'--    when the PivotTable is updated (refreshed, sorted, filtered, etc)
    If Check_Setup(Me) = False Then Exit Sub
 
    Application.ScreenUpdating = False
    Application.EnableEvents = False
 
    Call Refresh_Notes(PT:=Target)
 
    Application.EnableEvents = True
    Application.ScreenUpdating = True
End Sub

You can use the system on more than one worksheet in the same workbook.
Each worksheet can only have one PivotTable, and the Sheet Code needs to be pasted into each worksheet.

You're a genius! Thanks for investing the time on this!
 
Upvote 0

Excel Facts

Can you sort left to right?
To sort left-to-right, use the Sort dialog box. Click Options. Choose "Sort left to right"
Re: Unreal

This is exactly what I've been looking for. Just a quick question though... I am super new to vibe, and I'm wondering what it does when the pivot table refreshes and gets new data. How does it know what object the note is attached to?
 
Upvote 0
Re: Unreal

sorry one more q... I am getting thie error when ever the code is executed:

Compile error:
Constants, fixed-length strings, arrays, user-defined types, and Declare statement not allowed as Public members of object modules

Any idea why?
 
Upvote 0
Re: Unreal

This is exactly what I've been looking for. Just a quick question though... I am super new to vibe, and I'm wondering what it does when the pivot table refreshes and gets new data. How does it know what object the note is attached to?

Hi and Welcome to MrExcel,

The code stores a list of the notes in a lookup table on an added sheet. The first column of the lookup table has a unique key phrase formed by joining the row field items corresponding to each note. An example key phrase could be "Europe|France|Paris|".

When the PivotTable is refreshed each displayed row is checked against the lookup table. If a matching key phrase is found, the previously stored note is displayed next to the PivotTable.
 
Upvote 0
sorry one more q... I am getting thie error when ever the code is executed:

Compile error:
Constants, fixed-length strings, arrays, user-defined types, and Declare statement not allowed as Public members of object modules

Any idea why?

That would happened if you've pasted the code in the wrong code module.

Below are more detailed instructions and the current version of the code for Windows users...
(This combines code from Posts #26 and #32).

Paste this code in the Sheet Code Module of the sheet that has the PivotTable.
(Right-Click on the Sheet's Tab > View Code... to get to the Sheet Code Module.)

Code:
Option Explicit

Private Sub Worksheet_Change(ByVal Target As Range)
'----When changes are made in the named range displaying
'--    PivotTable Notes, the Note database table
'--    will be updated with each New or Revised note.

    Dim rNotesChanged As Range, c As Range
    Application.ScreenUpdating = False
    If Check_Setup(Me) = False Then GoTo CleanUp
    Set rNotesChanged = Intersect(Target, _
        Range(sRngName))
    If rNotesChanged Is Nothing Then Exit Sub

    For Each c In rNotesChanged
        '---Update each changed note cell unless the change was due to
        '      being overlapped by a resized PivotTable
        If Not isPivotCell(c) Then _
            Call Update_Note_Database( _
                PT:=Me.PivotTables(1), _
                rNote:=Intersect(c.EntireRow, Range(sRngName)))
    Next c
CleanUp:
    Set rNotesChanged = Nothing
    Application.EnableEvents = True
    Application.ScreenUpdating = True
End Sub
 

Private Sub Worksheet_PivotTableUpdate(ByVal Target As PivotTable)
'----Refreshes display of PivotTable Notes from the Note database
'--    when the PivotTable is updated (refreshed, sorted, filtered, etc)
    If Check_Setup(Me) = False Then Exit Sub
 
    Application.ScreenUpdating = False
    Application.EnableEvents = False
 
    Call Refresh_Notes(PT:=Target)
 
    Application.EnableEvents = True
    Application.ScreenUpdating = True
End Sub


Paste the code below into a Standard Code Module.
To insert a Standard Code Module from within the Visual Basic Editor...
1. If the VBA Project Explorer pane isn't displayed: Ctrl+R
2. Right click on the label: VBAProject(your filename)
3. Insert > Module
4. Paste this into the code space where the cursor is now blinking.

Code:
Option Explicit

Public Const sRngName = "PT_Notes"

Public Function Check_Setup(ws As Worksheet) As Boolean
    Dim rNotes As Range, i As Long, bCompact As Boolean
    Dim PT As PivotTable, ptField As PivotField
    Dim tblNotes As ListObject
    Dim wsSave As Worksheet

 
'---Check if not exactly one PT on Worksheet- exit
    If ws.PivotTables.Count <> 1 Then GoTo StopNotes
    Set PT = ws.PivotTables(1)
    
'---Check if not at least one RowField and one DataField- exit
    If PT.DataFields.Count = 0 Or PT.RowFields.Count = 0 Then GoTo StopNotes
  
'---Check if Named Range "PT_Notes" doesn't exist- define it
    If Not NameExists(sRngName, ws.Name) Then
        With PT.TableRange1
            Set rNotes = Intersect(PT.DataBodyRange.EntireRow, _
                    .Resize(, 2).Offset(0, .Columns.Count))
        End With
        Set rNotes = rNotes.Resize(rNotes.Rows.Count _
            + PT.ColumnGrand)
        ws.Names.Add Name:=sRngName, RefersTo:=rNotes
        Call Format_NoteRange(rNotes)
    End If
 

'---Check if "|Notes" Worksheet doesn't exist- add it
    If Not SheetExists(ws.Name & "|Notes") Then
        Set wsSave = ActiveSheet
        Sheets.Add
        ActiveSheet.Name = ws.Name & "|Notes"
        wsSave.Activate
    End If
 

'---Check if Notes DataTable doesn't exist- add it
    With Sheets(ws.Name & "|Notes")
        On Error Resume Next
        Set tblNotes = .ListObjects(1)
        If tblNotes Is Nothing Then
            .Cells(1) = "KeyPhrase"
            .Cells(1, 2) = "Note1"
            .Cells(1, 3) = "Note2"
            Set tblNotes = .ListObjects.Add(xlSrcRange, _
                .Range("A1:C2"), , xlYes)
        End If
    End With
 

'---Check if any PT fields are not Table Headers - add
    With tblNotes
        For Each ptField In PT.RowFields
            If IsError(Application.Match(ptField.Name, .HeaderRowRange, 0)) Then
                .ListColumns.Add Position:=2
                .HeaderRowRange(1, 2) = ptField.Name
            End If
        Next ptField
    End With
    Check_Setup = True
    Exit Function
 

StopNotes:
    If NameExists(sRngName, ws.Name) Then
        Application.EnableEvents = False
        Call Clear_Notes_Range(ws)
        ws.Names(sRngName).Delete
        Application.EnableEvents = True
        Check_Setup = False
        Exit Function
    End If
End Function
 

Private Function Format_NoteRange(rNotes As Range)
'---Format body
    With rNotes
        .Interior.Color = 16316664
        .Font.Italic = True
        .HorizontalAlignment = xlLeft
        .IndentLevel = 1
        .Borders(xlInsideHorizontal).LineStyle = xlDot
        .Borders(xlBottom).LineStyle = xlDot
    End With
 
'---Format optional header
    With rNotes.Resize(1).Offset(-1)
        .Cells(1).Value = "Note1"
        .Cells(2).Value = "Note2"
        .Interior.Color = 16316664
        .Font.Italic = True
        .Font.Bold = True
        .HorizontalAlignment = xlCenter
        .Borders(xlBottom).LineStyle = xlContinuous
    End With
End Function
 

Private Function Clear_Notes_Range(ws As Worksheet)
'---Clear existing notes range
    On Error Resume Next
    Dim c As Range
    With ws.Range(sRngName)
        With .Offset(-1).Resize(.Rows.Count + 1)
            If Intersect(ws.PivotTables(1).TableRange2, _
                    .Cells) Is Nothing Then
                .ClearContents
                .ClearFormats
            Else 'PT overlaps notes
                For Each c In .Cells
                    c.ClearContents
                    c.ClearFormats
                Next c
                On Error GoTo 0
            End If
        End With
    End With
End Function
 

Public Function Refresh_Notes(PT As PivotTable)
    Dim sField As String, sKey As String, sFormula As String
    Dim ptField As PivotField
    Dim tblNotes As ListObject
    Dim rNotes As Range, c As Range
    Dim rLabels As Range, rLabelsAll As Range
    Dim vFields As Variant, vReturn As Variant
    Dim lPosition As Long, lOffset As Long
    Dim i As Long, lIdx As Long
    Dim lRow As Long, lCol As Long

    
'---Clear existing notes range
    Call Clear_Notes_Range(ws:=PT.Parent)
'---Redefine and format notes range
    With PT.TableRange1
        Set rNotes = Intersect(PT.DataBodyRange.EntireRow, _
            .Resize(, 2).Offset(0, .Columns.Count))
    End With
    Set rNotes = rNotes.Resize(rNotes.Rows.Count + PT.ColumnGrand)
    PT.Parent.Names(sRngName).RefersTo = rNotes
    Call Format_NoteRange(rNotes)
 
'---Make array of rowfields by position to trace each row in hierarchy

     With PT.RowFields
        ReDim vFields(1 To .Count)
        For lIdx = 1 To .Count
            vFields(PT.RowFields(lIdx).Position) = PT.RowFields(lIdx).Name
        Next lIdx
    End With
 
'---Build formula to use as Match KeyPhrase
    Set tblNotes = Sheets(PT.Parent.Name & "|Notes").ListObjects(1)
    With tblNotes
        On Error Resume Next
        sFormula = "="
        For lIdx = LBound(vFields) To UBound(vFields)
            lCol = Application.Match(vFields(lIdx), .HeaderRowRange, 0)
            sFormula = sFormula & "RC" & lCol & "&""|""&"
        Next lIdx
        sFormula = Left(sFormula, Len(sFormula) - 1)
        Intersect(.DataBodyRange, .ListColumns(1).Range).FormulaR1C1 = sFormula
    End With
 
'---Match KeyPhrases for each visible row of PT
    Application.EnableEvents = False
    With PT.TableRange1
        lOffset = .Column + .Columns.Count - PT.DataBodyRange.Column + 1
    End With
    
    With PT.DataBodyRange.Resize(, 1)
        For lRow = 1 To .Rows.Count + PT.ColumnGrand
            sKey = GetKey(rPC:=.Cells(lRow), vFields:=vFields)
            vReturn = Evaluate("=MATCH(""" & _
                sKey & """," & tblNotes.Name & "[KeyPhrase],0)")
            If (Not IsError(vReturn)) Then
                .Cells(lRow, lOffset) = Evaluate("=INDEX(" & tblNotes.Name & "[Note1]," & vReturn & ")")
                .Cells(lRow, lOffset + 1) = Evaluate("=INDEX(" & tblNotes.Name & "[Note2]," & vReturn & ")")
            End If
        Next lRow
    End With
    Application.EnableEvents = True
End Function


Private Function GetKey(rPC As Range, vFields As Variant) As String
    Dim i As Long
    Dim sNew As String
    
    With rPC.PivotCell.RowItems
        For i = LBound(vFields) To UBound(vFields)
            If i > .Count Then sNew = "" Else sNew = .Item(i).Caption
            GetKey = GetKey & sNew & "|"
        Next i
    End With
 End Function

Public Function Update_Note_Database(PT As PivotTable, rNote As Range)
    Dim tblNotes As ListObject
    Dim rPC As Range
    Dim iArray As Variant, i As Integer
 
    '---Make new record of note at top of database table
    Set tblNotes = Sheets(PT.Parent.Name & "|Notes").ListObjects(1)
    tblNotes.ListRows.Add (1)
    tblNotes.ListColumns("Note1").Range(2) = rNote(1).Value
    tblNotes.ListColumns("Note2").Range(2) = rNote(1, 2).Value
    
    Set rPC = Intersect(PT.DataBodyRange.Resize(, 1), rNote.EntireRow)
    With rPC.PivotCell.RowItems
        For i = 1 To .Count
            With .Item(i)
                tblNotes.ListColumns(.Parent.Name).Range(2) = .Caption
            End With
        Next i
    End With
    
'---Remove any previous notes with matching rowfield values
    With tblNotes.Range
        ReDim iArray(0 To .Columns.Count - 4)
        For i = 0 To UBound(iArray)
            iArray(i) = i + 2
        Next i
        .RemoveDuplicates Columns:=(iArray), Header:=xlYes
        If rNote(1).Value = "" And rNote(1, 2).Value = "" Then _
            tblNotes.ListRows(1).Delete
    End With
End Function
  
Private Function NameExists(sRngName As String, _
        sSheetName As String) As Boolean
    Dim rTest As Range
    On Error Resume Next
    Set rTest = Sheets(sSheetName).Range(sRngName)
    NameExists = Not rTest Is Nothing
End Function
 

Private Function SheetExists(sSheetName As String) As Boolean
    Dim sTest As String
    On Error Resume Next
    sTest = Worksheets(sSheetName).Name
    SheetExists = LCase(sTest) = LCase(sSheetName)
End Function

Public Function isPivotCell(rCell As Range) As Boolean
    On Error Resume Next
    isPivotCell = Not (IsError(rCell.PivotCell))
End Function
 
Upvote 0
That would happened if you've pasted the code in the wrong code module.
thank you, I am no longer getting the error. I didn't even know what the standard module meant, I had it pasted "this workbook" instead!

I am having a different issue though. As soon as I collapse the pivot, the note of the collapsed row gets pasted to the entire column.
 
Upvote 0
thank you, I am no longer getting the error. I didn't even know what the standard module meant, I had it pasted "this workbook" instead!

I am having a different issue though. As soon as I collapse the pivot, the note of the collapsed row gets pasted to the entire column.

Thanks for sending your file to me. It would have taken a lot of back and forth to figure out why that wasn’t working without seeing your file.

Because your PivotTable was created using PowerPivot, the PivotItems in the RowField can’t be accessed through the PivotCell.RowItems property. It looks like the PivotCell.MDX property could be used instead. MDX stands for Multidimensional Expressions - a query language for OLAP databases.

As explained a few posts ago, the current code builds a key phrase like: "Europe|France|Paris|" using the PivotCell.RowItems collection.

The PivotCell.MDX property will return an expression like: “([Measures].[Sum of Population], [Table1].[City].&[Paris], [Table1].[Continent].&[Europe], [Table1].[Country].&[France]) “

As a quick fix, the code could be modified to convert that expression to the simple “Europe|France|Paris|” that the rest of the code is expecting. Rather than doing that, I think it will be better to rework my code to utilize this accepted standard.

The current code stores data in a two-dimensional matrix, and that has made it difficult to add handling of: added/removed/rearranged fields, report filters, and storing comments specific to a single data item instead of the entire row. Using MDX methodologies has the potential to overcome those obstacles.

I hope to rework that soon. Until then the code in Post #41 appears to work for PivotTables created using PowerPivot. I described that as a version for Mac users because the Excel 2011 object model doesn’t have a PivotCell object. Because of that the “Mac version” also works for PivotTables from PowerPivot.
 
Upvote 0
Hi Jerry,

This tool is amazing, thank you so much!

I think I have found a bug. My excel file has about 50 columns and 10,000 rows. I can easily add all the notes but once I start minimizing the columns and reopen them they end up dissappearing. With less row/columns the code seems to do fine. I wonder if its a limitation/boundry issue?

Thanks again!
 
Upvote 0
I want all notes (old and new) to be stored in the “|Notes” sheet in the workbook. Should portion below be removed from existing code if I do want to keep old notes from the same rowfield?
'---Remove any previous notes with matching rowfield values
With tblNotes.Range
ReDim iArray(0 To .Columns.Count - 4)
For i = 0 To UBound(iArray)
iArray(i) = i + 2
Next i
.RemoveDuplicates Columns:=(iArray), Header:=xlYes
If rNote(1).Value = "" And rNote(1, 2).Value = "" Then _
tblNotes.ListRows(1).Delete
End With
End Function
 
Upvote 0
If you delete the lines shown in green font below, then superseded notes won't be deleted.

Code:
    With tblNotes.Range
        ReDim iArray(0 To .Columns.Count - 4)
        For i = 0 To UBound(iArray)
            iArray(i) = i + 2
        Next i
[B][COLOR="#008000"]  '      .RemoveDuplicates Columns:=(iArray), Header:=xlYes
  '      If rNote(1).Value = "" And rNote(1, 2).Value = "" Then _
  '          tblNotes.ListRows(1).Delete[/COLOR][/B]
    End With


If the list of notes in the table becomes very long, it has the potential to affect the speed of the lookups.

I see how some people might like the option to save old notes as you suggest. I'll try to add the option to keep a note history (perhaps with timestamps?) that would be separate from the "Current" notes for each key phrase.

Thanks for your input! :)
 
Upvote 0

Forum statistics

Threads
1,224,824
Messages
6,181,187
Members
453,020
Latest member
Mohamed Magdi Tawfiq Emam

We've detected that you are using an adblocker.

We have a great community of people providing Excel help here, but the hosting costs are enormous. You can help keep this site running by allowing ads on MrExcel.com.
Allow Ads at MrExcel

Which adblocker are you using?

Disable AdBlock

Follow these easy steps to disable AdBlock

1)Click on the icon in the browser’s toolbar.
2)Click on the icon in the browser’s toolbar.
2)Click on the "Pause on this site" option.
Go back

Disable AdBlock Plus

Follow these easy steps to disable AdBlock Plus

1)Click on the icon in the browser’s toolbar.
2)Click on the toggle to disable it for "mrexcel.com".
Go back

Disable uBlock Origin

Follow these easy steps to disable uBlock Origin

1)Click on the icon in the browser’s toolbar.
2)Click on the "Power" button.
3)Click on the "Refresh" button.
Go back

Disable uBlock

Follow these easy steps to disable uBlock

1)Click on the icon in the browser’s toolbar.
2)Click on the "Power" button.
3)Click on the "Refresh" button.
Go back
Back
Top