简体   繁体   中英

Charts Do Not Automatically Update When Data Changes

Hopefully this is an easy one. I have a series of charts in MS Excel that point to data on the same worksheet. The data on the worksheet is calculated using a VBA function. When the data is updated by the VBA function the new numbers are not reflected in the charts that are pointing to them. I tried calling Application.Calculate, but that didn't do the trick. Any thoughts?


UDPATE:

I was able to duplicate this issue on a much smaller scale. Here's how:

  • Create a new workbook
  • Rename Sheet 1 to "Summary"
  • Rename Sheet 2 to "Data"
  • Open the Summary sheet in the VBA editor and paste the following code:

     Private Sub Worksheet_Change(ByVal Target As Range) If Target.Parent.Range("worksheetDate") = Target Then Application.CalculateFull End If End Sub
  • Create a new VBA module

  • Paste the following code into the new VBA module (I apologize - I can't get Stack Overflow to format this correctly for the life of me - this is the best I could get it to do):
    .

     Function getWeekValue (weekNumber As Integer, valuesRange As Range) As Integer Dim aCell As Range Dim currentDate As Date Dim arrayIndex As Integer Dim weekValues(1 To 6) As Integer currentDate = ThisWorkbook.Names("worksheetDate").RefersToRange.Value arrayIndex = 1 For Each aCell In valuesRange If month(currentDate) = month(ThisWorkbook.Sheets("Data").Cells( _ aCell.Row - 1, aCell.Column)) Then weekValues(arrayIndex) = aCell.Value arrayIndex = arrayIndex + 1 End If Next getWeekValue = weekValues(weekNumber) End Function

    .

  • Modify the Data worksheet to match the following image:

替代文字

  • Select Cell B1 and name the range "worksheetDate"
  • Duplicate rows 1 through 3 in the following image:

替代文字

  • In row 4, under the "Week X" headers, enter the following formula

.

 = getWeekValue(1, Data!$A$2:$M$2)

incrementing the first argument to the getWeekValue function by one for each week (eg, pass 1 for Week 1, 2 for Week 2, 3, for Week 3, etc.

  • Create a bar graph using cells A3 through E4 as the data
  • Change the date in cell B2 to a date between 10/1/2010 and 12/31/2010, choosing a month other than the month that is currently in the cell. For example, if the date is 12/11/2010, change it to something like 11/11/2010 or 10/11/2010. Note that both the data and chart update correctly.
  • Modify the date in cell B2 gain. Note that the data updates, but the chart does not.

Oddly, after a period of time (several minutes) has elapsed, the chart finally updates. I'm not sure if this is because I have been performing other activities that triggered the update or because Excel is triggering an update after several minutes.

Just figured out the solution to this issue as I was suffering from the same.

I've just added "DoEvents()" prior to printing or exporting and the chart got refreshed.

example

Sub a()
   Dim w As Worksheet
   Dim a
   Set w = Worksheets(1)

   For Each a In w.Range("a1:a5")
     a.Value = a.Value + 1
   Next

   DoEvents

End Sub  

at the end of my changes I close the workbook and reopen it. that seems the easiest and most reliable way to update everything for me.

This solution worked for me. For the offending worksheet add:

Private Sub Worksheet_Activate()
  Dim rngSelection          As Range
  Dim objChartObject        As ChartObject
  Dim objChart              As Chart
  Dim objSeriesCollection   As SeriesCollection
  Dim objSeries             As Series
  Dim strFormula            As String

  Set rngSelection = Selection

  For Each objChartObject In Me.ChartObjects
    Set objChart = objChartObject.Chart
    Set objSeriesCollection = objChart.SeriesCollection
    For Each objSeries In objSeriesCollection
      strFormula = objSeries.Formula

      objSeries.Delete

      Set objSeries = objSeriesCollection.NewSeries

      objSeries.Formula = strFormula
    Next objSeries
  Next objChartObject

  rngSelection.Select
End Sub

It's possible that the issue is the argument list of getWeekValue, which includes only the week number and the data stream.

If you add a third argument, worksheetDate, then Excel's recalculation engine will be hit on the side of the head with the fact that getWeekValue uses the value held in worksheetDate. In your current implementation, this fact is held only in the VBA code, where it is probably invisible to the recalculation engine.

I write this so hedgingly because I am not privy to the inner workings of the recalculation engine. (Maybe someone who knows about this better than I can comment on my speculation) But I did do a test, in which getWeekValue does have that third argument, and the chart does recalculate properly. Nice added benefit of this approach: you can remove all that other VBA event management. -HTH

For example:

Sub a()
   Dim w As Worksheet
   Dim a
   Set w = Worksheets(1)

   For Each a In w.Range("a1:a5")
     a.Value = a.Value + 1
   Next

   w.ChartObjects(1).Chart.Refresh

End Sub  

替代文字

I've found that calling this Sub works...

Sub DoAllEvents()
    DoEvents
    DoEvents
End Sub

BUT Microsoft cautions about being caught with the next DoEvents executing before the first DoEvents completes, which can happen depending on how often it's called without a delay between calls. Thus DoEvents appears to be acting as a type of non maskable interrupt, and nesting non maskable interrupts can cause the machine to freeze for multiple reasons without any recovery other than reboot.

(Note: If one is not calling the routine above, often and quickly, nesting may not be an issue.)

Using the following Sub below, which I modified from their suggestion, prevents this from happening.

Sub DoAllEvents()
    On Error GoTo ErrorCheck
    Dim i
    For i = 1 To 4000    ' Start loop. Can be higher, MS sample shows 150000
        'I've found twice is enough, but only increased it to four or 4000.
        If i Mod 1000 = 0 Then     ' If loop has repeated 1000 times.
            DoEvents    ' Yield to operating system.
        End If
    Next i
    Exit Sub
ErrorCheck:
    Debug.Print "Error: "; Error, Err
    Resume Next
End Sub

I appears that the number of DoEvents needed is based on the number of background tasks running on your machine, and updating the graph appears to be a background task for the application. I only needed two DoEvents because I call the routine frequently; however, I may end up upping it later if needed. I also keep the Mod at 1000 so to not change the lag between each DoEvents as Microsoft suggests, preventing nesting. One possible reason you might want to increase the number from 2000 to a higher number is if you system does not update the graph. Increasing this number allows the machine to handle larger numbers of background events that DoEvents might encounter through multiple calls as they are probably on a stack, and the DoEvents event is only allowed to run a specific number of cycles before marking its place in the stack to allow unhandled events and returning, leaving them to be handled on the next call. Thus the need for multiple calls. Changing this to their example of 150000 doesn't appear to slow the machine too much, to play it safe you might want to make it 150000.

Note: the first example Sub with two DoEvents is probably safe depending on how often you call the Sub, however, if called too often, your machine might freeze up. Your call. ;-)

PS: DoEvents will become one of your best calls if you create a lot of nested loops and the program doesn't behave as expected. Fortunately, this is available in all apps that use VBA!

Running Excel 2019.

Added the following to the macro code:

ActiveSheet.ChartObjects(1).Chart.Refresh    
DoEvents

The chart now updates during macro execution

UDF getWeekValue has to be marked as volatile.

 Function getWeekValue (weekNumber As Integer, valuesRange As Range) As Integer   
 
 Application.Volatile '!!

 Dim aCell As Range  
 Dim currentDate As Date
 
 '... 

Just an idea: in your Worksheet_Change Sub, insert as the first line:

Application.EnableEvents = False

in order to avoid self-firing events....
Of course set it back to True at the end of the Sub.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM