[[https://melpa.org/#/metrics-tracker][file:https://melpa.org/packages/metrics-tracker-badge.svg]] [[https://www.gnu.org/licenses/gpl-3.0.txt][file:https://img.shields.io/badge/license-GPL_3-green.svg]]
metrics tracker
overview
[[http://www.gnu.org/software/emacs/][emacs]] is a text editor. an extensible one. it is mainly used for coding, but it can also do anything else. emacs includes a diary which you can use to keep track of which things you do on which days.
with [[https://github.com/ianxm/emacs-tracker][metrics-tracker]], emacs can generate tables and graphs from the personal metrics data found in your diary entries.
using metrics-tracker, you can use your emacs diary to track daily personal metrics. each metric is a count of something per day. the point is to measure behaviors that you would like to increase (like exercise) or decrease (like watching buffy the vampire slayer) so that you can see if you are making progress toward that goal.
in addition to the metrics you enter, metrics-tracker can compute metrics derived from your base metrics or other derived metrics using arbitrary mathematical expressions.
each of these screenshots is described in the gallery section later in this document.
[[https://ianxm-githubfiles.s3.amazonaws.com/emacs-tracker/animation_v3.gif]]
this is a port of [[https://github.com/ianxm/tracker][tracker]].
installation
** melpa
** manual install
usage ** entering metrics data
metrics entries are regular emacs diary entries so they can be created by updating the [[https://www.gnu.org/software/emacs/manual/html_node/emacs/Diary.html][emacs diary]] in the normal way, but diary entries that aren't in a certain format will be ignored by metrics-tracker. metric-tracker reads diary entries from the file pointed to by the ~diary-file~ variable.
tip: consider using abbrev mode in diary mode and setting abbreviations for your metrics to save yourself a few keystrokes.
*** diary entry format
emacs is very loose on [[https://www.gnu.org/software/emacs/manual/html_node/emacs/Format-of-Diary-File.html#Format-of-Diary-File][diary entry formatting]], but entries that
metrics-tracker uses must look like:
[date] [time] [metric-name] [value]
where,
- date :: the date of a particular day. although the emacs diary
allows dates like "wednesday," which apply to all wednesdays,
metrics-tracker only uses dates for specific days. emacs' date
handling is [[https://www.gnu.org/software/emacs/manual/html_node/emacs/Date-Formats.html#Date-Formats][flexible]]. some examples of valid dates are:
- ~2019-12-31~
- ~31 Dec 2019~
- ~December 31, 2019~
- ~31/Dec/2019~
- time :: the time of day is optional and ignored by
metrics-tracker if it is provided. if provided, it must be
formatted as:
- ~10:30~
- ~10:30a~
- ~10:30 a~
- ~10:30:10 am~
- metric-name :: is any string. it can be as long as you like and
can include spaces but keeping them short helps with
readability. valid values may look like:
- ~pushups~
- ~watched tv~
- value :: is a number (integer or decimal) or a duration
(hh:mm:ss.ss). for number values, metrics-tracker doesn't care
about units. ~value~ is just a number. if you're tracking how
much tv you watch, a "4" could mean 4 shows or 4 hours; it's up
to you. do not include commas. for duration values, hours and
fractional seconds are optional. metrics-tracker converts
durations to decimal hours. valid values may be:
- ~40~
- ~1.2~
- ~10:21.21~
- ~3:00:10~
here is an example diary file where all entries are valid metrics.
there's no advantage to mixing date formats. the example does it
for demonstration purposes.
2019-12-29 beer 1 2019-12-31 coding emacs-tracker 1 2019-12-31 wine 2 2020-01-02 bike commute 11 January 1, 2020 7:10 pm beer 1 04/Jan/2020 coding emacs-scrum 2 4 Jan 2020 coding emacs-scrum 2 Jan 4, 2020 run time 18 Jan 4, 2020 run dist 2 04/Jan/2020 10:00pm beer 1
*** whitelist / blacklist
by default metrics-tracker will pick up any diary entries that match
the format it is looking for, which means it might pick up entries
you don't want in your report. if there are a few metrics that
get picked up that you don't want to see, you can exclude them by
adding them to ~metrics-tracker-metric-names-blacklist~. this custom
variable takes a list of metric names as a list of strings, such
as:
'("run time" "run dist")
if metrics-tracker picks up lots of metrics that you don't want to see,
you could instead whitelist the ones you want by adding them to
the ~metrics-tracker-metric-names-whitelist~ custom variable. this uses
the same format as ~metrics-tracker-metric-names-blacklist~. if you
specify a whitelist, only those are considered and the blacklist
is ignored.
** reporting
metrics-tracker provides several ways to extract information from the metrics data in your diary.
*** standard options
reports are configured with several options.
**** metric name
metric name tells metric-tracker the name of the metric or
metrics to include in the current report. ~cal~ reports can only
use one metric, but ~table~ and ~graph~ reports can combine
multiple.
**** date grouping
date grouping tells metrics-tracker how many days to clump
together. in a graph, this is the x axis.
possible choices:
- day
- week
- month
- year
- full
**** value transform
the value transform tells metrics-tracker what the value at each
date grouping should mean. this controls how entries within
each date grouping are combined and transformed.
possible choices:
- total :: sum all of the values in the date grouping
- count :: count entries in the date grouping
- accum :: accumulate entries
- accum-count :: accumulate entry counts
- min :: the minimum of all values in a date grouping
- max :: the maximum of all values in a date grouping
- avg :: the average of all values in a date grouping
- percent :: percent of days within the date grouping with an entry
- per-day :: the average value for each day in the date grouping
- per-week :: the average value for each week in the date grouping
- per-month :: the average value for each month in the date grouping
- per-year :: the average value for each year in the date grouping
- diff-total :: the difference of ~total~ from one date grouping to the next
- diff-count :: the difference of ~count~ from one date grouping to the next
- diff-min :: the difference of ~min~ from one date grouping to the next
- diff-max :: the difference of ~max~ from one date grouping to the next
- diff-avg :: the difference of ~avg~ from one date grouping to the next
- diff-percent :: the difference of ~percent~ from one date grouping to the next
- diff-per-day :: the difference of ~per-day~ from one date grouping to the next
- diff-per-week :: the difference of ~per-week~ from one date grouping to the next
- diff-per-month :: the difference of ~per-month~ from one date grouping to the next
- diff-per-year :: the difference of ~per-year~ from one date grouping to the next
**** date range
it is possible to restrict reports to specified date ranges. you
can specify either the start date, end date, neither, or both.
as with diary entry dates, date range strings may be specified in
any date format ~parse-time-string~ can use.
**** graph-type [graphs only]
metrics-tracker can present metrics data using various graph types.
possible choices:
- line
- bar
- stacked
- scatter
**** graph-output [graphs only]
the graph output option specifies the file format for the graph.
possible choices:
- ascii
- svg
- png
*** index report
@@html:<kbd>@@M-x@@html:</kbd>@@ ~metrics-tracker-index~
this creates a table containing all of the metrics found in your
emacs diary. the index is like a dashboard. it gives you a broad
overview of everything you're tracking.
by default it is sorted by recency. I find it useful to glance
down the list occasionally to see the metrics I've been away from
for a long time.
the sort column and direction can be changed by moving over
another column and hitting ~S~. the arrow in the header indicates
the sort column and direction.
the index report has the following columns:
- metric :: the metric name
- days ago :: the number of days since "last"
- first :: the date of the first entry
- last :: the date of the last entry
- count :: the number of entries for this metric
*** table report
@@html:<kbd>@@M-x@@html:</kbd>@@ ~metrics-tracker-table~
emacs will prompt for the following input parameters:
- metric name
- date grouping
- value transform
@@html:<kbd>@@C-u@@html:</kbd>@@ @@html:<kbd>@@M-x@@html:</kbd>@@
~metrics-tracker-table~
with an argument, emacs will accept multiple metrics and prompt
for the following additional parameters:
- start-date
- end-date
table report creates a table containing the transformed data for
the requested metric(s).
the table can be sorted by either column by moving over the column
and hitting ~S~. the arrow in the header indicates the sort
column and direction.
if the date grouping is ~full~ and the report only includes one
metric, the result is just one value. instead of rendering a
table with one value, metrics-tracker will print it in the echo
area.
*** graph report
metrics-tracker can generate graphs from metric data. it uses
gnuplot for graph generation, so gnuplot must be installed on your
system and available on your ~PATH~. I tested with gnuplot 5.0.
@@html:<kbd>@@M-x@@html:</kbd>@@ ~metrics-tracker-graph~
emacs will prompt for the following input parameters:
- metric name
- date grouping
- value transform
- graph-type
- graph-output
@@html:<kbd>@@C-u@@html:</kbd>@@ @@html:<kbd>@@M-x@@html:</kbd>@@
~metrics-tracker-graph~
with an argument, emacs will accept multiple metrics and prompt
for the following additional parameters:
- start-date
- end-date
*** calendar report
@@html:<kbd>@@M-x@@html:</kbd>@@ ~metrics-tracker-cal~
metrics-tracker can render metric data onto a calendar. the
number at each date position is one of:
- period :: no metric was recorded on this day
- underscore :: before first metric entry or after last one
- number :: the value for the day
emacs will prompt for the following input parameters:
- metric-name
- value transform
@@html:<kbd>@@C-u@@html:</kbd>@@ @@html:<kbd>@@M-x@@html:</kbd>@@
~metrics-tracker-cal~
with an argument, emacs will prompt for the following additional
parameters:
- start-date
- end-date
** derived metrics
it is possible to derive metrics by combining existing metrics using mathematical expressions by editing `metrics-tracker-derived-metrics' in [[https://www.gnu.org/software/emacs/manual/html_node/emacs/Easy-Customization.html][customize]]. the expression uses ~$N~ to refer to the Nth metric the derived metric is based on. for example, if you have metrics for "run dist" and "run time" you could define a derived metric called "run mph" which is based on those metrics and defined as ~$1/$2~.
the expression is optional. if no expression is given, all base metrics are summed together (as if the expression was ~$1 + $2 + ... + $N~). for example, if you have one metric for "running" and another for "cycling" then you can create a derived metric called "cardio" that depends on them and omit the expression. cardio will be the total of running and cycling. when you sum metrics like this, the ~total~ may become meaningless if you recorded them in different units, but the ~percent~ and ~count~ will still be useful.
derived metrics can be based on other derived metrics, but cycles are obviously not allowed. since it is easy to combine metrics in this way, you can record metrics as granularly as you want, and put them together when you view them. the following image is a dependency graph (not generated by metrics-tracker) showing my derived metrics and their dependencies to get an idea of how metrics can be combined.
[[https://ianxm-githubfiles.s3.amazonaws.com/emacs-tracker/depgraph_60pct_v3.png]]
derived metrics can be used in all reports as if they were base metrics.
*** goodness metric
because derived metrics can accept arbitrary math expressions, it is possible to create a derived metric that combines all of your metrics, scaling to normalize them and negating metrics that are "bad." the result would be your "goodness," according to your own definition of what is it to be good. you could then compare your goodness from week to week or year to year.
** named reports
to make it easier to pull up a report that you use repeatedly, you can save it as a named report. do this by generating the report and then invoking
@@html:kbd>@@M-x@@html:</kbd@@ ~metrics-tracker-save-named-report~
or by modifying the variable ~metrics-tracker-named-reports~ in [[https://www.gnu.org/software/emacs/manual/html_node/emacs/Easy-Customization.html][customize]]. the fields in named reports are the same as the input parameters requested during report generation.
you can display a named report by running
@@html:kbd>@@M-x@@html:</kbd@@ ~metrics-tracker-show-named-report~
and choosing which report to show from the list. the report will be rendered using current data (not the data at the time the report was saved).
customization
metrics-tracker defines several variables that can be used to customize behavior. all of these have been mentioned above.
details ** gap handling
gaps in data are handled differently based on the situation.
in table reports gaps are filled with zeros, unless date grouping is set to ~day~ in which case gaps are ignored.
in line or scatter graph reports gaps are ignored. in bar or stacked graph reports gaps are filed with zeros.
in calendar reports, gaps are marked with dots.
** date grouping clipping
if the value transform is set to ~percent~ or one of the ~per-...~ options, the metric value is scaled by the number of days in the date grouping. for example, if date grouping is year and value transform is ~per-month~, the metric value for each year is divided by 12.
if the current year is incomplete (say it's january) this will appear to undercount it, since we'd divide by 12 but we only have one month of metrics. if the purpose of the graph is to compare performance, then this isn't helpful.
in order to overcome this we divide by the portion of the year that's complete, instead of the whole year. this means that the current year's value will represent what you're on pace to get to by the end of the year, and is comparable to the other values in the graph.
the same applies to the first date grouping. it is clipped to start on the date of the first metric entry.
one unfortunate outcome of this is that if we clip a date grouping to a very short period, our extrapolations may result in numbers that are out of our normal range. for example, if you run two times a week your percent of runs per week is 28%, but if you happen to check your graph on monday, and you happened to have run on sunday and monday, it'll say you've run 100% this week.
** min value transform
metrics-tracker ignores gap-filling zeros when computing minimum value.
gallery
these are descriptions of the screenshots in the gif slideshow in the overview section.
[[https://ianxm-githubfiles.s3.amazonaws.com/emacs-tracker/0_index_60pct_v2.png][https://ianxm-githubfiles.s3.amazonaws.com/emacs-tracker/0_index_20pct_v3.png]] :: this is a metric index report. it lists all metrics found in the diary (base metrics as well as derived metrics) along with some useful stats about each.
[[https://ianxm-githubfiles.s3.amazonaws.com/emacs-tracker/1_config_derived_60pct_v2.png][https://ianxm-githubfiles.s3.amazonaws.com/emacs-tracker/1_config_derived_20pct_v3.png]] :: this is what the customize panel looks like when editing derived metrics. the example shows a derived metric that sums four base metrics, and two derived metrics that combine two base metrics as a rate.
[[https://ianxm-githubfiles.s3.amazonaws.com/emacs-tracker/2_config_named_60pct_v2.png][https://ianxm-githubfiles.s3.amazonaws.com/emacs-tracker/2_config_named_20pct_v3.png]] :: this is the customize panel for editing named reports. the example shows a line graph report, a cal report, and a table report.
[[https://ianxm-githubfiles.s3.amazonaws.com/emacs-tracker/3_bar_60pct_v2.png][https://ianxm-githubfiles.s3.amazonaws.com/emacs-tracker/3_bar_20pct_v3.png]] :: this is a bar graph of the percent of days by year on which I did any drinking, non-work coding, or working out. all three metrics are derived from multiple base metrics. there are significant shifts over time.
[[https://ianxm-githubfiles.s3.amazonaws.com/emacs-tracker/4_line_60pct_v2.png][https://ianxm-githubfiles.s3.amazonaws.com/emacs-tracker/4_line_20pct_v3.png]] :: this is a line graph showing total drinks by month. "drinks" is the sum of beers, shots, and wine. there is an obvious trend here.
[[https://ianxm-githubfiles.s3.amazonaws.com/emacs-tracker/5_ascii_60pct_v2.png][https://ianxm-githubfiles.s3.amazonaws.com/emacs-tracker/5_ascii_20pct_v3.png]] :: this is an ascii line graph of cycling miles per week by year. "cycling" is the sum of bike commutes and joyrides.
[[https://ianxm-githubfiles.s3.amazonaws.com/emacs-tracker/6_stacked_60pct_v2.png][https://ianxm-githubfiles.s3.amazonaws.com/emacs-tracker/6_stacked_20pct_v3.png]] :: this is a stacked graph showing the percent of days where I cycled or ran on an elliptical. "cycling" is the sum of bike commutes and joyrides. I've been getting on the elliptical more recently as I've not been able to bike commute as often.
[[https://ianxm-githubfiles.s3.amazonaws.com/emacs-tracker/7_scatter_60pct_v2.png][https://ianxm-githubfiles.s3.amazonaws.com/emacs-tracker/7_scatter_20pct_v3.png]] :: this is a scatter graph showing the total miles bike commuting or running on an elliptical by week. in this data I can see pattern shifts which correlate to life changes (moves, new jobs, had kids).
[[https://ianxm-githubfiles.s3.amazonaws.com/emacs-tracker/8_table_60pct_v2.png][https://ianxm-githubfiles.s3.amazonaws.com/emacs-tracker/8_table_20pct_v3.png]] :: this is a table of average miles and average speed per week. speed is not entered into the diary, but is computed from distance and time.
[[https://ianxm-githubfiles.s3.amazonaws.com/emacs-tracker/9_cal_60pct_v2.png][https://ianxm-githubfiles.s3.amazonaws.com/emacs-tracker/9_cal_20pct_v3.png]] :: this is a calendar of hours coding for the first month of this project.
todo