Add a weekly average graph.
This commit is contained in:
parent
5119550036
commit
75c49fe88f
@ -134,6 +134,13 @@ foreach my $row ( @filelines ) {
|
|||||||
$seen_days{$date}++;
|
$seen_days{$date}++;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
# Remove weeks for which there is less than a day of results in that week
|
||||||
|
# (In a full day, assuming a reading is taken every 15 minutes, there will be 96 readings)
|
||||||
|
foreach my $year ( sort keys %seen_weeks ) {
|
||||||
|
foreach my $week ( sort keys %{$seen_weeks{$year}} ) {
|
||||||
|
delete $seen_weeks{$year}{$week} if ( scalar $seen_weeks{$year}{$week} < 96 );
|
||||||
|
}
|
||||||
|
}
|
||||||
$total_day_graphs = scalar keys %seen_days;
|
$total_day_graphs = scalar keys %seen_days;
|
||||||
$total_week_graphs = scalar keys %seen_weeks;
|
$total_week_graphs = scalar keys %seen_weeks;
|
||||||
|
|
||||||
@ -157,7 +164,7 @@ foreach my $d ( sort keys %seen_days ) {
|
|||||||
push @sortedlines, qq($row);
|
push @sortedlines, qq($row);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
# @sortedlines = map { " $_" } @sortedlines; # indent data structure
|
@sortedlines = map { " $_" } @sortedlines; # indent data structure
|
||||||
push @data, join "\n", sort @sortedlines;
|
push @data, join "\n", sort @sortedlines;
|
||||||
push @data, qq(EOD);
|
push @data, qq(EOD);
|
||||||
}
|
}
|
||||||
@ -172,7 +179,7 @@ foreach my $row (@filelines) {
|
|||||||
push @sortedlines, qq($1$2);
|
push @sortedlines, qq($1$2);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
#@sortedlines = map { " $_" } @sortedlines; # indent data structure
|
@sortedlines = map { " $_" } @sortedlines; # indent data structure
|
||||||
push @data, join "\n", sort @sortedlines;
|
push @data, join "\n", sort @sortedlines;
|
||||||
push @data, qq(EOD);
|
push @data, qq(EOD);
|
||||||
|
|
||||||
@ -184,7 +191,7 @@ push @data, qq(
|
|||||||
foreach my $time ( sort keys %$intervals ) {
|
foreach my $time ( sort keys %$intervals ) {
|
||||||
push @sortedlines, qq("$time","$intervals->{$time}->{max}","$intervals->{$time}->{min}");
|
push @sortedlines, qq("$time","$intervals->{$time}->{max}","$intervals->{$time}->{min}");
|
||||||
}
|
}
|
||||||
#@sortedlines = map { " $_" } @sortedlines; # indent data structure
|
@sortedlines = map { " $_" } @sortedlines; # indent data structure
|
||||||
push @data, join "\n", sort @sortedlines;
|
push @data, join "\n", sort @sortedlines;
|
||||||
push @data, qq(EOD);
|
push @data, qq(EOD);
|
||||||
|
|
||||||
@ -193,14 +200,14 @@ push @data, qq(EOD);
|
|||||||
foreach my $year ( sort keys %seen_weeks ) {
|
foreach my $year ( sort keys %seen_weeks ) {
|
||||||
foreach my $week ( sort keys %{$seen_weeks{$year}} ) {
|
foreach my $week ( sort keys %{$seen_weeks{$year}} ) {
|
||||||
my $time = Time::Piece->strptime( $year, "%Y" );
|
my $time = Time::Piece->strptime( $year, "%Y" );
|
||||||
my $mon = $time + ( ONE_WEEK * ( $week - 1 ) );
|
my $mon = $time + ( ONE_WEEK * ( $week - 1 ) ) + ( ONE_DAY );
|
||||||
my $sun = $time + ( ONE_WEEK * ( $week - 1 ) ) + ( ONE_DAY * 6 );
|
my $sun = $time + ( ONE_WEEK * ( $week - 1 ) ) + ( ONE_DAY * 7 );
|
||||||
my $label = $mon->strftime("%Y%m%d");
|
my $label = $mon->strftime("%Y%m%d");
|
||||||
|
|
||||||
# Select data from the week in question
|
# Select data from the week in question
|
||||||
my @weeklines;
|
my @weeklines;
|
||||||
foreach my $row (@filelines) {
|
foreach my $row (@filelines) {
|
||||||
foreach my $dow ( 0 .. 7 ) {
|
foreach my $dow ( 1 .. 7 ) {
|
||||||
my $day = $mon + ( ONE_DAY * $dow );
|
my $day = $mon + ( ONE_DAY * $dow );
|
||||||
my $d = $day->strftime("%Y-%m-%d");
|
my $d = $day->strftime("%Y-%m-%d");
|
||||||
if ( $row =~ m#^"$d .*$#ms ) {
|
if ( $row =~ m#^"$d .*$#ms ) {
|
||||||
@ -209,20 +216,6 @@ foreach my $year ( sort keys %seen_weeks ) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
push @data, qq(
|
|
||||||
\$DataWeek$label << EOD
|
|
||||||
"timestamp","blood glucose","meal","method","comment");
|
|
||||||
@sortedlines = ();
|
|
||||||
foreach my $row (@weeklines) {
|
|
||||||
if ($row =~ m#^(")\d{4}-\d{2}-\d{2} (.*)$# ) {
|
|
||||||
push @sortedlines, qq($1$2);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
# @sortedlines = map { " $_" } @sortedlines; # indent data structure
|
|
||||||
push @data, join "\n", sort @sortedlines;
|
|
||||||
push @data, qq(EOD);
|
|
||||||
|
|
||||||
|
|
||||||
push @data, qq(
|
push @data, qq(
|
||||||
\$DataWeekAvg$label << EOD
|
\$DataWeekAvg$label << EOD
|
||||||
"timestamp","blood glucose","meal","method","comment");
|
"timestamp","blood glucose","meal","method","comment");
|
||||||
@ -233,19 +226,19 @@ foreach my $year ( sort keys %seen_weeks ) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
my $week_intervals = calculate_max_min( 'lines' => \@sortedlines, 'format' => '"%H:%M:%S"' );
|
my $week_intervals = calculate_max_min( 'lines' => \@sortedlines, 'format' => '"%H:%M:%S"' );
|
||||||
# @sortedlines = map { " $_" } @sortedlines; # indent data structure
|
@sortedlines = map { " $_" } @sortedlines; # indent data structure
|
||||||
push @data, join "\n", sort @sortedlines;
|
push @data, join "\n", sort @sortedlines;
|
||||||
push @data, qq(EOD);
|
push @data, qq(EOD);
|
||||||
|
|
||||||
|
|
||||||
push @data, qq(
|
push @data, qq(
|
||||||
\$DataMaxMin$label << EOD
|
\$DataWeekMaxMin$label << EOD
|
||||||
"timestamp","max","min");
|
"timestamp","max","min");
|
||||||
@sortedlines = ();
|
@sortedlines = ();
|
||||||
foreach my $time ( sort keys %{$week_intervals} ) {
|
foreach my $time ( sort keys %{$week_intervals} ) {
|
||||||
push @sortedlines, qq("$time","$intervals->{$time}->{max}","$intervals->{$time}->{min}");
|
push @sortedlines, qq("$time","$intervals->{$time}->{max}","$intervals->{$time}->{min}");
|
||||||
}
|
}
|
||||||
# @sortedlines = map { " $_" } @sortedlines; # indent data structure
|
@sortedlines = map { " $_" } @sortedlines; # indent data structure
|
||||||
push @data, sort @sortedlines;
|
push @data, sort @sortedlines;
|
||||||
push @data, qq(EOD);
|
push @data, qq(EOD);
|
||||||
}
|
}
|
||||||
@ -296,6 +289,7 @@ set samples 10000
|
|||||||
|
|
||||||
set xdata
|
set xdata
|
||||||
stats \$DataAvg using 2
|
stats \$DataAvg using 2
|
||||||
|
MedianTotal = STATS_median
|
||||||
MeanTotal = STATS_mean
|
MeanTotal = STATS_mean
|
||||||
|
|
||||||
set xdata time
|
set xdata time
|
||||||
@ -305,7 +299,18 @@ plot \$DataAvg using 1:2 smooth mcsplines
|
|||||||
unset table
|
unset table
|
||||||
|
|
||||||
set table \$SmoothDataAvg
|
set table \$SmoothDataAvg
|
||||||
|
# Use bezier smoothing
|
||||||
plot \$DataAvg using 1:2 smooth bezier
|
plot \$DataAvg using 1:2 smooth bezier
|
||||||
|
#
|
||||||
|
## Alternate: Try a five-point average using data_feedback.dem
|
||||||
|
## This is more responsive to outlier points than the bezier, so bezier serves our purposes better
|
||||||
|
#samples(x) = \$1 > 4 ? 5 : (\$1+1)
|
||||||
|
#avg5(x) = (shift5(x), (back1+back2+back3+back4+back5)/samples(\$1))
|
||||||
|
#shift5(x) = (back5 = back4, back4 = back3, back3 = back2, back2 = back1, back1 = x)
|
||||||
|
## Initialize a running sum
|
||||||
|
#init(x) = (back1 = back2 = back3 = back4 = back5 = sum = 0)
|
||||||
|
#plot sum = init(0), \$DataAvg using 1:(avg5(\$2)) every 2 smooth mcsplines, \$DataAvg using 1:2 smooth bezier
|
||||||
|
#
|
||||||
unset table
|
unset table
|
||||||
|
|
||||||
|
|
||||||
@ -316,7 +321,43 @@ unset table
|
|||||||
);
|
);
|
||||||
|
|
||||||
|
|
||||||
|
# Sample the average $interval values by week into a smoothed plot, and store each in a new table
|
||||||
|
foreach my $year ( sort keys %seen_weeks ) {
|
||||||
|
foreach my $week ( sort keys %{$seen_weeks{$year}} ) {
|
||||||
|
my $time = Time::Piece->strptime( "$year", "%Y" );
|
||||||
|
my $mon = $time + ( ONE_WEEK * ( $week - 1 ) ) + ( ONE_DAY );
|
||||||
|
my $label = $mon->strftime("%Y%m%d");
|
||||||
|
push @data, qq(
|
||||||
|
set datafile separator ","
|
||||||
|
|
||||||
|
set timefmt "%H:%M:%S"
|
||||||
|
set format x "%s" timedate
|
||||||
|
set format y "%.2f" numeric
|
||||||
|
set samples 10000
|
||||||
|
set xdata
|
||||||
|
print "DataWeekAvg$label"
|
||||||
|
stats \$DataWeekAvg$label using 2
|
||||||
|
MedianTotal$label = STATS_mean
|
||||||
|
MeanTotal$label = STATS_mean
|
||||||
|
|
||||||
|
set xdata time
|
||||||
|
|
||||||
|
set table \$DataWeekAvgTable$label
|
||||||
|
plot \$DataWeekAvg$label using 1:2 smooth mcsplines
|
||||||
|
unset table
|
||||||
|
|
||||||
|
set table \$SmoothDataWeekAvg$label
|
||||||
|
plot \$DataWeekAvg$label using 1:2 smooth bezier
|
||||||
|
unset table
|
||||||
|
|
||||||
|
# Convert DataWeekMaxMin from CSV to table
|
||||||
|
set table \$DataWeekMaxMinTable$label
|
||||||
|
plot \$DataWeekMaxMin$label using 1:2:3 with table
|
||||||
|
unset table
|
||||||
|
);
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
@ -338,7 +379,6 @@ unset table
|
|||||||
# and the new $SmoothData, which contains a table, needs a whitespace separator
|
# and the new $SmoothData, which contains a table, needs a whitespace separator
|
||||||
push @data, qq(
|
push @data, qq(
|
||||||
# ensure separator handles tables
|
# ensure separator handles tables
|
||||||
#reset
|
|
||||||
set datafile separator whitespace
|
set datafile separator whitespace
|
||||||
|
|
||||||
set key off
|
set key off
|
||||||
@ -384,7 +424,7 @@ set grid ytics ls 100 front
|
|||||||
set object 1 rect from graph 0, first $min_glucose to graph 1,first $max_glucose fc ls 6 fs solid 0.2 back
|
set object 1 rect from graph 0, first $min_glucose to graph 1,first $max_glucose fc ls 6 fs solid 0.2 back
|
||||||
|
|
||||||
AVG = Mean$label
|
AVG = Mean$label
|
||||||
AVG_LABEL = gprintf("Average glucose: %.2f", AVG)
|
AVG_LABEL = gprintf("Median glucose: %.2f", AVG)
|
||||||
set object 2 rect at graph 0.9, graph 0.9 fc ls 2 fs transparent solid 0.5 front size char strlen(AVG_LABEL), char 3
|
set object 2 rect at graph 0.9, graph 0.9 fc ls 2 fs transparent solid 0.5 front size char strlen(AVG_LABEL), char 3
|
||||||
set label 2 AVG_LABEL at graph 0.9, graph 0.9 front center
|
set label 2 AVG_LABEL at graph 0.9, graph 0.9 front center
|
||||||
|
|
||||||
@ -451,25 +491,25 @@ set grid ytics ls 100 front
|
|||||||
|
|
||||||
set object 1 rect from graph 0, first $min_glucose to graph 1,first $max_glucose fc ls 6 fs solid 0.05 back
|
set object 1 rect from graph 0, first $min_glucose to graph 1,first $max_glucose fc ls 6 fs solid 0.05 back
|
||||||
|
|
||||||
AVG = MeanTotal
|
AVG = MedianTotal
|
||||||
AVG_LABEL = gprintf("Average glucose: %.2f", AVG)
|
AVG_LABEL = gprintf("Median glucose: %.2f", AVG)
|
||||||
set object 2 rect at graph 0.9, graph 0.9 fc ls 2 fs transparent solid 0.5 front size char strlen(AVG_LABEL), char 3
|
set object 2 rect at graph 0.9, graph 0.9 fc ls 2 fs transparent solid 0.5 front size char strlen(AVG_LABEL), char 3
|
||||||
set label 2 AVG_LABEL at graph 0.9, graph 0.9 front center
|
set label 2 AVG_LABEL at graph 0.9, graph 0.9 front center
|
||||||
|
|
||||||
A1C = 0
|
A1C = 0
|
||||||
if (A1C == 0 && '$units' eq 'mg/dL') {
|
if (A1C == 0 && '$units' eq 'mg/dL') {
|
||||||
A1C = (MeanTotal + 46.7) / 28.7
|
A1C = (MedianTotal + 46.7) / 28.7
|
||||||
}
|
}
|
||||||
if (A1C == 0 && '$units' eq 'mmol/L') {
|
if (A1C == 0 && '$units' eq 'mmol/L') {
|
||||||
A1C = (MeanTotal + 2.59) / 1.59
|
A1C = (MedianTotal + 2.59) / 1.59
|
||||||
}
|
}
|
||||||
# mg/dL numbers tend to be higher than 35
|
# mg/dL numbers tend to be higher than 35
|
||||||
if (A1C == 0 && MeanTotal >= 35) {
|
if (A1C == 0 && MedianTotal >= 35) {
|
||||||
A1C = (MeanTotal + 46.7) / 28.7
|
A1C = (MedianTotal + 46.7) / 28.7
|
||||||
}
|
}
|
||||||
# mmol/L numbers tend to be lower than 35
|
# mmol/L numbers tend to be lower than 35
|
||||||
if (A1C == 0 && MeanTotal < 35) {
|
if (A1C == 0 && MedianTotal < 35) {
|
||||||
A1C = (MeanTotal + 2.59) / 1.59
|
A1C = (MedianTotal + 2.59) / 1.59
|
||||||
}
|
}
|
||||||
|
|
||||||
A1C_LABEL = gprintf("Average A1c: %.1f", A1C)
|
A1C_LABEL = gprintf("Average A1c: %.1f", A1C)
|
||||||
@ -494,45 +534,8 @@ plot 1/0
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
# Plot and display a graph with the average glucose values for every $interval for recorded days in a given week
|
||||||
|
|
||||||
=cut
|
|
||||||
|
|
||||||
foreach my $year ( sort keys %seen_weeks ) {
|
|
||||||
foreach my $week ( sort keys %{$seen_weeks{$year}} ) {
|
|
||||||
my $time = Time::Piece->strptime( "$year", "%Y" );
|
|
||||||
my $mon = $time + ( ONE_WEEK * ( $week - 1 ) );
|
|
||||||
my $sun = $time + ( ONE_WEEK * ( $week - 1 ) ) + ( ONE_DAY * 6 );
|
|
||||||
my $label = $mon->strftime("%Y-%m-%d");
|
|
||||||
my $title = $mon->strftime("%Y-%m-%d") . " to " . $sun->strftime("%Y-%m-%d");
|
|
||||||
push @data, qq(
|
push @data, qq(
|
||||||
#reset
|
|
||||||
set datafile separator ","
|
|
||||||
|
|
||||||
set timefmt "%H:%M:%S"
|
|
||||||
set format x "%s" timedate
|
|
||||||
set format y "%.2f" numeric
|
|
||||||
set samples 10000
|
|
||||||
set xdata
|
|
||||||
stats \$DataAvg using 2
|
|
||||||
MeanTotal = STATS_mean
|
|
||||||
|
|
||||||
set xdata time
|
|
||||||
|
|
||||||
set table \$DataAvgTable
|
|
||||||
plot \$DataAvg using 1:2 smooth mcsplines
|
|
||||||
unset table
|
|
||||||
|
|
||||||
set table \$SmoothDataAvg
|
|
||||||
plot \$DataAvg using 1:2 smooth bezier
|
|
||||||
unset table
|
|
||||||
|
|
||||||
# Convert DataMaxMin from CSV to table
|
|
||||||
set table \$DataMaxMinTable
|
|
||||||
plot \$DataMaxMin using 1:2:3 with table
|
|
||||||
unset table
|
|
||||||
|
|
||||||
reset
|
|
||||||
set datafile separator whitespace
|
set datafile separator whitespace
|
||||||
|
|
||||||
set key off
|
set key off
|
||||||
@ -557,7 +560,15 @@ set tmargin 5
|
|||||||
set bmargin 5
|
set bmargin 5
|
||||||
|
|
||||||
set multiplot title layout $graphs_per_page,1
|
set multiplot title layout $graphs_per_page,1
|
||||||
|
);
|
||||||
|
foreach my $year ( sort keys %seen_weeks ) {
|
||||||
|
foreach my $week ( sort keys %{$seen_weeks{$year}} ) {
|
||||||
|
my $time = Time::Piece->strptime( "$year", "%Y" );
|
||||||
|
my $mon = $time + ( ONE_WEEK * ( $week - 1 ) ) + ( ONE_DAY );
|
||||||
|
my $sun = $time + ( ONE_WEEK * ( $week - 1 ) ) + ( ONE_DAY * 7 );
|
||||||
|
my $title = $mon->strftime("%A, %d %B %Y") . " to " . $sun->strftime("%A, %d %B %Y");
|
||||||
|
my $label = $mon->strftime("%Y%m%d");
|
||||||
|
push @data, qq(
|
||||||
set title "Average Daily Glucose from $title" font "Calibri,18"
|
set title "Average Daily Glucose from $title" font "Calibri,18"
|
||||||
set xlabel "Time" offset 0,-0.25
|
set xlabel "Time" offset 0,-0.25
|
||||||
set ylabel "Blood glucose"
|
set ylabel "Blood glucose"
|
||||||
@ -567,32 +578,32 @@ set grid ytics ls 100 front
|
|||||||
|
|
||||||
set object 1 rect from graph 0, first $min_glucose to graph 1,first $max_glucose fc ls 6 fs solid 0.05 back
|
set object 1 rect from graph 0, first $min_glucose to graph 1,first $max_glucose fc ls 6 fs solid 0.05 back
|
||||||
|
|
||||||
AVG = MeanTotal
|
AVG = MedianTotal$label
|
||||||
AVG_LABEL = gprintf("Average glucose: %.2f", AVG)
|
AVG_LABEL = gprintf("Median glucose: %.2f", AVG)
|
||||||
set object 2 rect at graph 0.9, graph 0.9 fc ls 2 fs transparent solid 0.5 front size char strlen(AVG_LABEL), char 3
|
set object 2 rect at graph 0.9, graph 0.9 fc ls 2 fs transparent solid 0.5 front size char strlen(AVG_LABEL), char 3
|
||||||
set label 2 AVG_LABEL at graph 0.9, graph 0.9 front center
|
set label 2 AVG_LABEL at graph 0.9, graph 0.9 front center
|
||||||
|
|
||||||
A1C = 0
|
A1C = 0
|
||||||
if (A1C == 0 && '$units' eq 'mg/dL') {
|
if (A1C == 0 && '$units' eq 'mg/dL') {
|
||||||
A1C = (MeanTotal + 46.7) / 28.7
|
A1C = (MedianTotal$label + 46.7) / 28.7
|
||||||
}
|
}
|
||||||
if (A1C == 0 && '$units' eq 'mmol/L') {
|
if (A1C == 0 && '$units' eq 'mmol/L') {
|
||||||
A1C = (MeanTotal + 2.59) / 1.59
|
A1C = (MedianTotal$label + 2.59) / 1.59
|
||||||
}
|
}
|
||||||
# mg/dL numbers tend to be higher than 35
|
# mg/dL numbers tend to be higher than 35
|
||||||
if (A1C == 0 && MeanTotal >= 35) {
|
if (A1C == 0 && MedianTotal$label >= 35) {
|
||||||
A1C = (MeanTotal + 46.7) / 28.7
|
A1C = (MedianTotal$label + 46.7) / 28.7
|
||||||
}
|
}
|
||||||
# mmol/L numbers tend to be lower than 35
|
# mmol/L numbers tend to be lower than 35
|
||||||
if (A1C == 0 && MeanTotal < 35) {
|
if (A1C == 0 && MedianTotal$label < 35) {
|
||||||
A1C = (MeanTotal + 2.59) / 1.59
|
A1C = (MedianTotal$label + 2.59) / 1.59
|
||||||
}
|
}
|
||||||
|
|
||||||
A1C_LABEL = gprintf("Average A1c: %.1f", A1C)
|
A1C_LABEL = gprintf("Average A1c: %.1f", A1C)
|
||||||
set object 3 rect at graph 0.07, graph 0.9 fc ls 4 fs transparent solid 0.5 front size char strlen(A1C_LABEL), char 3
|
set object 3 rect at graph 0.07, graph 0.9 fc ls 4 fs transparent solid 0.5 front size char strlen(A1C_LABEL), char 3
|
||||||
set label 3 A1C_LABEL at graph 0.07, graph 0.9 front center
|
set label 3 A1C_LABEL at graph 0.07, graph 0.9 front center
|
||||||
|
|
||||||
plot \$DataMaxMinTable using (strftime("%H:%M:%S", \$1)):2:3 with filledcurves lc 111, \$SmoothDataAvg using (strftime("%H:%M:%S", \$1)):2:( \$2 > $max_glucose || \$2 < $min_glucose ? 110 : 1 ) with lines lw 3 lc variable
|
plot \$DataWeekMaxMinTable$label using (strftime("%H:%M:%S", \$1)):2:3 with filledcurves lc 111, \$SmoothDataWeekAvg$label using (strftime("%H:%M:%S", \$1)):2:( \$2 > $max_glucose || \$2 < $min_glucose ? 110 : 1 ) with lines lw 3 lc variable
|
||||||
|
|
||||||
# Add an x grid
|
# Add an x grid
|
||||||
set multiplot previous
|
set multiplot previous
|
||||||
@ -614,7 +625,6 @@ plot 1/0
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
=cut
|
|
||||||
|
|
||||||
push @data, qq(
|
push @data, qq(
|
||||||
unset multiplot
|
unset multiplot
|
||||||
|
Loading…
Reference in New Issue
Block a user