I love apsrtable(), and have found it somewhat simple to extend to other classes (in particular, I have adapted it for mlogit objects. But for some reason, the apsrtableSummary.sarlm() function doesn't work quite like other hacks I have written.
Typically, we need to redefine the coefficients matrix so that apsrtable() knows where to find it. The code for this is
"apsrtableSummary.sarlm" <- function (x){
s <- summary(x)
s$coefficients <- s$Coef
return(s)
}
We also need to redefine the modelInfo for the new class, like this:
setMethod("modelInfo", "summary.sarlm", function(x){
env <- sys.parent()
digits <- evalq(digits, envir=env)
model.info <- list(
"$\\rho$" = formatC(x$rho, format="f", digits=digits),
"$p(\\rho)$" = formatC(x$LR1$p.value, format="f", digits=digits),
"$N$" = length(x$fitted.values),
"AIC" = formatC(AIC(x), format="f", digits=digits),
"\\mathcal{L}" = formatC(x$LL, format="f", digits=digits)
)
class(model.info) <- "model.info"
return(model.info)
})
After defining these two functions however, a call to apsrtable() doesn't print the coefficients (MWE using example from lagsarlm in spdep package).
library(spdep)
library(apsrtable)
data(oldcol)
COL.lag.eig <- lagsarlm(CRIME ~ INC + HOVAL, data=COL.OLD,
nb2listw(COL.nb, style="W"), method="eigen")
summary(COL.lag.eig)
# Load functions above
apsrtable(COL.lag.eig)
## OUTPUT ##
\begin{table}[!ht]
\caption{}
\label{}
\begin{tabular}{ l D{.}{.}{2} }
\hline
& \multicolumn{ 1 }{ c }{ Model 1 } \\ \hline
% & Model 1 \\
$\rho$.rho & 0.43 \\
$p(\rho)$.Likelihood ratio & 0.00 \\
$N$ & 49 \\
AIC & 374.78 \\
\mathcal{L} & -182.39 \\ \hline
\multicolumn{2}{l}{\footnotesize{Standard errors in parentheses}}\\
\multicolumn{2}{l}{\footnotesize{$^*$ indicates significance at $p< 0.05 $}}
\end{tabular}
\end{table}
As you can see, everything works out great except for that the coefficients and standard errors are not there. It's clear that the summary redefinition works, because
apsrtableSummary(COL.lag.eig)$coefficients
Estimate Std. Error z value Pr(>|z|)
(Intercept) 45.0792505 7.17734654 6.280768 3.369041e-10
INC -1.0316157 0.30514297 -3.380762 7.228517e-04
HOVAL -0.2659263 0.08849862 -3.004863 2.657002e-03
I've pulled my hair out for several days trying to find a way out of this. Any tips?
Well, I think I may be the only person on earth who uses both of these packages together, but I figured out a way to work through this problem.
It turns out that the source of the error is in the coef method for summary.sarlm class objects. Typically this method returns a matrix with the coefficients table, but for this class it just returns the coefficients. The following code fixes that problem.
setMethod("coef", "apsrtableSummary.sarlm", function(object) object$coefficients)
I also found it useful to include the rho term as a model coefficient (the methods are not consistent on this).
apsrtableSummary.sarlm <- function (x){
s <- summary(x)
s$rholine<- c(unname(s$rho), s$rho.se, unname(s$rho/s$rho.se),
unname(2 * (1 - pnorm(abs(s$rho/s$rho.se)))))
s$Coef <- rbind(s$rholine, s$Coef)
rownames(s$Coef)[1] <- "$\\rho$"
s$coefficients <- s$Coef
return(s)
}
Related
I'm looking for a nicely formated markdown output of test results that are produced within a for loop and structured with headings. For example
df <- data.frame(x = rnorm(1000),
y = rnorm(1000),
z = rnorm(1000))
for (v in c("y","z")) {
cat("##", v, " (model 0)\n")
summary(lm(x~1, df))
cat("##", v, " (model 1)\n")
summary(lm(as.formula(paste0("x~1+",v)), df))
}
whereas the output should be
y (model 0)
Call:
lm(formula = x ~ 1, data = df)
Residuals:
Min 1Q Median 3Q Max
-3.8663 -0.6969 -0.0465 0.6998 3.1648
Coefficients:
Estimate Std. Error t value Pr(>|t|)
(Intercept) -0.05267 0.03293 -1.6 0.11
Residual standard error: 1.041 on 999 degrees of freedom
y (model 1)
Call:
lm(formula = as.formula(paste0("x~1+", v)), data = df)
Residuals:
Min 1Q Median 3Q Max
-3.8686 -0.6915 -0.0447 0.6921 3.1504
Coefficients:
Estimate Std. Error t value Pr(>|t|)
(Intercept) -0.05374 0.03297 -1.630 0.103
y -0.02399 0.03189 -0.752 0.452
Residual standard error: 1.042 on 998 degrees of freedom
Multiple R-squared: 0.0005668, Adjusted R-squared: -0.0004346
F-statistic: 0.566 on 1 and 998 DF, p-value: 0.452
z (model 0)
and so on...
There are several results discussing parts of the question like here or here suggesting the asis-tag in combination with the cat-statement. This one includes headers.
Closest to me request seems to be this question from two years ago. However, even though highly appreciated, some of suggestions are deprecated like the asis_output or I can't get them to work in general conditions like the formattable suggestion (e.g. withlm-output). I just wonder -- as two years have past since then -- if there is a modern approach that facilitates what I'm looking for.
Solution Type 1
You could do a capture.output(cat(.)) approach with some lapply-looping. Send the output to a file and use rmarkdown::render(.).
This is the R code producing a *.pdf.
capture.output(cat("---
title: 'Test Results'
author: 'Tom & co.'
date: '11 10 2019'
output: pdf_document
---\n\n```{r setup, include=FALSE}\n
knitr::opts_chunk$set(echo = TRUE)\n
mtcars <- data.frame(mtcars)\n```\n"), file="_RMD/Tom.Rmd") # here of course your own data
lapply(seq(mtcars), function(i)
capture.output(cat("# Model", i, "\n\n```{r chunk", i, ", comment='', echo=FALSE}\n\
print(summary(lm(mpg ~ ", names(mtcars)[i] ,", mtcars)))\n```\n"),
file="_RMD/Tom.Rmd", append=TRUE))
rmarkdown::render("_RMD/Tom.Rmd")
Produces:
Solution Type 2
When we want to automate the output of multiple model summaries in the rmarkdown itself, we could chose between 1. selecting chunk option results='asis' which would produce code output but e.g. # Model 1 headlines, or 2. to choose not to select it, which would produce Model 1 but destroys the code formatting. The solution is to use the option and combine it with inline code that we can paste() together with another sapply()-loop within the sapply() for the models.
In the main sapply we apply #G.Grothendieck's venerable solution to nicely substitute the Call: line of the output using do.call("lm", list(.)). We need to wrap an invisible(.) around it to avoid the unnecessary sapply() output [[1]] [[2]]... of the empty lists produced.
I included a ". " into the cat(), because leading white space like ` this` will be rendered to this in lines 6 and 10 of the summary outputs.
This is the rmarkdown script producing a *pdf that can also be executed ordinary line by line:
---
title: "Test results"
author: "Tom & co."
date: "15 10 2019"
output: pdf_document
---
```{r setup, include=FALSE}
knitr::opts_chunk$set(echo = TRUE)
```
# Overview
This is an example of an ordinary code block with output that had to be included.
```{r mtcars, fig.width=3, fig.height=3}
head(mtcars)
```
# Test results in detail
The test results follow fully automated in detail.
```{r mtcars2, echo=FALSE, message=FALSE, results="asis"}
invisible(sapply(tail(seq(mtcars), -2), function(i) {
fo <- reformulate(names(mtcars)[i], response="mpg")
s <- summary(do.call("lm", list(fo, quote(mtcars))))
cat("\n## Model", i - 2, "\n")
sapply(1:19, function(j)
cat(paste0("`", ". ", capture.output(s)[j]), "` \n"))
cat(" \n")
}))
```
***Note:*** This is a concluding remark to show that we still can do other stuff afterwards.
Produces:
(Note: Site 3 omitted)
Context
I was hit by the same need as that of OP when trying to generate multiple plots in a loop, but one of them would apparently crash the graphical device (because of unpredictable bad input) even when called using try() and prevent all the remaining figures from being generated. I needed really independent code blocks, like in the proposed solution.
Solution
I've thought of preprocessing the source file before it was passed to knitr, preferably inside R, and found that the jinjar package was a good candidate. It uses a dynamic template syntax based on the Jinja2 templating engine from Python/Django. There are no syntax clashes with document formats accepted by R Markdown, but the tricky part was integrating it nicely with its machinery.
My hackish solution was to create a wrapper rmarkdown::output_format() that executes some code inside the rmarkdown::render() call environment to process the source file:
preprocess_jinjar <- function(base_format) {
if (is.character(base_format)) {
base_format <- rmarkdown:::create_output_format_function(base_format)
}
function(...) {
# Find the markdown::render() environment.
callers <- sapply(sys.calls(), function(x) deparse(as.list(x)[[1]]))
target <- grep('^(rmarkdown::)?render$', callers)
target <- target[length(target)] # render may be called recursively
render_envir <- sys.frames()[[target]]
# Modify input with jinjar.
input_paths <- evalq(envir = render_envir, expr = {
original_knit_input <- sub('(\\.[[:alnum:]]+)$', '.jinjar\\1', knit_input)
file.rename(knit_input, original_knit_input)
input_lines <- jinjar::render(paste(input_lines, collapse = '\n'))
writeLines(input_lines, knit_input)
normalize_path(c(knit_input, original_knit_input))
})
# Add an on_exit hook to revert the modification.
rmarkdown::output_format(
knitr = NULL,
pandoc = NULL,
on_exit = function() file.rename(input_paths[2], input_paths[1]),
base_format = base_format(...),
)
}
}
Then I can call, for example:
rmarkdown::render('input.Rmd', output_format = preprocess_jinjar('html_document'))
Or, more programatically, with the output format specified in the source file metadata as usual:
html_jinjar <- preprocess_jinjar('html_document')
rmarkdown::render('input.Rmd')
Here is a minimal example for input.Rmd:
---
output:
html_jinjar:
toc: false
---
{% for n in [1, 2, 3] %}
# Section {{ n }}
```{r block-{{ n }}}
print({{ n }}**2)
```
{% endfor %}
Caveats
It's a hack. This code depends on the internal logic of markdown::render() and likely there are edge cases where it won't work. Use at your own risk.
For this solution to work, the output format contructor must be called by render(). Therefore, evaluating it before passing it to render() will fail:
render('input.Rmd', output_format = 'html_jinja') # works
render('input.Rmd', output_format = html_jinja) # works
render('input.Rmd', output_format = html_jinja()) # fails
This second limitation could be circumvented by putting the preprocessing code inside the pre_knit() hook, but then it would only run after other output format hooks, like intermediates_generator() and other pre_knit() hooks of the format.
Our teacher asked us to use kable() function when finishing our data analysis problem. However, when I run the sample code the teacher provided, the unicode seems doesn't display correctly:
The sample code is the following:
n <- 100
x <- rnorm(n)
y <- 2*x + rnorm(n)
out <- lm(y ~ x)
library(knitr)
kable(summary(out)$coef,digits=2)
And the R console returns me the following graph:
| | Estimate| Std. Error| t value| Pr(>|t|)|
|:-----------|--------:|----------:|-------:|------------------:|
|(Intercept) | -0.07| 0.09| -0.79| 0.43|
|x | 2.05| 0.09| 22.81| 0.00|
The correct form of the last column should be Pr(>|t|) instead.
However, if change my code to:
kable(summary(out)$coef, format="latex",digits=2)
The returned result is:
\begin{tabular}{l|r|r|r|r}
\hline
& Estimate & Std. Error & t value & Pr(>|t|)\\
\hline
(Intercept) & -0.07 & 0.09 & -0.79 & 0.43\\
\hline
x & 2.05 & 0.09 & 22.81 & 0.00\\
\hline
\end{tabular}
I suspect the problem is with the markdown system on my computer. Do anyone know how to fix this problem?
I pasted the result from kable(summary(out)$coef, format="latex",digits=2) into a latex compiler and then ran it with the following change Pr(\ge \mid t\mid). It worked. Sometimes R-Markdown doesn't do the job.
> df = data.frame(Parameters = c(expression(beta[1])))
Error in as.data.frame.default(x[[i]], optional = TRUE) :
cannot coerce class ""expression"" to a data.frame
I'm trying to write math notation in a data.frame, but it seems that the two are not compatible. Is there a way around this?
I have also tried
> data.frame(Parameters = paste(expression(beta[1])))
Parameters
1 beta[1]
How can I get to show up?
If you want to store the latex code for those symbols inside a dataframe then be able to generate correct latex code from xtable, you will need to override the sanitize function in print.xtable by feeding in a dummy function that returns the input exactly (See this question: Using xtable with R and Latex, math mode in column names?):
df = data.frame(Parameter = c("$\\beta_{0}$", "$\\beta_{1}$", "$\\beta_{2}$"),
Estimate = beta, row.names = 1)
print(xtable(t(df)), sanitize.text.function = function(x){x})
Latex Table:
\begin{table}[ht]
\centering
\begin{tabular}{rrrr}
\hline
& $\beta_{0}$ & $\beta_{1}$ & $\beta_{2}$ \\
\hline
Estimate & 0.05 & 0.10 & 0.15 \\
\hline
\end{tabular}
\end{table}
Similar to xtable, stargazer has some cool options to generate nice looking tables in latex. One thing you can do is to change the variable names to math notation using the covariate.labels argument in stargazer:
library(stargazer)
beta = 1:3*0.05
df = data.frame(Parameter = c("beta0", "beta1", "beta2"),
Estimate = beta, row.names = 1)
stargazer(t(df), covariate.labels = c(NA, "$\\beta_{0}$", "$\\beta_{1}$", "$\\beta_{2}$"),
header = FALSE, summary = FALSE)
This outputs a latex table code:
\begin{table}[!htbp] \centering
\caption{}
\label{}
\begin{tabular}{#{\extracolsep{5pt}} cccc}
\\[-1.8ex]\hline
\hline \\[-1.8ex]
& $\beta_{0}$ & $\beta_{1}$ & $\beta_{2}$ \\
\hline \\[-1.8ex]
Estimate & $0.050$ & $0.100$ & $0.150$ \\
\hline \\[-1.8ex]
\end{tabular}
\end{table}
You can copy and paste the code here to render the latex table.
Also note that the default for type= in stargazer is "latex", which generates latex code, but you can also specify type="text" to generate a table in your console. This option, however, does not allow you to render the math symbols.
stargazer(t(df), covariate.labels = c(NA, "$\\beta_{0}$", "$\\beta_{1}$", "$\\beta_{2}$"),
header = FALSE, summary = FALSE, type = "text")
# ==========================
# 0 1 2
# --------------------------
# Estimate 0.050 0.100 0.150
# --------------------------
Another option using my package:
library(huxtable)
dfr = data.frame(Parameter = c("$\\beta_{0}$", "$\\beta_{1}$", "$\\beta_{2}$"),
Estimate = 'beta')
ht <- as_hux(dfr)
escape_contents(ht) <- FALSE
ht # will print as TeX within a markdown pdf_document
I am not very sure what you are trying to do here. If you are trying to create a dataframe df with a column named "Parameter" with values taken from a vector within a list beta, then the below code will do the job.
df = data.frame(Parameters = beta[[1]])
# Assuming that the first object in beta is a vector that you want to set as "Paramters" column.
Please provide more information as to what these objects are if this is not what you were looking for.
I'm currently doing some data analysis on population data, so reporting the standard errors in the tables of parameter coefficients just doesn't really make statistical sense. I've done a fair bit of searching and can't find any way to customize the xtable output to remove it. Can anyone point me in the right direction?
Thanks a lot, I didn't post this lightly; if it's something obvious, I apologize for having wasted time!
so after my (other) whole long-winded answer... this works too:
xtable(summary(model1)$coefficients[,c(1,3,4)])
Or more generically:
sm <- summary(SomeModel)
SE.indx <- which(colnames(sm$coefficients) == "Std. Error") # find which column is Std. Error (usually 2nd)
sm$coefficients <- sm$coefficients[, -SE.indx] # Remove it
xtable(sm$coefficients) # call xtable on just the coefficients table
Results:
% latex table generated in R 2.15.1 by xtable 1.7-0 package
% Sun Dec 9 00:01:46 2012
\begin{table}[ht]
\begin{center}
\begin{tabular}{rrrr}
\hline
& Estimate & t value & Pr($>$$|$t$|$) \\
\hline
(Intercept) & 29.80 & 30.70 & 0.00 \\
crim & -0.31 & -6.91 & 0.00 \\
age & -0.09 & -6.50 & 0.00 \\
\hline
\end{tabular}
\end{center}
\end{table}
Using the first example in help(lm):
xtable(as.matrix(coef(lm.D9)))
% latex table generated in R 2.15.2 by xtable 1.7-0 package
% Sat Dec 8 19:53:09 2012
\begin{table}[ht]
\begin{center}
\begin{tabular}{rr}
\hline
& x \\
\hline
(Intercept) & 5.03 \\
groupTrt & -0.37 \\
\hline
\end{tabular}
\end{center}
\end{table}
I agreed with not using std erros if this were descriptions of a population and not just a sample. By that reasoning, however, you would not want to leave in p-values or t-statistics. That was the reason I only included the coefficients. To remove the standard error column only from the summary coefficient matrix:
xtable( coef(summary(lm.D9))[,-2] )
% latex table generated in R 2.15.2 by xtable 1.7-0 package
% Sat Dec 8 21:02:17 2012
\begin{table}[ht]
\begin{center}
\begin{tabular}{rrrr}
\hline
& Estimate & t value & Pr($>$$|$t$|$) \\
\hline
(Intercept) & 5.03 & 22.85 & 0.00 \\
groupTrt & -0.37 & -1.19 & 0.25 \\
\hline
\end{tabular}
\end{center}
\end{table}
Looking at str(summary(Model1)) we see that $coefficients has the Std. Error value we want to remove.
lesserSummary <- function(x) {
## returns same as summary(x), but with "Std. Error" remove from coefficients.
## and class of object is "modifiedSummary"
# grab the summary
sm <- summary(x)
# find which column is std error
SE.indx <- which(colnames(sm$coefficients) == "Std. Error")
# remove it
sm$coefficients <- sm$coefficients[, -SE.indx]
# give it some class
class(sm) <- "modifiedSummary"
# return it
sm
}
xtable.modifiedSummary <-
function (x, caption = NULL, label = NULL, align = NULL, digits = NULL, display = NULL, ...) {
# x is a modifiedSummary object
# This function is a modification of xtable:::xtable.summary.lm
# Key Difference is simply the number of columns that x$coef is expected to have
# (Here 3. Originally 4)
x <- data.frame(x$coef, check.names = FALSE)
class(x) <- c("xtable", "data.frame")
caption(x) <- caption
label(x) <- label
align(x) <- switch(1 + is.null(align), align, c("r", "r", "r", "r"))
digits(x) <- switch(1 + is.null(digits), digits, c(0, 4, 2, 4))
display(x) <- switch(1 + is.null(display), display, c("s", "f", "f", "f"))
return(x)
}
xtable_mod <- function(x) {
# Wrapper function to xtable.modified summary, calling first lesserSummary on x
xtable(lesserSummary(x))
}
EXAMPLE:
xtable_mod(model1)
% latex table generated in R 2.15.1 by xtable 1.7-0 package
% Sat Dec 8 23:44:54 2012
\begin{table}[ht]
\begin{center}
\begin{tabular}{rrrr}
\hline
& Estimate & t value & Pr($>$$|$t$|$) \\
\hline
(Intercept) & 29.8007 & 30.70 & 0.0000 \\
crim & -0.3118 & -6.91 & 0.0000 \\
age & -0.0896 & -6.50 & 0.0000 \\
\hline
\end{tabular}
\end{center}
\end{table}
Below are the steps taken to arrive at the above conclusion.
You can likely modify the call to xtable, but you first need to follow it down a bit:
start by looking at the source for xtable:
xtable
# function (x, caption = NULL, label = NULL, align = NULL, digits = NULL,
# display = NULL, ...)
# {
# UseMethod("xtable")
# }
# <environment: namespace:xtable>
We see that it simply has a call to UseMethod(). So lets see which methods are available:
methods(xtable)
# [1] xtable.anova* xtable.aov* xtable.aovlist*
# [4] xtable.coxph* xtable.data.frame* xtable.glm*
# [7] xtable.lm* xtable.matrix* xtable.prcomp*
# [10] xtable.summary.aov* xtable.summary.aovlist* xtable.summary.glm*
# [13] xtable.summary.lm* xtable.summary.prcomp* xtable.table*
# [16] xtable.ts* xtable.zoo*
There are several. Note that the ones with an asterisk * are non-visible.
The method called is determined by the class of the object we are calling xtable on.
Let's say our output is Model1 We take a look at its class: '
class(Model1)
# [1] "lm"
So the source we want to look at is xtable.lm.
xtable.lm
# Error: object 'xtable.lm' not found
Error? That's right, it is non-visible. So we use the package name with triple-colons. Note: please be sure to read the notice in the help file ?":::"
xtable:::xtable.lm
# function (x, caption = NULL, label = NULL, align = NULL, digits = NULL,
# display = NULL, ...)
# {
# return(xtable.summary.lm(summary(x), caption = caption, label = label,
# align = align, digits = digits, display = display))
# }
# <environment: namespace:xtable>
We notice that xtable.lm calls xtable.summary.lm and passes as its first argument a summary(x), where x is our model.
So that leads us to two place to investigate: summary and xtable.summary.lm
It's common practice for tables of regression outcomes in academic papers to have a row(s) that describe some feature of the estimated model. For example, you might have a row name:
"Model included individual fixed effects" and then each associated cell will have a Yes/No as appropriate.
My question is whether it is possible in any of the many tools for making LaTeX tables with R (c.f., Tools for making latex tables in R) to pass the table-generating functions such a row To make this more concrete, I'm imagining having a parameter like:
model.info.row <- list(name = "Fixed effects", values = c("Y", "N", "Y"))
I've read through the memisc mtable and toLaTeX documentation and did not see anything that seems capable of this---not sure about other packages / approaches, but this seems like such a common use case that I suspect there is some way of doing this.
You might try to add that new line(s) directly to the table you want to pass to e.g. xtable. Really lame example:
Let us have some model:
m <- lm(mtcars$hp ~ mtcars$wt)
Grab the table which is returned in xtable and other helpers:
df <- as.data.frame(summary(m)$coefficient)
Add a new line with some values:
df[3, ] <- c(sample(c('foo', 'bar'), 4, replace = TRUE))
Update the rowname of your custom line:
rownames(df)[3] <- 'FOOBAR'
Check out results:
> df
Estimate Std. Error t value Pr(>|t|)
(Intercept) -1.82092177119464 32.3246158121787 -0.0563323561763288 0.95545056134944
mtcars$wt 46.1600502824445 9.62530003926982 4.79569988406785 4.14582744107531e-05
FOOBAR bar foo bar bar
Or just call xtable:
> xtable(df)
% latex table generated in R 2.15.0 by xtable 1.7-0 package
% Tue Jun 12 01:39:46 2012
\begin{table}[ht]
\begin{center}
\begin{tabular}{rllll}
\hline
& Estimate & Std. Error & t value & Pr($>$$|$t$|$) \\
\hline
(Intercept) & -1.82092177119464 & 32.3246158121787 & -0.0563323561763288 & 0.95545056134944 \\
mtcars\$wt & 46.1600502824445 & 9.62530003926982 & 4.79569988406785 & 4.14582744107531e-05 \\
FOOBAR & bar & foo & bar & bar \\
\hline
\end{tabular}
\end{center}
\end{table}
I ended up writing some hacky R code (note that it only works on a system w/ sed, wc and awk available) that's more flexible and works well the memisc 'mtable' function, which is my preferred way of generating LaTeX tables. Basically you write your table to a text file, then call this function with (1) the line number in the file where you want to make an insertion (2) the line you want to insert and (3) the name of the file with you want to make the insertions into (note that this function will overwrite your existing file). The code is:
insert.note <-function(linenumber, line, file){
num.lines <- as.numeric(system(paste("wc", file, "| awk '{print $1}'"), intern=TRUE))
tmp <- tempfile()
system(paste("head -n ", linenumber, file, "> ", tmp))
sink(tmp, append=TRUE)
cat(line)
sink()
system(paste("tail -n", num.lines - linenumber, file, ">>", tmp))
system(paste("mv", tmp, file))
}
As a helper function, this code creates a valid line of LaTeX using mtable's double & column spacing:
create.note <- function(l, include.row.end = TRUE){
n <- length(l)
s <- ""
i <- 1
for(note in l){
if(i < n){
cap <- "&&"
} else {
if(include.row.end){
cap <- "\\\\ \n "
} else {
cap <- " \n"
}
}
s <- paste(s, note, cap)
i <- i + 1
}
s
}
The include.row.end parameter is in case you want to pass it something like "\midrule" and don't want to get an extra line.