def rescale(values, out_range = (0., 1.), in_range = None, clamp = False,
        scale = None):
    """Rescales a list of numbers into a given range.

    `out_range` gives the range of the output values; by default, the minimum
    of the original numbers in the list will be mapped to the first element
    in the output range and the maximum will be mapped to the second element.
    Elements between the minimum and maximum values in the input list will be
    interpolated linearly between the first and second values of the output
    range.

    `in_range` may be used to override which numbers are mapped to the first
    and second values of the output range. This must also be a tuple, where
    the first element will be mapped to the first element of the output range
    and the second element to the second.

    If `clamp` is ``True``, elements which are outside the given `out_range`
    after rescaling are clamped to the output range to ensure that no number
    will be outside `out_range` in the result.

    If `scale` is not ``None``, it will be called for every element of `values`
    and the rescaling will take place on the results instead. This can be used,
    for instance, to transform the logarithm of the original values instead of
    the actual values. A typical use-case is to map a range of values to color
    identifiers on a logarithmic scale. Scaling also applies to the `in_range`
    parameter if present.

    Examples:

        >>> rescale(list(range(5)), (0, 8))
        [0.0, 2.0, 4.0, 6.0, 8.0]
        >>> rescale(list(range(5)), (2, 10))
        [2.0, 4.0, 6.0, 8.0, 10.0]
        >>> rescale(list(range(5)), (0, 4), (1, 3))
        [-2.0, 0.0, 2.0, 4.0, 6.0]
        >>> rescale(list(range(5)), (0, 4), (1, 3), clamp=True)
        [0.0, 0.0, 2.0, 4.0, 4.0]
        >>> rescale([0]*5, (1, 3))
        [2.0, 2.0, 2.0, 2.0, 2.0]
        >>> from math import log10
        >>> rescale([1, 10, 100, 1000, 10000], (0, 8), scale=log10)
        [0.0, 2.0, 4.0, 6.0, 8.0]
        >>> rescale([1, 10, 100, 1000, 10000], (0, 4), (10, 1000), scale=log10)
        [-2.0, 0.0, 2.0, 4.0, 6.0]
    """
    if scale is not None:
        values = [scale(value) for value in values]

    if in_range is None:
        mi, ma = min(values), max(values)
    else:
        mi, ma = in_range
        if scale is not None:
            mi, ma = scale(mi), scale(ma)

    ratio = float(ma - mi)
    if not ratio:
        return [(out_range[0] + out_range[1]) / 2.] * len(values)

    min_out, max_out = list(map(float, out_range))
    ratio = (max_out - min_out) / ratio
    result = [(x - mi) * ratio + min_out for x in values]

    if clamp:
        return [max(min(x, max_out), min_out) for x in result]
    else:
        return result