/hledger-vega

Chart your hledger data with interactive graphs

Primary LanguageShell

hledger-vega

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.

Basic workflow

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.

Getting started

Everything you need to create a suite of charts for your own data can be found here.

It includes:

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.

Caveats

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.

Making your own charts

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.

Create the args files

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

Create the report file

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

Generate the data files

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.

Chart the csv files

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!

Further customisation

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.