Add script to generate pdf reports.
This commit is contained in:
11
README.md
11
README.md
@@ -9,9 +9,9 @@ handle the same use-case. I have tried a couple of them, as well as the
|
|||||||
integrated CSV import of hledger, and ran into issues with all of them. That's
|
integrated CSV import of hledger, and ran into issues with all of them. That's
|
||||||
why I wrote yet another CSV to ledger tool.
|
why I wrote yet another CSV to ledger tool.
|
||||||
|
|
||||||
There are two scripts, getofx, and toldg. The former uses the Python
|
There are two main scripts, getofx, and toldg. The former uses the Python
|
||||||
[ofxtools](https://ofxtools.readthedocs.io/en/latest/) library to download bank
|
[ofxtools](https://ofxtools.readthedocs.io/en/latest/) library to download bank
|
||||||
transactions via OFX and stores them into CSV files. The latter takes CSV files
|
transactions via OFX and stores them into CSV files. The latter takes CSV files
|
||||||
and transforms them into ledger accounting files.
|
and transforms them into ledger accounting files.
|
||||||
|
|
||||||
The OFX script works well for my workflow, but I am not sure if it would be
|
The OFX script works well for my workflow, but I am not sure if it would be
|
||||||
@@ -31,6 +31,12 @@ my workflows are editor based, and the mapping file-based approach makes it easy
|
|||||||
to manipulate transactions. Also, the script relies on a single configuration
|
to manipulate transactions. Also, the script relies on a single configuration
|
||||||
file, which makes the configuration clearer.
|
file, which makes the configuration clearer.
|
||||||
|
|
||||||
|
The directory `tools` contains additional scripts for personal use. Currently
|
||||||
|
their main use-case is to generate a PDF report with figures. I use hledger to
|
||||||
|
generate CSV data, plot figures with pandas, and then generate a report with
|
||||||
|
pandoc. A shell script executes this process. This workflow fulfills my
|
||||||
|
requirements, but is currently not useful for anybody else.
|
||||||
|
|
||||||
## Dependencies
|
## Dependencies
|
||||||
|
|
||||||
The scripts rely on a couple of newer Python features, such as data-classes,
|
The scripts rely on a couple of newer Python features, such as data-classes,
|
||||||
@@ -84,4 +90,5 @@ getting warnings.
|
|||||||
- [x] Use OFX parser from ofxtools instead of parsing the XML
|
- [x] Use OFX parser from ofxtools instead of parsing the XML
|
||||||
- [x] Autoappend latest OFX data to CSV file
|
- [x] Autoappend latest OFX data to CSV file
|
||||||
- [x] Include example workspace with mock data to demo my workflow
|
- [x] Include example workspace with mock data to demo my workflow
|
||||||
|
- [x] Write script to generate PDF reports
|
||||||
|
|
||||||
|
|||||||
32
report.py
32
report.py
@@ -1,32 +0,0 @@
|
|||||||
import subprocess
|
|
||||||
import numpy as np
|
|
||||||
import matplotlib.pyplot as plt
|
|
||||||
import pandas as pd
|
|
||||||
|
|
||||||
def configure_plot():
|
|
||||||
plt.figure()
|
|
||||||
axes = plt.gca()
|
|
||||||
axes.set_xlim([0, 300])
|
|
||||||
axes.set_ylim([-256, 100])
|
|
||||||
plt.xlabel("#bets []")
|
|
||||||
plt.ylabel("win [$]")
|
|
||||||
|
|
||||||
def report():
|
|
||||||
df = pd.read_csv("report.csv",
|
|
||||||
index_col='Account',
|
|
||||||
parse_dates=True)
|
|
||||||
df = df.drop(columns="Total:")
|
|
||||||
#print(df)
|
|
||||||
# print(df.info())
|
|
||||||
df.plot.bar()
|
|
||||||
plt.savefig('figure_1.png')
|
|
||||||
# plt.show()
|
|
||||||
|
|
||||||
|
|
||||||
if __name__ == "__main__":
|
|
||||||
c = "hledger balance -M -V -b 2020 --depth 2 ^expenses: --transpose -o report.csv".split()
|
|
||||||
subprocess.call(c)
|
|
||||||
c = r"sed -i s/\$//g report.csv".split()
|
|
||||||
subprocess.call(c)
|
|
||||||
report()
|
|
||||||
|
|
||||||
48
tools/report.sh
Normal file
48
tools/report.sh
Normal file
@@ -0,0 +1,48 @@
|
|||||||
|
#!/bin/sh
|
||||||
|
|
||||||
|
CSV_FILE="data.csv"
|
||||||
|
REPORT_MD="report.md"
|
||||||
|
REPORT_PDF="/home/felixm/report.pdf"
|
||||||
|
YEAR="2018-04"
|
||||||
|
HLEDGER="hledger balance -M -V -b $YEAR --depth 1 --transpose -o $CSV_FILE"
|
||||||
|
|
||||||
|
# Networth
|
||||||
|
$HLEDGER -H '^assets'
|
||||||
|
sed -i 's/\$//g' $CSV_FILE
|
||||||
|
python tofig.py $CSV_FILE "figure_1.png"
|
||||||
|
|
||||||
|
$HLEDGER '^assets'
|
||||||
|
sed -i 's/\$//g' $CSV_FILE
|
||||||
|
sed -i 's/assets/cashflow/g' $CSV_FILE
|
||||||
|
python tofig.py $CSV_FILE "figure_2.png" --type bar
|
||||||
|
|
||||||
|
$HLEDGER '^expenses'
|
||||||
|
sed -i 's/\$//g' $CSV_FILE
|
||||||
|
python tofig.py $CSV_FILE "figure_3.png" --type bar
|
||||||
|
|
||||||
|
$HLEDGER '^income'
|
||||||
|
sed -i 's/\$-//g' $CSV_FILE
|
||||||
|
python tofig.py $CSV_FILE "figure_4.png" --type bar
|
||||||
|
|
||||||
|
rm $CSV_FILE
|
||||||
|
|
||||||
|
cat > $REPORT_MD <<- EOM
|
||||||
|
# Financial Report
|
||||||
|
|
||||||
|
# Networth
|
||||||
|

|
||||||
|
|
||||||
|
# Cashflow
|
||||||
|

|
||||||
|
|
||||||
|
# Expenses
|
||||||
|

|
||||||
|
|
||||||
|
# Income
|
||||||
|

|
||||||
|
EOM
|
||||||
|
|
||||||
|
pandoc $REPORT_MD -o $REPORT_PDF
|
||||||
|
rm figure_*
|
||||||
|
rm $REPORT_MD
|
||||||
|
|
||||||
40
tools/tofig.py
Normal file
40
tools/tofig.py
Normal file
@@ -0,0 +1,40 @@
|
|||||||
|
import matplotlib.pyplot as plt
|
||||||
|
import pandas as pd
|
||||||
|
import argparse
|
||||||
|
|
||||||
|
|
||||||
|
def line_format(label):
|
||||||
|
"""
|
||||||
|
Convert time label to the format of pandas line plot
|
||||||
|
"""
|
||||||
|
month = label.month_name()[:3]
|
||||||
|
if month == 'Jan':
|
||||||
|
month = f'{label.year}\n{month}'
|
||||||
|
return month
|
||||||
|
|
||||||
|
|
||||||
|
def create_figure(args):
|
||||||
|
df = pd.read_csv(args.csv_file, index_col='Account', parse_dates=True)
|
||||||
|
df = df.drop(columns="Total:")
|
||||||
|
figsize=(10, 6)
|
||||||
|
if args.type == 'bar':
|
||||||
|
ax = df.plot(grid=True, kind='bar', figsize=figsize)
|
||||||
|
ax.set_xticklabels(map(lambda x: line_format(x), df.index))
|
||||||
|
else:
|
||||||
|
ax = df.plot(grid=True, figsize=figsize)
|
||||||
|
plt.savefig(args.png_file)
|
||||||
|
# plt.show()
|
||||||
|
|
||||||
|
|
||||||
|
def get_args():
|
||||||
|
parser = argparse.ArgumentParser(description='Transform a CSV file into a bar chart.')
|
||||||
|
parser.add_argument('csv_file', type=str, help='CSV data file')
|
||||||
|
parser.add_argument('png_file', type=str, help='Chart png file')
|
||||||
|
parser.add_argument('--type', default='', type=str, help='Chart png file')
|
||||||
|
return parser.parse_args()
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
args = get_args()
|
||||||
|
create_figure(args)
|
||||||
|
|
||||||
Reference in New Issue
Block a user