JSON to PDF Magic: Harnessing LaTeX and JSON for Effortless Customization and Dynamic PDF Generation

21 April 2023 Igor Rodionov
JSON to PDF Process
DynamicDocs API converts JSON to PDF to generate dynamic PDFs

In this article, we show how to control the layout and content of the PDF document via the JSON body of the API call. We present three different JSON examples and produce three different types of documents using the same end-point. In each case, making changes to the PDF is done by editing the JSON payload. To do this, we utilise the power of LaTeX to control the layout of the PDF document.

What is LaTeX?

LaTeX is a programming language specifically designed for creating PDF documents. Source files in LaTeX have a .tex extension and are usually compiled into PDF format. While it's highly popular in academia for crafting dissertations and scholarly articles, LaTeX is also excellent for producing visually appealing documents. Its strength lies in the separation of content and stylistic rules, allowing for precise control over the document's appearance. However, a significant drawback of LaTeX is the steep learning curve involved in mastering the language for document layout.

PDF Generation via JSON to PDF

In many cases, PDF generation requirements change, and developers need to perform additional development by changing the PDF template and then ensuring the new design/changes works as expected. This process can be time-consuming. We introduce a new template called General JSON to PDF Template which lets API users change the layout and content in one source, the JSON body of the API call. By simply changing the JSON to create a different output, developers do not need to alter templates. This simplifies the PDF generation process and gives developers an edge.

Getting Started

To get started we will use General JSON to PDF Template end-point:

https://api.advicement.io/v1/templates/pub-general-json-to-pdf-template-v1/compile

The corresponding JSON payload structure for the end-point is as follows:

{ "documentSettings": { "font": "roboto", "fontSize": 8, "primaryHEXColour": "343D49", "secondaryHEXColour": "0dbb72", "textHEXColour": "444444", "documentName": "General JSON to PDF Template from ADVICEment", "topMargin": "-0.1cm", "rightMargin": "1cm", "bottomMargin": "-0.1cm", "leftMargin": "1cm", "headheight": "3.13cm", "headsep": "0.5cm", "footskip": "1.5cm", "includehead": true, "includefoot": true, "showframe": true, "header": { "headerLine": false, "leftContent": "", "centerContent": "\\begin{tikzpicture}[remember picture,overlay] \\node at ([xshift=0.00cm, yshift=-1.5cm]current page.north) {\\bfseries\\color{black}\\Huge{HEADER}}; \\end{tikzpicture}", "rightContent": "", "adjustMargin": "1cm" }, "footer": { "footerLine": false, "leftContent": "", "centerContent": "\\begin{tikzpicture}[remember picture,overlay] \\node at ([xshift=0.00cm, yshift=0.75cm]current page.south) {\\bfseries\\color{black}\\Huge{FOOTER}}; \\end{tikzpicture}", "rightContent": "", "adjustMargin": "1cm" }, "latexPreamble": "\\definecolor{Blue}{HTML}{00FFFF}" }, "documentContent": { "content": [ { "type": "latex", "content": "Some content here with LaTeX commands", "order": 1 } ] } }

This JSON object contains two main keys: "documentSettings" and "documentContent". It is a configuration file for generating a PDF document using LaTeX, a typesetting system used for creating high-quality documents. The "documentSettings" key describes various settings for the document, such as font, font size, colors, margins, header/footer details, while "documentContent" key describes the layout of the document using LaTeX commands.

  1. "documentSettings": This key contains an object with properties related to the overall document settings.

    • "font": An optional string which contains the font of the document. Possible options are: 'helvetica', 'avant garde', 'sans serif', 'charter', 'open sans', 'bera', 'venturis', 'raleway', 'overlock', 'roboto', 'spectral', 'clear sans', 'noto sans', 'noto mono', 'josefin', 'bera sans', 'latin modern', 'theano modern', 'droid sans', 'fira sans', 'XCharter', 'bookman', 'gyre bonum', 'gyre schola', 'gyre termes'.

    • "fontSize": An optional integer which contains the font size of the document. Possible options are: 8, 9, 10, 11, 12, 14.

    • "primaryHEXColour", "secondaryHEXColour", "textHEXColour": Define the primary, secondary, and text colors using their respective HEX codes.

    • "documentName": Sets the document name to "General JSON to PDF Template from ADVICEment".

    • "topMargin", "rightMargin", "bottomMargin", "leftMargin": Define the margins of the document.

    • "headheight", "headsep", "footskip": Define the header height, header separation, and footer skip values.

    • "includehead", "includefoot": Specify whether to include the header and footer in the document.

    • "showframe": Indicates whether to display the frame around the document.

    • "header" and "footer": Define the properties of the header and footer, such as:

      • "headerLine" and "footerLine": Specify whether to display a line for the header and footer.

      • "leftContent", "centerContent", "rightContent": Define the content for the left, center, and right parts of the header and footer.

      • "adjustMargin": Sets the margin adjustment for the header and footer.

    • "latexPreamble": Contains LaTeX commands which are included before '\begin{document}' in the LaTeX file.

  2. "documentContent": This key contains an object with a "content" property that holds an array of content elements to be included in the document.

    • "type": Specifies the content type, in this case, "latex". Possible options are: 'heading', 'section', 'subsection', 'paragraph', 'newpage', 'enumerate', 'itemize', 'kable' and 'chart'.

    • "content": Contains the LaTeX-formatted content to be included in the document.

    • "order": Specifies the order in which the content should appear.

In summary, this JSON object defines a configuration for a PDF document created using LaTeX. The document settings include font, font size, colors, margins, header/footer configurations, and a custom color defined in the LaTeX preamble. The document content is specified as an array of elements, each with a type, content, and order.

JSON to PDF with Dynamic Images

In this section, we provide both an image of the PDF and the corresponding JSON body of the API call used to generate it. By examining these two elements next to each other, you can gain a deeper understanding of how the JSON structure influences the final PDF output. This hands-on approach offers valuable insights into the versatility and power of using JSON to control the layout and content of your PDF documents through API calls.

PDF Contract Example
DynamicDocs API converts JSON to PDF to generate PDFs with dynamic images. An example of the dynamic image is the logo in the PDF above.

{ "documentSettings": { "font": "open sans", "fontSize": 8, "primaryHEXColour": "343D49", "secondaryHEXColour": "0dbb72", "textHEXColour": "444444", "documentName": "Contract Template from ADVICEment", "topMargin": "0.5cm", "rightMargin": "1cm", "bottomMargin": "0.5cm", "leftMargin": "1cm", "headheight": "1.25cm", "headsep": "0.75cm", "footskip": "1.0cm", "includehead": true, "includefoot": true, "showframe": false, "header": { "headerLine": true, "leftContent": "", "centerContent": "\\advGetImage{key = logo, typeKey=logoType, widthKey = logoWidth}\\medskip", "rightContent": "" }, "footer": { "footerLine": true, "leftContent": "", "centerContent": "\\thepage", "rightContent": "" }, "latexPreamble": "\\setcounter{tocdepth}{5} \\setcounter{secnumdepth}{5} \\renewcommand{\\thesection}{\\arabic{section}}" }, "documentContent": { "content": [ { "type": "latex", "content": "\\smallskip {\\huge \\bfseries Business Contract Template} \\par \\smallskip", "order": 1 }, { "type": "section", "content": "Introduction", "order": 2 }, { "type": "paragraph", "content": "Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.", "order": 2 }, { "type": "latex", "content": "\\medskip", "order": 3 }, { "type": "paragraph", "content": "Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.", "order": 4 }, { "type": "subsection", "content": "Terms", "order": 5 }, { "type": "latex", "content": "\\begin{itemize} \\item \\textbf{Agreement} - Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. \\item \\textbf{Partner} - Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. \\item \\textbf{Result} - Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. \\item \\textbf{User} - Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. \\end{itemize}", "order": 5.5 }, { "type": "subsubsection", "content": "Extra Terns", "order": 6 }, { "type": "latex", "content": "\\begin{itemize} \\item \\textbf{Agreement} - Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. \\item \\textbf{Partner} - Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. \\item \\textbf{Result} - Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. \\item \\textbf{User} - Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. \\end{itemize}", "order": 7 }, { "type": "section", "content": "General Provisions", "order": 8 }, { "type": "paragraph", "content": "Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum. At vero eos et accusamus et iusto odio dignissimos ducimus qui blanditiis praesentium voluptatum deleniti atque corrupti quos dolores et quas molestias excepturi sint occaecati cupiditate non provident, similique sunt in culpa qui officia deserunt mollitia animi, id est laborum et dolorum fuga. Et harum quidem rerum facilis est et expedita distinctio. Nam libero tempore, cum soluta nobis est eligendi optio cumque nihil impedit quo minus id quod maxime placeat facere possimus, omnis voluptas assumenda est, omnis dolor repellendus. Temporibus autem quibusdam et aut officiis debitis aut rerum necessitatibus saepe eveniet ut et voluptates repudiandae sint et molestiae non recusandae. Itaque earum rerum hic tenetur a sapiente delectus, ut aut reiciendis voluptatibus maiores alias consequatur aut perferendis doloribus asperiores repellat. At vero eos et accusamus et iusto odio dignissimos ducimus qui blanditiis praesentium voluptatum deleniti atque corrupti quos dolores et quas molestias excepturi sint occaecati cupiditate non provident, similique sunt in culpa qui officia deserunt mollitia animi, id est laborum et dolorum fuga. Et harum quidem rerum facilis est et expedita distinctio. Nam libero tempore, cum soluta nobis est eligendi optio cumque nihil impedit quo minus id quod maxime placeat facere possimus, omnis voluptas assumenda est, omnis dolor repellendus. Temporibus autem quibusdam et aut officiis debitis aut rerum necessitatibus saepe eveniet ut et voluptates repudiandae sint et molestiae non recusandae. Itaque earum rerum hic tenetur a sapiente delectus, ut aut reiciendis voluptatibus maiores alias consequatur aut perferendis doloribus asperiores repellat.", "order": 9 }, { "type": "latex", "content": "\\medskip", "order": 9.5 }, { "type": "paragraph", "content": "Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum. At vero eos et accusamus et iusto odio dignissimos ducimus qui blanditiis praesentium voluptatum deleniti atque corrupti quos dolores et quas molestias excepturi sint occaecati cupiditate non provident, similique sunt in culpa qui officia deserunt mollitia animi, id est laborum et dolorum fuga. Et harum quidem rerum facilis est et expedita distinctio. Nam libero tempore, cum soluta nobis est eligendi optio cumque nihil impedit quo minus id quod maxime placeat facere possimus, omnis voluptas assumenda est, omnis dolor repellendus. Temporibus autem quibusdam et aut officiis debitis aut rerum necessitatibus saepe eveniet ut et voluptates repudiandae sint et molestiae non recusandae. Itaque earum rerum hic tenetur a sapiente delectus, ut aut reiciendis voluptatibus maiores alias consequatur aut perferendis doloribus asperiores repellat. At vero eos et accusamus et iusto odio dignissimos ducimus qui blanditiis praesentium voluptatum deleniti atque corrupti quos dolores et quas molestias excepturi sint occaecati cupiditate non provident, similique sunt in culpa qui officia deserunt mollitia animi, id est laborum et dolorum fuga. Et harum quidem rerum facilis est et expedita distinctio. Nam libero tempore, cum soluta nobis est eligendi optio cumque nihil impedit quo minus id quod maxime placeat facere possimus, omnis voluptas assumenda est, omnis dolor repellendus. Temporibus autem quibusdam et aut officiis debitis aut rerum necessitatibus saepe eveniet ut et voluptates repudiandae sint et molestiae non recusandae. Itaque earum rerum hic tenetur a sapiente delectus, ut aut reiciendis voluptatibus maiores alias consequatur aut perferendis doloribus asperiores repellat.", "order": 10 }, { "type": "latex", "content": "\\bigskip \\begin{tikzpicture} \\node (block) [rectangle, thick, draw=lightgray, fill=white, anchor=north west, inner sep=1,outer sep =1, minimum width = 19cm, minimum height = 3.0cm] at (0,0) {}; \\draw [black,thick] ([yshift=1cm,xshift=0.5cm]block.south west)--([yshift=1cm,xshift=5cm]block.south west); \\node [anchor=center] at ([yshift=0.5cm, xshift=2.75cm]block.south west) {Signature 1}; \\draw [black,thick] ([yshift=1cm,xshift=-0.5cm]block.south east)--([yshift=1cm,xshift=-5cm]block.south east); \\node [anchor=center] at ([yshift=0.5cm, xshift=-2.75cm]block.south east) {Signature 2}; \\end{tikzpicture}", "order": 11 } ] }, "logo": "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", "logoType": "png", "logoWidth": "4.5cm" }

The \\advGetImage function in the JSON file is used to dynamically insert images into the generated PDF. The function appears in the "header" section of the JSON file, indicating that it is used to display a logo in the header of the PDF document.

The \\advGetImage function has the following parameters:

  • key: Represents the key to access the image data (base64-encoded string) in the JSON. In this case, the key is "logo".

  • typeKey: Represents the key to access the image type (e.g., PNG, JPEG) in the JSON. In this case, the key is "logoType".

  • widthKey: Represents the key to access the image width in the JSON. In this case, the key is "logoWidth".

When the PDF is generated, the \\advGetImage function retrieves the image data, type, and width from the JSON file using the provided keys. Then, it embeds the image into the PDF document with the specified width, maintaining the aspect ratio of the original image.

JSON to PDF with Dynamic Tables

In this section, we provide both an image of the PDF and the corresponding JSON body of the API call used to generate it. As shown below this PDF contains dynamic tables which are discussed in this secion.

PDF Invoice Example
DynamicDocs API converts JSON to PDF to generate PDFs with dynamic tables. The PDF above contains three dynamic tables.

{ "documentSettings": { "font": "clear sans", "fontSize": 8, "primaryHEXColour": "343D49", "secondaryHEXColour": "0dbb72", "textHEXColour": "444444", "documentName": "Invoice Template from ADVICEment", "topMargin": "0.5cm", "rightMargin": "1cm", "bottomMargin": "0.5cm", "leftMargin": "1cm", "headheight": "1.25cm", "headsep": "0.75cm", "footskip": "1.0cm", "includehead": true, "includefoot": true, "showframe": false, "header": { "headerLine": true, "leftContent": "\\advGetImage{key = logo, typeKey=logoType, widthKey = logoWidth}\\medskip", "centerContent": "", "rightContent": "\\color{gray} \\Huge Invoice #: 123456789 \\vspace{0.4cm}" }, "footer": { "footerLine": true }, "latexPreamble": "\\usepackage{anyfontsize} \\definecolor{Facebook}{HTML}{3B5998} \\definecolor{Twitter}{HTML}{00ACEE}" }, "documentContent": { "content": [ { "type": "latex", "content": "\\renewcommand{\\arraystretch}{1.5}", "order": 0 }, { "type": "latex", "content": "\\begin{multicols}{2}", "order": 1 }, { "type": "kable", "content": "kable(data.frame(lapply(params$firstColumnData,latexifyWithCommands)), escape = FALSE, format = 'latex', format.args = list(scientific = FALSE, big.mark = ' '), col.names = c('Invoice Details', ''), align = c('L{4cm}','R{4cm}'),booktabs = T, bottomrule = '',toprule = '',midrule = '',linesep = '') %>% row_spec(0, bold = T, color = 'white', background = 'Secondary') %>% kable_styling(font_size = 9) %>% stri_replace_all_fixed('\\\\begin{table}', '') %>% stri_replace_all_fixed('\\\\end{table}', '')" , "order": 2 }, { "type": "latex", "content": "\\columnbreak", "order": 3 }, { "type": "kable", "content": "kable(data.frame(lapply(params$secondColumnData,latexifyWithCommands)), escape = FALSE, format = 'latex', format.args = list(scientific = FALSE, big.mark = ' '), col.names = c('Payee Details', ''), align = c('L{4cm}','R{4cm}'),booktabs = T, bottomrule = '',toprule = '',midrule = '',linesep = '') %>% row_spec(0, bold = T, color = 'white', background = 'Secondary') %>% kable_styling(font_size = 9) %>% stri_replace_all_fixed('\\\\begin{table}', '') %>% stri_replace_all_fixed('\\\\end{table}', '')", "order": 4 }, { "type": "latex", "content": "\\end{multicols}", "order": 5 }, { "type": "latex", "content": "\\vspace{1cm} \\begin{center} \\color{gray} \\Huge Invoice Details \\end{center} ", "order": 6 }, { "type": "kable", "content": "kable(data.frame(lapply(params$invoiceDetailsData,latexifyWithCommands)), escape = FALSE, format = 'latex', format.args = list(scientific = FALSE, big.mark = ' '), col.names = c('Description', 'Amount'), align = c('|L{7.5cm}','R{7.5cm}|'),booktabs = T, longtable=T, bottomrule = '',toprule = '\\\\hline',midrule = '',linesep = '') %>% row_spec(0, bold = T, color = 'white', background = 'Secondary', hline_after = T) %>% kable_styling(font_size = 9) %>% kable_styling(latex_options = 'hold_position') %>% row_spec(c( nrow(params$invoiceDetailsData)-1,nrow(params$invoiceDetailsData)), hline_after = T)", "order": 7 }, { "type": "latex", "content": "\\vfill", "order": 8 }, { "type": "latex", "content": "\\begin{multicols}{2}", "order": 9 }, { "type": "latex", "content": "{\\color{gray} \\Huge Important Info \\bigskip} \\begin{itemize} \\item Please retain this invoice for your records. \\item Note that this invoice is based on the actual hours it took to do the cleaning.\\item To view your booking history, go to account bookings.\\item To update your card details, go to account cards. \\item In case of any questions, please consult our Help Centre. \\end{itemize} \\bigskip \\textbf{Thank you for your ongoing support!}", "order": 10 }, { "type": "latex", "content": "\\columnbreak", "order": 11 }, { "type": "latex", "content": "{\\color{gray} \\Huge Connect With Us \\bigskip}", "order": 12 }, { "type": "latex", "content": "\\vspace{-0.1cm} \\fbox{\\parbox{.45\\textwidth}{\\centering\\medskip \\fcolorbox{black}{Facebook}{\\hspace{8mm}{\\large \\color{White}{\\href{https://www.facebook.com}{\\textbf{Facebook}}}}\\hspace{5mm}} \\ \\medskip{\\centering\\fcolorbox{black}{Twitter}{\\hspace{10.5mm}{\\large \\color{White}{\\href{https://twitter.com}{\\textbf{Twitter}}}\\hspace{10.5mm}}}}\\par \\bigskip{\\Large Contact Info:\\par}\\medskip Phone : \\textbf{082-123-4567} \\par \\smallskip Email: \\color{gray!95} support@info.com \\par \\hspace{8mm}}}", "order": 13 }, { "type": "latex", "content": "\\end{multicols}", "order": 14 } ] }, "firstColumnData": [ { "column1": "Invoice Date", "column2": "2023-03-01" }, { "column1": "Invoice Issued By", "column2": "Company (Pty) Ltd" }, { "column1": "", "column2": "" }, { "column1": "On Behalf Of:", "column2": "123 Street" }, { "column1": "", "column2": "Cnr Edith Cavell and Kapteijn" }, { "column1": "", "column2": "Hillbrow" }, { "column1": "", "column2": "Johannebsurg" }, { "column1": "", "column2": "South Africa" }, { "column1": "", "column2": "2001" } ], "secondColumnData": [ { "column1": "Invoice Issued To", "column2": "John Smith" }, { "column1": "", "column2": "info@gmail.com" }, { "column1": "", "column2": "" }, { "column1": "Address", "column2": "123 Street" }, { "column1": "", "column2": "Cnr Edith Cavell and Kapteijn" }, { "column1": "", "column2": "Hillbrow" }, { "column1": "", "column2": "Johannebsurg" }, { "column1": "", "column2": "South Africa" }, { "column1": "", "column2": "2001" } ], "invoiceDetailsData": [ { "column1": "PDF Generation - Monthly Cost", "column2": "$ 499" }, { "column1": "Template Setup", "column2": "$ 1000" }, { "column1": "Tax", "column2": "$ 65" }, { "column1": "\\textbf{Total}", "column2": "\\textbf{$ 1 564}" } ], "logo": "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", "logoType": "png", "logoWidth": "4.5cm" }

The dynamic tables in the JSON are generated using the kable function from the R package knitr. kable is used to create tables in LaTeX format within the 'documentContent' array.

For example, the first table is generated with the following code:

{
  "type": "kable",
  "content": "kable(data.frame(lapply(params$firstColumnData,latexifyWithCommands)), escape = FALSE, format = 'latex', format.args = list(scientific = FALSE, big.mark = ' '), col.names = c('Invoice Details', ''),  align = c('L{4cm}','R{4cm}'),booktabs = T, bottomrule = '',toprule = '',midrule = '',linesep = '') %>% row_spec(0, bold = T, color = 'white', background = 'Secondary') %>% kable_styling(font_size = 9) %>% stri_replace_all_fixed('\\\\begin{table}', '') %>% stri_replace_all_fixed('\\\\end{table}', '')" ,
  "order": 2
}
						

This code creates a table with two columns, 'Invoice Details' and an empty column header. The table is constructed from the data in 'firstColumnData' in the JSON using params$firstColumnData. The latexifyWithCommands function is applied to each element of this list to ensure proper LaTeX formatting.

Additionally, some table formatting options are set, such as:

  • 'escape = FALSE': Prevents escaping of special characters in the table

  • format = 'latex': Specifies that the table should be output in LaTeX format

  • align = c('L{4cm}','R{4cm}'): Sets the alignment of the columns

The table is further styled using the kableExtra package. For example, row_spec(0, bold = T, color = 'white', background = 'Secondary') specifies that the first row should be bold, with white text and a background color defined by 'Secondary'. The table is stripped of the default \\begin{table} and \\end{table} LaTeX commands using stri_replace_all_fixed.

A similar process is followed for generating the other tables within the 'documentContent' array, with the corresponding data sources in the JSON ('secondColumnData', 'invoiceDetailsData') being used to create the content of each table.

For more information on how to use kable and create tables consult the Create Awesome LaTeX Table with knitr::kable and kableExtra document.

JSON to PDF with Dynamic Charts

In this section, we provide both an image of the PDF and the corresponding JSON body of the API call used to generate a report. As shown below this PDF contains dynamic charts which are discussed in this secion.

PDF Invoice Example
DynamicDocs API converts JSON to PDF to generate PDFs with dynamic charts. The PDF above contains two dynamic charts.

{ "documentSettings": { "font": "roboto", "fontSize": 8, "primaryHEXColour": "343D49", "secondaryHEXColour": "0dbb72", "textHEXColour": "444444", "documentName": "Report Template from ADVICEment", "topMargin": "-0.1cm", "rightMargin": "1cm", "bottomMargin": "-0.1cm", "leftMargin": "1cm", "headheight": "3.13cm", "headsep": "0.5cm", "footskip": "1.5cm", "includehead": true, "includefoot": true, "showframe": false, "header": { "headerLine": false, "leftContent": "\\begin{tikzpicture} \\node (rectange) [rectangle, shading = axis, shading angle=135, left color=Primary, right color=Secondary, anchor=south west, inner sep=0,outer sep =0, fill = Primary, minimum width = 21cm, minimum height = 3.0cm] at ([xshift=0.0cm, yshift=0cm]current page.north west) {}; \\node[right] at ([xshift=0.90cm, yshift=-0.9cm]rectange.north west) {\\bfseries\\color{white}\\huge{Report Template by ADVICEment}}; \\node[right] at ([xshift=0.90cm, yshift=-1.675cm]rectange.north west) {\\color{white}\\LARGE April 2023}; \\node (subtitle) [minimum width=11cm, anchor=north west, text width=11cm, inner sep=0.0cm, outer sep=0] at ([xshift=1.00cm, yshift=-2.25cm]rectange.north west) {\\color{white}\\normalsize\\bfseries{Best Dynamic PDF Generation} }; \\node (logo) [left] at ([xshift=-0.99cm, yshift=-1.5cm]rectange.north east) {\\advGetImage{key = logo, typeKey=logoType, widthKey = logoWidth}}; \\end{tikzpicture}", "centerContent": "", "rightContent": "", "adjustMargin": "1cm" }, "footer": { "footerLine": false, "leftContent": "\\begin{tikzpicture} \\node (rectange) [rectangle, shading = axis, shading angle=135, left color=Primary, right color=Secondary, anchor=south west, inner sep=0,outer sep =0, fill = Primary, minimum width = 21cm, minimum height = 1.0cm] at ([xshift=0.0cm, yshift=0cm]current page.south west) {}; \\node[right] at ([xshift=0.90cm, yshift=0.5cm]rectange.south west) {\\bfseries\\color{white}\\tiny{Legal notice goes here and other fun things}}; \\end{tikzpicture}", "centerContent": "", "rightContent": "", "adjustMargin": "1cm" }, "latexPreamble": " \\usepackage{lipsum} \\usepackage{paracol}" }, "documentContent": { "content": [ { "type": "latex", "content": "\\sloppy", "order": 1 }, { "type": "latex", "content": "\\columnratio{0.65,0.35} \\begin{paracol}{2} \\begin{leftcolumn}", "order": 2 }, { "type": "section", "content": "Description", "order": 3 }, { "type": "paragraph", "content": "\\lipsum[1]", "order": 4 }, { "type": "section", "content": "Cumulative Chart", "order": 5 }, { "type": "chart", "content": "ggplot(data=params$performanceGraph)+geom_line(aes(x=as.Date(Date), y=CumulativeBenchmarkReturn, color =' Benchmark ' ), linetype='solid', size=1)+geom_line(aes(x=as.Date(Date), y=CumulativeFundReturn, color =' Fund '), linetype='solid', size=1)+scale_colour_manual(breaks = c(' Fund ',' Benchmark '), values=c('#343D49','#0dbb72')) +theme_economist()+theme(panel.background = element_rect(fill = '#FFFFFF', colour = '#FFFFFF'),plot.background = element_rect(fill = '#FFFFFF', colour = '#FFFFFF'),axis.title.x=element_blank()) +theme(panel.grid.major = element_line(colour = '#A7A8AA', size=0.5))+theme(panel.grid.minor = element_blank())+theme(axis.line = element_line(colour = '#A7A8AA', size = 0.5)) +theme(axis.text = element_text(size = 12, colour = '#28334A'))+theme(axis.text.x = element_text(angle = 90, vjust = 0.5)) +theme(axis.ticks.x = element_line(colour = '#A7A8AA', size = 0.5))+theme(legend.position='bottom', legend.title=element_blank(),legend.background=element_rect(fill = '#FFFFFF', colour = '#FFFFFF'))+ theme(legend.text=element_text(size=16,color='#58595b'))+theme(legend.key = element_rect(fill = 'white'))+theme(axis.title.y=element_text(colour = '#28334A',size=12,margin=unit(c(0,0.2,0,0.2),units='cm'))) +theme(axis.title.y = element_blank()) +theme(legend.spacing=unit(0.1, units = 'cm'),legend.margin=margin(t = 0.1, unit='cm')) +scale_x_date(breaks = seq(as.Date('2004-06-30'), as.Date('2050-06-30'), by='6 months'), labels=date_format('%b-%Y'), expand = c(0.1, 0.1))+scale_y_continuous(breaks = pretty(c(params$performanceGraph$CumulativeFundReturn,params$performanceGraph$CumulativeBenchmarkReturn),n=8),labels=dollar_format(prefix='',big.mark = ' '))", "order": 5, "height": 4, "width": 10 }, { "type": "section", "content": "Asset Allocation", "order": 6 }, { "type": "chart", "content": "ggplot(params$assetAllocationChart,aes(x = factor(Name, levels = params$assetAllocationChart$Name), y = Weight))+geom_bar(stat='identity', position=position_dodge(width=1), width = 0.75, fill = '#0dbb72')+geom_label(aes(label = Label), fill = 'white', colour = 'black', position= position_dodge(width=1), size = 5) +theme_economist()+scale_colour_economist()+theme(legend.position='bottom')+theme(legend.position='bottom', legend.direction = 'horizontal', legend.title=element_blank(),legend.background=element_rect(fill = '#FFFFFF', colour = '#FFFFFF'),legend.box.background=element_rect(fill = '#FFFFFF', colour = '#FFFFFF'),legend.key=element_rect(fill = '#FFFFFF', colour = '#FFFFFF'))+theme(legend.text=element_text(size=12,color='#2D2323',face='plain'))+guides(fill = guide_legend(nrow = 1))+theme(panel.background = element_rect(fill = '#FFFFFF', colour = '#FFFFFF'),plot.background = element_rect(fill = '#FFFFFF', colour = '#FFFFFF')) +theme(panel.grid.major = element_line(colour = 'lightgrey', size=0.5))+theme(panel.grid.minor = element_blank())+theme(axis.title.x=element_blank()) +theme(axis.title.y=element_text(colour = '#2D2323',size=12,margin=unit(c(0.0,0.25,0.0,0.25),units='cm'))) +theme(legend.spacing.x = unit(0.1, 'cm'))+theme(axis.text = element_text(size=12,color='#2D2323', face='plain'))+theme(axis.title = element_text(size=12,color='#2D2323', face='plain'))+scale_y_continuous(breaks = pretty(c(params$assetAllocationChart$Weight),n=6),labels=percent_format(accuracy = 0.1))+labs(y='Weight')+coord_cartesian(clip = 'off')", "order": 7, "height": 3.5, "width": 10 }, { "type": "section", "content": "Overview", "order": 8 }, { "type": "paragraph", "content": "\\lipsum[2-4]", "order": 9 }, { "type": "latex", "content": "\\end{leftcolumn} \\begin{rightcolumn} \\begin{tcolorbox}[colback=White,colframe=Secondary,width=6.3cm] \\color{TextColour} \\setlength{\\tabcolsep}{0pt} \\renewcommand{\\arraystretch}{2.75}", "order": 10 }, { "type": "section", "content": "Summary", "order": 11 }, { "type": "kable", "content": "kable(data.frame(lapply(params$infoTable,latexifyWithCommands)), escape = FALSE, format = 'latex', format.args = list(scientific = FALSE, big.mark = ' '), col.names = NULL, align = c('L{2.0cm}','R{3.00cm}'),booktabs = T,bottomrule = '',toprule = '',midrule = '',linesep = '')", "order": 12 }, { "type": "latex", "content": "\\end{tcolorbox} \\end{rightcolumn}", "order": 13 }, { "type": "latex", "content": " \\end{paracol}", "order": 14 } ] }, "infoTable": [ { "Column1": "\\textbf{Company}", "Column2": "XX Technologies Private Limited" }, { "Column1": "\\textbf{Sponsor}", "Column2": "YYY" }, { "Column1": "\\textbf{Key Persons}", "Column2": "John Smith \\newline Jan Van Der Merwe" }, { "Column1": "\\textbf{Existing Shareholders}", "Column2": "ZZZ" }, { "Column1": "\\textbf{Investor}", "Column2": "Mr Smith" }, { "Column1": "\\textbf{Type of Security}", "Column2": "Ordinary Bonds" }, { "Column1": "\\textbf{Pre-money Valuation}", "Column2": "$ 1 000 000" }, { "Column1": "\\textbf{Amount of Financing}", "Column2": "$ 500 000" }, { "Column1": "\\textbf{Investment conditions}", "Column2": "Condition 1 \\newline Condition 2 \\newline Condition 3" }, { "Column1": "\\textbf{Capitalization}", "Column2": "The pre-financing and post-financing capital structure will be as set forth in the table." }, { "Column1": "\\textbf{Closing Date}", "Column2": "1st December 2023" }, { "Column1": "\\textbf{Board of Directors}", "Column2": "Paul Smith \\newline Greg Smith" }, { "Column1": "\\textbf{Dividends}", "Column2": "The holders of the Preference shares, shall be entitled to receive non-cumulative dividends in preference to holders of Equity Shares at the rate of 1%." }, { "Column1": "\\textbf{Exit Rights}", "Column2": "The Company shall make best efforts to provide the Investor an exit within 60 months." }, { "Column1": "\\textbf{Due Diligence}", "Column2": "Yes" } ], "performanceGraph": [ { "Date": "2017-11-30", "Benchmark": -0.97267, "Fund": -0.63828, "CumulativeFundReturn": 100, "CumulativeBenchmarkReturn": 100 }, { "Date": "2017-12-31", "Benchmark": 5.65561, "Fund": 5.48700, "CumulativeFundReturn": 111.874435153, "CumulativeBenchmarkReturn": 109.896525389 }, { "Date": "2018-01-31", "Benchmark": 1.85912, "Fund": 1.93257, "CumulativeFundReturn": 114.036486924, "CumulativeBenchmarkReturn": 111.939633672 }, { "Date": "2018-02-28", "Benchmark": 3.93107, "Fund": 4.04714, "CumulativeFundReturn": 118.651703201, "CumulativeBenchmarkReturn": 116.340059029 }, { "Date": "2018-03-31", "Benchmark": 2.07089, "Fund": 2.27211, "CumulativeFundReturn": 121.347600415, "CumulativeBenchmarkReturn": 118.749333677 }, { "Date": "2018-04-30", "Benchmark": -0.70247, "Fund": -0.63793, "CumulativeFundReturn": 120.573487668, "CumulativeBenchmarkReturn": 117.915155233 }, { "Date": "2018-05-31", "Benchmark": -1.95493, "Fund": -2.07087, "CumulativeFundReturn": 118.076567484, "CumulativeBenchmarkReturn": 115.609996489 }, { "Date": "2018-06-30", "Benchmark": -1.16986, "Fund": -0.99037, "CumulativeFundReturn": 116.907172583, "CumulativeBenchmarkReturn": 114.257521384 }, { "Date": "2018-07-31", "Benchmark": 2.41846, "Fund": 2.50782, "CumulativeFundReturn": 119.838994038, "CumulativeBenchmarkReturn": 117.020793836 }, { "Date": "2018-08-31", "Benchmark": -1.86541, "Fund": -1.97324, "CumulativeFundReturn": 117.474283072, "CumulativeBenchmarkReturn": 114.837876246 }, { "Date": "2018-09-30", "Benchmark": 0.29964, "Fund": 0.24257, "CumulativeFundReturn": 117.759240440, "CumulativeBenchmarkReturn": 115.181976458 }, { "Date": "2018-10-31", "Benchmark": -1.70793, "Fund": -1.67568, "CumulativeFundReturn": 115.785972400, "CumulativeBenchmarkReturn": 113.214748927 }, { "Date": "2018-11-30", "Benchmark": 3.86599, "Fund": 3.71250, "CumulativeFundReturn": 120.084526625, "CumulativeBenchmarkReturn": 117.591619799 }, { "Date": "2018-12-31", "Benchmark": 0.63850, "Fund": 0.79004, "CumulativeFundReturn": 121.033242419, "CumulativeBenchmarkReturn": 118.342442291 }, { "Date": "2019-01-31", "Benchmark": 2.90183, "Fund": 3.10592, "CumulativeFundReturn": 124.792438102, "CumulativeBenchmarkReturn": 121.776538784 }, { "Date": "2019-02-28", "Benchmark": -0.44066, "Fund": -0.44422, "CumulativeFundReturn": 124.238085133, "CumulativeBenchmarkReturn": 121.239918288 }, { "Date": "2019-03-31", "Benchmark": 1.33168, "Fund": 1.43188, "CumulativeFundReturn": 126.017025426, "CumulativeBenchmarkReturn": 122.854446032 }, { "Date": "2019-04-30", "Benchmark": 0.74959, "Fund": 0.70414, "CumulativeFundReturn": 126.904361709, "CumulativeBenchmarkReturn": 123.775350674 }, { "Date": "2019-05-31", "Benchmark": 0.63846, "Fund": 0.65404, "CumulativeFundReturn": 127.734366996, "CumulativeBenchmarkReturn": 124.565606778 }, { "Date": "2019-06-30", "Benchmark": 2.27430, "Fund": 2.21016, "CumulativeFundReturn": 130.557500882, "CumulativeBenchmarkReturn": 127.398602373 }, { "Date": "2019-07-31", "Benchmark": -0.74383, "Fund": -0.72763, "CumulativeFundReturn": 129.607525338, "CumulativeBenchmarkReturn": 126.450973349 }, { "Date": "2019-08-31", "Benchmark": 0.97689, "Fund": 0.99692, "CumulativeFundReturn": 130.899608680, "CumulativeBenchmarkReturn": 127.686260263 }, { "Date": "2019-09-30", "Benchmark": 0.50809, "Fund": 0.61227, "CumulativeFundReturn": 131.701067714, "CumulativeBenchmarkReturn": 128.335021383 }, { "Date": "2019-10-31", "Benchmark": -0.34954, "Fund": -0.23716, "CumulativeFundReturn": 131.388725462, "CumulativeBenchmarkReturn": 127.886439149 }, { "Date": "2019-11-30", "Benchmark": 0.22171, "Fund": 0.36795, "CumulativeFundReturn": 131.872170277, "CumulativeBenchmarkReturn": 128.169976173 }, { "Date": "2019-12-31", "Benchmark": 1.86239, "Fund": 1.98303, "CumulativeFundReturn": 134.487234975, "CumulativeBenchmarkReturn": 130.557000992 }, { "Date": "2020-01-31", "Benchmark": 1.18597, "Fund": 1.08745, "CumulativeFundReturn": 135.949716412, "CumulativeBenchmarkReturn": 132.105367857 }, { "Date": "2020-02-29", "Benchmark": -0.04372, "Fund": 0.04716, "CumulativeFundReturn": 136.013830298, "CumulativeBenchmarkReturn": 132.047611390 }, { "Date": "2020-03-31", "Benchmark": -9.74728, "Fund": -9.01032, "CumulativeFundReturn": 123.758548944, "CumulativeBenchmarkReturn": 119.176560975 }, { "Date": "2020-04-30", "Benchmark": 3.91826, "Fund": 3.73456, "CumulativeFundReturn": 128.380386209, "CumulativeBenchmarkReturn": 123.846208493 }, { "Date": "2020-05-31", "Benchmark": 7.06428, "Fund": 6.83238, "CumulativeFundReturn": 137.151822040, "CumulativeBenchmarkReturn": 132.595051430 }, { "Date": "2020-06-30", "Benchmark": -1.18342, "Fund": -1.06462, "CumulativeFundReturn": 135.691676312, "CumulativeBenchmarkReturn": 131.025895072 }, { "Date": "2020-07-31", "Benchmark": 0.60863, "Fund": 0.49038, "CumulativeFundReturn": 136.357081154, "CumulativeBenchmarkReturn": 131.823357977 }, { "Date": "2020-08-31", "Benchmark": 0.88928, "Fund": 1.07681, "CumulativeFundReturn": 137.825387840, "CumulativeBenchmarkReturn": 132.995636735 }, { "Date": "2020-09-30", "Benchmark": -0.04772, "Fund": 0.08648, "CumulativeFundReturn": 137.944579235, "CumulativeBenchmarkReturn": 132.932171217 }, { "Date": "2020-10-31", "Benchmark": 0.88891, "Fund": 0.80999, "CumulativeFundReturn": 139.061916532, "CumulativeBenchmarkReturn": 134.113818580 }, { "Date": "2020-11-30", "Benchmark": 3.25401, "Fund": 3.72446, "CumulativeFundReturn": 144.241221988, "CumulativeBenchmarkReturn": 138.477895648 }, { "Date": "2020-12-31", "Benchmark": 2.43968, "Fund": 2.56726, "CumulativeFundReturn": 147.944269184, "CumulativeBenchmarkReturn": 141.856313173 }, { "Date": "2021-01-31", "Benchmark": 0.76247, "Fund": 0.91356, "CumulativeFundReturn": 149.295828850, "CumulativeBenchmarkReturn": 142.937925004 }, { "Date": "2021-02-28", "Benchmark": 0.05895, "Fund": 0.49611, "CumulativeFundReturn": 150.036500387, "CumulativeBenchmarkReturn": 143.022186911 }, { "Date": "2021-03-31", "Benchmark": -2.54122, "Fund": -2.85359, "CumulativeFundReturn": 145.755073816, "CumulativeBenchmarkReturn": 139.387678493 }, { "Date": "2021-04-30", "Benchmark": 1.89623, "Fund": 1.88968, "CumulativeFundReturn": 148.509378295, "CumulativeBenchmarkReturn": 142.030789469 }, { "Date": "2021-05-31", "Benchmark": 3.73286, "Fund": 3.95766, "CumulativeFundReturn": 154.386874556, "CumulativeBenchmarkReturn": 147.332599997 }, { "Date": "2021-06-30", "Benchmark": 1.09316, "Fund": 0.92910, "CumulativeFundReturn": 155.821283007, "CumulativeBenchmarkReturn": 148.943181047 }, { "Date": "2021-07-31", "Benchmark": 0.82569, "Fund": 0.80770, "CumulativeFundReturn": 157.079851510, "CumulativeBenchmarkReturn": 150.172989999 }, { "Date": "2021-08-31", "Benchmark": 1.70121, "Fund": 1.87359, "CumulativeFundReturn": 160.022883900, "CumulativeBenchmarkReturn": 152.727747922 }, { "Date": "2021-09-30", "Benchmark": -2.11882, "Fund": -2.25441, "CumulativeFundReturn": 156.415312003, "CumulativeBenchmarkReturn": 149.491721853 }, { "Date": "2021-10-31", "Benchmark": -0.48298, "Fund": -0.24249, "CumulativeFundReturn": 156.036020513, "CumulativeBenchmarkReturn": 148.769706735 }, { "Date": "2021-11-30", "Benchmark": 0.65862, "Fund": 0.65640, "CumulativeFundReturn": 157.060240952, "CumulativeBenchmarkReturn": 149.749533777 }, { "Date": "2021-12-31", "Benchmark": 2.68809, "Fund": 2.89675, "CumulativeFundReturn": 161.609883482, "CumulativeBenchmarkReturn": 153.774936020 } ], "assetAllocationChart": [ { "Name": "Local Equity", "Weight": 0.4525, "Label": "45.25%" }, { "Name": "Foreign Equity", "Weight": 0.1941, "Label": "29.41%" }, { "Name": "Local Bonds", "Weight": 0.3382, "Label": "33.82%" }, { "Name": "Foreign Bonds", "Weight": 0.1027, "Label": "10.27%" }, { "Name": "Cash", "Weight": 0.0125, "Label": "1.25%" } ], "logo": "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", "logoType": "png", "logoWidth": "4.5cm" }

Based on the JSON above, there are two charts being created in the PDF document. These charts are generated using the R package ggplot2, and their code is provided within the JSON. The charts are part of the document content and are represented as objects with the "type": "chart" key-value pair.

Cumulative Chart

{
  "type": "chart",
  "content": "ggplot(data=params$performanceGraph)+geom_line(aes(x=as.Date(Date), y=CumulativeBenchmarkReturn, color =' Benchmark ' ), linetype='solid', size=1)+geom_line(aes(x=as.Date(Date), y=CumulativeFundReturn, color =' Fund '), linetype='solid', size=1)+scale_colour_manual(breaks = c(' Fund ',' Benchmark '), values=c('#343D49','#0dbb72')) +theme_economist()+theme(panel.background = element_rect(fill = '#FFFFFF', colour = '#FFFFFF'),plot.background = element_rect(fill = '#FFFFFF', colour = '#FFFFFF'),axis.title.x=element_blank()) +theme(panel.grid.major = element_line(colour = '#A7A8AA', size=0.5))+theme(panel.grid.minor = element_blank())+theme(axis.line = element_line(colour = '#A7A8AA', size = 0.5)) +theme(axis.text = element_text(size = 12, colour = '#28334A'))+theme(axis.text.x = element_text(angle = 90, vjust = 0.5)) +theme(axis.ticks.x = element_line(colour = '#A7A8AA', size = 0.5))+theme(legend.position='bottom', legend.title=element_blank(),legend.background=element_rect(fill = '#FFFFFF', colour = '#FFFFFF'))+ theme(legend.text=element_text(size=16,color='#58595b'))+theme(legend.key = element_rect(fill = 'white'))+theme(axis.title.y=element_text(colour = '#28334A',size=12,margin=unit(c(0,0.2,0,0.2),units='cm'))) +theme(axis.title.y = element_blank()) +theme(legend.spacing=unit(0.1, units = 'cm'),legend.margin=margin(t = 0.1, unit='cm')) +scale_x_date(breaks = seq(as.Date('2004-06-30'), as.Date('2050-06-30'), by='6 months'), labels=date_format('%b-%Y'), expand = c(0.1, 0.1))+scale_y_continuous(breaks = pretty(c(params$performanceGraph$CumulativeFundReturn,params$performanceGraph$CumulativeBenchmarkReturn),n=8),labels=dollar_format(prefix='',big.mark = ' '))",
  "order": 5,
  "height": 4,
  "width": 10
}
						

This chart is a line chart showing the Cumulative Benchmark Return and the Cumulative Fund Return. The code for this chart is provided in the "content" field as a ggplot2 expression. The chart's dimensions are set with the "height" and "width" fields, measuring 4 units high and 10 units wide.

Asset Allocation Chart

{
  "type": "chart",
  "content": "ggplot(params$assetAllocationChart,aes(x = factor(Name, levels = params$assetAllocationChart$Name), y = Weight))+geom_bar(stat='identity', position=position_dodge(width=1), width = 0.75, fill = '#0dbb72')+geom_label(aes(label = Label), fill = 'white', colour = 'black', position= position_dodge(width=1), size = 5) +theme_economist()+scale_colour_economist()+theme(legend.position='bottom')+theme(legend.position='bottom', legend.direction = 'horizontal', legend.title=element_blank(),legend.background=element_rect(fill = '#FFFFFF', colour = '#FFFFFF'),legend.box.background=element_rect(fill = '#FFFFFF', colour = '#FFFFFF'),legend.key=element_rect(fill = '#FFFFFF', colour = '#FFFFFF'))+theme(legend.text=element_text(size=12,color='#2D2323',face='plain'))+guides(fill = guide_legend(nrow = 1))+theme(panel.background = element_rect(fill = '#FFFFFF', colour = '#FFFFFF'),plot.background = element_rect(fill = '#FFFFFF', colour = '#FFFFFF')) +theme(panel.grid.major = element_line(colour = 'lightgrey', size=0.5))+theme(panel.grid.minor = element_blank())+theme(axis.title.x=element_blank()) +theme(axis.title.y=element_text(colour = '#2D2323',size=12,margin=unit(c(0.0,0.25,0.0,0.25),units='cm'))) +theme(legend.spacing.x = unit(0.1, 'cm'))+theme(axis.text = element_text(size=12,color='#2D2323', face='plain'))+theme(axis.title = element_text(size=12,color='#2D2323', face='plain'))+scale_y_continuous(breaks = pretty(c(params$assetAllocationChart$Weight),n=6),labels=percent_format(accuracy = 0.1))+labs(y='Weight')+coord_cartesian(clip = 'off')",
  "order": 7,
  "height": 3.5,
  "width": 10
}
						

This chart is a bar chart displaying the weight of each asset in the portfolio. The ggplot2 code for generating this chart is provided in the "content" field. The chart's dimensions are set with the "height" and "width" fields, measuring 3.5 units high and 10 units wide.

Once the R code for generating these charts is executed, the resulting chart images are incorporated into the PDF document as specified by their respective order in the "documentContent" section of the JSON data.

For more information on how to use ggplot2 and create charts consult the ggplot2 official page or the ggplot2 cheat graphic.
Note that dynamic charts are only available on the Business Plan or higher. For more information visit our DynamicDocs API Pricing page.

Data and Layout Separation

In the aforementioned examples, it is crucial to recognize that the table and chart data reside independently from the PDF layout within the JSON. This distinction is significant as it allows for seamless updates to the document's underlying data in the JSON, automatically reflecting the changes within the document. This approach offers considerable benefits for developers tasked with PDF generation, streamlining their workflow and enhancing efficiency.

General JSON to PDF Postman Collection

To make it easierto test the General JSON to PDF Endpoint, we've provided a ready-to-use Postman collection. This allows you to generate the PDFs mentioned above with ease. Feel free to use the button below to access the collection and explore its features, or even fork the collection to customize it according to your needs.

Harnessing LaTeX and JSON for Effortless Customization

In conclusion, this article has demonstrated the versatility and efficiency of using JSON in conjunction with LaTeX to generate PDF documents through API calls. By showcasing three distinct examples, we have illustrated the ease of adapting the layout and content of PDFs by simply modifying the JSON payload. LaTeX, while possessing a steep learning curve, offers unparalleled control over the appearance and structure of documents. The General JSON to PDF Template introduced in this article streamlines the PDF generation process by allowing developers to make layout and content changes within the JSON body of the API call, eliminating the need to modify templates. This innovative approach saves time, reduces complexity, and enhances the developer experience in creating professional and aesthetically pleasing PDF documents.