2. Decimals diagram - automated

The LaTeX in this section is for a diagram for addition or subtraction of decimals.
The values in the diagram can be randomly generated by python.
The required LaTeX and python files are:
The 2 custom python modules required are:
The python file, decimals_diagram_maker, when run, will ask for 3 inputs:
Choose the arithmetic process: "Enter 1, 2, or 3 for +, -, random for the process".
Choose the number of integer places: "Enter 0, 1, 2, 3, or 4 for the number of places before the decimal point".
Choose the number of decimal places: "Enter 1, 2, 3, 4, or 5 for the number of decimal places ".
Choose the file name base: "Enter the base filename to be added to the prefix asd_:".
The filename will have β€œ_q” added for the question diagram and β€œ_ans” for the answer diagram.

2.1. A decimals diagram with answers

addition_q

addition_ans

subtraction_q

subtraction_ans


2.2. Splitting the LaTeX and modifying it for python

The LaTeX file is built from 2 templates.
The Document template contains the preamble and the scaffold for the document.
The Diagram template contains the decimal diagram LaTeX.

2.2.1. Document template

The LaTeX document template is below.
1% decimals template
2\documentclass[border = 1mm]{standalone}
3\usepackage{siunitx}
4
5\sisetup{output-decimal-marker={.}}
6
7\begin{document}
8    <<diagram>>
9\end{document}
<<diagram>> is placeholder text for the text that python will use to add the LaTeX for the decimals diagram.

2.2.2. Diagram template

The LaTeX decimals diagram template is below.
The placeholders are marked by << >>.
1% decimals diagram template
2\begin{tabular}{c S[table-format=<<numip>>.<<numdp>>]}
3     &<<num1>> \tabularnewline
4    $<<process>>$&<<num2>> \tabularnewline
5    \hline
6     &<<answer>> \tabularnewline
7    \hline
8\end{tabular}

2.2.3. Python to create a decimals diagram

The Python to create a decimals diagram is below.
This script creates a LaTeX file with a diagram and converts it to PDF and PNG formats. It does the following steps:

decimals_diagram_maker.py

  1from pathlib import Path
  2import subprocess
  3import os
  4import time
  5import decimals_functions as decf
  6import magick_pdf_to_png
  7
  8
  9currfile_dir = Path(__file__).parent
 10tex_template_path = currfile_dir / "decimals_template.tex"
 11texans_template_path = currfile_dir / "decimals_template.tex"
 12tex_diagram_template_path = currfile_dir / "decimals_diagram_template.tex"
 13
 14
 15def convert_to_pdf(tex_path, outputdir):
 16    tex_path = Path(tex_path).resolve()
 17    outputdir = Path(outputdir).resolve()
 18    # for testing
 19    # print(f"tex_path: {tex_path}")
 20    # print(f"outputdir: {outputdir}")
 21    try:
 22        # Generate the PDF
 23        subprocess.run(["latexmk", "-pdf", "-outdir=" + str(outputdir), str(tex_path)], check=True, stdout=subprocess.DEVNULL, stderr=subprocess.DEVNULL)
 24        # # Clean auxiliary files after successful PDF generation
 25        subprocess.run(["latexmk", "-c", "-outdir=" + str(outputdir), str(tex_path)], check=True, stdout=subprocess.DEVNULL, stderr=subprocess.DEVNULL)
 26        # for hosted remove stdout=subprocess.DEVNULL, stderr=subprocess.DEVNULL for debugging any errors
 27        # Remove the .tex file manually
 28        if tex_path.exists():
 29            os.remove(tex_path)
 30    except subprocess.CalledProcessError as e:
 31        print(f"Error: {e}")
 32
 33
 34# tex_keys = ["num1", "num2", "process"]
 35tex_keys_q = ["answer"]
 36
 37
 38def make1_diagram(tex_diagram_template_txt, nump, numip, numdp):
 39    tex_diagram_template_txt_ans = tex_diagram_template_txt
 40    kv = decf.get_dec_dict(nump, numip, numdp)
 41
 42    for key, value in kv.items():
 43        tex_diagram_template_txt_ans = tex_diagram_template_txt_ans.replace(
 44            "<<" + key + ">>", value
 45        )
 46
 47    for key, value in kv.items():
 48        if key in tex_keys_q:
 49            tex_diagram_template_txt = tex_diagram_template_txt.replace(
 50                "<<" + key + ">>", ""
 51            )
 52        else:
 53            tex_diagram_template_txt = tex_diagram_template_txt.replace(
 54                "<<" + key + ">>", value
 55            )
 56    tex_diagram_template_txt = tex_diagram_template_txt.replace("<<numip>>", str(numip))
 57    tex_diagram_template_txt = tex_diagram_template_txt.replace("<<numdp>>", str(numdp))
 58    tex_diagram_template_txt_ans = tex_diagram_template_txt_ans.replace("<<numip>>", str(numip))
 59    tex_diagram_template_txt_ans = tex_diagram_template_txt_ans.replace("<<numdp>>", str(numdp))
 60    # return tex_diagram_template_txt
 61    return tex_diagram_template_txt, tex_diagram_template_txt_ans
 62
 63
 64def main():
 65    nump = input("Enter 1, 2, or 3 for +, -, random for the process \n")
 66    if nump.strip().isdigit():
 67        nump = int(nump)
 68        if not nump in [1, 2]:
 69            nump = 3  # random by default
 70    else:
 71        nump = 3  # random by default
 72    #
 73    numip = input("Enter 0, 1, 2, 3, or 4 for the number of places before the decimal point \n")
 74    if numip.strip().isdigit():
 75        numip = int(numip)
 76        if not numip in [0, 1, 2, 3, 4]:
 77            numip = 1  # 1 by default
 78    else:
 79        numip = 1  # 1 by default
 80    #
 81    numdp = input("Enter 1, 2, 3, 4, or 5 for the number of decimal places \n")
 82    if numdp.strip().isdigit():
 83        numdp = int(numdp)
 84        if not numdp in [1, 2, 3, 4, 5]:
 85            numdp = 1  # 1 by default
 86    else:
 87        numdp = 1  # 1 by default
 88    #
 89    filename = input("Enter the base filename to be added to the prefix asd_: \n")
 90    if not filename:
 91        filename = "1"  # "asd_1_q and asd_1_ans as default file"
 92    # set names of files that are made
 93    # questions
 94    tex_output_path = currfile_dir / f"asd_{filename}_q.tex"
 95    pdf_path = currfile_dir / f"asd_{filename}_q.pdf"
 96    png_path = currfile_dir / f"asd_{filename}_q.png"
 97
 98    # answers
 99    tex_output_path_ans = currfile_dir / f"asd_{filename}_ans.tex"
100    pdf_path_ans = currfile_dir / f"asd_{filename}_ans.pdf"
101    png_path_ans = currfile_dir / f"asd_{filename}_ans.png"
102
103
104    # Read in the LaTeX template file
105    with open(tex_template_path, "r") as infile:
106        tex_template_txt = infile.read()
107    # Read in the LaTeX template file for answers
108    with open(texans_template_path, "r") as infile:
109        tex_template_txt_ans = infile.read()
110    # Read in the LaTeX diagram template file
111    with open(tex_diagram_template_path, "r") as infile:
112        tex_diagram_template_txt = infile.read()
113
114    # Generate the <<diagram>> replacement tex
115    diagram_text, diagram_text_ans = make1_diagram(tex_diagram_template_txt, nump, numip, numdp)
116    # Replace the <<diagram>> placeholder in the LaTeX template
117    tex_template_txt = tex_template_txt.replace("<<diagram>>", diagram_text)
118    tex_template_txt_ans = tex_template_txt_ans.replace("<<diagram>>", diagram_text_ans)
119    # Write the question diagram tex to an output file
120    with open(tex_output_path, "w") as outfile:
121        outfile.write(tex_template_txt)
122    # Write the answer diagram tex to an output file
123    with open(tex_output_path_ans, "w") as outfile:
124        outfile.write(tex_template_txt_ans)
125
126    # Wait for the files to be created
127    time.sleep(1)
128    # convert to pdf
129    convert_to_pdf(tex_output_path, currfile_dir)
130    convert_to_pdf(tex_output_path_ans, currfile_dir)
131
132    # Wait for the files to be created
133    time.sleep(1)
134    # convert to png
135    magick_pdf_to_png.convert_pdf_to_png(pdf_path, png_path)
136    magick_pdf_to_png.convert_pdf_to_png(pdf_path_ans, png_path_ans)
137
138
139if __name__ == "__main__":
140    print("starting")
141    main()
142    print("finished")