mirror of
https://github.com/oliexdev/openScale.git
synced 2025-08-29 11:10:35 +02:00
add an optional goal and linear regression weight line
This commit is contained in:
@@ -20,6 +20,7 @@ import android.content.Intent;
|
||||
import android.content.SharedPreferences;
|
||||
import android.content.res.ColorStateList;
|
||||
import android.graphics.Color;
|
||||
import android.graphics.DashPathEffect;
|
||||
import android.os.Bundle;
|
||||
import android.preference.PreferenceManager;
|
||||
import android.support.design.widget.FloatingActionButton;
|
||||
@@ -332,6 +333,137 @@ public class GraphFragment extends Fragment implements FragmentUpdateListener {
|
||||
enableMonth.setBackgroundTintList(ColorStateList.valueOf(Color.parseColor("#d3d3d3")));
|
||||
}
|
||||
|
||||
if (prefs.getBoolean("goalLine", true)) {
|
||||
Stack<PointValue> valuesGoalLine = new Stack<PointValue>();
|
||||
|
||||
float goalWeight = openScale.getSelectedScaleUser().goal_weight;
|
||||
|
||||
valuesGoalLine.push(new PointValue(0, goalWeight));
|
||||
valuesGoalLine.push(new PointValue(31, goalWeight));
|
||||
|
||||
Line goalLine = new Line(valuesGoalLine)
|
||||
.setHasPoints(false);
|
||||
|
||||
goalLine.setPathEffect(new DashPathEffect(new float[] {10,30}, 0));
|
||||
|
||||
lines.add(goalLine);
|
||||
}
|
||||
|
||||
if (prefs.getBoolean("regressionLine", true)) {
|
||||
|
||||
/*
|
||||
// quadratic regression y = ax^2 + bx + c
|
||||
double x_value = 0.0;
|
||||
double y_value = 0.0;
|
||||
|
||||
double s40 = 0; //sum of x^4
|
||||
double s30 = 0; //sum of x^3
|
||||
double s20 = 0; //sum of x^2
|
||||
double s10 = 0; //sum of x
|
||||
double s00 = scaleDataList.size();
|
||||
//sum of x^0 * y^0 ie 1 * number of entries
|
||||
|
||||
double s21 = 0; //sum of x^2*y
|
||||
double s11 = 0; //sum of x*y
|
||||
double s01 = 0; //sum of y
|
||||
|
||||
for(ScaleData scaleEntry: scaleDataList) {
|
||||
calDB.setTime(scaleEntry.getDateTime());
|
||||
|
||||
x_value = calDB.get(field);
|
||||
y_value = scaleEntry.getConvertedWeight(openScale.getSelectedScaleUser().scale_unit);
|
||||
|
||||
s40 += Math.pow(x_value, 4);
|
||||
s30 += Math.pow(x_value, 3);
|
||||
s20 += Math.pow(x_value, 2);
|
||||
s10 += x_value;
|
||||
|
||||
s21 += Math.pow(x_value, 2) * y_value;
|
||||
s11 += x_value * y_value;
|
||||
s01 += y_value;
|
||||
}
|
||||
|
||||
// solve equations using Cramer's law
|
||||
double a = (s21*(s20 * s00 - s10 * s10) -
|
||||
s11*(s30 * s00 - s10 * s20) +
|
||||
s01*(s30 * s10 - s20 * s20))
|
||||
/
|
||||
(s40*(s20 * s00 - s10 * s10) -
|
||||
s30*(s30 * s00 - s10 * s20) +
|
||||
s20*(s30 * s10 - s20 * s20));
|
||||
|
||||
double b = (s40*(s11 * s00 - s01 * s10) -
|
||||
s30*(s21 * s00 - s01 * s20) +
|
||||
s20*(s21 * s10 - s11 * s20))
|
||||
/
|
||||
(s40 * (s20 * s00 - s10 * s10) -
|
||||
s30 * (s30 * s00 - s10 * s20) +
|
||||
s20 * (s30 * s10 - s20 * s20));
|
||||
|
||||
double c = (s40*(s20 * s01 - s10 * s11) -
|
||||
s30*(s30 * s01 - s10 * s21) +
|
||||
s20*(s30 * s11 - s20 * s21))
|
||||
/
|
||||
(s40 * (s20 * s00 - s10 * s10) -
|
||||
s30 * (s30 * s00 - s10 * s20) +
|
||||
s20 * (s30 * s10 - s20 * s20));
|
||||
*/
|
||||
|
||||
// linear regression y = a + x*b
|
||||
double sumx = 0.0;
|
||||
double sumy = 0.0;
|
||||
|
||||
double x_value = 0.0;
|
||||
double y_value = 0.0;
|
||||
|
||||
for(ScaleData scaleEntry: scaleDataList) {
|
||||
calDB.setTime(scaleEntry.getDateTime());
|
||||
|
||||
x_value = calDB.get(field);
|
||||
y_value = scaleEntry.getConvertedWeight(openScale.getSelectedScaleUser().scale_unit);
|
||||
|
||||
sumx += x_value;
|
||||
sumy += y_value;
|
||||
}
|
||||
|
||||
double xbar = sumx / scaleDataList.size();
|
||||
double ybar = sumy / scaleDataList.size();
|
||||
|
||||
double xxbar = 0.0;
|
||||
double xybar = 0.0;
|
||||
|
||||
for(ScaleData scaleEntry: scaleDataList) {
|
||||
calDB.setTime(scaleEntry.getDateTime());
|
||||
|
||||
x_value = calDB.get(field);
|
||||
y_value = scaleEntry.getConvertedWeight(openScale.getSelectedScaleUser().scale_unit);
|
||||
|
||||
xxbar += (x_value - xbar) * (x_value - xbar);
|
||||
xybar += (y_value - xbar) * (y_value - ybar);
|
||||
}
|
||||
|
||||
double b = xybar / xxbar;
|
||||
double a = ybar - b * xbar;
|
||||
|
||||
|
||||
Stack<PointValue> valuesLinearRegression = new Stack<PointValue>();
|
||||
|
||||
for (int i = 0; i < 31; i++) {
|
||||
y_value = a + b * i; // linear regression
|
||||
//y_value = a * i*i + b * i + c; // quadratic regression
|
||||
|
||||
valuesLinearRegression.push(new PointValue((float) i, (float) y_value));
|
||||
}
|
||||
|
||||
Line linearRegressionLine = new Line(valuesLinearRegression)
|
||||
.setColor(ChartUtils.COLOR_VIOLET)
|
||||
.setHasPoints(false);
|
||||
|
||||
linearRegressionLine.setPathEffect(new DashPathEffect(new float[] {10,30}, 0));
|
||||
|
||||
lines.add(linearRegressionLine);
|
||||
}
|
||||
|
||||
LineChartData lineData = new LineChartData(lines);
|
||||
lineData.setAxisXBottom(new Axis(axisValues).
|
||||
setHasLines(true).
|
||||
|
@@ -150,6 +150,9 @@
|
||||
<string name="label_ignoreOutOfRange">Ignore data that are out of range</string>
|
||||
<string name="label_initial_weight">Initial weight</string>
|
||||
<string name="label_average_data">Calculate average per day/month</string>
|
||||
<string name="label_regression_line">Regression weight line</string>
|
||||
<string name="label_goal_line">Goal line</string>
|
||||
|
||||
|
||||
<string name="error_max_scale_users">Maximum number of concurrent scale users reached.</string>
|
||||
<string name="info_step_on_scale">Please step barefoot on the scale for reference measurements.</string>
|
||||
|
@@ -4,4 +4,5 @@
|
||||
<CheckBoxPreference android:title="@string/label_enable_points" android:summaryOn="@string/info_is_visible" android:summaryOff="@string/info_is_not_visible" android:key="pointsEnable" android:defaultValue="true"/>
|
||||
<CheckBoxPreference android:title="@string/label_delete_confirmation" android:summaryOn="@string/info_is_enable" android:summaryOff="@string/info_is_not_enable" android:key="deleteConfirmationEnable" android:defaultValue="true" />
|
||||
<CheckBoxPreference android:title="@string/label_average_data" android:summaryOn="@string/info_is_enable" android:summaryOff="@string/info_is_not_enable" android:key="averageData" android:defaultValue="true" />
|
||||
</PreferenceScreen>
|
||||
<CheckBoxPreference android:title="@string/label_goal_line" android:summaryOn="@string/info_is_visible" android:summaryOff="@string/info_is_not_visible" android:key="goalLine" android:defaultValue="true" />
|
||||
<CheckBoxPreference android:title="@string/label_regression_line" android:summaryOn="@string/info_is_visible" android:summaryOff="@string/info_is_not_visible" android:key="regressionLine" android:defaultValue="true" /></PreferenceScreen>
|
Reference in New Issue
Block a user