# Mapping a range of values to another

### Question

I am looking for ideas on how to translate one range values to another in Python. I am working on hardware project and am reading data from a sensor that can return a range of values, I am then using that data to drive an actuator that requires a different range of values.

For example lets say that the sensor returns values in the range 1 to 512, and the actuator is driven by values in the range 5 to 10. I would like a function that I can pass a value and the two ranges and get back the value mapped to the second range. If such a function was named `translate` it could be used like this:

``````sensor_value = 256
actuator_value = translate(sensor_value, 1, 512, 5, 10)
``````

In this example I would expect the output `actuator_value` to be `7.5` since the `sensor_value` is in the middle of the possible input range.

1
53
12/28/2009 3:53:11 PM

One solution would be:

``````def translate(value, leftMin, leftMax, rightMin, rightMax):
# Figure out how 'wide' each range is
leftSpan = leftMax - leftMin
rightSpan = rightMax - rightMin

# Convert the left range into a 0-1 range (float)
valueScaled = float(value - leftMin) / float(leftSpan)

# Convert the 0-1 range into a value in the right range.
return rightMin + (valueScaled * rightSpan)
``````

You could possibly use algebra to make it more efficient, at the expense of readability.

81
12/28/2009 12:40:36 PM

### Using scipy.interpolate.interp1d

You can also use `scipy.interpolate` package to do such conversions (if you don't mind dependency on SciPy):

``````>>> from scipy.interpolate import interp1d
>>> m = interp1d([1,512],[5,10])
>>> m(256)
array(7.4951076320939336)
``````

or to convert it back to normal float from 0-rank scipy array:

``````>>> float(m(256))
7.4951076320939336
``````

You can do also multiple conversions in one command easily:

``````>>> m([100,200,300])
array([ 5.96868885,  6.94716243,  7.92563601])
``````

As a bonus, you can do non-uniform mappings from one range to another, for intance if you want to map [1,128] to [1,10], [128,256] to [10,90] and [256,512] to [90,100] you can do it like this:

``````>>> m = interp1d([1,128,256,512],[1,10,90,100])
>>> float(m(400))
95.625
``````

`interp1d` creates piecewise linear interpolation objects (which are callable just like functions).

### Using numpy.interp

As noted by ~unutbu, `numpy.interp` is also an option (with less dependencies):

``````>>> from numpy import interp
>>> interp(256,[1,512],[5,10])
7.4951076320939336
``````