diff --git a/infrastructure_planning/macros.py b/infrastructure_planning/macros.py index 82fb980..a1eca5b 100644 --- a/infrastructure_planning/macros.py +++ b/infrastructure_planning/macros.py @@ -255,22 +255,32 @@ def get_table_from_variables(ls, g, keys): return DataFrame(rows, columns=keys).set_index('name') -def interpolate_values(source_table, target_column, target_value): +def interpolate_values(source_table, source_column, target_value): t = source_table - assert len(t) > 0 - assert len(t) == len(set(t[target_column])) - # Get indices of two rows nearest to target value - difference = t[target_column] - target_value - sorted_indices = difference.abs().argsort() - index0 = sorted_indices[0] - index1 = sorted_indices[1] if len(sorted_indices) > 1 else index0 - # Compute fraction of difference in target column + source_values = t[source_column] + minimum_source_value = source_values.min() + maximum_source_value = source_values.max() + message_template = 'source_column (%s) values must be %%s' % source_column + assert len(t) > 0, 'table must have at least one row' + assert len(t) == len(set(source_values)), message_template % 'unique' + assert minimum_source_value >= 0, message_template % 'positive' + if len(t) == 1: + return t.ix[t.index[0]] + if target_value <= minimum_source_value: + return t.ix[source_values.argmin()] + if target_value >= maximum_source_value: + return t.ix[source_values.argmax()] + # Get two rows nearest to target value + sorted_indices = (source_values - target_value).abs().argsort() + row0 = t.ix[sorted_indices[0]] + row1 = t.ix[sorted_indices[1]] + # Compute fraction of interpolation fraction = divide_safely( - t[target_column].ix[index0], - t[target_column].ix[index1], - ExpectedPositive(target_column)) + target_value - row0[source_column], + row1[source_column] - row0[source_column], + ExpectedPositive(message_template % 'unique and positive')) # Interpolate - return t.ix[index0] + (t.ix[index1] - t.ix[index0]) * fraction + return row0 + (row1 - row0) * fraction def rename_keys(value_by_key, prefix='', suffix=''): diff --git a/missions/ProductionCountdown-20161212.md b/missions/ProductionCountdown-20161212.md index 55447b2..59ee0fa 100644 --- a/missions/ProductionCountdown-20161212.md +++ b/missions/ProductionCountdown-20161212.md @@ -21,7 +21,8 @@ It is important to keep the project alive while it still has users. # Objectives 1. Sort goals. -2. Update model. +2. Fix bugs. +3. Update model. # Log @@ -30,10 +31,16 @@ It is important to keep the project alive while it still has users. _ Rename standard_output.log to stdout.log _ Rename standard_error.log to stderr.log _ Get default parameters for tanzania training + + Check that everything still works -# Tasks +20161212-1100 - 20161212-1200: 1 hour + +I found a serious bug in the way that values are being interpolated in `interpolate_values`. Use parameters from minimum capacity if actual is less than minimum + +# Tasks + Consider total population and % connected to compute unconnected household count Grow population using total population Size capacity using unconnected household count diff --git a/tests/test_macros.py b/tests/test_macros.py new file mode 100644 index 0000000..8a3997b --- /dev/null +++ b/tests/test_macros.py @@ -0,0 +1,25 @@ +import pytest +from infrastructure_planning.macros import interpolate_values +from pandas import DataFrame + + +SOURCE_TABLE = DataFrame([ + [2, 200], + [6, 600], +], columns=[ + 'x', 'y', +]) + + +@pytest.mark.parametrize('x, y', [ + (0, 200), + (1, 200), + (2, 200), + (3, 300), + (4, 400), + (5, 500), + (6, 600), + (7, 600), +]) +def test_interpolate_values(x, y): + assert interpolate_values(SOURCE_TABLE, 'x', x)['y'] == y