]> git.donarmstrong.com Git - xtable.git/blob - pkg/R/print.xtable.R
79c486cef98fbdc4d0911419c637f5845ab27385
[xtable.git] / pkg / R / print.xtable.R
1 ### xtable package\r
2 ###\r
3 ### Produce LaTeX and HTML tables from R objects.\r
4 ###\r
5 ### Copyright 2000-2012 David B. Dahl <dahl@stat.tamu.edu>\r
6 ###\r
7 ### Maintained by Charles Roosen <croosen@mango-solutions.com>\r
8 ###\r
9 ### This file is part of the `xtable' library for R and related languages.\r
10 ### It is made available under the terms of the GNU General Public\r
11 ### License, version 2, or at your option, any later version,\r
12 ### incorporated herein by reference.\r
13 ###\r
14 ### This program is distributed in the hope that it will be\r
15 ### useful, but WITHOUT ANY WARRANTY; without even the implied\r
16 ### warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR\r
17 ### PURPOSE.  See the GNU General Public License for more\r
18 ### details.\r
19 ###\r
20 ### You should have received a copy of the GNU General Public\r
21 ### License along with this program; if not, write to the Free\r
22 ### Software Foundation, Inc., 59 Temple Place - Suite 330, Boston,\r
23 ### MA 02111-1307, USA\r
24 print.xtable <- function(x,\r
25   type = getOption("xtable.type", "latex"),\r
26   file = getOption("xtable.file", ""),\r
27   append = getOption("xtable.append", FALSE),\r
28   floating = getOption("xtable.floating", TRUE),\r
29   floating.environment = getOption("xtable.floating.environment", "table"),\r
30   table.placement = getOption("xtable.table.placement", "ht"),\r
31   caption.placement = getOption("xtable.caption.placement", "bottom"),\r
32   latex.environments = getOption("xtable.latex.environments", c("center")),\r
33   tabular.environment = getOption("xtable.tabular.environment", "tabular"),\r
34   size = getOption("xtable.size", NULL),\r
35   hline.after = getOption("xtable.hline.after", c(-1,0,nrow(x))),\r
36   NA.string = getOption("xtable.NA.string", ""),\r
37   include.rownames = getOption("xtable.include.rownames", TRUE),\r
38   include.colnames = getOption("xtable.include.colnames", TRUE),\r
39   only.contents = getOption("xtable.only.contents", FALSE),\r
40   add.to.row = getOption("xtable.add.to.row", NULL),\r
41   sanitize.text.function = getOption("xtable.sanitize.text.function", NULL),\r
42   sanitize.rownames.function = getOption("xtable.sanitize.rownames.function",\r
43                                          sanitize.text.function),\r
44   sanitize.colnames.function = getOption("xtable.sanitize.colnames.function",\r
45                                          sanitize.text.function),\r
46   math.style.negative = getOption("xtable.math.style.negative", FALSE),\r
47   html.table.attributes = getOption("xtable.html.table.attributes", "border=1"),\r
48   print.results = getOption("xtable.print.results", TRUE),\r
49   format.args = getOption("xtable.format.args", NULL),\r
50   rotate.rownames = getOption("xtable.rotate.rownames", FALSE),\r
51   rotate.colnames = getOption("xtable.rotate.colnames", FALSE),\r
52   booktabs = getOption("xtable.booktabs", FALSE),\r
53   scalebox = getOption("xtable.scalebox", NULL),\r
54   width = getOption("xtable.width", NULL),\r
55   ...)\r
56 {\r
57     ## If caption is length 2, treat the second value as the "short caption"\r
58     caption <- attr(x,"caption",exact = TRUE)\r
59     short.caption <- NULL\r
60     if (!is.null(caption) && length(caption) > 1){\r
61         short.caption <- caption[2]\r
62         caption <- caption[1]\r
63     }\r
64 \r
65     ## Claudio Agostinelli <claudio@unive.it> dated 2006-07-28 hline.after\r
66     ## By default it print an \hline before and after the columns names\r
67     ## independently they are printed or not and at the end of the table\r
68     ## Old code that set hline.after should include c(-1, 0, nrow(x)) in the\r
69     ## hline.after vector\r
70     ## If you do not want any \hline inside the data, set hline.after to NULL\r
71     ## PHEADER instead the string '\\hline\n' is used in the code\r
72     ## Now hline.after counts how many time a position appear\r
73     ## I left an automatic PHEADER in the longtable is this correct?\r
74 \r
75     ## Claudio Agostinelli <claudio@unive.it> dated 2006-07-28 include.rownames,\r
76     ## include.colnames\r
77     pos <- 0\r
78     if (include.rownames) pos <- 1\r
79 \r
80     ## Claudio Agostinelli <claudio@unive.it> dated 2006-07-28\r
81     ## hline.after checks\r
82     if (any(hline.after < -1) | any(hline.after > nrow(x))) {\r
83         stop("'hline.after' must be inside [-1, nrow(x)]")\r
84     }\r
85 \r
86     ## Claudio Agostinelli <claudio@unive.it> dated 2006-07-28\r
87     ## add.to.row checks\r
88     if (!is.null(add.to.row)) {\r
89         if (is.list(add.to.row) && length(add.to.row) == 2) {\r
90             if (is.null(names(add.to.row))) {\r
91                 names(add.to.row) <- c('pos', 'command')\r
92             } else if (any(sort(names(add.to.row))!= c('command', 'pos'))) {\r
93                 stop("the names of the elements of 'add.to.row' must be 'pos' and 'command'")\r
94             }\r
95             if (is.list(add.to.row$pos) && is.vector(add.to.row$command,\r
96                                                      mode = 'character')) {\r
97                 if ((npos <- length(add.to.row$pos)) !=\r
98                     length(add.to.row$command)) {\r
99                     stop("the length of 'add.to.row$pos' must be equal to the length of 'add.to.row$command'")\r
100                 }\r
101                 if (any(unlist(add.to.row$pos) < -1) |\r
102                     any(unlist(add.to.row$pos) > nrow(x))) {\r
103                     stop("the values in add.to.row$pos must be inside the interval [-1, nrow(x)]")\r
104                 }\r
105             } else {\r
106                 stop("the first argument ('pos') of 'add.to.row' must be a list, the second argument ('command') must be a vector of mode character")\r
107             }\r
108         } else {\r
109             stop("'add.to.row' argument must be a list of length 2")\r
110         }\r
111     } else {\r
112         add.to.row <- list(pos = list(),\r
113                            command = vector(length = 0, mode = "character"))\r
114         npos <- 0\r
115     }\r
116 \r
117     ## Claudio Agostinelli <claudio@unive.it> dated 2006-07-28 add.to.row\r
118     ## Add further commands at the end of rows\r
119     if (type == "latex") {\r
120         ## Original code before changes in version 1.6-1\r
121         ## PHEADER <- "\\hline\n"\r
122 \r
123         ## booktabs code from Matthieu Stigler <matthieu.stigler@gmail.com>,\r
124         ## 1 Feb 2012\r
125         if(!booktabs){\r
126             PHEADER <- "\\hline\n"\r
127         } else {\r
128             PHEADER <- ifelse(-1%in%hline.after, "\\toprule\n", "")\r
129             if(0%in%hline.after) {\r
130                 PHEADER <- c(PHEADER, "\\midrule\n")\r
131             }\r
132             if(nrow(x)%in%hline.after) {\r
133                 PHEADER <- c(PHEADER, "\\bottomrule\n")\r
134             }\r
135         }\r
136     } else {\r
137         PHEADER <- ""\r
138     }\r
139 \r
140     lastcol <- rep(" ", nrow(x)+2)\r
141     if (!is.null(hline.after)) {\r
142         ## booktabs change - Matthieu Stigler: fill the hline arguments\r
143         ## separately, 1 Feb 2012\r
144         ##\r
145         ## Code before booktabs change was:\r
146         ##    add.to.row$pos[[npos+1]] <- hline.after\r
147 \r
148         if (!booktabs){\r
149             add.to.row$pos[[npos+1]] <- hline.after\r
150         } else {\r
151             for(i in 1:length(hline.after)) {\r
152                 add.to.row$pos[[npos+i]] <- hline.after[i]\r
153             }\r
154         }\r
155         add.to.row$command <- c(add.to.row$command, PHEADER)\r
156     }\r
157 \r
158     if ( length(add.to.row$command) > 0 ) {\r
159         for (i in 1:length(add.to.row$command)) {\r
160             addpos <- add.to.row$pos[[i]]\r
161             freq <- table(addpos)\r
162             addpos <- unique(addpos)\r
163             for (j in 1:length(addpos)) {\r
164                 lastcol[addpos[j]+2] <- paste(lastcol[addpos[j]+2],\r
165                                               paste(rep(add.to.row$command[i],\r
166                                                         freq[j]),\r
167                                                     sep = "", collapse = ""),\r
168                                               sep = " ")\r
169             }\r
170         }\r
171     }\r
172 \r
173     if (length(type)>1) stop("\"type\" must have length 1")\r
174     type <- tolower(type)\r
175     if (!all(!is.na(match(type, c("latex","html"))))) {\r
176         stop("\"type\" must be in {\"latex\", \"html\"}")\r
177     }\r
178     if (!all(!is.na(match(floating.environment,\r
179                           c("table","table*","sidewaystable"))))) {\r
180         stop("\"type\" must be in {\"table\", \"table*\", \"sidewaystable\"}")\r
181     }\r
182     if (!is.null(table.placement) &&\r
183         !all(!is.na(match(unlist(strsplit(table.placement,  split = "")),\r
184                           c("H","h","t","b","p","!"))))) {\r
185         stop("\"table.placement\" must contain only elements of {\"h\",\"t\",\"b\",\"p\",\"!\"}")\r
186     }\r
187     if (!all(!is.na(match(caption.placement, c("bottom","top"))))) {\r
188         stop("\"caption.placement\" must be either {\"bottom\",\"top\"}")\r
189     }\r
190 \r
191     if (type == "latex") {\r
192         BCOMMENT <- "% "\r
193         ECOMMENT <- "\n"\r
194         ## See e-mail from "John S. Walker <jsw9c@uic.edu>" dated 5-19-2003\r
195         ## regarding "texfloat"\r
196         ## See e-mail form "Fernando Henrique Ferraz P. da Rosa"\r
197         ## <academic@feferraz.net>" dated 10-28-2005 regarding "longtable"\r
198         if ( tabular.environment == "longtable" & floating == TRUE ) {\r
199             warning("Attempt to use \"longtable\" with floating = TRUE. Changing to FALSE.")\r
200             floating <- FALSE\r
201         }\r
202         if ( floating == TRUE ) {\r
203             ## See e-mail from "Pfaff, Bernhard <Bernhard.Pfaff@drkw.com>"\r
204             ## dated 7-09-2003 regarding "suggestion for an amendment of\r
205             ## the source"\r
206             ## See e-mail from "Mitchell, David"\r
207             ## <David.Mitchell@dotars.gov.au>" dated 2003-07-09 regarding\r
208             ## "Additions to R xtable package"\r
209             ## See e-mail from "Garbade, Sven"\r
210             ## <Sven.Garbade@med.uni-heidelberg.de> dated 2006-05-22\r
211             ## regarding the floating environment.\r
212             BTABLE <- paste("\\begin{", floating.environment, "}",\r
213                             ifelse(!is.null(table.placement),\r
214                                    paste("[", table.placement, "]", sep = ""),\r
215                                    ""), "\n", sep = "")\r
216             if ( is.null(latex.environments) ||\r
217                 (length(latex.environments) == 0) ) {\r
218                 BENVIRONMENT <- ""\r
219                 EENVIRONMENT <- ""\r
220             } else {\r
221                 BENVIRONMENT <- ""\r
222                 EENVIRONMENT <- ""\r
223                 if ("center" %in% latex.environments){\r
224                     BENVIRONMENT <- paste(BENVIRONMENT, "\\centering\n",\r
225                                           sep = "")\r
226                 }\r
227                 for (i in 1:length(latex.environments)) {\r
228                     if (latex.environments[i] == "") next\r
229                     if (latex.environments[i] != "center"){\r
230                         BENVIRONMENT <- paste(BENVIRONMENT,\r
231                                               "\\begin{", latex.environments[i],\r
232                                               "}\n", sep = "")\r
233                         EENVIRONMENT <- paste("\\end{", latex.environments[i],\r
234                                               "}\n", EENVIRONMENT, sep = "")\r
235                     }\r
236                 }\r
237             }\r
238             ETABLE <- paste("\\end{", floating.environment, "}\n", sep = "")\r
239         } else {\r
240             BTABLE <- ""\r
241             ETABLE <- ""\r
242             BENVIRONMENT <- ""\r
243             EENVIRONMENT <- ""\r
244         }\r
245 \r
246         tmp.index.start <- 1\r
247         if ( ! include.rownames ) {\r
248             while ( attr(x, "align", exact = TRUE)[tmp.index.start] == '|' )\r
249                 tmp.index.start <- tmp.index.start + 1\r
250             tmp.index.start <- tmp.index.start + 1\r
251         }\r
252         ## Added "width" argument for use with "tabular*" or\r
253         ## "tabularx" environments - CR, 7/2/12\r
254         if (is.null(width)){\r
255             WIDTH <-""\r
256         } else if (is.element(tabular.environment,\r
257                               c("tabular", "longtable"))){\r
258             warning("Ignoring 'width' argument.  The 'tabular' and 'longtable' environments do not support a width specification.  Use another environment such as 'tabular*' or 'tabularx' to specify the width.")\r
259             WIDTH <- ""\r
260         } else {\r
261             WIDTH <- paste("{", width, "}", sep = "")\r
262         }\r
263 \r
264         BTABULAR <-\r
265             paste("\\begin{", tabular.environment, "}",\r
266                   WIDTH, "{",\r
267                   paste(c(attr(x, "align",\r
268                                exact = TRUE)[\r
269                                tmp.index.start:length(attr(x, "align",\r
270                                                            exact = TRUE))],\r
271                           "}\n"),\r
272                         sep = "", collapse = ""),\r
273                   sep = "")\r
274 \r
275         ## fix 10-26-09 (robert.castelo@upf.edu) the following\r
276         ## 'if' condition is added here to support\r
277         ## a caption on the top of a longtable\r
278         if (tabular.environment == "longtable" && caption.placement == "top") {\r
279             if (is.null(short.caption)){\r
280                 BCAPTION <- "\\caption{"\r
281             } else {\r
282                 BCAPTION <- paste("\\caption[", short.caption, "]{", sep = "")\r
283             }\r
284             ECAPTION <- "} \\\\ \n"\r
285             if ((!is.null(caption)) && (type == "latex")) {\r
286                 BTABULAR <- paste(BTABULAR,  BCAPTION, caption, ECAPTION,\r
287                                   sep = "")\r
288             }\r
289         }\r
290         ## Claudio Agostinelli <claudio@unive.it> dated 2006-07-28\r
291         ## add.to.row position -1\r
292         BTABULAR <- paste(BTABULAR, lastcol[1], sep = "")\r
293         ## the \hline at the end, if present, is set in full matrix\r
294         ETABULAR <- paste("\\end{", tabular.environment, "}\n", sep = "")\r
295 \r
296         ## Add scalebox - CR, 7/2/12\r
297         if (!is.null(scalebox)){\r
298             BTABULAR <- paste("\\scalebox{", scalebox, "}{\n", BTABULAR,\r
299                               sep = "")\r
300             ETABULAR <- paste(ETABULAR, "}\n", sep = "")\r
301         }\r
302 \r
303         ## BSIZE contributed by Benno <puetz@mpipsykl.mpg.de> in e-mail\r
304         ## dated Wednesday, December 01, 2004\r
305         if (is.null(size) || !is.character(size)) {\r
306             BSIZE <- ""\r
307             ESIZE <- ""\r
308         } else {\r
309             if(length(grep("^\\\\", size)) == 0){\r
310                 size <- paste("\\", size, sep = "")\r
311             }\r
312             BSIZE <- paste("{", size, "\n", sep = "")\r
313             ESIZE <- "}\n"\r
314         }\r
315         BLABEL <- "\\label{"\r
316         ELABEL <- "}\n"\r
317         if (is.null(short.caption)){\r
318         BCAPTION <- "\\caption{"\r
319     } else {\r
320         BCAPTION <- paste("\\caption[", short.caption, "]{", sep = "")\r
321     }\r
322         ECAPTION <- "}\n"\r
323         BROW <- ""\r
324         EROW <- " \\\\ \n"\r
325         BTH <- ""\r
326         ETH <- ""\r
327         STH <- " & "\r
328         BTD1 <- " & "\r
329         BTD2 <- ""\r
330         BTD3 <- ""\r
331         ETD  <- ""\r
332         ## Based on contribution from Jonathan Swinton\r
333         ## <jonathan@swintons.net> in e-mail dated Wednesday, January 17, 2007\r
334         sanitize <- function(str) {\r
335             result <- str\r
336             result <- gsub("\\\\", "SANITIZE.BACKSLASH", result)\r
337             result <- gsub("$", "\\$", result, fixed = TRUE)\r
338             result <- gsub(">", "$>$", result, fixed = TRUE)\r
339             result <- gsub("<", "$<$", result, fixed = TRUE)\r
340             result <- gsub("|", "$|$", result, fixed = TRUE)\r
341             result <- gsub("{", "\\{", result, fixed = TRUE)\r
342             result <- gsub("}", "\\}", result, fixed = TRUE)\r
343             result <- gsub("%", "\\%", result, fixed = TRUE)\r
344             result <- gsub("&", "\\&", result, fixed = TRUE)\r
345             result <- gsub("_", "\\_", result, fixed = TRUE)\r
346             result <- gsub("#", "\\#", result, fixed = TRUE)\r
347             result <- gsub("^", "\\verb|^|", result, fixed = TRUE)\r
348             result <- gsub("~", "\\~{}", result, fixed = TRUE)\r
349             result <- gsub("SANITIZE.BACKSLASH", "$\\backslash$",\r
350                            result, fixed = TRUE)\r
351             return(result)\r
352         }\r
353         sanitize.numbers <- function(x) {\r
354             result <- x\r
355             if ( math.style.negative ) {\r
356                 ## Jake Bowers <jwbowers@illinois.edu> in e-mail\r
357                 ## from 2008-08-20 suggested disabling this feature to avoid\r
358                 ## problems with LaTeX's dcolumn package.\r
359                 ## by Florian Wickelmaier <florian.wickelmaier@uni-tuebingen.de>\r
360                 ## in e-mail from 2008-10-03 requested the ability to use the\r
361                 ## old behavior.\r
362                 for(i in 1:length(x)) {\r
363                     result[i] <- gsub("-", "$-$", result[i], fixed = TRUE)\r
364                 }\r
365             }\r
366             return(result)\r
367         }\r
368         sanitize.final <- function(result) {\r
369             return(result)\r
370         }\r
371     } else {\r
372         BCOMMENT <- "<!-- "\r
373         ECOMMENT <- " -->\n"\r
374         BTABLE <- paste("<TABLE ", html.table.attributes, ">\n", sep = "")\r
375         ETABLE <- "</TABLE>\n"\r
376         BENVIRONMENT <- ""\r
377         EENVIRONMENT <- ""\r
378         BTABULAR <- ""\r
379         ETABULAR <- ""\r
380         BSIZE <- ""\r
381         ESIZE <- ""\r
382         BLABEL <- "<A NAME="\r
383         ELABEL <- "></A>\n"\r
384         BCAPTION <- paste("<CAPTION ALIGN=\"", caption.placement, "\"> ",\r
385                           sep = "")\r
386         ECAPTION <- " </CAPTION>\n"\r
387         BROW <- "<TR>"\r
388         EROW <- " </TR>\n"\r
389         BTH <- " <TH> "\r
390         ETH <- " </TH> "\r
391         STH <- " </TH> <TH> "\r
392         BTD1 <- " <TD align=\""\r
393         align.tmp <- attr(x, "align", exact = TRUE)\r
394         align.tmp <- align.tmp[align.tmp!="|"]\r
395         BTD2 <- matrix(align.tmp[(2-pos):(ncol(x)+1)],\r
396                        nrow = nrow(x), ncol = ncol(x)+pos, byrow = TRUE)\r
397         ## Based on contribution from Jonathan Swinton <jonathan@swintons.net>\r
398         ## in e-mail dated Wednesday, January 17, 2007\r
399         BTD2[regexpr("^p", BTD2)>0] <- "left"\r
400         BTD2[BTD2 == "r"] <- "right"\r
401         BTD2[BTD2 == "l"] <- "left"\r
402         BTD2[BTD2 == "c"] <- "center"\r
403         BTD3 <- "\"> "\r
404         ETD  <- " </TD>"\r
405         sanitize <- function(str) {\r
406             result <- str\r
407             result <- gsub("&", "&amp ", result, fixed = TRUE)\r
408             result <- gsub(">", "&gt ", result, fixed = TRUE)\r
409             result <- gsub("<", "&lt ", result, fixed = TRUE)\r
410             ## Kurt Hornik <Kurt.Hornik@wu-wien.ac.at> on 2006/10/05\r
411             ## recommended not escaping underscores.\r
412             ## result <- gsub("_", "\\_", result, fixed=TRUE)\r
413             return(result)\r
414         }\r
415         sanitize.numbers <- function(x) {\r
416             return(x)\r
417         }\r
418         sanitize.final <- function(result) {\r
419             ## Suggested by Uwe Ligges <ligges@statistik.uni-dortmund.de>\r
420             ## in e-mail dated 2005-07-30.\r
421             result$text <- gsub("  *", " ",  result$text, fixed = TRUE)\r
422             result$text <- gsub(' align="left"',  "", result$text,\r
423                                 fixed = TRUE)\r
424             return(result)\r
425         }\r
426     }\r
427 \r
428     result <- string("", file = file, append = append)\r
429     info <- R.Version()\r
430     ## modified Claudio Agostinelli <claudio@unive.it> dated 2006-07-28\r
431     ## to set automatically the package version\r
432     result <- result + BCOMMENT + type + " table generated in " +\r
433               info$language + " " + info$major + "." + info$minor +\r
434               " by xtable " +  packageDescription('xtable')$Version +\r
435               " package" + ECOMMENT\r
436     result <- result + BCOMMENT + date() + ECOMMENT\r
437     ## Claudio Agostinelli <claudio@unive.it> dated 2006-07-28 only.contents\r
438     if (!only.contents) {\r
439         result <- result + BTABLE\r
440         result <- result + BENVIRONMENT\r
441         if ( floating == TRUE ) {\r
442             if ((!is.null(caption)) &&\r
443                 (type == "html" ||caption.placement == "top")) {\r
444                 result <- result + BCAPTION + caption + ECAPTION\r
445             }\r
446             if (!is.null(attr(x, "label", exact = TRUE)) &&\r
447                 (type == "latex" && caption.placement == "top")) {\r
448                 result <- result + BLABEL +\r
449                           attr(x, "label", exact = TRUE) + ELABEL\r
450             }\r
451         }\r
452         result <- result + BSIZE\r
453         result <- result + BTABULAR\r
454     }\r
455     ## Claudio Agostinelli <claudio@unive.it> dated 2006-07-28\r
456     ## include.colnames, include.rownames\r
457     if (include.colnames) {\r
458         result <- result + BROW + BTH\r
459         if (include.rownames) {\r
460             result <- result + STH\r
461         }\r
462         ## David G. Whiting in e-mail 2007-10-09\r
463         if (is.null(sanitize.colnames.function)) {\r
464             CNAMES <- sanitize(names(x))\r
465         } else {\r
466             CNAMES <- sanitize.colnames.function(names(x))\r
467         }\r
468         if (rotate.colnames) {\r
469             ##added by Markus Loecher, 2009-11-16\r
470             CNAMES <- paste("\\begin{sideways}", CNAMES, "\\end{sideways}")\r
471         }\r
472         result <- result + paste(CNAMES, collapse = STH)\r
473 \r
474         result <- result + ETH + EROW\r
475     }\r
476 \r
477     cols <- matrix("", nrow = nrow(x), ncol = ncol(x)+pos)\r
478     if (include.rownames) {\r
479         ## David G. Whiting in e-mail 2007-10-09\r
480         if (is.null(sanitize.rownames.function)) {\r
481             RNAMES <- sanitize(row.names(x))\r
482         } else {\r
483             RNAMES <- sanitize.rownames.function(row.names(x))\r
484         }\r
485         if (rotate.rownames) {\r
486             ##added by Markus Loecher, 2009-11-16\r
487             RNAMES <- paste("\\begin{sideways}", RNAMES, "\\end{sideways}")\r
488         }\r
489         cols[, 1] <- RNAMES\r
490     }\r
491 \r
492 ## Begin vectorizing the formatting code by Ian Fellows [ian@fellstat.com]\r
493 ## 06 Dec 2011\r
494 ##\r
495 ##  disp <- function(y) {\r
496 ##    if (is.factor(y)) {\r
497 ##      y <- levels(y)[y]\r
498 ##    }\r
499 ##    if (is.list(y)) {\r
500 ##      y <- unlist(y)\r
501 ##    }\r
502 ##    return(y)\r
503 ##  }\r
504     varying.digits <- is.matrix( attr( x, "digits", exact = TRUE ) )\r
505     ## Code for letting "digits" be a matrix was provided by\r
506     ## Arne Henningsen <ahenningsen@agric-econ.uni-kiel.de>\r
507     ## in e-mail dated 2005-06-04.\r
508     ##if( !varying.digits ) {\r
509     ## modified Claudio Agostinelli <claudio@unive.it> dated 2006-07-28\r
510     ##  attr(x,"digits") <- matrix( attr( x, "digits",exact=TRUE ),\r
511     ## nrow = nrow(x), ncol = ncol(x)+1, byrow = TRUE )\r
512     ##}\r
513     for(i in 1:ncol(x)) {\r
514         xcol <- x[, i]\r
515         if(is.factor(xcol))\r
516             xcol <- as.character(xcol)\r
517         if(is.list(xcol))\r
518             xcol <- sapply(xcol, unlist)\r
519         ina <- is.na(xcol)\r
520         is.numeric.column <- is.numeric(xcol)\r
521 \r
522         if(is.character(xcol)) {\r
523             cols[, i+pos] <- xcol\r
524         } else {\r
525             if (is.null(format.args)){\r
526                 format.args <- list()\r
527             }\r
528             if (is.null(format.args$decimal.mark)){\r
529                 format.args$decimal.mark <- options()$OutDec\r
530             }\r
531             if(!varying.digits){\r
532                 curFormatArgs <- c(list(\r
533                                    x = xcol,\r
534                                    format = ifelse( attr( x, "digits",\r
535                                    exact = TRUE )[i+1] < 0, "E",\r
536                                    attr( x, "display", exact = TRUE )[i+1] ),\r
537                                    digits = abs( attr( x, "digits",\r
538                                    exact = TRUE )[i+1] )),\r
539                                    format.args)\r
540                 cols[, i+pos] <- do.call("formatC", curFormatArgs)\r
541             }else{\r
542                 for( j in 1:nrow( cols ) ) {\r
543                     curFormatArgs <- c(list(\r
544                                        x = xcol[j],\r
545                                        format = ifelse( attr( x, "digits",\r
546                                        exact = TRUE )[j, i+1] < 0, "E",\r
547                                        attr( x, "display",\r
548                                             exact = TRUE )[i+1] ),\r
549                                        digits = abs( attr( x, "digits",\r
550                                        exact = TRUE )[j, i+1] )),\r
551                                        format.args)\r
552                     cols[j, i+pos] <- do.call("formatC", curFormatArgs)\r
553                 }\r
554             }\r
555         }\r
556         ## End Ian Fellows changes\r
557 \r
558         if ( any(ina) ) cols[ina, i+pos] <- NA.string\r
559         ## Based on contribution from Jonathan Swinton <jonathan@swintons.net>\r
560         ## in e-mail dated Wednesday, January 17, 2007\r
561         if ( is.numeric.column ) {\r
562             cols[, i+pos] <- sanitize.numbers(cols[, i+pos])\r
563         } else {\r
564             if (is.null(sanitize.text.function)) {\r
565                 cols[, i+pos] <- sanitize(cols[, i+pos])\r
566             } else {\r
567                 cols[, i+pos] <- sanitize.text.function(cols[, i+pos])\r
568             }\r
569         }\r
570     }\r
571 \r
572     multiplier <- 5\r
573     full <- matrix("", nrow = nrow(x), ncol = multiplier*(ncol(x)+pos)+2)\r
574     full[, 1] <- BROW\r
575     full[, multiplier*(0:(ncol(x)+pos-1))+2] <- BTD1\r
576     full[, multiplier*(0:(ncol(x)+pos-1))+3] <- BTD2\r
577     full[, multiplier*(0:(ncol(x)+pos-1))+4] <- BTD3\r
578     full[, multiplier*(0:(ncol(x)+pos-1))+5] <- cols\r
579     full[, multiplier*(0:(ncol(x)+pos-1))+6] <- ETD\r
580 \r
581     full[, multiplier*(ncol(x)+pos)+2] <- paste(EROW, lastcol[-(1:2)],\r
582                                                 sep = " ")\r
583 \r
584     if (type == "latex") full[, 2] <- ""\r
585     result <- result + lastcol[2] + paste(t(full), collapse = "")\r
586     if (!only.contents) {\r
587         if (tabular.environment == "longtable") {\r
588             ## booktabs change added the if() - 1 Feb 2012\r
589             if(!booktabs) {\r
590                 result <- result + PHEADER\r
591             }\r
592 \r
593             ## fix 10-27-09 Liviu Andronic (landronimirc@gmail.com) the\r
594             ## following 'if' condition is inserted in order to avoid\r
595             ## that bottom caption interferes with a top caption of a longtable\r
596             if(caption.placement == "bottom"){\r
597                 if ((!is.null(caption)) && (type == "latex")) {\r
598                     result <- result + BCAPTION + caption + ECAPTION\r
599                 }\r
600             }\r
601             if (!is.null(attr(x, "label", exact = TRUE))) {\r
602                 result <- result + BLABEL + attr(x, "label", exact = TRUE) +\r
603                     ELABEL\r
604             }\r
605             ETABULAR <- "\\end{longtable}\n"\r
606         }\r
607         result <- result + ETABULAR\r
608         result <- result + ESIZE\r
609         if ( floating == TRUE ) {\r
610             if ((!is.null(caption)) &&\r
611                 (type == "latex" && caption.placement == "bottom")) {\r
612                 result <- result + BCAPTION + caption + ECAPTION\r
613             }\r
614             if (!is.null(attr(x, "label", exact = TRUE)) &&\r
615                 caption.placement == "bottom") {\r
616                 result <- result + BLABEL + attr(x, "label", exact = TRUE) +\r
617                     ELABEL\r
618             }\r
619         }\r
620         result <- result + EENVIRONMENT\r
621         result <- result + ETABLE\r
622     }\r
623     result <- sanitize.final(result)\r
624 \r
625     if (print.results){\r
626         print(result)\r
627     }\r
628 \r
629     return(invisible(result$text))\r
630 }\r
631 \r
632 "+.string" <- function(x, y) {\r
633     x$text <- paste(x$text, as.string(y)$text, sep = "")\r
634     return(x)\r
635 }\r
636 \r
637 print.string <- function(x, ...) {\r
638     cat(x$text, file = x$file, append = x$append)\r
639     return(invisible())\r
640 }\r
641 \r
642 string <- function(text, file = "", append = FALSE) {\r
643     x <- list(text = text, file = file, append = append)\r
644     class(x) <- "string"\r
645     return(x)\r
646 }\r
647 \r
648 as.string <- function(x, file = "", append = FALSE) {\r
649     if (is.null(attr(x, "class", exact = TRUE)))\r
650         switch(data.class(x),\r
651                character = return(string(x, file, append)),\r
652                numeric = return(string(as.character(x), file, append)),\r
653                stop("Cannot coerse argument to a string"))\r
654     if (class(x) == "string")\r
655         return(x)\r
656     stop("Cannot coerse argument to a string")\r
657 }\r
658 \r
659 is.string <- function(x) {\r
660     return(class(x) == "string")\r
661 }\r
662 \r