Chart your hledger data with interactive graphs. A reasonably comprehensive example of what can be done can be seen here.
I've tried many different approaches to generating graphs, from vanilla gnuplot to postprocessing in R with ggplot2. They were all either too limiting, or required too much maintenance to keep working. I wanted to keep the interface as close as possible to running a hledger command, so it would be as accessible as possible for others, while maintaining customisability. There's a long way to go to meet all these goals, but I think this is a good start.
This requires a basic webserver running on your computer to execute the vega specifications.
Note that this requires a version of hledger which supports the --layout=tidy
option, which is currently only available in the master branch.
Suggestions for how to make this more accessible and useful are very welcome.
This project uses a combination of vega-lite specifications, hledger args files, and report files to generate the graphs. Each graph requires a JSON file giving the vega-lite specification, which are then embedded in an html file. Each graph takes its data from a CSV file which is the result of one or more hledger calls. Each CSV file is generated by a report file which lists the args files to be used in that report, optionally along with a label to be used for the data. The args files are usual hledger args files.
Everything you need to create a suite of charts for your own data can be found here.
It includes:
- A collection of args files to specify the hledger calls needed.
- A collection of report files telling tow to combine the hledger data into csv files
- The hledger-vega bash script, which will the generate csv files.
- A collection of vega-lite specifications, which specify how to generate the charts from the csv files.
- A basic html file, which embeds the charts in a webpage for viewing.
To get started, clone the directory and run hledger-vega
to generate your data.
Next start up web server in the src
directory, and then point your web
browser to the served html file.
There are many static web servers you can use for these purposes.
If you have access to python, you can run python3 -m http.server
to create a simple one.
You can run this with make serve
, and then visit
127.0.0.1:8000 in your web browser.
Note that the provided args files assume that your chart of accounts uses the standard top-level names assets, liabilities, expenses, and revenue(s)/income. If you use a different naming system you should alter the args files to suit your system.
The income statement chart will filter out the first 14 days by default, to
avoid huge spikes due to the moving average, and the savings chart will filter
out the first 90 days.
This can cause the charts to appear blank if you have fewer days than that.
To change this, modify the datum.window_size >=
line in the appropriate
.json
file.
Let's go through a quick example of how to generate a basic chart. Suppose we'd like to chart our income statement: a measure of how much we're earning and spending over a given period.
First, we need to decide which data series we want to plot, and the corresponding queries to pass to hledger. We will want to plot both expenses and income. First, let's figure out the common options between the calls.
hledger bal --daily --depth=0 --cost --value=then,USD
This will make sure costs are accumulated daily, boiled down to a single number
each day, converted to cost, and then valued in USD (or your own local
currency).
It's not strictly necessary to separate these out, but let's do it to save some work.
We will put these options into args/change.args
.
--value=then,USD
--cost
--daily
--depth=0
Next, let's create the query for our expenses.
I do not want my taxes included as an expense, so I'll leave them out.
hledger bal --daily --depth=0 --cost --value=then,USD "^expenses" not:"^expenses:.*taxes"
First we import the change.args
file we just created to get the common
options, then include the rest of the query in args/expenses.args
.
@change.args
^expenses
not:^expenses:taxes
Now let's do income.
I only want to include post-tax income, and furthermore do not want any
retirement income included.
We also should use --invert
, since revenues are negative in hledger.
hledger bal --daily --depth=0 --cost --value=then,USD --invert "^income" "^expenses:.*taxes" not:"retirement"
Let's put that into args/income.args
.
@change.args
--invert
^income
^expenses:taxes
not:retirement
Now that we've specified our data series, we need to tell hledger-vega how to
put them together into a csv file suitable for charting.
This is fairly simple; we just need to specify the args files to use, one on
each line, along with the name for each series, separated with a semicolon.
Create a file reports/incomestatement.report
.
expenses;Total expenses
income;Total income
We've now given hledger-vega all the information it needs to generate our csv
files.
Just run hledger-vega, and it should create a file data/incomestatement.csv
.
You will need to run this whenever you want to update the data your chart uses.
All that's left is to create the vega-lite specification to display this chart,
located at incomestatement.json.
Notice that it uses the incomestatment.csv
file we generated earlier:
"data": { "url": "data/incomestatement.csv"}
.
We can now use vega-embed to embed this in our html file
index.html.
The line vegaEmbed('#vis1', "reports/incomestatement.json");
says to embed the chart
specified by incomestatement.json
in the element with id vis1
.
Fire up your webserver in a place that can see these files, and they should be visible!
You can customise things further, limited only by what you can get out of hledger and your skills with vega-lite. There are further examples of vega-lite specifications and reports in the docs directory. Let me know if you create any new examples that you find useful. Maybe others will find them useful too.