Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to generate PDF documents using Julia

Tags:

julia

I want to generate student feedback reports using a loop like this:

for student in studentList
    # Report/feedback content goes here:

    # Here I want to use text with variables for example
    student * " received " * xPoints

    "Q1"
    "Good effort but missing units"

    "Q2"
    "More text ..."

    # end of the feedback
end

My goal is to generate 30+ PDF files for all students, with the score for each question, supplemented with some free text for each student. One way I thought of would be to write to multiple TeX files and compile them to PDFs at the end.

I'm not determined to output PDFs, if there is a better method of generating multiple, human-readable reports programmatically in Julia.

like image 228
StefanSzynisz Avatar asked Oct 31 '18 00:10

StefanSzynisz


1 Answers

As for now we can start with the basics and output a HTML file, which is faster. You can use a templating library, and in this case we can use mustache. The template is hardcoded, but it is simple to include it in an external file.

Remember to install the templating library Mustache:

import Pkg; Pkg.add("Mustache")

The basic idea is the following:

  • have a list of dictionaries with the data
  • have a template of the report, where parts to be substituted are in {{ ... }} guards
  • save the report of a single student in a file html through iteration.

You can add some code to directly send a mail to the student, without even saving the file, if your computer is configured to do so (as long as you do not include external CSS, the mail will be formatted accordingly to the HTML instructions).

using Mustache

students = [
  Dict( "name" => "John", "surname" => "Smith", "mark" => 30 ),
  Dict( "name" => "Elisa", "surname" => "White", "mark" => 100 )
]

tmpl = mt"""
<html>
<body>
Hello <b>{{name}}, {{surname}}</b>. Your mark is {{mark}}
</body>
</html>
"""

for student in students
  rendered = render(tmpl, student)
  filename = string("/tmp/", student["name"], "_", student["surname"], ".html")
  open(filename, "w") do file
    write(file, rendered)
  end
end

The result for a single student is something like:

<html>
<body>
Hello <b>Elisa, White</b>. Your mark is 100
</body>
</html>

If you prefer a PDF, i think the faster way is to have a piece of LaTeX as template (in place of a HTML template), to export the result of Mustache into a file and then to compile it from the script with a system call:

using Mustache

students = [
  Dict( "name" => "John", "surname" => "Smith", "mark" => 30 ),
  Dict( "name" => "Elisa", "surname" => "White", "mark" => 100 )
]

tmpl = mt"""
\documentclass{standalone}

\begin{document}

Hello \textbf{ {{name}}, {{surname}}}. Your mark is ${{mark}}$.

\end{document}
"""

for student in students
  rendered = render(tmpl, student)
  filename = string("/tmp/", student["name"], "_", student["surname"], ".tex")
  open(filename, "w") do file
    write(file, rendered)
  end
  run(`pdflatex $filename`)
end

which results in something like:

enter image description here

A reference to Mustache.jl, where you can find some instructions on how to iterate over different questions with a single line of template. This is an example in which the marks are an array of values (again for tex):

using Mustache

students = [
  Dict( "name" => "John", "surname" => "Smith", "marks" => [25, 32, 40, 38] ),
  Dict( "name" => "Elisa", "surname" => "White", "marks" => [40, 40, 36, 35] )
]

tmpl = """
\\documentclass{article}

\\begin{document}

Hello \\textbf{ {{name}}, {{surname}} }. Your marks are: 
\\begin{itemize}
  {{#marks}} 
    \\item Mark for question is {{.}} 
  {{/marks}}
\\end{itemize}
\\end{document}
"""

for student in students
  rendered = render(tmpl, student)
  filename = string("/tmp/", student["name"], "_", student["surname"], ".tex")
  open(filename, "w") do file
    write(file, rendered)
  end
  run(`pdflatex $filename`)
end

which results in:

enter image description here

like image 162
Matteo Ragni Avatar answered Oct 01 '22 01:10

Matteo Ragni