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 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.
this is a port of tracker.
- run M-x
package-install
RETmetrics-tracker
- download metrics-tracker.el
- run M-x
package-install-file
RET - choose
metrics-tracker.el
metrics entries are regular emacs diary entries so they can be
created by updating the 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.
emacs is very loose on 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 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
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.
metrics-tracker provides several ways to extract information from the metrics data in your diary.
reports are configured with several options.
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 tells metrics-tracker how many days to clump together. in a graph, this is the x axis.
possible choices:
- day
- week
- month
- year
- full
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
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.
metrics-tracker can present metrics data using various graph types.
possible choices:
- line
- bar
- stacked
- scatter
the graph output option specifies the file format for the graph.
possible choices:
- ascii
- svg
- png
M-x 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
M-x metrics-tracker-table
emacs will prompt for the following input parameters:
- metric name
- date grouping
- value transform
C-u M-x
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.
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.
M-x metrics-tracker-graph
emacs will prompt for the following input parameters:
- metric name
- date grouping
- value transform
- graph-type
- graph-output
C-u M-x
metrics-tracker-graph
with an argument, emacs will accept multiple metrics and prompt for the following additional parameters:
- start-date
- end-date
M-x 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
C-u M-x
metrics-tracker-cal
with an argument, emacs will prompt for the following additional parameters:
- start-date
- end-date
it is possible to derive metrics by combining existing metrics
using mathematical expressions by editing
`metrics-tracker-derived-metrics’ in 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.
derived metrics can be used in all reports as if they were base metrics.
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.
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
M-x metrics-tracker-save-named-report
or by modifying the variable metrics-tracker-named-reports
in
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
M-x 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).
metrics-tracker defines several variables that can be used to customize behavior. all of these have been mentioned above.
- metrics-tracker-named-reports
- a list of saved reports that can be shown by name
- metrics-tracker-derived-metrics
- a list of derived metrics as described above
- metrics-tracker-dark-mode
- if
t
, enable dark mode for image graphs - metrics-tracker-graph-colors
- two lists of colors to use for graph series in light mode and dark mode
- metrics-tracker-metric-name-whitelist
- if set, read only these metrics when parsing the diary file
- metrics-tracker-metric-name-blacklist
- if set, ignore these metrics when parsing the diary file
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.
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.
metrics-tracker ignores gap-filling zeros when computing minimum value.
these are descriptions of the screenshots in the gif slideshow in the overview section.
- 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.
- 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.
- this is the customize panel for editing named reports. the example shows a line graph report, a cal report, and a table report.
- 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.
- 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.
- this is an ascii line graph of cycling miles per week by year. “cycling” is the sum of bike commutes and joyrides.
- 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.
- 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).
- 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.
- this is a calendar of hours coding for the first month of this project.
- reports
- streaks
- bursts
- records
- correlations
- sync to cloud
- quality checks