Repository: kivy/kivy

Issue:
interpolate example converges, but never reaches the end value
https://github.com/kivy/kivy/blob/master/kivy/utils.py#L49

```
 # use interpolate, and you'll have a nicer transition
self.pos = interpolate(self.pos, new_pos)
```

The example will never reach the end point. It only works when the step value is decreased, after every step.
## <bountysource-plugin>

Want to back this issue? **[Post a bounty on it!](https://www.bountysource.com/issues/7262426-interpolate-example-converges-but-never-reaches-the-end-value?utm_campaign=plugin&utm_content=tracker%2F42681&utm_medium=issues&utm_source=github)** We accept bounties via [Bountysource](https://www.bountysource.com/?utm_campaign=plugin&utm_content=tracker%2F42681&utm_medium=issues&utm_source=github).
</bountysource-plugin>



Discussion:
After writing the tests for this unit, I conclude that we must either clarify its intent or make it work differently. Now, I think it's behavior is correct because if you want to reach the end value, you use Animation. Interpolate might just a function that you use if you think you need some kind of progressive  slowing movement towards a endpoint, even though you never reach it.

@victor-rene Maybe it should be called [asymptote](http://en.wikipedia.org/wiki/Asymptote), but the comment `use interpolate, and you'll have a nicer transition` then definitely doesn't fit, because `transition` to me means, that the position actually reaches the new position, after `step` steps.

This issue has been automatically marked as stale because it has not had recent activity. It will be closed if no further activity occurs. Thank you for your contributions.

Let me restate the problem. I think it is worse than described above.

(Linear) interpolation is simple enough mathematical concept. You have two known points, (x1, y1) and (x2, y2) and you ask "If we drew a line between them, what would the value of y be at when x is set to a value between x1 and x2."

You can either express x as an absolute value (for which there is a standard formula), or you can assume x1=0 and x2=1, and express x as a float between 0 and 1 (for which there is a similar standard formula), or you can express x as a ratio by provided the total number of steps and the current step number, and convert that to a float. (This is useful when you have a known number of steps, but providing a float is more general.)

Interpolation also makes sense where x is replaced by time (what will be the value of y at a certain time). Interpolation also makes sense where y is replaced by a coordinate (a tuple).

The animation feature of Kivy offers a "linear" transition which uses linear interpolation, where one axis is time and the other is an screen coordinate.

So far, so good. But this is where I get a little harsh.

`kivy.utils` offers a function called `interpolate()` and the problem is... it is completely useless for performing interpolations!

It takes the two values of y (`value_from` and `value_to`), it assumes x1= 0 and x2 = 1, but rather than take x as a fraction, or taking two parameters, `step_no` and `total_steps`, it only takes one parameter (called `step` but effectively `total_steps`) and assumes `step_no` = 1.

You can find out where y would be when x=1/10. By changing the parameters, you could find out where y would be when x is 1/2, 1/3, 1/4 etc.

This is a blatant bug. The function is useless for its purpose.

What is worse is that it has a comment that overpromises what it can achieve:

         '''Interpolate between two values. This can be useful for smoothing some
         transitions. For example::

        # instead of setting directly
        self.pos = pos

        # use interpolate, and you'll have a nicer transition
        self.pos = interpolate(self.pos, new_pos)

Firstly, the first line is a single operation and it is done, where the second one needs to be scheduled to be repeated over and over again. There is already infrastructure to do this on the user's behalf: `animation`, and we should recommend that.

Secondly, because of the not-fit-for-purpose bug in the function signature, using this will not linearly move something towards its destination, but merely move it 10% of the remaining distance each time, so that, like Zeno's arrow, it never makes it.

To fix the function, we need to fix the signature, so it takes a fraction.

This is an API break - and a challenging one because some old code may not fail, just give bad answers. However, I don't feel bad because I can't believe the existing function is actually used as is by any substantial piece of software; it doesn't do anything useful. 

In fact, I think a much better suggestion is just to deprecate the whole thing and remove it as soon as we can. It isn't worth saving.











Resolving patch:
diff --git a/kivy/utils.py b/kivy/utils.py
--- a/kivy/utils.py
+++ b/kivy/utils.py
@@ -18,7 +18,8 @@
            'is_color_transparent', 'hex_colormap', 'colormap', 'boundary',
            'deprecated', 'SafeList',
            'interpolate', 'QueryDict',
-           'platform', 'escape_markup', 'reify', 'rgba', 'pi_version')
+           'platform', 'escape_markup', 'reify', 'rgba', 'pi_version',
+           'format_bytes_to_human')
 
 from os import environ, path
 from sys import platform as _sys_platform
@@ -41,29 +42,6 @@ def difference(set1, set2):
     return [s for s in set1 if s not in set2]
 
 
-def interpolate(value_from, value_to, step=10):
-    '''Interpolate between two values. This can be useful for smoothing some
-    transitions. For example::
-
-        # instead of setting directly
-        self.pos = pos
-
-        # use interpolate, and you'll have a nicer transition
-        self.pos = interpolate(self.pos, new_pos)
-
-    .. warning::
-        These interpolations work only on lists/tuples/doubles with the same
-        dimensions. No test is done to check the dimensions are the same.
-    '''
-    if type(value_from) in (list, tuple):
-        out = []
-        for x, y in zip(value_from, value_to):
-            out.append(interpolate(x, y, step))
-        return out
-    else:
-        return value_from + (value_to - value_from) / float(step)
-
-
 def strtotuple(s):
     '''Convert a tuple string into a tuple
     with some security checks. Designed to be used
@@ -354,6 +332,28 @@ def new_func(*args, **kwargs):
     return new_func
 
 
+@deprecated
+def interpolate(value_from, value_to, step=10):
+    '''Interpolate between two values, by providing the
+    reciprocal of the proportion between two points.
+
+    .. deprecated:: 2.3.0
+        For animations, consider using the
+        `AnimationTransition.linear()` for a similar purpose.
+
+    .. warning::
+        These interpolations work only on lists/tuples/doubles with the same
+        dimensions. No test is done to check the dimensions are the same.
+    '''
+    if type(value_from) in (list, tuple):
+        out = []
+        for x, y in zip(value_from, value_to):
+            out.append(interpolate(x, y, step))
+        return out
+    else:
+        return value_from + (value_to - value_from) / float(step)
+
+
 class SafeList(list):
     '''List with a clear() method.
 
@@ -393,7 +393,8 @@ def __getattr__(self, attr):
         try:
             return self.__getitem__(attr)
         except KeyError:
-            return super(QueryDict, self).__getattr__(attr)
+            raise AttributeError("%r object has no attribute %r" % (
+                self.__class__.__name__self, attr))
 
     def __setattr__(self, attr, value):
         self.__setitem__(attr, value)


Test patch:
diff --git a/kivy/tests/test_utils.py b/kivy/tests/test_utils.py
--- a/kivy/tests/test_utils.py
+++ b/kivy/tests/test_utils.py
@@ -5,10 +5,7 @@
 
 import os
 import unittest
-try:
-    from unittest.mock import patch   # python 3.x
-except:
-    from mock import patch   # python 2.x
+from unittest.mock import patch
 
 from kivy.utils import (boundary, escape_markup, format_bytes_to_human,
         is_color_transparent, SafeList, get_random_color, get_hex_from_color,