(data, months, trend_rollup)
return data_by_month, min_val, max_val
Transform input data into (x,y) values aggregated over each day of the month

    :param data: a SortedDict mapping from timestamp -> value
    :param months: a list of (mstart, mend) tuples for grouping the output data
    :param trend_rollup: a function accepting a list of data points to aggregate data per-day;
        this function should return a tuple q1, q2, q3, where the points defined by the q2's describe the
        solid line of the trend plot, and points in the range [q1, q3] are filled in on the trend plot.
        (many trend_rollups will want to return the mean and interquartile range, hence the variable names; however,
        this interpretation is not required)
    :returns: a dict of month -> [<day-of-month>, <lower-range>, <aggregated-value>, <upper-range>] lists,
        as well as the min/max aggregated values for the trend rollup
        (the min/max values sets the range for the trend plot)
Transform input data into (x,y) values aggregated over each day of the month
Transform input data into ( x y ) values aggregated over each day of the month
def transform_trend_data(data, months, trend_rollup):
    """ Transform input data into (x,y) values aggregated over each day of the month

    :param data: a SortedDict mapping from timestamp -> value
    :param months: a list of (mstart, mend) tuples for grouping the output data
    :param trend_rollup: a function accepting a list of data points to aggregate data per-day;
        this function should return a tuple q1, q2, q3, where the points defined by the q2's describe the
        solid line of the trend plot, and points in the range [q1, q3] are filled in on the trend plot.
        (many trend_rollups will want to return the mean and interquartile range, hence the variable names; however,
        this interpretation is not required)
    :returns: a dict of month -> [<day-of-month>, <lower-range>, <aggregated-value>, <upper-range>] lists,
        as well as the min/max aggregated values for the trend rollup
        (the min/max values sets the range for the trend plot)
    """
    data_by_month = {}
    min_val, max_val = (
        0,
        0,
    )  # min_val sets the minimum y-value of the plot axis, which should always be 0 or less
    for mstart, mend in months:
        aggregated_daily_data = []

        # For each day in the month aggregate the data according to the chosen method
        for dstart, dend in arrow.Arrow.span_range("day", mstart, mend):
            dstart_index = data.bisect_left(dstart)
            dend_index = data.bisect_right(dend)
            day_slice = data.values()[dstart_index:dend_index]
            if not day_slice:  # if there's no data for a given day, np.percentile will fail
                continue

            q1, q2, q3 = trend_rollup(day_slice)
            min_val = min(v for v in (min_val, q1, q2, q3) if v is not None)
            max_val = max(v for v in (max_val, q2, q2, q3) if v is not None)
            aggregated_daily_data.append((dstart.day, q1, q2, q3))

        data_by_month[mstart] = zip(*aggregated_daily_data)
    return data_by_month, min_val, max_val
def transform_trend_data ( data , months , trend_rollup ) : data_by_month = { } min_val , max_val = ( 0 , 0 , ) # min_val sets the minimum y-value of the plot axis, which should always be 0 or less for mstart , mend in months : aggregated_daily_data = [ ] # For each day in the month aggregate the data according to the chosen method for dstart , dend in arrow . Arrow . span_range ( "day" , mstart , mend ) : dstart_index = data . bisect_left ( dstart ) dend_index = data . bisect_right ( dend ) day_slice = data . values ( ) [ dstart_index : dend_index ] if not day_slice : # if there's no data for a given day, np.percentile will fail continue q1 , q2 , q3 = trend_rollup ( day_slice ) min_val = min ( v for v in ( min_val , q1 , q2 , q3 ) if v is not None ) max_val = max ( v for v in ( max_val , q2 , q2 , q3 ) if v is not None ) aggregated_daily_data . append ( ( dstart . day , q1 , q2 , q3 ) ) data_by_month [ mstart ] = zip ( * aggregated_daily_data ) return data_by_month , min_val , max_val