• Hi All

    Please note that at the Chandoo.org Forums there is Zero Tolerance to Spam

    Post Spam and you Will Be Deleted as a User

    Hui...

  • When starting a new post, to receive a quicker and more targeted answer, Please include a sample file in the initial post.

VBA addition subtraction and loop on percentages

chirayu

Well-Known Member
Hi All,
I need some help with the macro I have created in the sample file, it runs endlessly and doesn't add or subtract the way I want it to. File attached.

I want it to add 0.01 on a loop if the old chart % is less than the new Vlookup & subtract 0.01 if the old chart % is more than the new Vlookup

Also I have an Offset function that checks if the next cell is blank as I need it to do for all % cells in a given row range i.e. Jan to Dec
 

Attachments

  • sample.xlsm
    13.4 KB · Views: 11
Hi Debraj,

Basically its dummy data - The top data row will have a vlookup that will update basis a drop down list.

After that I will autorun my macro by assigning it to my dropdown.

It will check to see if the data in the cells in the second row of data are less than or more than the vlookup and add or subtract 0.01 accordingly till both cell values are the same

If the vlookup shows #N/A then the output will be equal to #N/A

Then it will move one cell right and repeat the function till it hits a blank cell

I'm trying to use the macro to create a dynamic chart in excel
 
Here's the macro, with my comments
Code:
Sub test()

Dim val As Variant
val = 0.01

Do Until ActiveCell.Offset(0, 1).value = ""

    If ActiveCell.Offset(-1, 0).value = "#N/A" Then
      
        ActiveCell.value = "#N/A"
      
    ElseIf ActiveCell.value < ActiveCell.Offset(-1, 0).value Then
       'DANGER WILL ROBINSON!!!
       'If ActiveCell is < Offset, you are subtracting...so ActiveCell keeps get smaller and smaller
       'But is moving AWAY from Offset value. This loop will go on forever!
       'Also, you are checking for exact match. I think mean ">=", not just "="
        Do Until ActiveCell.value = ActiveCell.Offset(-1, 0).value
            ActiveCell.value = ActiveCell.value - val
        Loop
  
    Else
        Do Until ActiveCell.value = ActiveCell.Offset(-1, 0).value
       'Same problem as above, but reverse.
            ActiveCell.value = ActiveCell.value + val
        Loop
      
    End If
    ActiveCell.Offset(0, 1).Select

Loop

End Sub
 
Last edited:
Here's how I would propose re-writing the macro.
Code:
Sub test()
Dim c As Range
'Better to use a constant than define variable and assign
Const val As Double = 0.01
Dim myRange As Range

'Define the range as only being numbers
Set myRange = Range("6:6").SpecialCells(xlCellTypeConstants, xlNumbers)

Application.ScreenUpdating = False
For Each c In myRange
    If c.value < c.Offset(1).value Then
        Do
            c.value = c.value + val
        Loop Until c.value >= c.Offset(1)
    Else
        Do
            c.value = c.value - val
        Loop Until c.value <= c.Offset(1)
    End If
Next c
Application.ScreenUpdating = True

End Sub
 
Hey Luke yeah I figured out that it was supposed to be > rather than < but it still loops endlessly

will try your solution
 
In that case, instead of incrementing by a set amount, we'll need to increase by a percentage of the difference. How's this? Close to DataPig, but since you're not using an array, just does 1 col at a time.
Code:
Sub test()
Dim c As Range
Const upLimit = 1000 'Controls how fast animation goes
Dim myRange As Range
Dim newValue As Double
Dim oldValue As Double
Dim i As Long


'Define the range as only being numbers
Set myRange = Range("6:6").SpecialCells(xlCellTypeConstants, xlNumbers)

For Each c In myRange
    oldValue = c.value
    newValue = c.Offset(1).value
    DoEvents
    For i = 1 To upLimit
        c.value = oldValue - (oldValue - newValue) * (i / upLimit)
    Next i
Next c

End Sub
 
Hi Luke,

1) OoOoOoOo that code looks awesome and mind boggling. Wish I knew that much Excel. Tutorial?
2) The animation isn't as fluid as that of Datapig - I even changed the speed to 10,000 but just does the calculation slower - chart update isn't fluid
3) Also how do I deal with #N/A occurences - macro stops at it - ideally it should say #N/A and move on to next cell
 
Hi chirayu,

All 3 questions are somewhat related, so I'll try to cover them all in explanation.
First, how the code works. We limit the amount of work the code needs to do, and prevent errors due to the N/A by using the SpecialCells method to limit our range down. The SpecialCells method is the same dialogue you see in a workbook if you hit Ctrl+G, and click the 'special button'. One VB note when dealing with SpecialCells, is that if no cells match your criteria, an error will occur, and that can mess people up sometimes.
So, we've limited the range of cells we want to look at. Next, we want to look at each cell, and see how it compares the newValue.
Let's say that oldValue = 5, and newValue = 10. We want to end up with newValue. So, formula will be:
oldValue - oldValue + newValue = newValue
However, we want to capture the 'change' and cause it to step incrementally. So, we put that portion in parenthesis, watching our signs
oldValue - (oldValue - newValue) = newValue

Next, we want this change to move incrementally. This is where the i = 1 to upLimit comes in. We multiply the parenthesis by some fraction, will will for from ~ 0 to 100%, causing our oldValue to 'slowly' reach newValue.

DataPig is smoother, because he's dealing all with arrays. This cuts down the # of times VB is reading/writing to the workbook, which improves speed. Also, by using an array, he can modify all the values, and the update the values in workbook at the same time. Think of it as doing a paste onto the range, as opposed to doing each cell 1 at a time.

Now, the problem with #n/A. Since DataPig uses an array, we can't use SpecialCells, because we want to deal wiht the whole range. So, we need to add in an If...Then statement to check our values before trying to do math on them. Here's a re-write of DataPig's code, which works in your workbook.
Code:
Sub Chart1Change()
Const OldData As String = "C6:N6"  '<<Change this Range
Const NewData As String = "C7:N7"  '<<Change this Range
Call AnimateChart(OldData, NewData)
End Sub

Function AnimateChart(OldDataSet As String, NewDataSet As String)
Dim NewData As Variant
Dim OldData As Variant
Dim AnimationArray As Variant
Dim OldPoint As Long
Dim NewPoint As Long
Dim x As Integer
Dim i As Integer
Dim p As Double

NewData = ActiveSheet.Range(NewDataSet).value
OldData = ActiveSheet.Range(OldDataSet).value
AnimationArray = ActiveSheet.Range(NewDataSet).value

For i = 1 To 15
    'Luke M, simplifying this line mathematically
    'p = 100 / 100 / 15 * i
    p = i / 15
    'Luke M, not counting numbers, counting # of data points
    For x = 1 To UBound(NewData)
        'Luke M, ignoring non-numbers
        If TypeName(OldData(1, x)) <> "String" Then
            OldPoint = OldData(1, x)
            NewPoint = NewData(1, x)
            AnimationArray(1, x) = OldPoint - (OldPoint - NewPoint) * p
        End If
    Next x
    Range(OldDataSet).value = AnimationArray
    DoEvents
Next i
End Function
 
O_O that is awesome... I did one change to try to make the animation like that of Datapig I converted I and P to double and made this
Code:
For i = 0.1 To 1
  'Luke M, simplifying this line mathematically
  'p = 100 / 100 / 15 * i
  p = i / 1
however it goes really fast so it basically looks the same as a normal combobox functionality so twiddling with I and P to figure it out but unsure if this is what I'm supposed to do - muddling around with code lol

P.S. also noticed something weird - it puts #N/A in Dec but probably to do with range I guess - so I extended it beyond last cell and it worked i.e. Jan to Dec is in C6:N6 so I changed range to C6:O6 and it fixed the issue
 
Last edited:
Ok. The greater therange in your For i = x...y step, the slower the process will go. Might be good to play around wiht it a bit.
 
Nevermind - The change does help incremental change but gives incorrect values

I figured out why it wasn't doing incremental change - I compared the Datapig code to your code and I removed
Code:
UBound (NewData)
and replaced it with
Code:
WorksheetFunction.Count(NewData)
and incremental change worked but the #N/A issue started where macro stops
 
Last edited:
Remember that these 2 numbers need to match
For i = 0.1 To 1 <--This number
p = i / 1 <-- must match this number

Also, I just remembered why you don't want to do i = 0.1 to 1. The default step of the For function is 1, so you will overshoot. Should probably change it back to
Code:
For i = 1 to 100
p = i / 100

Or, to show the correlation, could do
Code:
Const upLimit as Long = 100 'Change as desired to speed up/slow down
For i = 1 to upLimit
     p = i / upLimit
'....
 
Thanks Luke,

Tried Const upLimit - no speed change - I think my animated chart dream will remain a pipe dream lol but I did get to learn new stuff by looking at your code explanations :)
 
Back
Top