61

Would TeX (LaTeX, ConTeXt, etc) be a good solution for PDF business reports that require dynamically generated graphs and tables?

I need to create financial reports that must look top-notch in their graphics, charts, and typesetting. These reports are typically several pages long and will contain charts, tables of numbers, and typeset text.

I have been using some 'general' PDF libraries, but these have been expensive and typically have some sort of limitation simply because 1) you are working at a higher level with the data and 2) their author's just didn't give them as much flexibility as I need.

This question applies to other TeX flavors, but some of these specifics are related to ConTeXt. It has some amazing features:

  • drawing support (MetaPost, TikZ/PGF)
  • lua scripting (specifically, adding a JSON parser and using it to populate a .tex file would be awesome)
  • as much layout control as you could possibly want

So I could create my own reports where I lay things out and draw charts myself. Is there anybody out there using TeX for business reporting solutions like this? Would I be off my rocker to suggest such a thing?

1
  • It is probably reasonable to use TeX for this. I've created a template in LaTeX that was used by a company in the medical industry to create patient reports of a sort. This was only two pages with fairly fixed layout though. Maybe this question should be community wiki.
    – TH.
    Sep 26, 2010 at 22:50

9 Answers 9

35

TeX/Latex and all their friends are the best solution for any type of reports (sorry if I am biased).

I use them for probably the most unlike application. Construction reports - as in Building Construction! I have been doing so for quite a long time. The reports include anything from graphs to financial summaries and commissioning data for electro-mechanical services.

Some pointers, before you automate anything write a few static reports. Define what changes weekly/monthly such as graphs, tables etc. and then automate via python/lua or whatever language you are comfortable.

At the moment - I just import tables via PgfplotsTable. This makes it easy to interface with external programs via csv delimited tables. The datatool package also provides similar functionality. All graphs are automated via LaTeX. No need to struggle to interface with external programs.

Use LaTeX to start with and PGF/TikZ for graphics. Get some pointers from Tufte for presentation and readability. It is not necessary to buy anything.

One of the drawbacks I had at the beginning was to convince people to give sections of the content in plain text files and to get them to divorce excel.

1
  • Yiannis, I've been out on the internet this evening trying to track down a solution to an automated reporting problem that I am currently managing for one of my main clients. I'm looking to speak with a specialist/engage that specialist's services when it comes to auto report generation in LaTex. Is there any chance I could speak with you/see a sample of some of the reporting work you've done? Our company is at: www.polhooper.com, and my work email is aaron@polhooper.com. Cheers, Aaron
    – aaron
    Jul 14, 2014 at 7:38
22

I have already implemented a report generation tool in a business setting in LaTeX/Python/gnuplot, and it works great! The only problem for me was to get the idea accepted in the company. I ended up writing a proof of concept utility that generates professional looking reports. There are no problems what so ever. The reports generated is about 100 pages long and used to take the company days to write. Now the entire thing is generated in ten seconds. :)

So how do you convince you coworkers of the LaTeX way? Most people had never heard of LaTeX and even though most people were interested in the idea, they wanted it "implemented" in MS Word. Even now they are skeptical of the idea since I am the only TeXer in the company and nobody else can alter the software if I leave. My software is used by other people in the company, and saves us huge amounts of money, but I still doubt that I will get to use more engineering time on TeX ...

Good luck, though!

3
  • This looks interesting. Did you write your own document classes?
    – Kit
    Sep 28, 2010 at 22:51
  • 3
    I got a proof of concept working using ConTeXt, MetaPost, and Pgfplots. Like you, the main drawback I see is "What if I get hit by a bus".
    – Shizzmo
    Sep 30, 2010 at 14:40
  • 1
    @Kit - Yes. The company has strict layout guidelines, but there was no problem making document classes that passed the document control. I am very satisfied with the result and with the company document classes it is now easy for my coworkers to make documents, and some are already planning to make auto generation tools with them. Sep 30, 2010 at 16:12
19

You might want to check out R and Sweave. R is great for analysing data and generating tables and graphs. Sweave is a tool for integrating this output into LaTeX.

I wrote a post on getting started with Sweave.

2
  • Very interesting. I would never have thought about using R. Thanks!
    – Shizzmo
    Sep 27, 2010 at 22:27
  • 2
    I see you switched to knitr, though. (You wrote a very nice post on its R+Markdown support; I use it for R+LaTeX, myself.) I, too, prefer knitr (for its modular design and its saner option structure, in my case), so I've written it up in an answer below.
    – Esteis
    Feb 13, 2013 at 14:16
10

R + Sweave is powerful but crufty. The equally powerful and more modern combination is R and knitr.

Sweave was not so much designed as constructed, and it shows. Knitr expressly tries to do the same things as Sweave, but

  • Its chunk options are grouped and tidied and generally better organized (and less inclined to touch each other) than Sweave’s options.
  • It allows any input language (e.g. R, Python and Awk) and any output markup languages (provided: LaTeX, HTML, Markdown and reStructuredText). (I'm writing a ConTeXt renderer myself, but it's a side project and not done yet.)
  • Things like caching chunks and pretty-printing code are built-in.

This is an example knitr + LaTeX document, taken from the knitr minimal examples:

\documentclass{article}
\usepackage{graphicx}
%% begin.rcode setup, include=FALSE
% opts_chunk$set(fig.path='figure/latex-', cache.path='cache/latex-')
%% end.rcode
\begin{document}

Boring stuff as usual:

%% a chunk with default options
%% begin.rcode
% 1+1
%
% x=rnorm(5)
%% end.rcode

Now we know the first element of x is \rinline{x[1]}. And we also
know the 26 letters are \rinline{LETTERS}. 

How about figures? Let's use the Cairo PDF device (assumes R $\geq$ 2.14.0).

%% begin.rcode cairo-scatter, fig.width=5, fig.height=5, out.width='.8\\textwidth'
% plot(cars) # a scatter plot
%% end.rcode

\end{document}

You would compile this document as follows (after adding the provided knit script to your path):

knit mydocument.Rtex        # compile to tex
# or
knit --pdf mydocument.Rtex  # compile to pdf

As you see, code chunks are kept in comments, so that even if you don't have knitr the document is still a valid LaTeX file. If you prefer the Sweave `<>...@ style of mixing LaTeX and R, save your file as .Rnw, instead, and write your chunks like so:

<<cairo-scatter, fig.width=5, fig.height=5, out.width='.8\\textwidth'>>=
... chunk contents...
@

In conclusion, this is why you want to use (a) literate reporting as (b) implemented by knitr:

  • The programming language gets first pass, which gives you lots of power
  • Your document is mostly Markdown/LaTeX/other markup language, which is way nicer for reading/writing documents.
  • R’s knit package implements this in a nicer way than R’s Sweave package.
  • There must be similar packages in other languages, but I don't know any (barring the ones aimed more at literate source code).
3

I'm reading happily how many professionals employ TeX for any kind of business. I expected this using LaTeX myself for writing contracts and motions, but sometimes I wondered whether I were one of very few people who do this.

To all those professionals who use LaTeX: Please consider publishing an article about what you do in your local TUG-magazin.

Alexander

2

In my opinion TeX and compatible tools are perfectly suitable for this task. I haven't used it for this personally though, just for academic work.

Also you can use any program which can output PDFs for the charts in case Metapost/TikZ isn't good enough for you.

6
  • 3
    Why do you say that ConTeXt is not free for commercial use? AFAIK, ConTeXt is distributed under GNU GPL (see readme). Only the documentation is under a non-commercial license.
    – Aditya
    Sep 26, 2010 at 23:17
  • 1
    Another -1 vote from me. The information about ConTeXt is blatantly wrong. Also, all pdfs on the pragma-ade website are free for use, and the updated reference manual is released under GNU FDL. Sep 27, 2010 at 7:49
  • @Roman: I am interested to learn where you got that misinformation from. Sep 27, 2010 at 8:46
  • @Taco: I faintly remember reading it somewhere, maybe the pragma ADE website? Hasn't the licence changed recently? Anyway, I hope I didn't offend anyone :) Sep 27, 2010 at 11:43
  • 4
    I removed the part where I incorrectly stated that ConTeXt is not free. Sep 28, 2010 at 21:48
2

At work i've created a bunch of Python scripts to analyze a server log file, which in turn generates plots and tables (TikZ, longtable) as a LateX document. I then generate PDF files using pdflatex.

Before that i've used a Python PDF reporting library, but i've encountered strange bugs, when the file/tables got too long. I am quite happy with it.

For layout-sensitive stuff i using whole-page TikZ graphics, e.g. my CV. my only regret is that i've not found an painless way to include TTF/OTF fonts.

1
  • 3
    To use your system fonts, switch to XeLaTeX or LuaLaTeX. I don't expect you will have any problem with the transition.
    – nplatis
    Feb 10, 2012 at 7:33
2

I use LaTeX for that purpose and I find it perfect. What I really love is the difference between what I see (simple text) and what the client sees (fancy report). I use the book document class because the Table of Contents is slick.

For dynamically generated charts and tables you'll need sweave.

1

i use LaTeX for creating reports as a "view" for a django application.

source code is available in my git repo

I'm working on new reports based on ConTeXT, with flowcharts and maybe some Metapost plots. Here is the template, notice django templates tags that is between {{ }} or {% %}. This often causes confusion whith django tags.

 {% autoescape off %}
  {% load static %}
 \documentclass[headlines=6,headinclude=true,11pt]{scrartcl}
 \usepackage{scrlayer-scrpage}
 \usepackage[left=1.5cm,right=1.5cm,top=4cm,bottom=2cm,includefoot]{geometry}
 \setlength{\footheight}{35pt}
 \usepackage[usenames,dvipsnames,svgnames,table]{xcolor}
 \usepackage{graphicx}
 \usepackage[skins]{tcolorbox}
 \usepackage{titlesec}
 \usepackage{longtable}
 \usepackage{booktabs}
 \usepackage{fontawesome}
 \usepackage{ifthen}
 \usepackage{polyglossia}
 \defaultfontfeatures{Mapping=tex-text}
 \setdefaultlanguage{french}
 \setmainfont[Mapping=tex-text]{Linux Libertine O}
 \setsansfont{Roboto}
 \setotherlanguage{arabic}
 \newfontfamily\arabicfont[Script=Arabic]{Noto Kufi Arabic}
 \definecolor{lightGris}{RGB}{185,185,185}
 \definecolor{darkGris}{RGB}{115,115,115}
 \definecolor{Gris}{RGB}{63,75,81}

   \ihead{\begin{tabular}{c} \textcolor{Gris}{\textsf{\bfseries{Clinique médico chirurgicale EL ABRAR}}}\\
    \textcolor{Gris}{\bfseries{\textarabic{العيادة الطبية 
    الجراحية الأبرار}}}\\
       \textcolor{Gris}{\textsf{\bfseries{Cardiologie médicale et 
       interventionnelle}}}\\\textcolor{Gris}{\bfseries{\textarabic{ مصلحة أمراض القلب}}}\\
  \end{tabular}
 } 
   %%%% eviter l'italic dans le header
   %\renewcommand{\headfont}{\sffamily}
   \chead{\includegraphics[height=5\baselineskip]{media/logo.png}}

   \ohead{\begin{tabular}{r}\textcolor{Gris}{\textsf{\bfseries{Dr Yahyaoui Mohamed Kaddour}}}\\
         \textcolor{Gris}{\textsf{\bfseries{Cardiologue}}}\\ 
 \textcolor{Gris }
 {\textsf{\bfseries{kaddourkardio{\faAt}gmail.com}}}\end{tabular}}



   \cfoot{\textcolor{Gris}{\textit{\textbf{``Votre coeur mérite ce qu'il y a de
    mieux''} } }\\
 \vspace{-3mm}
 \hrulefill\\
 \begin{minipage}{0.32\textwidth}
 \textcolor{Gris}{\sffamily{ {\faHospitalO} 15,rue Tolozane} }\\
 \textcolor{Gris}{\sffamily{Les palmiers, Oran} }
 \end{minipage}
 \hfill
 \begin{minipage}{0.25\textwidth}
\textcolor{Gris}{\sffamily{\sffamily{ {\faPhone} (+213) 041-496-066} } } 
  \\
   \textcolor{Gris}{\sffamily{ {\faFax} (+213) 041-233-491} }
\end{minipage}
\hfill
 \begin{minipage}{0.27\textwidth}
 \textcolor{Gris}{\sffamily{\sffamily{ {\faMobile} (+213) 0561 882-066}} } \\
  \textcolor{Gris}{\sffamily{\small{\faEnvelopeO} {clinique-
  elabrar{\faAt}laposte.net} }}
\end{minipage} }


\begin{document}

\begin{center}
  \textcolor{Gris}{\bfseries{\huge{\textsf{RAPPORT MÉDICAL}}} }
 \end{center}

  \section*{Patient}
  \begin{description}
   \item[Nom prénoms:] {{consultation.patient}}
   \item[Adresse:] {{patient.adresse}}
   \item[Date de naissance:] {{patient.birth}}
       \item[Motifs de consultation:] {% if consultation.emergency == True %}Consultation dans le cadre de l'urgence pour {% else %}Consultation ce jour le {{ consultation.consultation_date }} {% endif %}pour {% for motif in consultation.motif_consultation.all %}{{ motif }} {% endfor %}. 

   \end{description}
   \subsection*{Facteurs de risques - antécédents }
   \begin{description}

  \item[FDR:]

       \begin{itemize}
        {% if patient.hypertension == True %} \item Hypertension artérielle.{% endif %}
        {% if patient.diabete == True %} \item Diabète. {% endif %}
          {% if patient.dyslipidemia == True %} \item Dyslipidémie. {% endif %}
            {% if patient.smoker == True %} \item Tabagique. {% endif %}
              {% if patient.heredity == True %} \item Hérédité coronarienne. {% endif %}
                {% if patient.obesity == True %} \item Obésité.{% endif %}

                \end{itemize}

              \item[Antécédents:]
                {{ patient.history }}
              \item[Allergies connues:] {{ patient.allergy }}
              \end{description}
              \subsection*{Histoire de la maladie}
              {{ consultation.histoire }}

              % \begin{center}
              %   \rule{8cm}{0.4pt}
              % \end{center}


              \subsection*{Examen clinique}
              \subsubsection*{Signes fonctionnels}
              \begin{itemize}
                {% if consultation.fever == True %}\item fièvre.{% endif %}
                  {% if consultation.dyspnea_nyha == 1 %}
           \item Eupnéique au repos{% else %}\item Dyspnée au stade {{ 
      consultation.dyspnea_nyha }} de la \textit{NYHA}{% endif %}.
                      {% if consultation.angina_scc == 1 %}\item Absence 
       d'angor.{% else %}\item Angor au stade {{ consultation.angina_scc 
    }} de la 
     \textit{SCC}.{% endif %}
     {% if consultation.syncope == True %} \item Syncope.{% endif %}

 \end{itemize}
 \subsubsection*{Signes physiques}
  L'examen clinique retrouve à l'auscultation: {{  
consultation.auscultation }} avec
  une fréquence cardiaque à = {{ consultation.heart_rate}} Bpm.\\

   En périphérie les pouls sont {{ consultation.pulse }} avec une PA = 
 {{ consultation.systolic_bp }}/{{ consultation.diastolic_bp }}mmHg.\\

\section*{Bilan para clinique}
\subsection*{ECG}
 Le rythme est en {% if consultation.rythm == 'S' %}sinusal{% elif 
 consultation.rythm == 'F' %}fibrillation atriale{% elif 
  consultation.rythm == 'R'%}flutter auriculaire{% elif  
 consultation.rythm == 'T' %}tacchycardie 
ventriculaire{% elif consultation.rythm == 'P' %}électro stimulé{% endif %}
      à fréquence cardiaque de {{ consultation.freq }} puls/min.\\

   {% if consultation.bundle_block == 'G' %}Il existe un bloc de branche 
 gauche.\\{% elif consultation.bundle_block == 'D' %}Il existe un bloc 
de 
branche droit.\\{% endif %}
{% if consultation.hypertrophy == True %}On note aussi une hypertrophie ventriculaire gauche électrique.\\{% endif %}
    Sur le plan ischémique: {% if consultation.lesion == 'S' %} une 
 lésion en septal{% elif consultation.lesion == 'A' %} une lésion en 
antérieur{% elif consultation.lesion == 'L' %} une lésion en latéral{% 
  elif consultation.lesion == 'P' %} une lésion en postérieur{% else 
 %}absence de lésions électriques{% endif %},
          {% if consultation.ischaemia == 'S' %} une ischémie en 
 septal{% elif consultation.ischaemia == 'A' %} une ischémie en antérieur{% 
  elif consultation.ischaemia == 'L' %} une ischémie en latéral{% elif 
  consultation.ischaemia == 'P' %} une ischémie postérieur{% else %}absence 
  d'ischémie électrique{% endif %},
                  {% if consultation.t_inversion == 'S' %} onde T 
  inversée en septal{% elif consultation.t_inversion == 'A' %} onde T 
  inversée en antérieur{% elif consultation.t_inversion == 'L' %} onde T 
 inversée en en latéral{% elif consultation.t_inversion == 'P' %} onde T 
 inversée en postérieur{% endif %}. \\
           Le QT corrigé est estimé à  {{ consultation.corrected_qt }} 
    msec. 

 {% if consultation.telethorax %}
 \subsection*{Téléthorax}
  Le téléthorax retrouve: {{ consultation.telethorax }} \\ 
  {% endif %}

\subsection*{Échocardiographie du {{ consultation.date_echo }} }

À l'écho cardiographie on a : {{consultation.echocoeur }}.\\

{% if eto %} \textbf{l'ETO} retrouve: {{consultation.eto }}{% endif %}

  \subsection*{Biologie}

 voir bilans. \\

\section*{en résumé}

 {{ consultation.resume }}

 \subsection*{Traitement}

 {{consultation.ordonnance}}

 \subsection*{Dispositions complémentaires}
 {{ consultation.dispositions }}
              \\

\begin{center}
\rule{8cm}{0.4pt} 
\end{center}
\vspace{2cm}
\flushbottom\raggedleft Oran le \today\\
\raggedleft Dr \textsc{Yahyaoui M K}\\
\end{document}


            {% endautoescape %}
3
  • 1
    Please add the example here on TeX.SX instead of on another site. Probably you should also consider posting a real answer to the OP's questions.
    – TeXnician
    Mar 8, 2017 at 20:56
  • the git repo contains the whole app, based on django, and latex files are just "templates" to render reports as prints. Sorry for the inconveniance.
    – tuxador
    Mar 8, 2017 at 22:42
  • Okay, probably I haven't expressed myself very clearly. It would be nice, if you could post an example of code for such a template (still having the link in your post).
    – TeXnician
    Mar 9, 2017 at 5:22

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .