2

I've found this script for linear interpolation in Python on Stack Overflow. It works perfectly well in Python 2.7, but fails in newer versions.

Here is the code:

from bisect import bisect_left

class Interpolate(object):
    def __init__(self, x_list, y_list):
        if any(y - x <= 0 for x, y in zip(x_list, x_list[1:])):
            raise ValueError("x_list must be in strictly ascending order!")
        x_list = self.x_list = map(float, x_list)
        y_list = self.y_list = map(float, y_list)
        intervals = zip(x_list, x_list[1:], y_list, y_list[1:])
        self.slopes = [(y2 - y1)/(x2 - x1) for x1, x2, y1, y2 in intervals]

    def __getitem__(self, x):
        i = bisect_left(self.x_list, x) - 1
        return self.y_list[i] + self.slopes[i] * (x - self.x_list[i])

i = Interpolate ([0,2,3], [9,5,8])
y = i[1]

This is the error I’m getting:

TypeError: 'Interpolate' object does not support indexing.

What has been changed that means the code won’t work anymore?

alexwlchan
  • 5,699
  • 7
  • 38
  • 49
FilthyL
  • 29
  • 1
  • What version of Python are you running with? I get a slightly different error with Python 3.4.1: on line `intervals = zip(x_list, x_list[1:], y_list, y_list[1:])`, I have `TypeError: 'map' object is not subscriptable`. // Oh wait, I see. – alexwlchan Apr 10 '15 at 10:02
  • I'm running Python 2.7.9. Checking it on 3.4.3 right now. – FilthyL Apr 10 '15 at 10:06
  • 2
    lattest time I had to do an interpolation, I used the library SciPy, which has nicely already made the function for me (aimed at scientists and numerical computing so it is bug free and efficient). https://docs.scipy.org/doc/scipy-0.15.1/reference/interpolate.html – Stephane Rolland Apr 10 '15 at 10:07
  • 2
    Where did you find that code? – user Apr 10 '15 at 10:13
  • 3
    I cannot repeat the exact error code, please edit the question so that it contains the exact error and code that reproduces the error in question – Antti Haapala -- Слава Україні Apr 10 '15 at 10:19
  • I've already posted the exact error, I dont not get any other... – FilthyL Apr 10 '15 at 10:21
  • The SciPy is not always available – FilthyL Apr 10 '15 at 10:28
  • 3
    You should include a reference to the question or author when you post code written by someone else: in this case [the original code by Lauritz V. Thaulow is an answer to this question](http://stackoverflow.com/questions/7343697/linear-interpolation-python) – LinkBerest Apr 10 '15 at 18:24

1 Answers1

3

This is a change to the map() function in Python 3. In Python 2.x, it would return a list, but now it returns an iterator.

Quoting from What’s New in Python 3:

map() and filter() return iterators. If you really need a list, a quick fix is e.g. list(map(...)), but a better fix is often to use a list comprehension (especially when the original code uses lambda), or rewriting the code so it doesn’t need a list at all. Particularly tricky is map() invoked for the side effects of the function; the correct transformation is to use a regular for loop (since creating a list would just be wasteful).

So the problem is occurring on these two lines:

x_list = self.x_list = map(float, x_list)
y_list = self.y_list = map(float, y_list)
intervals = zip(x_list, x_list[1:], y_list, y_list[1:])

When you try to subscript x_list and y_list when creating intervals (this is the [1:] slice), it fails because you can’t subscript an iterator.

One fix is to replace the x_list and y_list lines with these list comprehensions:

x_list = self.x_list = [float(x) for x in x_list]
y_list = self.y_list = [float(y) for y in y_list]

Not only will this allow subscripting (and so the code works as you expect), but this will still work on old versions of Python and I think it’s clearer what’s going on.

alexwlchan
  • 5,699
  • 7
  • 38
  • 49
  • 1
    An alternative fix is to explicitly transform the maps to lists; `list(map(float, x_list))`. Readability arguments could be made for either case. – Joost Apr 10 '15 at 10:06
  • I've tried using the fix like you told on both 2.7.9 and 3.4.3, alexwlchan, but it didnt help. It still works on 2.7 tho – FilthyL Apr 10 '15 at 10:18
  • @FilthyL Hmm. I’m using 2.7.6 and 3.4.1, and the code works fine. Could you post the entire traceback of the error? It’s possible I’m looking in the wrong place. – alexwlchan Apr 10 '15 at 10:20
  • File "", line 1 in y=i[1] TypeError: 'Interpolate' object does not support indexing – FilthyL Apr 10 '15 at 10:25
  • Looks like the pc is the problem, checked it on another one, works! Thanks a lot ! – FilthyL Apr 10 '15 at 10:31