def make_three_color(data, time, step, config, shape=(1280, 1280), lower_val=(0, 0, 0), upper_val=(2.5, 2.5, 2.5)):
    """
    create a three color image according to the config file
    :param data: a dictionary of fetched data where keys correspond to products
    :param config: a config object
    :param shape: the size of a composite image
    :param lower_val: a tuple of lower values for RGB, any value below this is set to the low value
    :param upper_val: a tuple of upper values for RGB, any value above this is set to the high value
    :return: a (m,n,3) numpy array for a three color image where all values are between 0 and 1
    """
    order = {'red': 0, 'green': 1, 'blue': 2}

    three_color = np.zeros((shape[0], shape[1], 3))
    channel_colors = {color: config.default[color] for color in ['red', 'green', 'blue']}

    for color, channel in channel_colors.items():
        if data[channel][1] is None or \
                abs((time - date_parser.parse(data[channel][0]['date-end'])).total_seconds()) > step.total_seconds()/2.0:
            return np.zeros((shape[0], shape[1], 3))

        three_color[:, :, order[color]] = data[channel][1]

        # scale the image by the power
        three_color[:, :, order[color]] = np.power(three_color[:, :, order[color]],
                                                   config.default["{}_power".format(color)])

        # adjust the percentile thresholds
        lower = lower_val[order[color]]
        upper = upper_val[order[color]]
        three_color[np.where(three_color[:, :, order[color]] < lower)] = lower
        three_color[np.where(three_color[:, :, order[color]] > upper)] = upper

    # image values must be between (0,1) so scale image
    for color, index in order.items():
        three_color[:, :, index] /= upper_val[order[color]]
    return three_color