Finish first version of document generation
This commit is contained in:
parent
df9d01baa5
commit
7d0381d4b9
@ -1,12 +1,35 @@
|
|||||||
import pandas as pd
|
import pandas as pd
|
||||||
from banking_breakdown import latex_generator
|
from banking_breakdown import document_builder
|
||||||
|
import subprocess
|
||||||
|
import os
|
||||||
|
import shutil
|
||||||
|
|
||||||
|
import pandas as pd
|
||||||
|
|
||||||
|
from banking_breakdown import types
|
||||||
|
import numpy as np
|
||||||
|
|
||||||
|
|
||||||
def main():
|
def main():
|
||||||
src = latex_generator.generate_latex()
|
categories = ["A", "B", "C", "D", "E", "F", "G"]
|
||||||
latex_generator.build_document(src)
|
values = np.array([10, 12, 53, 12, 90, 23, 32])
|
||||||
# df = pd.read_csv('res/statement.csv', delimiter=';')
|
values = values / values.sum() * 100
|
||||||
# print(df['Betrag'])
|
|
||||||
|
total_value = np.random.normal(size=10) + 4
|
||||||
|
net_income = np.diff(total_value)
|
||||||
|
|
||||||
|
category_overview_df = pd.DataFrame(
|
||||||
|
{"category": categories, "value": values.astype('int32')})
|
||||||
|
t = np.linspace(0, total_value.size, total_value.size)
|
||||||
|
total_value_df = pd.DataFrame({"t": t, "value": total_value})
|
||||||
|
t = np.linspace(0, net_income.size, net_income.size)
|
||||||
|
net_income_df = pd.DataFrame({"t": t, "value": net_income})
|
||||||
|
|
||||||
|
report_data = types.ReportData(category_overview=category_overview_df,
|
||||||
|
net_income=net_income_df,
|
||||||
|
total_value=total_value_df)
|
||||||
|
|
||||||
|
document_builder.build_document(report_data)
|
||||||
|
|
||||||
|
|
||||||
if __name__ == "__main__":
|
if __name__ == "__main__":
|
||||||
|
|||||||
27
banking_breakdown/document_builder.py
Normal file
27
banking_breakdown/document_builder.py
Normal file
@ -0,0 +1,27 @@
|
|||||||
|
import subprocess
|
||||||
|
import os
|
||||||
|
import shutil
|
||||||
|
from banking_breakdown import types
|
||||||
|
|
||||||
|
|
||||||
|
def build_document(report_data: types.ReportData):
|
||||||
|
# Copy files from 'res/' folder
|
||||||
|
os.makedirs(os.path.dirname("build/report.tex"), exist_ok=True)
|
||||||
|
shutil.copyfile("res/report.tex", "build/report.tex")
|
||||||
|
shutil.copyfile("res/.latexmkrc", "build/.latexmkrc")
|
||||||
|
|
||||||
|
# Write data as csv files
|
||||||
|
report_data.net_income.to_csv('build/net_income.csv', index=False)
|
||||||
|
report_data.category_overview.to_csv('build/category_overview.csv',
|
||||||
|
index=False)
|
||||||
|
report_data.total_value.to_csv('build/total_value.csv', index=False)
|
||||||
|
|
||||||
|
# Build dockerfile and compile document
|
||||||
|
subprocess.call("docker build . -f res/Dockerfile.alpine"
|
||||||
|
" -t banking-breakdown",
|
||||||
|
shell=True)
|
||||||
|
subprocess.call("docker run --rm -u `id -u`:`id -g`"
|
||||||
|
" -v $(realpath .):/project"
|
||||||
|
" -w /project/build banking-breakdown"
|
||||||
|
" latexmk -pdf report.tex",
|
||||||
|
shell=True)
|
||||||
@ -1,70 +0,0 @@
|
|||||||
import subprocess
|
|
||||||
import textwrap
|
|
||||||
import os
|
|
||||||
import shutil
|
|
||||||
import docker
|
|
||||||
|
|
||||||
|
|
||||||
def generate_latex() -> str:
|
|
||||||
result = textwrap.dedent("""\
|
|
||||||
\\documentclass{article}
|
|
||||||
|
|
||||||
% Packages necessary for common.tex
|
|
||||||
\\usepackage{amsmath}
|
|
||||||
\\usepackage{pgfplots}
|
|
||||||
\\pgfplotsset{compat=newest}
|
|
||||||
|
|
||||||
% Other packages
|
|
||||||
\\usepackage{float}
|
|
||||||
\\usepackage{subcaption}
|
|
||||||
\\usepackage[a4paper, total={6.5in, 9in}]{geometry}
|
|
||||||
\\usetikzlibrary{positioning}
|
|
||||||
\\usepackage{ifthen}
|
|
||||||
|
|
||||||
|
|
||||||
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
|
||||||
%%%%%% Set common options %%%%%%%
|
|
||||||
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
|
||||||
|
|
||||||
|
|
||||||
\\input{../lib/latex-common/common.tex}
|
|
||||||
\\pgfplotsset{colorscheme/rocket}
|
|
||||||
|
|
||||||
|
|
||||||
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
|
||||||
%%%%%%% Actual Document %%%%%%%%%
|
|
||||||
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
|
||||||
|
|
||||||
|
|
||||||
\\title{Banking Report}
|
|
||||||
\\author{}
|
|
||||||
|
|
||||||
|
|
||||||
\\begin{document}
|
|
||||||
|
|
||||||
\\maketitle
|
|
||||||
|
|
||||||
Test
|
|
||||||
|
|
||||||
|
|
||||||
\\end{document}
|
|
||||||
""")
|
|
||||||
|
|
||||||
return result
|
|
||||||
|
|
||||||
|
|
||||||
def build_document(src: str):
|
|
||||||
os.makedirs(os.path.dirname("build/doc.tex"), exist_ok=True)
|
|
||||||
with open("build/doc.tex", "w") as out_file:
|
|
||||||
out_file.write(src)
|
|
||||||
|
|
||||||
shutil.copyfile("res/.latexmkrc", "build/.latexmkrc")
|
|
||||||
|
|
||||||
subprocess.call("docker build . -f res/Dockerfile.alpine"
|
|
||||||
" -t banking-breakdown",
|
|
||||||
shell=True)
|
|
||||||
subprocess.call("docker run --rm -u `id -u`:`id -g`"
|
|
||||||
" -v $(realpath .):/project"
|
|
||||||
" -w /project/build banking-breakdown"
|
|
||||||
" latexmk -pdf doc.tex",
|
|
||||||
shell=True)
|
|
||||||
9
banking_breakdown/types.py
Normal file
9
banking_breakdown/types.py
Normal file
@ -0,0 +1,9 @@
|
|||||||
|
from dataclasses import dataclass
|
||||||
|
import pandas as pd
|
||||||
|
|
||||||
|
|
||||||
|
@dataclass
|
||||||
|
class ReportData:
|
||||||
|
category_overview: pd.DataFrame
|
||||||
|
net_income: pd.DataFrame
|
||||||
|
total_value: pd.DataFrame
|
||||||
@ -2,3 +2,6 @@ FROM alpine:3.19
|
|||||||
|
|
||||||
RUN apk update && apk upgrade
|
RUN apk update && apk upgrade
|
||||||
RUN apk add make texlive texmf-dist-pictures
|
RUN apk add make texlive texmf-dist-pictures
|
||||||
|
RUN apk add texmf-dist-fontsextra
|
||||||
|
RUN apk add texmf-dist-latexextra
|
||||||
|
|
||||||
|
|||||||
170
res/report.tex
Normal file
170
res/report.tex
Normal file
@ -0,0 +1,170 @@
|
|||||||
|
\documentclass{article}
|
||||||
|
|
||||||
|
% Packages necessary for common.tex
|
||||||
|
\usepackage{amsmath}
|
||||||
|
\usepackage{pgfplots}
|
||||||
|
\pgfplotsset{compat=newest}
|
||||||
|
|
||||||
|
% Other packages
|
||||||
|
\usepackage[a4paper, total={12cm, 25cm}]{geometry}
|
||||||
|
\usepackage{float}
|
||||||
|
\usepackage{calc}
|
||||||
|
\usepackage{ifthen}
|
||||||
|
\usepackage{tikz}
|
||||||
|
\usepackage[l3]{csvsimple}
|
||||||
|
\usepackage{subcaption}
|
||||||
|
|
||||||
|
|
||||||
|
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
||||||
|
%%%%%% Set common options %%%%%%%
|
||||||
|
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
||||||
|
|
||||||
|
|
||||||
|
\input{../lib/latex-common/common.tex}
|
||||||
|
\pgfplotsset{colorscheme/rocket}
|
||||||
|
|
||||||
|
|
||||||
|
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
||||||
|
%%%% Define Custom Commands %%%%%
|
||||||
|
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
||||||
|
|
||||||
|
|
||||||
|
\newcommand{\slice}[6]{
|
||||||
|
\pgfmathparse{0.5*#1+0.5*#2}
|
||||||
|
\let\midangle\pgfmathresult
|
||||||
|
|
||||||
|
% slice
|
||||||
|
\fill[thick,color=#5] (0,0) -- (#1:1) arc (#1:#2+1:1) -- (0,0);
|
||||||
|
|
||||||
|
% outer label
|
||||||
|
\node[label=\midangle:#4] at (\midangle:1) {};
|
||||||
|
|
||||||
|
% inner label
|
||||||
|
\pgfmathparse{min((#2-#1-10)/110*(-0.3),0)}
|
||||||
|
\let\temp\pgfmathresult
|
||||||
|
\pgfmathparse{max(\temp,-0.5) + 0.8}
|
||||||
|
\let\innerpos\pgfmathresult
|
||||||
|
\node[color=#6] at (\midangle:\innerpos) {#3};
|
||||||
|
}
|
||||||
|
|
||||||
|
\newcounter{pieElem}
|
||||||
|
\newcounter{pieSliceA}
|
||||||
|
\newcounter{pieSliceB}
|
||||||
|
\newcommand{\pie}[1]{
|
||||||
|
% Count elements
|
||||||
|
\setcounter{pieElem}{0}%
|
||||||
|
\foreach\pieElem in {#1}{\stepcounter{pieElem}}%
|
||||||
|
\edef\numElements{\arabic{pieElem}}
|
||||||
|
|
||||||
|
% Draw pie chart
|
||||||
|
\setcounter{pieSliceA}{0}%
|
||||||
|
\setcounter{pieSliceB}{0}%
|
||||||
|
\foreach \xi/\t [count=\xk from 0] in {#1} {
|
||||||
|
% Get colors
|
||||||
|
\pgfmathparse{1000 / (\numElements - 1) * \xk}
|
||||||
|
\extractcolormapcolor{pieColor\xk}{\pgfmathresult}
|
||||||
|
\pgfmathparse{(\xk / \numElements < 0.5)*1000}
|
||||||
|
\extractcolormapcolor{pieTextColor\xk}{\pgfmathresult}
|
||||||
|
|
||||||
|
% Draw slice
|
||||||
|
\setcounter{pieSliceA}{\thepieSliceB}
|
||||||
|
\addtocounter{pieSliceB}{\xi}
|
||||||
|
\slice{\thepieSliceA/100*360}{\thepieSliceB/100*360}{\xi\%}{\t}{pieColor\xk}{pieTextColor\xk}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
\newcommand{\csvPie}[1]{
|
||||||
|
% Count elements
|
||||||
|
\setcounter{pieElem}{0}%
|
||||||
|
\csvreader[head to column names]{#1}{}{%
|
||||||
|
\stepcounter{pieElem}
|
||||||
|
}
|
||||||
|
\edef\numElements{\arabic{pieElem}}
|
||||||
|
|
||||||
|
% Draw pie chart
|
||||||
|
\setcounter{pieElem}{0}%
|
||||||
|
\setcounter{pieSliceA}{0}%
|
||||||
|
\setcounter{pieSliceB}{0}%
|
||||||
|
\csvreader[head to column names]{#1}{}{%
|
||||||
|
% Get colors
|
||||||
|
\pgfmathparse{1000 / (\numElements - 1) * \thepieElem}
|
||||||
|
\extractcolormapcolor{pieColor\thepieElem}{\pgfmathresult}
|
||||||
|
\pgfmathparse{(\thepieElem / \numElements < 0.5)*1000}
|
||||||
|
\extractcolormapcolor{pieTextColor\thepieElem}{\pgfmathresult}
|
||||||
|
|
||||||
|
% Draw slice
|
||||||
|
\setcounter{pieSliceA}{\thepieSliceB}
|
||||||
|
\addtocounter{pieSliceB}{\value}
|
||||||
|
\slice{\thepieSliceA/100*360}{\thepieSliceB/100*360}{\value\%}{\category}
|
||||||
|
{pieColor\thepieElem}{pieTextColor\thepieElem}
|
||||||
|
|
||||||
|
\stepcounter{pieElem}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
||||||
|
%%%%%%% Actual Document %%%%%%%%%
|
||||||
|
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
||||||
|
|
||||||
|
|
||||||
|
\title{Expense Report\vspace{-1cm}}
|
||||||
|
\author{}
|
||||||
|
|
||||||
|
|
||||||
|
\begin{document}
|
||||||
|
|
||||||
|
\maketitle
|
||||||
|
\vspace{1cm}
|
||||||
|
|
||||||
|
\begin{figure}[H]
|
||||||
|
\centering
|
||||||
|
|
||||||
|
\begin{tikzpicture}[scale=3]
|
||||||
|
\csvPie{category_overview.csv}
|
||||||
|
\end{tikzpicture}
|
||||||
|
\end{figure}
|
||||||
|
|
||||||
|
\begin{figure}[H]
|
||||||
|
\centering
|
||||||
|
|
||||||
|
\begin{subfigure}[t]{\textwidth}
|
||||||
|
\centering
|
||||||
|
|
||||||
|
\begin{tikzpicture}
|
||||||
|
\begin{axis}[
|
||||||
|
width=\textwidth,
|
||||||
|
height=0.375\textwidth,
|
||||||
|
ylabel={Net income},
|
||||||
|
y label style={at={(-0.1,0.5)},anchor=south},
|
||||||
|
]
|
||||||
|
\addplot+[ybar, color=scol2, fill=scol2, line width=1pt]
|
||||||
|
table[col sep=comma, x=t, y=value, discard if lt={value}{0}]
|
||||||
|
{net_income.csv};
|
||||||
|
\addplot+[ybar, color=scol0, fill=scol0, line width=1pt]
|
||||||
|
table[col sep=comma, x=t, y=value, discard if gt={value}{0}]
|
||||||
|
{net_income.csv};
|
||||||
|
\end{axis}
|
||||||
|
\end{tikzpicture}
|
||||||
|
\end{subfigure}
|
||||||
|
\begin{subfigure}[t]{\textwidth}
|
||||||
|
\centering
|
||||||
|
|
||||||
|
\begin{tikzpicture}
|
||||||
|
\begin{axis}[
|
||||||
|
width=\textwidth,
|
||||||
|
height=0.375\textwidth,
|
||||||
|
area style,
|
||||||
|
ylabel={Total amount},
|
||||||
|
y label style={at={(-0.1,0.5)},anchor=south},
|
||||||
|
]
|
||||||
|
\addplot+[mark=none, color=scol1, line width=1pt]
|
||||||
|
table[col sep=comma, x=t, y=value]
|
||||||
|
{total_value.csv} \closedcycle;
|
||||||
|
\end{axis}
|
||||||
|
\end{tikzpicture}
|
||||||
|
\end{subfigure}
|
||||||
|
\end{figure}
|
||||||
|
|
||||||
|
\end{document}
|
||||||
|
|
||||||
Loading…
Reference in New Issue
Block a user