Create Fillable PDF Textbox via R

Create Fillable PDF Textbox via R

The hyperref package (which is loaded automatically) allows fillable fields. It is just a matter of use its specific commands, which you can find here. Try this code (click on the right of the word Name).

---
title: "Fillable Textbox?"
author: "The Need To Edit"
date: "Wednesday, October 21, 2015"
output: pdf_document
---

Since Rmarkdown uses knitr and it loads automatically hyperref I think hat this should work.

In fact it is just a matter of use some \LaTeX\ commands of the hyperref package.

```{r, echo=FALSE}
plot(cars)
```

\begin{Form}
\TextField{Name}
\end{Form}

Of course this PDF is fillable as a PDF, and then it will not work inside the RStudio (if you use it) PDF viewer.

Create fillable PDF form with exams2nops

TL;DR

  • exams2nops() does not support this and will not be extended in this direction because its focus is generating PDF exams for printing/scanning/etc.
  • exams2pdf() can be customized to use different LaTeX templates and you can try to set up a suitable template using the {hyperref} package.
  • The support for the resulting PDF forms differs a lot between PDF viewers, typically with Acrobat Reader being the only one with decent support.
  • My personal experience with the heterogeneity on students' systems plus sending solutions via e-mail is that this is not a very reliable solution but would be the source of a lot of problems. Personally, I would avoid going down this road.
  • If your university hosts a Moodle system, I would recommend generating exams via exams2moodle(). At least the responsibility for the stability of the system is then with the university.

Details:

By using the {hyperref} package you can use the {Form} environment with commands like \CheckBox{}, \TextEntry{}, etc. A brief overview is given here: https://tex.stackexchange.com/questions/14842/creating-fillable-pdfs

A more elaborate worked example is available at: https://martin-thoma.com/creating-pdf-forms-with-latex/

Based on these I adapted the exam.tex template provided within the R/exams package and set up a form.tex template. The full LaTeX code is included below. This tries to do the following:

  • Set up a form that can be submitted by e-mail when completed.
  • The form consists of "fixed" fields for name and student ID.
  • Then it sets up commands \exnum, \exstring, exmchoice etc. that can be used by exams2pdf(). See Section 3 in vignette("exams", package = "exams") for details. Thus, these commands are repeated as often as necessary for a given exam.
  • At the end there are buttons to "Submit" or "Clear" the form.

For illustration, try:

exams2pdf(
c("deriv.Rmd", "swisscapital.Rmd", "boxplots.Rmd", "ttest.Rmd", "function.Rmd", "lm.Rmd"),
template = "form.tex"
)

where form.tex from below needs to be in your current working directory.

The result is a form1.pdf displayed automatically in your default PDF viewer (see options(pdfviewer = ...)). Alternatively, you can also add an argument dir = "." to store the file in your current working directory.

For me on Debian GNU/Linux with TeXLive this works and produces a PDF file that can be viewed and filled in using the Evince PDF viewer. However, neither "Submit" nor "Clear" works.

When I open the same file under Acrobat Reader in Windows 10, then only the TextEntry fields for Name/ID work, the others don't. The check boxes work but all checkboxes for (a) are linked, as are all (b), etc.

My impression is that composing the {Form} on the fly like this does not work for Acrobat Reader. But I would appreciate pointers how this can be fixed. An alternative would be to exactly code the form you need for a specific exam with unique name tags in all form elements etc.

Bonus note:

The template below also activates the {attachfile} LaTeX package which can be used to embed files (e.g., data sets) into the PDF. This works for me but only under Acrobat Reader. To automatically convert all \url{} commands (as created for the lm exercise, used above) into \attachfile{} commands, the development version of exams2pdf() gained an argument attachfile = FALSE which can be set to TRUE. See this thread in the R/exams forum on R-Forge for more details:
https://R-Forge.R-project.org/forum/forum.php?thread_id=32091&forum_id=4377&group_id=1337

LaTeX template: form.tex

\documentclass[10pt,a4paper]{article}

%% packages
\usepackage[utf8]{inputenc}
\usepackage{a4wide,color,verbatim,Sweave,url,xargs,amsmath,booktabs,longtable,eurosym}

%%% %% optionally: two-column layout for exercise form
%%% \usepackage{multicol}

%% embed supplementary data files etc.
\usepackage{attachfile}
\attachfilesetup{color=0.5 0 0}

%% support PDF forms
\usepackage{hyperref}

%% new environments
\newenvironment{question}{\item}{}
\newenvironment{solution}{\comment}{\endcomment}
\newenvironment{answerlist}{\renewcommand{\labelenumi}{(\alph{enumi})}\begin{enumerate}}{\end{enumerate}}

%% paragraphs
\setlength{\parskip}{0.7ex plus0.1ex minus0.1ex}
\setlength{\parindent}{0em}

%% compatibility with pandoc
\providecommand{\tightlist}{\setlength{\itemsep}{0pt}\setlength{\parskip}{0pt}}
\setkeys{Gin}{keepaspectratio}

%% fonts: Helvetica
\usepackage{helvet}
\IfFileExists{sfmath.sty}{
\RequirePackage[helvet]{sfmath}
}{}
\renewcommand{\sfdefault}{phv}
\renewcommand{\rmdefault}{phv}

\newcommandx{\exmchoice}[9][2=-,3=-,4=-,5=-,6=-,7=-,8=-,9=-]{%
\CheckBox[name=a, width=1em]{(a)}~~%
\if #2- \else \CheckBox[name=b, width=1em]{(b)}~~ \fi%
\if #3- \else \CheckBox[name=c, width=1em]{(c)}~~ \fi%
\if #4- \else \CheckBox[name=d, width=1em]{(d)}~~ \fi%
\if #5- \else \CheckBox[name=e, width=1em]{(e)}~~ \fi%
\if #6- \else \CheckBox[name=f, width=1em]{(f)}~~ \fi%
\if #7- \else \CheckBox[name=g, width=1em]{(g)}~~ \fi%
\if #8- \else \CheckBox[name=h, width=1em]{(h)}~~ \fi%
\if #9- \else \CheckBox[name=i, width=1em]{(i)}~~ \fi%
}
\newcommandx{\exclozechoice}[9][2=-,3=-,4=-,5=-,6=-,7=-,8=-,9=-]{\setcounter{enumiii}{1}%
\CheckBox[name=ca, width=1em]{\roman{enumiii}.} \stepcounter{enumiii}%
\if #2- \else \CheckBox[name=cb, width=1em]{\roman{enumiii}.} \stepcounter{enumiii} \fi%
\if #3- \else \CheckBox[name=cc, width=1em]{\roman{enumiii}.} \stepcounter{enumiii} \fi%
\if #4- \else \CheckBox[name=cd, width=1em]{\roman{enumiii}.} \stepcounter{enumiii} \fi%
\if #5- \else \CheckBox[name=ce, width=1em]{\roman{enumiii}.} \stepcounter{enumiii} \fi%
\if #6- \else \CheckBox[name=cf, width=1em]{\roman{enumiii}.} \stepcounter{enumiii} \fi%
\if #7- \else \CheckBox[name=cg, width=1em]{\roman{enumiii}.} \stepcounter{enumiii} \fi%
\if #8- \else \CheckBox[name=ch, width=1em]{\roman{enumiii}.} \stepcounter{enumiii} \fi%
\if #9- \else \CheckBox[name=ci, width=1em]{\roman{enumiii}.} \fi%
}
\newcommand{\exnum}[9]{\TextField[name=num, width=4cm]{}}
\newcommand{\exstring}[1]{\TextField[name=string, width=4cm]{}}

%% new commands
\makeatletter
\newcommand{\ID}[1]{\def\@ID{#1}}
\newcommand{\Date}[1]{\def\@Date{#1}}
\ID{00001}
\Date{YYYY-MM-DD}

%% \exinput{header}

\newcommand{\myID}{\@ID}
\newcommand{\myDate}{\@Date}
\makeatother

%% headings
\markboth{\textnormal{\bf \large Statistics Exam: \myID}}%
{\textnormal{\bf \large Statistics Exam: \myID}}
\pagestyle{myheadings}

\begin{document}

%% title page
\thispagestyle{empty}
{\sf
\textbf{\LARGE{R University}}

\textbf{\large{Statistics Exam \myDate \hfill Exam ID \myID}}

\vspace*{2cm}

\begin{Form}[action=mailto:info@example.com,encoding=html,method=post]
\begin{tabular}{ll}
\textbf{Name} & \TextField[name=Name, width=10cm]{}\\
\textbf{Student ID} & \TextField[name=ID, width=10cm]{}\\
\end{tabular}

\vspace*{1cm}

%%% \begin{multicols}{2}

%% \exinput{questionnaire}

%%% \end{multicols}

\Submit{Submit} ~~ \Reset{Clear}

\end{Form}
}
\newpage

\begin{enumerate}

%% \exinput{exercises}

\end{enumerate}

\end{document}

Creating a fillable and colored textbox in R Markdown (PDF)

The \TextField command takes some optional arguments to define color and default text:

---
output:
pdf_document:
keep_tex: yes
---

\begin{Form}
\TextField[width = 10cm,%
height = 3cm,%
multiline=true,%
bordercolor = 0 0 0.5,%
backgroundcolor = 0 0 0.5,%
color = 1 1 1,%
value = {%
This is the textbox.
I would like a dark blue textbox with white writing
}%
]{}
\end{Form}

This produces:

Sample Image

One can edit the \TextField to contain multi-line text, but I am not able to set a value with multiple lines. Using \string\n (c.f. https://tex.stackexchange.com/questions/416218/how-to-add-line-breaks-to-hyperref-pdf-form-textfield) does not work for me. This might depend on the PDF viewer, though. I am using Evince.

R for making interactive PDF documents?

You could use RMarkdown and Latex for this. See here for creating forms withing RMarkdown. And here for how to do calculations in pdf forms with Latex.

Since most of the work will be done in Latex you could just skip the RMarkdown part and do it in Latex only.

Filling PDF forms in R?

staplr package now supports this with get_fields and set_fields functions. Note that for this to work pdftk
server must be installed and in your path

get_fields returns a list of fields and their types from a pdf that you can modify

set_fields allows you to fill form according to your modifications. See below code for an example

pdfFile = system.file('testForm.pdf',package = 'staplr')

fields = get_fields(pdfFile)
# You'll get a list of fields that the pdf contains
# along with some additional information about the fields.

# You make modifications in any of the fields by
fields$TextField1$value = 'this is text'

# and apply the changes you have made in a new file
set_fields(pdfFile, 'newFile.pdf', fields)

Note: Currently github version of staplr has fixes that are yet to make into CRAN that affect staplr's ability to write in non-english alphabets. For best experience you may want to install it by doing

devtools::install_github('pridiltal/staplr')

Fillable textboxes in PDF are not unique - all are duplicates of each other in the pdf, how to fix?

You need to add a unique name to each field otherwise they all get the same name and then, in Acrobat, the same value when you edit one of them. See the name property below.

\begin{Form} \TextField[name = foo, width = 10cm, height = 3cm, multiline=true]{ } \end{Form}

Text mining from PDF form to dataframe using R

There are many ways to approach this and this is intended only to show how a possible solution could look like. I had a quick go at it and worked out something that works under the assumptions:

  • Groups are separated by the text "Sample: Soro"
  • The groups have a regular structure (e.g. date of collection is always the 6st line in a group)
  • Date formats are regular
  • etc.

If your pdf contains irregularities this task may well become a lot harder.
Note also that I am not great at Regex; I am trying to match just the simplest of cases. Others may well come up with better solutions.
I converted your data into a tibble with one character column called lines.

Approach: setup a meaningful grouping and slice the relevant lines. Then use regex and class coercion (char to date, char to num).

library(dplyr)
library(tibble)
library(stringr)

data <- data %>%
mutate(treatments = lead(cumsum(str_detect(lines, pattern = fixed("Sample: Soro", ignore_case = TRUE))), 1)) %>% # grouping variable
mutate(treatments = ifelse(is.na(treatments), max(treatments, na.rm = TRUE), treatments)) %>% # the `lead` function leaves the last row as `NA`. Fix this.
group_by(treatments) %>% #group the data
slice(c(1,6)) %>% #slice the wanted rows by group
ungroup() %>% # remove grouping
mutate(lines = str_squish(lines)) %>% # get rid of extra spaces
mutate(date = as.Date(str_extract(lines, pattern = "[0-9]{2}\\/[0-9]{2}\\/[0-9]{4}"), "%d/%m/%Y")) %>% # extract dates
mutate(exam = str_extract(lines, pattern = "^[[:alpha:]]+")) %>% # extract exam
mutate(qty = str_extract(lines, pattern = "[0-9]+[,.]?[0-9]*")) %>% # extract quantity
mutate(unit = "mg/dL") %>% # set unit
mutate(qty = as.numeric(str_replace(qty, ",", "."))) %>% # replace comma separator by dot
group_by(treatments) %>% # group
mutate(date = lead(date,1)) %>% # move the date up one row by group
slice(1) %>% # slice 1st row by group
ungroup() %>% # remove group
select(-treatments, -lines)

With this result:

> data
# A tibble: 4 x 4
date exam qty unit
<date> <chr> <dbl> <chr>
1 2020-02-05 GLICOSE 77 mg/dL
2 2020-02-05 UREIA 27 mg/dL
3 2020-02-05 CREATININA 0.87 mg/dL
4 2020-02-05 ÁCIDO 5.2 mg/dL

Hope this helps to get you on your way.



Related Topics



Leave a reply



Submit