mirror of
https://github.com/oliexdev/openScale.git
synced 2025-08-30 03:30:30 +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.SharedPreferences;
|
||||||
import android.content.res.ColorStateList;
|
import android.content.res.ColorStateList;
|
||||||
import android.graphics.Color;
|
import android.graphics.Color;
|
||||||
|
import android.graphics.DashPathEffect;
|
||||||
import android.os.Bundle;
|
import android.os.Bundle;
|
||||||
import android.preference.PreferenceManager;
|
import android.preference.PreferenceManager;
|
||||||
import android.support.design.widget.FloatingActionButton;
|
import android.support.design.widget.FloatingActionButton;
|
||||||
@@ -332,6 +333,137 @@ public class GraphFragment extends Fragment implements FragmentUpdateListener {
|
|||||||
enableMonth.setBackgroundTintList(ColorStateList.valueOf(Color.parseColor("#d3d3d3")));
|
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);
|
LineChartData lineData = new LineChartData(lines);
|
||||||
lineData.setAxisXBottom(new Axis(axisValues).
|
lineData.setAxisXBottom(new Axis(axisValues).
|
||||||
setHasLines(true).
|
setHasLines(true).
|
||||||
|
@@ -150,6 +150,9 @@
|
|||||||
<string name="label_ignoreOutOfRange">Ignore data that are out of range</string>
|
<string name="label_ignoreOutOfRange">Ignore data that are out of range</string>
|
||||||
<string name="label_initial_weight">Initial weight</string>
|
<string name="label_initial_weight">Initial weight</string>
|
||||||
<string name="label_average_data">Calculate average per day/month</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="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>
|
<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_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_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" />
|
<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