]*>[^>]+color: green[^>]+>6")
59 | })
60 |
61 | test_that("The total should be added to the output if used with addmargins", {
62 | var1 <- LETTERS[1:3]
63 | var2 <- LETTERS[c(4:5, 5)]
64 | total_out <-
65 | table(var1, var2) %>%
66 | addmargins %>%
67 | htmlTable(css.total = "background: purple")
68 |
69 | expect_match(total_out, "]+background: purple[^>]+>[^>]*Sum ",
70 | info = "Expect the variable name to appear as a cgroup")
71 |
72 | expect_match(total_out, "]*>var2",
73 | info = "Expect the variable name to appear as a cgroup")
74 | })
75 |
--------------------------------------------------------------------------------
/tests/testthat/test-htmlTable_styles.R:
--------------------------------------------------------------------------------
1 | library(testthat)
2 | library(XML)
3 |
4 | context("htmlTable - styles check")
5 |
6 | test_that("Check that row styles are present",{
7 | mx <-
8 | matrix(ncol=6, nrow=8)
9 | rownames(mx) <- paste(c("1st", "2nd",
10 | "3rd",
11 | paste0(4:8, "th")),
12 | "row")
13 | colnames(mx) <- paste(c("1st", "2nd",
14 | "3rd",
15 | paste0(4:6, "th")),
16 | "hdr")
17 |
18 | for (nr in 1:nrow(mx)){
19 | for (nc in 1:ncol(mx)){
20 | mx[nr, nc] <-
21 | paste0(nr, ":", nc)
22 | }
23 | }
24 |
25 | css.cell = rep("font-size: 1em", times = ncol(mx) + 1)
26 | css.cell[1] = "font-size: 2em"
27 | out <- htmlTable(mx,
28 | css.cell=css.cell,
29 | cgroup = c("Cgroup 1", "Cgroup 2"),
30 | n.cgroup = c(2,4))
31 | for (n in rownames(mx)) {
32 | expect_match(out, sprintf("\n[^<]* ]+>%s", n))
33 | }
34 | for (nr in 1:nrow(mx)){
35 | for (nc in 1:ncol(mx)){
36 | expect_match(out, sprintf("\n[^<]* ]+>%s", mx[nr, nc]) )
37 | }
38 | }
39 | })
40 |
41 |
42 | test_that("Check prPrepareCss",{
43 | mx <- matrix(1:5, ncol = 5, nrow = 1)
44 | rownames(mx) <- "1st"
45 | colnames(mx) <- paste(c("1st", "2nd", "3rd", paste0(4:ncol(mx), "th")), "hdr")
46 |
47 | css.cell = rep("font-size: 1em", times = ncol(mx) + 1)
48 | css.cell[1] = "font-size: 2em"
49 | out <- prPrepareCss(mx, css = css.cell, header = names(mx), rnames = rownames(mx))
50 | expect_equal(dim(out), dim(mx))
51 |
52 |
53 | css.cell = matrix("padding-left: .5em;", nrow = nrow(mx) + 1, ncol = ncol(mx))
54 | out <- prPrepareCss(mx, css = css.cell, header = colnames(mx), rnames = rownames(mx))
55 | expect_equal(dim(out), dim(mx))
56 | })
57 |
58 |
59 | test_that("Test prGetStyle merge funciton", {
60 | styles <- c(background = "black", border ="1px solid grey")
61 | expect_equivalent(length(prGetStyle(styles)), 1)
62 | expect_match(prGetStyle(styles), "background: black;")
63 | expect_match(prGetStyle(styles), "border: [^;]+grey;")
64 | expect_match(prGetStyle(styles), "border: [^;]+grey;")
65 | expect_match(prGetStyle(styles, a=2), "border: [^;]+grey;")
66 |
67 | expect_error(prGetStyle(styles, "invalid style"))
68 | expect_error(prGetStyle(styles, "invalid style:"))
69 | expect_error(prGetStyle(styles, ":invalid style"))
70 |
71 | expect_match(prGetStyle(styles, "valid: style"), "valid: style;")
72 | expect_match(prGetStyle(styles, c(valid= "style")), "valid: style;")
73 | expect_match(prGetStyle(styles, c(valid= "style", valid1= "style")), "valid: style; valid1: style;")
74 | expect_match(prGetStyle(styles, c(valid= "style1", valid= "style2")), "valid: style2;")
75 | expect_match(prGetStyle(styles, c(valid= "style1", valid= "style2"), "valid: style3"), "valid: style3;")
76 | })
77 |
78 |
79 | test_that("Later style has precedence", {
80 | styles <- c(background = "black", border ="1px solid grey")
81 | expect_match(prGetStyle(border = "2px solid red", styles),
82 | styles["border"])
83 | expect_match(prGetStyle(styles, border = "2px solid red"),
84 | "2px solid red")
85 | })
86 |
--------------------------------------------------------------------------------
/inst/htmlwidgets/lib/table_pagination/table_pagination.css:
--------------------------------------------------------------------------------
1 | /* These styles have been adapted from DataTables:
2 | DataTables is designed and created by SpryMedia Ltd © 2007-2016.
3 | SpryMedia Ltd is registered in Scotland, company no. SC456502.
4 |
5 | MIT licensed
6 |
7 | https://datatables.net/
8 |
9 | */
10 |
11 | .page_button {
12 | box-sizing: border-box;
13 | display: inline-block;
14 | min-width: 1.5em;
15 | padding: 0.5em 1em;
16 | margin-left: 2px;
17 | text-align: center;
18 | text-decoration: none !important;
19 | cursor: pointer;
20 | color: #333 !important;
21 | border: 1px solid transparent;
22 | border-radius: 2px;
23 | }
24 |
25 | .page_button:active {
26 | background-color: #2b2b2b;
27 | background: -webkit-gradient(linear, left top, left bottom, color-stop(0%, #2b2b2b), color-stop(100%, #0c0c0c));
28 | /* Chrome,Safari4+ */
29 | background: -webkit-linear-gradient(top, #2b2b2b 0%, #0c0c0c 100%);
30 | /* Chrome10+,Safari5.1+ */
31 | background: -moz-linear-gradient(top, #2b2b2b 0%, #0c0c0c 100%);
32 | /* FF3.6+ */
33 | background: -ms-linear-gradient(top, #2b2b2b 0%, #0c0c0c 100%);
34 | /* IE10+ */
35 | background: -o-linear-gradient(top, #2b2b2b 0%, #0c0c0c 100%);
36 | /* Opera 11.10+ */
37 | background: linear-gradient(to bottom, #2b2b2b 0%, #0c0c0c 100%);
38 | /* W3C */
39 | box-shadow: inset 0 0 3px #111;
40 | }
41 |
42 | .page_button:hover {
43 | color: white !important;
44 | border: 1px solid #111;
45 | background-color: #585858;
46 | background: -webkit-gradient(linear, left top, left bottom, color-stop(0%, #585858), color-stop(100%, #111));
47 | /* Chrome,Safari4+ */
48 | background: -webkit-linear-gradient(top, #585858 0%, #111 100%);
49 | /* Chrome10+,Safari5.1+ */
50 | background: -moz-linear-gradient(top, #585858 0%, #111 100%);
51 | /* FF3.6+ */
52 | background: -ms-linear-gradient(top, #585858 0%, #111 100%);
53 | /* IE10+ */
54 | background: -o-linear-gradient(top, #585858 0%, #111 100%);
55 | /* Opera 11.10+ */
56 | background: linear-gradient(to bottom, #585858 0%, #111 100%);
57 | /* W3C */
58 | }
59 |
60 |
61 | .page_button_current {
62 | pointer-events: none;
63 | cursor: default;
64 | color: #333 !important;
65 | border: 1px solid #979797;
66 | background-color: white;
67 | background: -webkit-gradient(linear, left top, left bottom, color-stop(0%, white), color-stop(100%, #dcdcdc));
68 | /* Chrome,Safari4+ */
69 | background: -webkit-linear-gradient(top, white 0%, #dcdcdc 100%);
70 | /* Chrome10+,Safari5.1+ */
71 | background: -moz-linear-gradient(top, white 0%, #dcdcdc 100%);
72 | /* FF3.6+ */
73 | background: -ms-linear-gradient(top, white 0%, #dcdcdc 100%);
74 | /* IE10+ */
75 | background: -o-linear-gradient(top, white 0%, #dcdcdc 100%);
76 | /* Opera 11.10+ */
77 | background: linear-gradient(to bottom, white 0%, #dcdcdc 100%);
78 | /* W3C */
79 | }
80 |
81 | .page_button_disabled {
82 | pointer-events: none;
83 | cursor: default;
84 | color: #666 !important;
85 | border: 1px solid transparent;
86 | background: transparent;
87 | box-shadow: none;
88 | }
89 |
90 | .page_button_disabled:hover {
91 | pointer-events: none;
92 | cursor: default;
93 | }
94 |
95 | #showing_entries_div {
96 | float:left;
97 | }
98 |
99 | #page_numbers_div {
100 | float: right;
101 | }
--------------------------------------------------------------------------------
/man/interactiveTable.Rd:
--------------------------------------------------------------------------------
1 | % Generated by roxygen2: do not edit by hand
2 | % Please edit documentation in R/interactiveTable.R
3 | \name{interactiveTable}
4 | \alias{interactiveTable}
5 | \alias{interactiveTable.htmlTable}
6 | \alias{knit_print.interactiveTable}
7 | \alias{print.interactiveTable}
8 | \title{An interactive table that allows you to limit the size of boxes}
9 | \usage{
10 | interactiveTable(
11 | x,
12 | ...,
13 | txt.maxlen = 20,
14 | button = getOption("htmlTable.interactiveTable.button", default = FALSE),
15 | minimized.columns = NULL,
16 | js.scripts = c()
17 | )
18 |
19 | \method{interactiveTable}{htmlTable}(
20 | x,
21 | ...,
22 | txt.maxlen = 20,
23 | button = getOption("htmlTable.interactiveTable.button", default = FALSE),
24 | minimized.columns = NULL,
25 | js.scripts = c()
26 | )
27 |
28 | \method{knit_print}{interactiveTable}(x, ...)
29 |
30 | \method{print}{interactiveTable}(x, useViewer, ...)
31 | }
32 | \arguments{
33 | \item{x}{The table to be printed}
34 |
35 | \item{...}{The exact same parameters as \code{\link[=htmlTable]{htmlTable()}} uses}
36 |
37 | \item{txt.maxlen}{The maximum length of a text}
38 |
39 | \item{button}{Indicator if the cell should be clickable or if a button should appear with a plus/minus}
40 |
41 | \item{minimized.columns}{Notifies if any particular columns should be collapsed from start}
42 |
43 | \item{js.scripts}{If you want to add your own JavaScript code you can just add it here.
44 | All code is merged into one string where each section is wrapped in it's own
45 | \verb{} element.}
46 |
47 | \item{useViewer}{If you are using RStudio there is a viewer thar can render
48 | the table within that is envoced if in \code{\link[base:interactive]{base::interactive()}} mode.
49 | Set this to \code{FALSE} if you want to remove that functionality. You can
50 | also force the function to call a specific viewer by setting this to a
51 | viewer function, e.g. \code{useViewer = utils::browseURL} if you want to
52 | override the default RStudio viewer. Another option that does the same is to
53 | set the \code{options(viewer=utils::browseURL)} and it will default to that
54 | particular viewer (this is how RStudio decides on a viewer).
55 | \emph{Note:} If you want to force all output to go through the
56 | \code{\link[base:cat]{base::cat()}} the set \verb{[options][base::options](htmlTable.cat = TRUE)}.}
57 | }
58 | \value{
59 | An htmlTable with a javascript attribute containing the code that is then printed
60 | }
61 | \description{
62 | This function wraps the htmlTable and adds JavaScript code for toggling the amount
63 | of text shown in any particular cell.
64 | }
65 | \examples{
66 | library(magrittr)
67 | # A simple output
68 | long_txt <- "Lorem ipsum dolor sit amet, consectetur adipiscing elit,
69 | sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.
70 | Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi
71 | ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit
72 | in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur
73 | sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt
74 | mollit anim id est laborum"
75 | short_txt <- gsub("(^[^.]+).*", "\\\\1", long_txt)
76 |
77 | cbind(rep(short_txt, 2),
78 | rep(long_txt, 2)) \%>\%
79 | addHtmlTableStyle(col.rgroup = c("#FFF", "#EEF")) \%>\%
80 | interactiveTable(minimized.columns = ncol(.),
81 | header = c("Short", "Long"),
82 | rnames = c("First", "Second"))
83 | }
84 |
--------------------------------------------------------------------------------
/tests/visual_tests/word_test.Rmd:
--------------------------------------------------------------------------------
1 | ---
2 | title: "Pandoc test"
3 | output:
4 | html_document
5 | editor_options:
6 | chunk_output_type: inline
7 | ---
8 |
9 | ```{r echo=FALSE}
10 | knitr::opts_chunk$set(echo = FALSE, message=FALSE, warning=FALSE)
11 | ```
12 |
13 | ```{r}
14 | library(htmlTable)
15 | library(magrittr)
16 |
17 | mx <- matrix(1:6, ncol=3)
18 | htmlTable(mx,
19 | caption = "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.",
20 | tfoot = "Sed ut perspiciatis unde omnis iste natus error sit voluptatem accusantium doloremque laudantium, totam rem aperiam, eaque ipsa quae ab illo inventore veritatis et quasi architecto beatae vitae dicta sunt explicabo. Nemo enim ipsam voluptatem quia voluptas sit aspernatur aut odit aut fugit, sed quia consequuntur magni dolores eos qui ratione voluptatem sequi nesciunt. Neque porro quisquam est, qui dolorem ipsum quia dolor sit amet, consectetur, adipisci velit, sed quia non numquam eius modi tempora incidunt ut labore et dolore magnam aliquam quaerat voluptatem. Ut enim ad minima veniam, quis nostrum exercitationem ullam corporis suscipit laboriosam, nisi ut aliquid ex ea commodi consequatur? Quis autem vel eum iure reprehenderit qui in ea voluptate velit esse quam nihil molestiae consequatur, vel illum qui dolorem eum fugiat quo voluptas nulla pariatur?")
21 |
22 |
23 | set.seed(1)
24 | mx <- matrix(runif(3*10)*10, ncol=3) %>%
25 | set_colnames(LETTERS[1:3]) %>%
26 | set_rownames(LETTERS[1:10])
27 |
28 | txtRound(mx, 3) %>%
29 | htmlTable(
30 | align = "clr",
31 | caption = "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.",
32 | tfoot = "Sed ut perspiciatis unde omnis iste natus error sit voluptatem accusantium doloremque laudantium, totam rem aperiam, eaque ipsa quae ab illo inventore veritatis et quasi architecto beatae vitae dicta sunt explicabo. Nemo enim ipsam voluptatem quia voluptas sit aspernatur aut odit aut fugit, sed quia consequuntur magni dolores eos qui ratione voluptatem sequi nesciunt.
33 | † Neque porro quisquam est, qui dolorem ipsum quia dolor sit amet, consectetur, adipisci velit, sed quia non numquam eius modi tempora incidunt ut labore et dolore magnam aliquam quaerat voluptatem. Ut enim ad minima veniam, quis nostrum exercitationem ullam corporis suscipit laboriosam, nisi ut aliquid ex ea commodi consequatur?
34 | ‡ Quis autem vel eum iure reprehenderit qui in ea voluptate velit esse quam nihil molestiae consequatur, vel illum qui dolorem eum fugiat quo voluptas nulla pariatur?")
35 |
36 | htmlTable(mx,
37 | rgroup = c("Lorem", "ipsum", "dolor"),
38 | n.rgroup = c(2, 3),
39 | cgroup = c("", "Test"),
40 | n.cgroup = 1,
41 | align = "llr",
42 | caption = "Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.")
43 | ```
44 |
45 |
46 |
--------------------------------------------------------------------------------
/inst/examples/htmlTable_example.R:
--------------------------------------------------------------------------------
1 | library(magrittr)
2 |
3 | # Basic example
4 | output <- matrix(1:4,
5 | ncol = 2,
6 | dimnames = list(list("Row 1", "Row 2"),
7 | list("Column 1", "Column 2")))
8 | htmlTable(output)
9 | invisible(readline(prompt = "Press [enter] to continue"))
10 |
11 | # An advanced output
12 | output <- matrix(ncol = 6, nrow = 8)
13 |
14 | for (nr in 1:nrow(output)) {
15 | for (nc in 1:ncol(output)) {
16 | output[nr, nc] <-
17 | paste0(nr, ":", nc)
18 | }
19 | }
20 |
21 | output %>% addHtmlTableStyle(align = "r",
22 | col.columns = c(rep("none", 2),
23 | rep("#F5FBFF", 4)),
24 | col.rgroup = c("none", "#F7F7F7"),
25 | css.cell = "padding-left: .5em; padding-right: .2em;") %>%
26 | htmlTable(header = paste(c("1st", "2nd",
27 | "3rd", "4th",
28 | "5th", "6th"),
29 | "hdr"),
30 | rnames = paste(c("1st", "2nd",
31 | "3rd",
32 | paste0(4:8, "th")),
33 | "row"),
34 | rgroup = paste("Group", LETTERS[1:3]),
35 | n.rgroup = c(2,4,nrow(output) - 6),
36 | cgroup = rbind(c("", "Column spanners", NA),
37 | c("", "Cgroup 1", "Cgroup 2†")),
38 | n.cgroup = rbind(c(1,2,NA),
39 | c(2,2,2)),
40 | caption = "Basic table with both column spanners (groups) and row groups",
41 | tfoot = "† A table footer commment",
42 | cspan.rgroup = 2)
43 | invisible(readline(prompt = "Press [enter] to continue"))
44 |
45 | # An advanced empty table
46 | suppressWarnings({
47 | matrix(ncol = 6,
48 | nrow = 0) %>%
49 | addHtmlTableStyle(col.columns = c(rep("none", 2),
50 | rep("#F5FBFF", 4)),
51 | col.rgroup = c("none", "#F7F7F7"),
52 | css.cell = "padding-left: .5em; padding-right: .2em;") %>%
53 | htmlTable(align = "r",
54 | header = paste(c("1st", "2nd",
55 | "3rd", "4th",
56 | "5th", "6th"),
57 | "hdr"),
58 | cgroup = rbind(c("", "Column spanners", NA),
59 | c("", "Cgroup 1", "Cgroup 2†")),
60 | n.cgroup = rbind(c(1,2,NA),
61 | c(2,2,2)),
62 | caption = "Basic empty table with column spanners (groups) and ignored row colors",
63 | tfoot = "† A table footer commment",
64 | cspan.rgroup = 2)
65 | })
66 | invisible(readline(prompt = "Press [enter] to continue"))
67 |
68 | # An example of how to use the css.cell for header styling
69 | simple_output <- matrix(1:4, ncol = 2)
70 |
71 | simple_output %>%
72 | addHtmlTableStyle(css.cell = rbind(rep("background: lightgrey; font-size: 2em;",
73 | times = ncol(simple_output)),
74 | matrix("",
75 | ncol = ncol(simple_output),
76 | nrow = nrow(simple_output)))) %>%
77 | htmlTable(header = LETTERS[1:2])
78 | invisible(readline(prompt = "Press [enter] to continue"))
79 |
80 | # See vignette("tables", package = "htmlTable")
81 | # for more examples, also check out tidyHtmlTable() that manages
82 | # the group arguments for you through tidy-select syntax
83 |
--------------------------------------------------------------------------------
/vignettes/custom.css:
--------------------------------------------------------------------------------
1 | body {
2 | background-color: #fff;
3 | margin: 1em auto;
4 | max-width: 700px;
5 | overflow: visible;
6 | padding-left: 2em;
7 | padding-right: 2em;
8 | font-family: "Open Sans", "Helvetica Neue", Helvetica, Arial, sans-serif;
9 | font-size: 14px;
10 | line-height: 1.35;
11 | }
12 | #header {
13 | text-align: center;
14 | }
15 | #TOC {
16 | clear: both;
17 | margin: 0 0 10px 10px;
18 | padding: 4px;
19 | width: 400px;
20 | border: 1px solid #CCCCCC;
21 | border-radius: 5px;
22 | background-color: #f6f6f6;
23 | font-size: 13px;
24 | line-height: 1.3;
25 | }
26 | #TOC .toctitle {
27 | font-weight: bold;
28 | font-size: 15px;
29 | margin-left: 5px;
30 | }
31 | #TOC ul {
32 | padding-left: 40px;
33 | margin-left: -1.5em;
34 | margin-top: 5px;
35 | margin-bottom: 5px;
36 | }
37 | #TOC ul ul {
38 | margin-left: -2em;
39 | }
40 | #TOC li {
41 | line-height: 16px;
42 | }
43 | table {
44 | margin: 1em auto;
45 | }
46 |
47 | p {
48 | margin: 0.5em 0;
49 | }
50 | blockquote {
51 | background-color: #f6f6f6;
52 | padding: 0.25em 0.75em;
53 | }
54 | hr {
55 | border-style: solid;
56 | border: none;
57 | border-top: 1px solid #777;
58 | margin: 28px 0;
59 | }
60 | dl {
61 | margin-left: 0;
62 | }
63 | dl dd {
64 | margin-bottom: 13px;
65 | margin-left: 13px;
66 | }
67 | dl dt {
68 | font-weight: bold;
69 | }
70 | ul {
71 | margin-top: 0;
72 | }
73 | ul li {
74 | list-style: circle outside;
75 | }
76 | ul ul {
77 | margin-bottom: 0;
78 | }
79 | pre, code {
80 | background-color: #f7f7f7;
81 | border-radius: 3px;
82 | color: #333;
83 | }
84 | pre {
85 | white-space: pre-wrap; /* Wrap long lines */
86 | border-radius: 3px;
87 | margin: 5px 0px 10px 0px;
88 | padding: 10px;
89 | }
90 | pre:not([class]) {
91 | background-color: #f7f7f7;
92 | }
93 | code {
94 | font-family: Consolas, Monaco, 'Courier New', monospace;
95 | font-size: 85%;
96 | }
97 | p > code, li > code {
98 | padding: 2px 0px;
99 | }
100 | div.figure {
101 | text-align: center;
102 | }
103 | img {
104 | background-color: #FFFFFF;
105 | padding: 2px;
106 | border: 1px solid #DDDDDD;
107 | border-radius: 3px;
108 | border: 1px solid #CCCCCC;
109 | margin: 0 5px;
110 | }
111 | h1 {
112 | margin-top: 0;
113 | font-size: 35px;
114 | line-height: 40px;
115 | }
116 | h2 {
117 | border-bottom: 4px solid #f7f7f7;
118 | padding-top: 10px;
119 | padding-bottom: 2px;
120 | font-size: 145%;
121 | }
122 | h3 {
123 | border-bottom: 2px solid #f7f7f7;
124 | padding-top: 10px;
125 | font-size: 120%;
126 | }
127 | h4 {
128 | border-bottom: 1px solid #f7f7f7;
129 | margin-left: 8px;
130 | font-size: 105%;
131 | }
132 | h5, h6 {
133 | border-bottom: 1px solid #ccc;
134 | font-size: 105%;
135 | }
136 | a {
137 | color: #0033dd;
138 | text-decoration: none;
139 | }
140 | a:hover {
141 | color: #6666ff; }
142 | a:visited {
143 | color: #800080; }
144 | a:visited:hover {
145 | color: #BB00BB; }
146 | a[href^="http:"] {
147 | text-decoration: underline; }
148 | a[href^="https:"] {
149 | text-decoration: underline; }
150 | /* Colours from https://gist.github.com/robsimmons/1172277 */
151 | code > span.kw { color: #555; font-weight: bold; } /* Keyword */
152 | code > span.dt { color: #902000; } /* DataType */
153 | code > span.dv { color: #40a070; } /* DecVal (decimal values) */
154 | code > span.bn { color: #d14; } /* BaseN */
155 | code > span.fl { color: #d14; } /* Float */
156 | code > span.ch { color: #d14; } /* Char */
157 | code > span.st { color: #d14; } /* String */
158 | code > span.co { color: #888888; font-style: italic; } /* Comment */
159 | code > span.ot { color: #007020; } /* OtherToken */
160 | code > span.al { color: #ff0000; font-weight: bold; } /* AlertToken */
161 | code > span.fu { color: #900; font-weight: bold; } /* Function calls */
162 | code > span.er { color: #a61717; background-color: #e3d2d2; } /* ErrorTok */
--------------------------------------------------------------------------------
/R/htmlTable_render_addCells.R:
--------------------------------------------------------------------------------
1 | #' Add a cell
2 | #'
3 | #' Adds a row of cells `val ... ` to a table string for
4 | #' [htmlTable()]
5 | #'
6 | #' @inheritParams htmlTable
7 | #' @param rowcells The cells with the values that are to be added
8 | #' @param cellcode Type of cell, can either be `th` or `td`
9 | #' @param style The cell style
10 | #' @param cgroup_spacer_cells The number of cells that occur between
11 | #' columns due to the cgroup arguments.
12 | #' @param has_rn_col Due to the alignment issue we need to keep track
13 | #' of if there has already been printed a rowname column or not and therefore
14 | #' we have this has_rn_col that is either 0 or 1.
15 | #' @param offset For rgroup rows there may be an offset != 1
16 | #' @param style_list The style_list
17 | #' @return `string` Returns the string with the new cell elements
18 | #' @keywords internal
19 | #' @family hidden helper functions for htmlTable
20 | #' @importFrom stringr str_interp
21 | prAddCells <- function(rowcells, cellcode, style_list, style, prepped_cell_css, cgroup_spacer_cells, has_rn_col, offset = 1, style_list_align_key = "align") {
22 | cell_str <- ""
23 | style <- prAddSemicolon2StrEnd(style)
24 |
25 | previous_was_spacer_cell <- FALSE
26 | for (nr in offset:length(rowcells)) {
27 | cell_value <- rowcells[nr]
28 | # We don't want missing to be NA in a table, it should be empty
29 | if (is.na(cell_value)) {
30 | cell_value <- ""
31 | }
32 |
33 | followed_by_spacer_cell <- nr != length(rowcells) &&
34 | nr <= length(cgroup_spacer_cells) &&
35 | cgroup_spacer_cells[nr] > 0
36 |
37 | align_style <- prGetAlign(style_list[[style_list_align_key]],
38 | index = nr + has_rn_col,
39 | style_list = style_list,
40 | followed_by_spacer_cell = followed_by_spacer_cell,
41 | previous_was_spacer_cell = previous_was_spacer_cell)
42 | cell_style <- c(prepped_cell_css[nr],
43 | style)
44 |
45 | if (!is.null(style_list$col.columns)) {
46 | cell_style %<>%
47 | c(`background-color` = style_list$col.columns[nr])
48 | }
49 |
50 |
51 | cell_str %<>% paste(str_interp("<${CELL_TAG} style='${STYLE}'>${CONTENT}${CELL_TAG}>",
52 | list(CELL_TAG = cellcode,
53 | STYLE = prGetStyle(cell_style,
54 | align_style),
55 | CONTENT = cell_value)),
56 | sep = "\n\t\t")
57 |
58 | # Add empty cell if not last column
59 | if (followed_by_spacer_cell) {
60 | align_style <- prGetAlign(style_list[[style_list_align_key]],
61 | index = nr + has_rn_col,
62 | style_list = style_list,
63 | spacerCell = TRUE,
64 | followed_by_spacer_cell = followed_by_spacer_cell,
65 | previous_was_spacer_cell = previous_was_spacer_cell)
66 |
67 | # The same style as previous but without align borders
68 | cell_style <- c(
69 | prepped_cell_css[nr],
70 | style,
71 | align_style
72 | )
73 | spanner_style <- style
74 |
75 | if (!is.null(style_list$col.columns)) {
76 | if (style_list$col.columns[nr] == style_list$col.columns[nr + 1]) {
77 | spanner_style %<>% c(`background-color` = style_list$col.columns[nr])
78 | }
79 | }
80 |
81 | cell_str %<>%
82 | paste("\n\t\t") %>%
83 | prAddEmptySpacerCell(style_list = style_list,
84 | cell_style = prGetStyle(cell_style, spanner_style),
85 | colspan = cgroup_spacer_cells[nr],
86 | cell_tag = cellcode,
87 | align_style = align_style)
88 | }
89 |
90 | previous_was_spacer_cell <- followed_by_spacer_cell
91 | }
92 | return(cell_str)
93 | }
94 |
--------------------------------------------------------------------------------
/R/htmlTable_helpers_prepareCss.R:
--------------------------------------------------------------------------------
1 | #' Prepares the cell style
2 | #'
3 | #' @param css The CSS styles that are to be converted into
4 | #' a matrix.
5 | #' @param name The name of the CSS style that is prepared
6 | #' @inheritParams htmlTable
7 | #' @return `matrix`
8 | #' @keywords internal
9 | prPrepareCss <- function(x, css, rnames, header = NULL, name = deparse(substitute(css)), style_list = NULL) {
10 | if (is.null(style_list)) {
11 | css.header <- rep("", times = ncol(x))
12 | css.rnames <- rep("", times = nrow(x) + !is.null(header))
13 | } else {
14 | css.header <- rep(ifelse(is.null(style_list$css.header),
15 | "",
16 | style_list$css.header),
17 | times = ncol(x))
18 | css.rnames <- rep(ifelse(is.null(style_list$css.rnames),
19 | "",
20 | style_list$css.rnames),
21 | times = nrow(x) + !missing(header))
22 | }
23 |
24 | if (is.matrix(css)) {
25 | if (any(grepl("^[^:]*[a-zA-Z]+[:]*:", css))) {
26 | rownames(css) <- NULL
27 | colnames(css) <- NULL
28 | }
29 | if (ncol(css) == ncol(x) + 1 &&
30 | !prSkipRownames(rnames)) {
31 | if (!is.null(header)) {
32 | if (nrow(css) == nrow(x) + 1) {
33 | css.rnames <- css[, 1]
34 | } else if (nrow(css) == nrow(x)) {
35 | css.rnames[2:length(css.rnames)] <- css[, 1]
36 | } else {
37 | stop(
38 | "There is an invalid number of rows for the ", name, " matrix.",
39 | " Your x argument has '", nrow(x), "' rows",
40 | " while your ", name, " has '", nrow(css), "' rows",
41 | " and there is a header"
42 | )
43 | }
44 | } else if (nrow(x) == nrow(css)) {
45 | css.rnames <- css[, 1]
46 | } else {
47 | stop(
48 | "There is an invalid number of rows for the ", name, " matrix.",
49 | " Your x argument has '", nrow(x), "' rows",
50 | " while your ", name, " has '", nrow(css), "' rows",
51 | " (there is no header)"
52 | )
53 | }
54 |
55 | css <- css[, -1, drop = FALSE]
56 | } else if (ncol(css) != ncol(x)) {
57 | stop(
58 | "There is an invalid number of columns for the ", name, " matrix.",
59 | " Your x argument has '", ncol(x), "' columns",
60 | " while your ", name, " has '", ncol(css), "' columns",
61 | " and there are ", ifelse(prSkipRownames(rnames),
62 | "no", ""
63 | ),
64 | " rownames."
65 | )
66 | }
67 |
68 | if (nrow(css) == nrow(x) + 1 && !is.null(header)) {
69 | for (i in 1:length(css.header)) {
70 | css.header[i] <- prGetStyle(css.header[i], css[1, i])
71 | }
72 | css <- css[-1, , drop = FALSE]
73 | } else if (nrow(css) != nrow(x)) {
74 | stop(
75 | "There is an invalid number of rows for the ", name, " matrix.",
76 | " Your x argument has '", nrow(x), "' rows",
77 | " while your ", name, " has '", nrow(css), "' rows",
78 | " and there is ", ifelse(is.null(header), "no", "a"),
79 | " header"
80 | )
81 | }
82 | } else if (is.vector(css)) {
83 | if (length(css) == ncol(x) + 1) {
84 | css.rnames <- rep(css[1], nrow(x) + prSkipRownames(rnames))
85 | css <-
86 | css[-1]
87 | } else if (length(css) == 1) {
88 | css.rnames <- rep(css, times = nrow(x) + !is.null(header))
89 | } else if (length(css) != ncol(x)) {
90 | stop(
91 | "The length of your ", name, " vector '", length(css), "'",
92 | " does not correspond to the column length '", ncol(x), "'",
93 | " (there are ", ifelse(prSkipRownames(rnames),
94 | "no", ""
95 | ),
96 | " rownames)"
97 | )
98 | }
99 |
100 | css <- matrix(css,
101 | nrow = nrow(x),
102 | ncol = ncol(x),
103 | byrow = TRUE
104 | )
105 | }
106 |
107 | return(structure(css,
108 | rnames = css.rnames,
109 | header = css.header,
110 | class = class(css)
111 | ))
112 | }
113 |
--------------------------------------------------------------------------------
/man/prGetThead.Rd:
--------------------------------------------------------------------------------
1 | % Generated by roxygen2: do not edit by hand
2 | % Please edit documentation in R/htmlTable_render_getThead.R
3 | \name{prGetThead}
4 | \alias{prGetThead}
5 | \title{Renders the table head (thead)}
6 | \usage{
7 | prGetThead(
8 | x,
9 | header = NULL,
10 | cgroup = NULL,
11 | n.cgroup = NULL,
12 | caption = NULL,
13 | compatibility,
14 | total_columns,
15 | css.cgroup,
16 | top_row_style,
17 | rnames,
18 | rowlabel = NULL,
19 | cgroup_spacer_cells,
20 | prepped_cell_css,
21 | style_list,
22 | cell_style
23 | )
24 | }
25 | \arguments{
26 | \item{x}{The matrix/data.frame with the data. For the \code{print} and \code{knit_print}
27 | it takes a string of the class \code{htmlTable} as \code{x} argument.}
28 |
29 | \item{header}{A vector of character strings specifying column
30 | header, defaulting to \code{\link[base:colnames]{colnames(x)}}}
31 |
32 | \item{cgroup}{A vector, matrix or list of character strings defining major column header. The default
33 | is to have none. These elements are also known as \emph{column spanners}. If you want a column \emph{not}
34 | to have a spanner then put that column as "". If you pass cgroup and \code{n.crgroup} as
35 | matrices you can have column spanners for several rows. See cgroup section below for details.}
36 |
37 | \item{n.cgroup}{An integer vector, matrix or list containing the number of columns for which each element in
38 | cgroup is a heading. For example, specify \code{cgroup=c("Major_1","Major_2")},
39 | \code{n.cgroup=c(3,3)} if \code{"Major_1"} is to span columns 1-3 and
40 | \code{"Major_2"} is to span columns 4-6.
41 | \code{rowlabel} does not count in the column numbers. You can omit \code{n.cgroup}
42 | if all groups have the same number of columns. If the \code{n.cgroup} is one less than
43 | the number of columns in the matrix/data.frame then it automatically adds those.}
44 |
45 | \item{caption}{Adds a table caption.}
46 |
47 | \item{compatibility}{Is default set to \code{LibreOffice} as some
48 | settings need to be in old HTML format as Libre Office can't
49 | handle some commands such as the css caption-alignment. Note: this
50 | option is not yet fully implemented for all details, in the future
51 | I aim to generate a HTML-correct table and one that is aimed
52 | at Libre Office compatibility. Word-compatibility is difficult as
53 | Word ignores most settings and destroys all layout attempts
54 | (at least that is how my 2010 version behaves). You can additinally use the
55 | \code{options(htmlTableCompat = "html")} if you want a change to apply
56 | to the entire document.
57 | MS Excel sometimes misinterprets certain cell data when opening HTML-tables (eg. 1/2 becomes 1. February).
58 | To avoid this please specify the correct Microsoft Office format for each cell in the table using the css.cell-argument.
59 | To make MS Excel interpret everything as text use "mso-number-format:\"\\@\"".}
60 |
61 | \item{total_columns}{The total number of columns including the rowlabel and the
62 | specer cells}
63 |
64 | \item{top_row_style}{The top row has a special style depending on
65 | the \code{ctable} option in the \code{htmlTable} call.}
66 |
67 | \item{rnames}{Default row names are generated from \code{\link[base:colnames]{rownames(x)}}. If you
68 | provide \code{FALSE} then it will skip the row names. \emph{Note:} For \code{data.frames}
69 | if you do \code{\link[base:colnames]{rownames(my_dataframe) <- NULL}} it still has
70 | row names. Thus you need to use \code{FALSE} if you want to
71 | supress row names for \code{data.frames}.}
72 |
73 | \item{rowlabel}{If the table has row names or \code{rnames},
74 | \code{rowlabel} is a character string containing the
75 | column heading for the \code{rnames}.}
76 |
77 | \item{cgroup_spacer_cells}{The spacer cells due to the multiple cgroup levels.
78 | With multiple rows in cgroup we need to keep track of how many spacer cells
79 | occur between the columns. This variable contains is of the size \code{ncol(x)-1}
80 | and 0 if there is no cgroup element between.}
81 |
82 | \item{style_list}{The list with all the styles}
83 | }
84 | \value{
85 | \code{string} Returns the html string for the \verb{... } element
86 | }
87 | \description{
88 | Renders the table head (thead)
89 | }
90 | \keyword{internal}
91 |
--------------------------------------------------------------------------------
/R/htmlTable_helpers_getStyle.R:
--------------------------------------------------------------------------------
1 |
2 | #' Gets the CSS style element
3 | #'
4 | #' A function for checking, merging, and more
5 | #' with a variety of different style formats.
6 | #'
7 | #' @param ... Styles can be provided as `vector`, `named vector`, or `string`.
8 | #' If you provide a name, e.g. `background: blue`, `align="center"`,
9 | #' the function will convert the `align` into proper `align: center`.
10 | #' @return `string` Returns the codes merged into one string with
11 | #' correct CSS ; and : structure.
12 | #' @keywords internal
13 | #' @import magrittr
14 | #' @family hidden helper functions for htmlTable
15 | prGetStyle <- function(...) {
16 | mergeNames <- function(sv) {
17 | sv <- sv[!is.na(sv)]
18 | if (!is.null(names(sv))) {
19 | sv <-
20 | mapply(function(n, v) {
21 | if (n == "") {
22 | return(v)
23 | }
24 | paste0(n, ": ", v)
25 | }, n = names(sv), v = sv, USE.NAMES = FALSE)
26 | }
27 | return(sv)
28 | }
29 | spltNames <- function(sv) {
30 | ret_sv <- c()
31 | for (i in 1:length(sv)) {
32 | ret_sv <- c(
33 | ret_sv,
34 | # Split on the ; in case it is not at the end/start
35 | unlist(strsplit(sv[i], "\\b;(\\b|\\W+)", perl = TRUE))
36 | )
37 | }
38 | return(ret_sv)
39 | }
40 |
41 | styles <- c()
42 | dots <- list(...)
43 | dots <- dots[sapply(dots, function(x) any(!is.na(x) & !is.null(x)))]
44 | if (length(dots) == 0) {
45 | return("")
46 | }
47 |
48 | for (i in 1:length(dots)) {
49 | element <- dots[[i]]
50 | if (length(element) == 1) {
51 | if (element == "") {
52 | next
53 | }
54 |
55 | if (!grepl("\\b[:](\\b|\\W+)", element, perl = TRUE)) {
56 | if (!is.null(names(element))) {
57 | element <-
58 | paste0(names(element), ": ", element)
59 | } else if (!is.null(names(dots)) &&
60 | names(dots)[i] != "") {
61 | element <-
62 | paste0(names(dots)[i], ": ", element)
63 | } else if (element != "none") {
64 | stop(
65 | "The style should be formatted according to 'style_name: value'",
66 | " you have provided style '", element, "'"
67 | )
68 | }
69 | }
70 | styles %<>%
71 | c(element)
72 | } else {
73 | if (!is.null(names(element))) {
74 | element <- mergeNames(element)
75 | }
76 |
77 | styles <- c(
78 | styles,
79 | spltNames(element)
80 | )
81 | }
82 | }
83 |
84 | if (!all(grepl("^[^:]+:.+", styles))) {
85 | stop(
86 | "Invalid styles detected, one or more styles lack the needed style 'name: value': ",
87 | paste(paste0("'", styles[!grepl("^[^:]+:.+", styles)], "'"), collapse = ", ")
88 | )
89 | }
90 |
91 | # Remove empty background colors - sometimes a background color appears with
92 | # just background-color:; for some unknown reason
93 | if (any(grepl("^background-color:( none|[ ]*;*$)", styles))) {
94 | styles <- styles[-grep("^background-color:( none|[ ]*;*$)", styles)]
95 | }
96 |
97 | # Merge background colors
98 | if (sum(grepl("^background-color:", styles)) > 1) {
99 | clrs <- styles[grep("^background-color:", styles)]
100 | clrs <- gsub("^background-color:[ ]*([^;]+);*", "\\1", clrs)
101 | clr <- prMergeClr(clrs)
102 | # Pick a color merge
103 | styles <- styles[-grep("^background-color:", styles)]
104 | styles <-
105 | c(
106 | styles,
107 | paste0("background-color: ", clr)
108 | )
109 | }
110 |
111 | style_names <- gsub("^([^:]+).+", "\\1", styles)
112 | if (!any(duplicated(style_names))) {
113 | unique_styles <- styles
114 | } else {
115 | # Only select the last style if two of the same type
116 | # exist. This in order to avoid any conflicts.
117 | unique_styles <- c()
118 | for (n in unique(style_names)) {
119 | unique_styles <-
120 | c(
121 | unique_styles,
122 | styles[max(which(n == style_names))]
123 | )
124 | }
125 | }
126 |
127 | unique_styles <- sapply(unique_styles, prAddSemicolon2StrEnd, USE.NAMES = FALSE)
128 | paste(unique_styles, collapse = " ")
129 | }
130 |
--------------------------------------------------------------------------------
/man/txtRound.Rd:
--------------------------------------------------------------------------------
1 | % Generated by roxygen2: do not edit by hand
2 | % Please edit documentation in R/txtFrmt_round.R, R/txtFrmt_round_data.frame.R
3 | \name{txtRound}
4 | \alias{txtRound}
5 | \alias{txtRound.default}
6 | \alias{txtRound.table}
7 | \alias{txtRound.matrix}
8 | \alias{txtRound.data.frame}
9 | \title{A convenient rounding function}
10 | \usage{
11 | txtRound(x, ...)
12 |
13 | \method{txtRound}{default}(
14 | x,
15 | digits = 0,
16 | digits.nonzero = NA,
17 | txt.NA = "",
18 | dec = getOption("htmlTable.decimal_marker", default = "."),
19 | scientific = NULL,
20 | txtInt_args = getOption("htmlTable.round_int", default = NULL),
21 | ...
22 | )
23 |
24 | \method{txtRound}{table}(x, ...)
25 |
26 | \method{txtRound}{matrix}(x, digits = 0, excl.cols = NULL, excl.rows = NULL, ...)
27 |
28 | \method{txtRound}{data.frame}(x, ..., digits = 0L)
29 | }
30 | \arguments{
31 | \item{x}{The value/vector/data.frame/matrix to be rounded}
32 |
33 | \item{...}{Passed to next method}
34 |
35 | \item{digits}{The number of digits to round each element to. For \code{matrix}
36 | or \code{data.frame} input you can provide a \code{vector}/\code{list}. An unnamed \code{vector}/\code{list}
37 | must equal the length of the columns to round. If you provide a named vector you
38 | can provide specify per column the number of digits, and then use \code{.default}
39 | for those columns that we don't need to have separate values for.}
40 |
41 | \item{digits.nonzero}{The number of digits to keep if the result is close to
42 | zero. Sometimes we have an entire table with large numbers only to have a
43 | few but interesting observation that are really interesting}
44 |
45 | \item{txt.NA}{The string to exchange \code{NA} with}
46 |
47 | \item{dec}{The decimal marker. If the text is in non-English decimal
48 | and string formatted you need to change this to the appropriate decimal
49 | indicator. The option for this is \code{htmlTable.decimal_marker}.}
50 |
51 | \item{scientific}{If the value should be in scientific format.}
52 |
53 | \item{txtInt_args}{A list of arguments to pass to \code{\link[=txtInt]{txtInt()}} if that is to be
54 | used for large values that may require a thousands separator. The option
55 | for this is \code{htmlTable.round_int}. If \code{TRUE} it will activate the \code{txtInt}
56 | functionality.}
57 |
58 | \item{excl.cols}{Columns to exclude from the rounding procedure when provided a matrix.
59 | This can be either a number or regular expression. Skipped if \code{x} is a vector.}
60 |
61 | \item{excl.rows}{Rows to exclude from the rounding procedure when provided a matrix.
62 | This can be either a number or regular expression.}
63 | }
64 | \value{
65 | \code{matrix/data.frame}
66 | }
67 | \description{
68 | Regular round often looses trailing 0:s as these are truncated, this function
69 | converts everything to strings with all 0:s intact so that tables have the
70 | correct representation, e.g. \code{txtRound(1.01, digits = 1)} turns into \code{1.0}.
71 | }
72 | \section{Tidy-select with \code{data.frame}}{
73 |
74 |
75 | The \code{txtRound} can use \code{data.frame} for input. This allows us to use
76 | \href{https://tidyselect.r-lib.org/articles/tidyselect.html}{tidyselect}
77 | patterns as popularized by \strong{dplyr}.
78 | }
79 |
80 | \examples{
81 | # Basic usage
82 | txtRound(1.023, digits = 1)
83 | # > "1.0"
84 |
85 | txtRound(pi, digits = 2)
86 | # > "3.14"
87 |
88 | txtRound(12344, digits = 1, txtInt_args = TRUE)
89 | # > "12,344.0"
90 |
91 |
92 | # Using matrix
93 | mx <- matrix(c(1, 1.11, 1.25,
94 | 2.50, 2.55, 2.45,
95 | 3.2313, 3, pi),
96 | ncol = 3, byrow=TRUE)
97 | txtRound(mx, digits = 1)
98 | #> [,1] [,2] [,3]
99 | #> [1,] "1.0" "1.1" "1.2"
100 | #> [2,] "2.5" "2.5" "2.5"
101 | #> [3,] "3.2" "3.0" "3.1"
102 |
103 | # Using a data.frame directly
104 | library(magrittr)
105 | data("mtcars")
106 | # If we want to round all the numerical values
107 | mtcars \%>\%
108 | txtRound(digits = 1)
109 |
110 | # If we want only want to round some columns
111 | mtcars \%>\%
112 | txtRound(wt, qsec_txt = qsec, digits = 1)
113 | }
114 | \seealso{
115 | Other text formatters:
116 | \code{\link{txtInt}()},
117 | \code{\link{txtMergeLines}()},
118 | \code{\link{txtPval}()}
119 | }
120 | \concept{text formatters}
121 |
--------------------------------------------------------------------------------
/tests/testthat/test-tidyHtmlTable.R:
--------------------------------------------------------------------------------
1 | library(testthat)
2 | library(dplyr)
3 | library(tibble)
4 | library(purrr)
5 | library(glue)
6 | library(XML)
7 | library(xml2)
8 | library(stringr)
9 |
10 | # Add row names
11 | test_that("Basic tidyHtmlTable functionality", {
12 | skip_if_not_installed("tidyr")
13 |
14 | mx <- tribble(~value, ~header, ~name, ~rgroup, ~cgroup1, ~cgroup2,
15 | 1, 2, 3, 1, 1, 3,
16 | 2, 3, 4, 1, 2, 3,
17 | 3, 4, 5, 2, 2, 4) %>%
18 | mutate_at(vars(starts_with("cgroup")), ~glue("{name} cg", name = .)) %>%
19 | mutate(rgroup = glue("{name}_rg", name = rgroup),
20 | header = glue("{name}_h", name = header))
21 | table_str <- mx %>%
22 | tidyHtmlTable(header = header,
23 | rowlabel = 'row',
24 | label = "test_table")
25 |
26 | parsed_table <- readHTMLTable(as.character(table_str))[["test_table"]]
27 | expect_equal(ncol(parsed_table), 4)
28 | expect_equal(nrow(parsed_table), length(mx$value))
29 | expect_equal(parsed_table %>%
30 | filter(row == 3) %>%
31 | pluck("2_h") %>%
32 | as.character(),
33 | mx %>%
34 | filter(name == 3) %>%
35 | pluck("value") %>%
36 | as.character())
37 |
38 | expect_equal(parsed_table %>%
39 | filter(row == 4) %>%
40 | pluck("3_h") %>%
41 | as.character(),
42 | mx %>%
43 | filter(name == 4) %>%
44 | pluck("value") %>%
45 | as.character())
46 |
47 | expect_equal(parsed_table %>%
48 | filter(row == 5) %>%
49 | pluck("4_h") %>%
50 | as.character(),
51 | mx %>%
52 | filter(name == 5) %>%
53 | pluck("value") %>%
54 | as.character())
55 |
56 | table_str <- mx %>%
57 | tidyHtmlTable(header = header,
58 | rgroup = rgroup,
59 | label = "test_table")
60 |
61 | parsed_table <- readHTMLTable(as.character(table_str))[["test_table"]]
62 | expect_equal(ncol(parsed_table), 4)
63 | expect_equal(nrow(parsed_table), length(mx$value) + length(mx$rgroup %>% unique))
64 |
65 | table_str <- mx %>%
66 | tidyHtmlTable(header = header,
67 | rgroup = rgroup,
68 | hidden_rgroup = "1_rg",
69 | label = "test_table")
70 | parsed_table <- readHTMLTable(as.character(table_str))[["test_table"]]
71 | expect_equal(ncol(parsed_table), 4)
72 | expect_equal(nrow(parsed_table), length(mx$value) + length(mx$rgroup %>% unique) - 1)
73 | expect_match(table_str, "2_rg")
74 | expect_false(grepl("1_rg", table_str))
75 |
76 | table_str <- mx %>%
77 | tidyHtmlTable(header = header,
78 | tspanner = rgroup,
79 | hidden_tspanner = "1_rg",
80 | label = "test_table")
81 | expect_match(table_str, "2_rg")
82 | expect_false(grepl("1_rg", table_str))
83 |
84 | table_str <- mx %>%
85 | tidyHtmlTable(header = header,
86 | rgroup = rgroup,
87 | cgroup = cgroup1,
88 | label = "test_table")
89 |
90 | parsed_table <- readHTMLTable(as.character(table_str))[["test_table"]]
91 | expect_equal(colnames(parsed_table) %>% keep(~grepl("[0-9]", .)) %>% length,
92 | unique(mx$header) %>% length)
93 | expect_equal(ncol(parsed_table), 5)
94 | expect_equal(nrow(parsed_table), length(mx$value) + length(mx$rgroup %>% unique))
95 |
96 | table_str <- mx %>%
97 | tidyHtmlTable(header = header,
98 | rgroup = rgroup,
99 | cgroup = starts_with("cgroup"),
100 | label = "test_table")
101 |
102 | parsed_table <- readHTMLTable(as.character(table_str))[["test_table"]]
103 | expect_equal(colnames(parsed_table) %>% keep(~grepl("[0-9]", .)) %>% length,
104 | unique(mx$header) %>% length)
105 | # Each cgroup generates a empty cell in-between which is how we detect the
106 | # cgroup as it adds these for layout purpose
107 | expect_equal(ncol(parsed_table), 3 + 1 + 2)
108 | expect_equal(nrow(parsed_table), length(mx$value) + length(mx$rgroup %>% unique))
109 | })
110 |
111 |
112 |
113 |
--------------------------------------------------------------------------------
/R/htmlTable_render_getThead.R:
--------------------------------------------------------------------------------
1 | #' Renders the table head (thead)
2 | #'
3 | #' @inheritParams htmlTable
4 | #' @inheritParams prGetCgroupHeader
5 | #' @param total_columns The total number of columns including the rowlabel and the
6 | #' specer cells
7 | #' @return `string` Returns the html string for the `... ` element
8 | #' @keywords internal
9 | #' @importFrom stringr str_interp
10 | prGetThead <- function(x,
11 | header = NULL,
12 | cgroup = NULL, n.cgroup = NULL,
13 | caption = NULL,
14 | compatibility,
15 | total_columns,
16 | css.cgroup,
17 | top_row_style,
18 | rnames,
19 | rowlabel = NULL,
20 | cgroup_spacer_cells,
21 | prepped_cell_css,
22 | style_list,
23 | cell_style) {
24 | first_row <- TRUE
25 | # Start the head
26 | head_str <- "\n\t"
27 |
28 | if (!is.null(caption) &
29 | compatibility == "LibreOffice" &
30 | !style_list$pos.caption %in% c("bottom", "below")) {
31 | head_str %<>% paste(str_interp("${CONTENT} ",
32 | list(COLSPAN = total_columns,
33 | CONTENT = caption)),
34 | sep = "\n\t")
35 | }
36 |
37 | # Add the cgroup table header
38 | if (!is.null(cgroup)) {
39 | for (i in 1:nrow(cgroup)) {
40 | cgrp_str <- prGetCgroupHeader(
41 | x = x,
42 | cgroup_vec = cgroup[i, ],
43 | n.cgroup_vec = n.cgroup[i, ],
44 | cgroup_vec.just = style_list$align.cgroup[i, ],
45 | css_4_cgroup_vec = style_list$css.cgroup[i, ],
46 | row_no = i,
47 | top_row_style = top_row_style,
48 | rnames = rnames,
49 | rowlabel = rowlabel,
50 | style_list = style_list,
51 | cgroup_spacer_cells = cgroup_spacer_cells,
52 | prepped_cell_css = prepped_cell_css
53 | )
54 | head_str %<>%
55 | paste0(cgrp_str)
56 | }
57 | first_row <- FALSE
58 | }
59 |
60 |
61 | # Add the header
62 | if (!is.null(header)) {
63 | header_rowlabel_str <- NA
64 | no_cgroup_rows <- ifelse(!is.null(cgroup), nrow(cgroup), 0)
65 | ts <- ifelse(no_cgroup_rows > 0, "", top_row_style)
66 |
67 | header_list <- NULL
68 | if (!is.null(rowlabel) && style_list$pos.rowlabel == no_cgroup_rows + 1) {
69 | header_list <- list(STYLE = prGetStyle(style_list$css.header.border_bottom,
70 | style_list$css.header[1],
71 | ts,
72 | attr(prepped_cell_css, "rnames")[1],
73 | align = prGetAlign(style_list$align.header, 1, style_list = style_list)),
74 | CONTENT = rowlabel)
75 | } else if (!prSkipRownames(rnames)) {
76 | header_list <- list(STYLE = prGetStyle(style_list$css.header.border_bottom,
77 | ts),
78 | CONTENT = "")
79 | }
80 |
81 | if (!is.null(header_list)) {
82 | header_rowlabel_str <- paste(str_interp("${CONTENT} ", header_list),
83 | sep = "\n\t\t")
84 | }
85 |
86 |
87 | cell_style <- c(style_list$css.header.border_bottom)
88 | if (first_row) {
89 | cell_style %<>% c(top_row_style)
90 | }
91 |
92 | cell_str <- prAddCells(
93 | rowcells = header,
94 | cellcode = "th",
95 | style_list = style_list,
96 | style = cell_style,
97 | cgroup_spacer_cells = cgroup_spacer_cells,
98 | has_rn_col = !prSkipRownames(rnames) * 1,
99 | prepped_cell_css = attr(prepped_cell_css, "header"),
100 | style_list_align_key = "align.header"
101 | )
102 |
103 | # The bottom border was ment to be here but it doesn't
104 | # work that well in the export
105 | if (is.na(header_rowlabel_str)) {
106 | head_str %<>% paste(paste0("", cell_str),
107 | " ",
108 | sep = "\n\t")
109 |
110 | } else {
111 | head_str %<>% paste(paste0("", header_rowlabel_str, cell_str),
112 | " ",
113 | sep = "\n\t")
114 | }
115 |
116 | first_row <- FALSE
117 | }
118 |
119 | #################################
120 | # Close head and start the body #
121 | #################################
122 | head_str %<>%
123 | paste0("\n\t ")
124 | return(head_str)
125 | }
126 |
--------------------------------------------------------------------------------
/R/htmlTable_helpers_attr4RgroupAdd.R:
--------------------------------------------------------------------------------
1 | #' Get the add attribute element
2 | #'
3 | #' Gets the add element attribute if it exists. If non-existant it will
4 | #' return NULL.
5 | #'
6 | #' @param rgroup_iterator The rgroup number of interest
7 | #' @param no_cols The `ncol(x)` of the core htmlTable x argument
8 | #' @inheritParams htmlTable
9 | #' @keywords internal
10 | #' @importFrom stats na.omit
11 | prAttr4RgroupAdd <- function(rgroup, rgroup_iterator, no_cols) {
12 | if (is.null(attr(rgroup, "add"))) {
13 | return(NULL)
14 | }
15 |
16 | add_elmnt <- attr(rgroup, "add")
17 | if (is.null(names(add_elmnt))) {
18 | if (is.null(dim(add_elmnt)) &&
19 | length(add_elmnt) == sum(rgroup != "")) {
20 | if (!is.list(add_elmnt)) {
21 | add_elmnt <- as.list(add_elmnt)
22 | }
23 | names(add_elmnt) <- (1:length(rgroup))[rgroup != ""]
24 | } else if (!is.null(dim(add_elmnt)) &&
25 | ncol(add_elmnt) %in% c(1, no_cols)) {
26 |
27 | # Convert matrix to stricter format
28 | tmp <- list()
29 | for (i in 1:nrow(add_elmnt)) {
30 | if (ncol(add_elmnt) == 1) {
31 | tmp[[i]] <- add_elmnt[i, ]
32 | } else {
33 | tmp2 <- as.list(add_elmnt[i, ])
34 | names(tmp2) <- 1:no_cols
35 | tmp[[i]] <- tmp2
36 | }
37 | }
38 | if (nrow(add_elmnt) == sum(rgroup != "")) {
39 | names(tmp) <- (1:length(rgroup))[rgroup != ""]
40 | } else if (!is.null(rownames(add_elmnt))) {
41 | names(tmp) <- rownames(add_elmnt)
42 | } else {
43 | stop(
44 | "You have provided a matrix as the
45 | add attribute to rgroups without rows that either
46 | match the number of rgroups available '", length(rgroup[rgroup != ""]), "'",
47 | " (you provided '", nrow(add_elmnt), "' rows).",
48 | " And you also failed to have rownames."
49 | )
50 | }
51 | add_elmnt <- tmp
52 | } else {
53 | stop(
54 | "The length of the rgroup 'add' attribute must either match",
55 | " (1) the length of the rgroup",
56 | " (2) or have names corresponding to the mapping integers"
57 | )
58 | }
59 | }
60 |
61 | if (!is.list(add_elmnt) &&
62 | !is.vector(add_elmnt)) {
63 | stop("The rgroup mus either be a list or a vector")
64 | }
65 |
66 | add_pos <- ifelse(grepl(
67 | "^[123456789][0-9]*$",
68 | names(add_elmnt)
69 | ),
70 | as.integer(names(add_elmnt)),
71 | NA
72 | )
73 | if (any(is.na(add_pos))) {
74 | # Look for rgroup names that match to those not
75 | # found through the integer match
76 | # If found the number is assigned to the add_pos
77 | available_rgroups <- rgroup
78 | if (!all(is.na(add_pos))) {
79 | available_rgroups <- available_rgroups[-na.omit(add_pos)]
80 | }
81 | for (missing_pos in which(is.na(add_pos))) {
82 | row_label <- names(add_elmnt)
83 | if (row_label %in% available_rgroups) {
84 | available_rgroups <-
85 | available_rgroups[available_rgroups != row_label]
86 | pos <- which(rgroup == row_label)
87 | if (length(pos) > 1) {
88 | stop(
89 | "There seem to be two identical row groups ('", row_label, "')",
90 | " that you whish to assign a add columns to through the 'add'",
91 | " attribute for the rgroup element."
92 | )
93 | } else {
94 | add_pos[missing_pos] <- pos
95 | }
96 | }
97 | }
98 | if (any(is.na(add_pos))) {
99 | failed_elements <- paste(names(add_elmnt)[is.na(add_pos)], collapse = "', '")
100 | available <- paste(rgroup, collapse = "', '")
101 | stop(
102 | "Failed to find matchin rgroup elements for: ",
103 | "'", failed_elements, "'",
104 | " from availabel rgroups: ",
105 | "'", available, "'"
106 | )
107 | }
108 | names(add_elmnt) <- add_pos
109 | }
110 |
111 | if (!is.list(add_elmnt)) {
112 | add_elmnt <- as.list(add_elmnt)
113 | }
114 |
115 | if (any(add_pos < 1)) {
116 | stop("The rgroup 'add' attribute cannot have integer names below 1")
117 | }
118 |
119 | if (any(!add_pos <= length(rgroup)) || any(rgroup[add_pos] == "")) {
120 | no_rgroups_empty <- paste(which(rgroup == ""), collapse = ", ")
121 | prob_positions <- paste(add_pos[add_pos > length(rgroup) | add_pos %in% which(rgroup == "")], collapse = "', '")
122 | stop(
123 | "The rgroup 'add' attribute cannot have integer names indicating",
124 | " positions larger than the length of the rgroup",
125 | " (=", length(rgroup), ") or matches",
126 | " one of the empty groups (no. ", no_rgroups_empty, ").",
127 | " The problematic position(s):",
128 | " '", prob_positions, "'"
129 | )
130 | }
131 |
132 | # Return the matching iterator
133 | if (rgroup_iterator %in% names(add_elmnt)) {
134 | return(add_elmnt[[as.character(rgroup_iterator)]])
135 | }
136 |
137 | return(NULL)
138 | }
139 |
--------------------------------------------------------------------------------
/tests/testthat/test-htmlTable_cgroup.R:
--------------------------------------------------------------------------------
1 | library(testthat)
2 | library(XML)
3 |
4 | test_that("Check that dimensions are correct with cgroup usage",{
5 | mx <- matrix(1:6, ncol = 3)
6 | colnames(mx) <- sprintf("Col %s", LETTERS[1:NCOL(mx)])
7 | table_str <- htmlTable(mx,
8 | cgroup = c("a", "b"),
9 | n.cgroup=c(1, 2))
10 | parsed_table <- readHTMLTable(as.character(table_str))[[1]]
11 | expect_equal(ncol(parsed_table), ncol(mx) + 1,
12 | info = "Cols did not match")
13 | expect_equal(nrow(parsed_table),
14 | nrow(mx), info="Rows did not match")
15 |
16 | expect_warning(htmlTable(mx,
17 | cgroup=c("a", "b", "c"),
18 | n.cgroup=c(1, 2, 0)))
19 |
20 | expect_error(htmlTable(mx,
21 | cgroup=c("a", "b", "c"),
22 | n.cgroup=c(1, 2, 10)))
23 |
24 | table_str <- htmlTable(mx,
25 | cgroup=rbind(c("aa", NA),
26 | c("a", "b")),
27 | n.cgroup=rbind(c(2, NA),
28 | c(1, 2)))
29 | parsed_table <- readHTMLTable(as.character(table_str))[[1]]
30 | expect_equal(ncol(parsed_table), ncol(mx) + 1,
31 | info="Cols did not match for multilevel cgroup")
32 |
33 |
34 | table_str <- htmlTable(mx,
35 | cgroup=rbind(c("aa", "bb"),
36 | c("a", "b")),
37 | n.cgroup=rbind(c(2, 1),
38 | c(1, 2)))
39 | parsed_table <- readHTMLTable(as.character(table_str))[[1]]
40 | expect_equal(ncol(parsed_table), ncol(mx) + 2,
41 | info="Cols did not match for multilevel cgroup")
42 |
43 | table_str <- htmlTable(mx,
44 | cgroup=c("a", "b"),
45 | n.cgroup=c(2, 1),
46 | tspanner=c("First spanner",
47 | "Secon spanner"),
48 | n.tspanner=c(1,1))
49 | expect_match(table_str, "td[^>]*colspan='4'[^>]*>First spanner",
50 | info="The expected number of columns should be 4")
51 | expect_match(table_str, "td[^>]*colspan='4'[^>]*>Secon spanner",
52 | info="The expected number of columns should be 4")
53 |
54 | expect_error(htmlTable(mx,
55 | cgroup=c("a", "b"),
56 | n.cgroup=c(2, 1),
57 | tspanner=c("First spanner",
58 | "Secon spanner"),
59 | n.tspanner=c(1,2)))
60 |
61 |
62 | mx <- rbind(mx,
63 | mx,
64 | mx,
65 | mx)
66 | table_str <- htmlTable(mx,
67 | rnames = LETTERS[1:nrow(mx)],
68 | cgroup=rbind(c("aa", "bb"),
69 | c("a", "b")),
70 | n.cgroup=rbind(c(2, 1),
71 | c(1, 2)),
72 | rgroup=paste(1:4, "rgroup"),
73 | n.rgroup=rep(2, 4),
74 | tspanner=c("First tspanner",
75 | "Second tspanner"),
76 | n.tspanner=c(4,4))
77 |
78 | expect_match(table_str, "td[^>]*colspan='6'[^>]*>1 rgroup",
79 | info="The expected number of columns should be 6")
80 | expect_match(table_str, "td[^>]*colspan='6'[^>]*>2 rgroup",
81 | info="The expected number of columns should be 6")
82 |
83 | parsed_table <- readHTMLTable(as.character(table_str))[[1]]
84 | expect_equal(as.character(parsed_table[1,1]),
85 | "First tspanner")
86 | expect_equal(as.character(parsed_table[2,1]),
87 | "1 rgroup")
88 | expect_equal(as.character(parsed_table[8,1]),
89 | "Second tspanner")
90 | expect_equal(as.character(parsed_table[9,1]),
91 | "3 rgroup")
92 | })
93 |
94 | test_that("Flexible number of cgroups",{
95 | mx <- matrix(1:6, ncol=3)
96 | colnames(mx) <- sprintf("Col %s", LETTERS[1:NCOL(mx)])
97 |
98 | expect_error(htmlTable(mx,
99 | cgroup = c("", "__test__"),
100 | n.cgroup = 1:3))
101 |
102 | expect_error(htmlTable(mx,
103 | cgroup = c("", "__test__", ""),
104 | n.cgroup = 1))
105 |
106 | out <- htmlTable(mx,
107 | cgroup = c("", "__test__"),
108 | n.cgroup = 1)
109 | expect_match(out,
110 | "colspan='2'[^>]*>__test__<")
111 | })
112 |
113 |
114 | test_that("Assume last element for n.cgroup",{
115 | mx <- matrix(1:6, ncol=3)
116 | colnames(mx) <- sprintf("Col %s", LETTERS[1:NCOL(mx)])
117 |
118 | out <- htmlTable(mx,
119 | cgroup = "__test__")
120 | expect_match(out,
121 | "colspan='3'[^>]*>__test__<")
122 |
123 | })
124 |
--------------------------------------------------------------------------------
/vignettes/text_formatters.Rmd:
--------------------------------------------------------------------------------
1 | ---
2 | title: "Text formatters"
3 | author: "Max Gordon"
4 | date: "`r Sys.Date()`"
5 | VignetteBuilder: knitr, rmarkdown
6 | output:
7 | rmarkdown::html_vignette:
8 | css: custom.css
9 | keep_md: true
10 | toc: true
11 | vignette: >
12 | %\VignetteIndexEntry{Text formatters}
13 | %\usepackage[utf8]{inputenc}
14 | %\VignetteEngine{knitr::rmarkdown}
15 | editor_options:
16 | chunk_output_type: inline
17 | ---
18 |
19 | Text formatters
20 | ===============
21 |
22 | Bundled with this package are some text formatting functions. The purpose of these is to convert numeric values into character/text that is more pleasent in publication tables.
23 |
24 | txtRound
25 | --------
26 |
27 | While `base::round()` is an excellent function in most cases we often want a table to retain trailing 0:s. E.g.
28 |
29 | ```{r message=FALSE}
30 | library(htmlTable)
31 | library(dplyr)
32 | library(magrittr)
33 | data("mtcars")
34 |
35 | mtcars %<>%
36 | mutate(am = factor(am, levels = 0:1, labels = c("Automatic", "Manual")),
37 | vs = factor(vs, levels = 0:1, labels = c("V-shaped", "straight")))
38 |
39 | mtcars %>%
40 | head(3) %>%
41 | select(Transmission = am, Gas = mpg, Weight = wt) %>%
42 | htmlTable()
43 | ```
44 |
45 | doesn't look visually that great, instead we would prefer to have something like this:
46 |
47 | ```{r}
48 | mtcars %>%
49 | head(3) %>%
50 | select(Transmission = am, Gas = mpg, Weight = wt) %>%
51 | txtRound(digits = 1) %>%
52 | htmlTable()
53 | ```
54 |
55 | ### Single/vector values
56 |
57 | At the core of the `txtRound` is the single/vector value conversion:
58 |
59 | ```{r}
60 | txtRound(c(1, 1.1034), digits = 2)
61 |
62 | # Use a character to convert
63 | txtRound("1.2333", digits = 2)
64 | ```
65 |
66 | If you have some values that need thousand separation you can also add `txtInt_args`.
67 |
68 | ```{r}
69 | # Large numbers can be combined with the txtInt option
70 | txtRound(12345.12, digits = 1, txtInt_args = TRUE)
71 |
72 | txtRound(12345.12, digits = 1, txtInt_args = list(language = "se", html = FALSE))
73 | ```
74 |
75 | ### Data frames
76 |
77 | As seen in the introduction we can use data frames for input. We can here rename the converted columns:
78 |
79 | ```{r}
80 | mtcars %>%
81 | head(3) %>%
82 | select(mpg, wt) %>%
83 | txtRound(mpg, wt_txt = wt, digits = 1)
84 | ```
85 |
86 | And we can specify the number of decimals that we're interested in per column:
87 |
88 | ```{r}
89 | mtcars %>%
90 | head(3) %>%
91 | select(mpg, qsec, wt) %>%
92 | txtRound(digits = list(wt = 2, .default = 1))
93 | ```
94 |
95 | ### Matrix
96 |
97 | We can also feed a matrix into the `txtRound`:
98 |
99 | ```{r}
100 | mtcars_matrix <- mtcars %>%
101 | select(mpg, qsec, wt) %>%
102 | head(3) %>%
103 | as.matrix()
104 |
105 | mtcars_matrix %>%
106 | txtRound(digits = 1)
107 | ```
108 |
109 | Here we have some options of excluding columns/rows using regular expressions:
110 |
111 | ```{r}
112 | mtcars_matrix %>%
113 | txtRound(excl.cols = "^wt$",
114 | excl.rows = "^Mazda RX4$",
115 | digits = 1)
116 | ```
117 |
118 | Similarly to the data.frame we can use the same syntax to pick column specific digits:
119 |
120 | ```{r}
121 | mtcars_matrix %>%
122 | txtRound(digits = list(mpg = 0, wt = 2, .default = 1))
123 | ```
124 |
125 | txtInt
126 | ------
127 |
128 | While scientific format is useful if familiar with the syntax it can be difficult to grasp for scholars with a less mathematical background. Therefore the thousand separator style can be quite useful, also known as [digital grouping](https://en.wikipedia.org/wiki/Decimal_separator#Digit_grouping):
129 |
130 | ```{r}
131 | txtInt(1e7)
132 | ```
133 |
134 | As Swedish and many other languages rely on space (SI-standard) we can specify language as a parameter. Note that as we don't want to have line breaks within a digit we can use [non-breaking space](https://en.wikipedia.org/wiki/Non-breaking_space) for keeping the number intact (the html-code is ` `):
135 |
136 | ```{r}
137 | txtInt(1e7, language = "SI", html = FALSE)
138 |
139 | txtInt(1e7, language = "SI", html = TRUE)
140 | ```
141 |
142 | Note that there are the option `htmlTable.language` and `htmlTable.html` that you can use for the input of these parameters.
143 |
144 | txtPval
145 | -------
146 |
147 | The p-value is perhaps the most controversial of statistical output, nevertheless it is still needed and used correctly it has it's use. P-values are frequently rounded as the decimals are not as important. The `txtPval` is a convenient function with some defaults that correspond to typical uses in medical publications.
148 |
149 | ```{r}
150 | txtPval(c(0.1233213, 0.035, 0.001, 0.000001), html = FALSE)
151 |
152 | # The < sign is less-than in html code '<'
153 | txtPval(c(0.05, 0.001, 0.000001), html = TRUE)
154 | ```
155 |
156 | txtMergeLines
157 | -------------
158 |
159 | In html we indicate new line using *<br />* while the latex style uses *hbox*. To help with these two there is the `txtMergeLines` that merges lines into one properly formatted unit:
160 |
161 | ```{r}
162 | txtMergeLines("Line 1",
163 | "Line 2",
164 | "Line 3")
165 | ```
166 |
167 | Note that you can also use a single multi-line string:
168 |
169 | ```{r}
170 | txtMergeLines("Line 1
171 | Line 2
172 | Line 3")
173 | ```
174 |
175 |
176 | ```{r}
177 | txtMergeLines("Line 1
178 | Line 2
179 | Line 3",
180 | html = FALSE)
181 | ```
182 |
183 |
--------------------------------------------------------------------------------
/R/htmlTable_render_getRgroupLine.R:
--------------------------------------------------------------------------------
1 | #' Gets the number of `rgroup` HTML line
2 | #'
3 | #' @param total_columns The total number of columns including the `rowlabel` and the
4 | #' spacer cells
5 | #' @param cspan The column span of the current `rgroup`
6 | #' @param style The css style corresponding to the `rgroup` css style that includes
7 | #' the color specific for the `rgroup`, i.e. `col.rgroup`.
8 | #' @param cgroup_spacer_cells The vector indicating the position of the `cgroup`
9 | #' spacer cells
10 | #' @param prepped_row_css The `css.cell` information for this particular row.
11 | #' @param rgroup_iterator An integer indicating the `rgroup`
12 | #' @inheritParams htmlTable
13 | #' @keywords internal
14 | prGetRgroupLine <- function(x,
15 | total_columns = NULL,
16 | rgroup = NULL,
17 | rgroup_iterator = NULL,
18 | cspan = NULL,
19 | rnames = NULL,
20 | style = NULL,
21 | cgroup_spacer_cells = NULL,
22 | style_list = NULL,
23 | prepped_row_css = NULL) {
24 | ret_str <- ""
25 | rgroup_elmnt <- rgroup[rgroup_iterator]
26 | add_elmnt <- prAttr4RgroupAdd(
27 | rgroup = rgroup,
28 | rgroup_iterator = rgroup_iterator,
29 | no_cols = ncol(x)
30 | )
31 |
32 | ## this will allow either css.rgroup or col.rgroup to
33 | ## color the rgroup label rows
34 | if (is.numeric(cspan) &&
35 | cspan < ncol(x) ||
36 | !is.null(add_elmnt)) {
37 | filler_cells <- rep("", ncol(x))
38 |
39 | if (!is.null(add_elmnt)) {
40 | if (!is.numeric(cspan)) {
41 | cspan <- ncol(x) + 1 * !prSkipRownames(rnames)
42 | }
43 |
44 | if (length(add_elmnt) > 1) {
45 | if (is.null(names(add_elmnt))) {
46 | stop(
47 | "The rgroup 'add' attribute element no '", rgroup_iterator, "'",
48 | " either be a single element or a named list/vector"
49 | )
50 | }
51 |
52 | add_pos <- as.integer(names(add_elmnt))
53 | if (any(is.na(add_pos)) ||
54 | any(add_pos < 1) ||
55 | any(add_pos > ncol(x))) {
56 | stop(
57 | "You have provided invalid element position for rgroup = '", rgroup_elmnt, "'",
58 | " the attribute seeems to be a list but the names are invalid",
59 | " '", paste(names(add_elmnt), collapse = "', '"), "'",
60 | " they should be integers between 1 and ", ncol(x)
61 | )
62 | }
63 |
64 | first_pos <- min(add_pos) - 1 + 1 * !prSkipRownames(rnames)
65 | if (is.null(cspan)) {
66 | cspan <- first_pos
67 | } else {
68 | cspan <- min(
69 | cspan,
70 | first_pos
71 | )
72 | }
73 |
74 | for (ii in 1:length(add_pos)) {
75 | filler_cells[add_pos[ii]] <- add_elmnt[[ii]]
76 | }
77 | } else if (length(add_elmnt) == 1) {
78 | if (is.null(names(add_elmnt)) ||
79 | names(add_elmnt) == "last") {
80 | add_pos <- ncol(x)
81 | } else {
82 | add_pos <- as.integer(names(add_elmnt))
83 | if (is.na(add_pos) ||
84 | add_pos < 1 ||
85 | add_pos > ncol(x)) {
86 | stop(
87 | "You have provided invalid element position for rgroup = '", rgroup_elmnt, "'",
88 | " the attribute seeems to be a list but the name is invalid",
89 | " '", names(add_elmnt), "'",
90 | " it should be an integer between 1 and ", ncol(x)
91 | )
92 | }
93 | }
94 |
95 | first_pos <- add_pos - 1 + 1 * !prSkipRownames(rnames)
96 | if (is.null(cspan)) {
97 | cspan <- first_pos
98 | } else {
99 | cspan <- min(
100 | cspan,
101 | first_pos
102 | )
103 | }
104 |
105 | filler_cells[add_pos] <- add_elmnt
106 | } else {
107 | stop(
108 | "The attribute to the rgroup '", rgroup_elmnt, "'",
109 | " does not have a length!"
110 | )
111 | }
112 | }
113 |
114 | true_span <- cspan +
115 | sum(cgroup_spacer_cells[0:(cspan - 1 * !prSkipRownames(rnames))]) * prGetEmptySpacerCellSize(style_list = style_list)
116 | ret_str %<>%
117 | sprintf(
118 | "%s\n\t%s ",
119 | .,
120 | true_span,
121 | prGetStyle(style),
122 | paste0(
123 | style_list$padding.tspanner,
124 | rgroup_elmnt
125 | )
126 | )
127 |
128 |
129 | cols_left <- ncol(x) - (cspan - 1 * !prSkipRownames(rnames))
130 | cell_str <- prAddCells(
131 | rowcells = filler_cells,
132 | cellcode = "td",
133 | style_list = style_list,
134 | style = style,
135 | cgroup_spacer_cells = cgroup_spacer_cells,
136 | has_rn_col = !prSkipRownames(rnames) * 1,
137 | offset = ncol(x) - cols_left + 1,
138 | prepped_cell_css = prepped_row_css
139 | )
140 | ret_str %<>%
141 | paste0(cell_str)
142 |
143 |
144 | ret_str %<>% paste0(" ")
145 | } else {
146 | ret_str %<>%
147 | sprintf(
148 | "%s\n\t%s ",
149 | .,
150 | total_columns,
151 | prGetStyle(style),
152 | paste0(
153 | style_list$padding.tspanner,
154 | rgroup_elmnt
155 | )
156 | )
157 | }
158 |
159 | return(ret_str)
160 | }
161 |
--------------------------------------------------------------------------------
/R/htmlTable_render_getCgroupHeader.R:
--------------------------------------------------------------------------------
1 | #' Retrieve a header row
2 | #'
3 | #' This function retrieves a header row, i.e. a row
4 | #' within the `` elements on top of the table. Used by
5 | #' [htmlTable()].
6 | #'
7 | #' @param cgroup_vec The `cgroup` may be a `matrix`, this is
8 | #' just one row of that `matrix`
9 | #' @param n.cgroup_vec The same as above but for the counter
10 | #' @param cgroup_vec.just The same as above bot for the justification
11 | #' @param row_no The row number within the header group. Useful for multi-row
12 | #' headers when we need to output the `rowlabel` at the `pos.rowlabel`
13 | #' level.
14 | #' @param style_list The list with all the styles
15 | #' @param top_row_style The top row has a special style depending on
16 | #' the `ctable` option in the `htmlTable` call.
17 | #' @param cgroup_spacer_cells The spacer cells due to the multiple cgroup levels.
18 | #' With multiple rows in cgroup we need to keep track of how many spacer cells
19 | #' occur between the columns. This variable contains is of the size `ncol(x)-1`
20 | #' and 0 if there is no cgroup element between.
21 | #' @return `string`
22 | #' @keywords internal
23 | #' @inheritParams htmlTable
24 | #' @family hidden helper functions for htmlTable
25 | #' @importFrom stringr str_interp
26 | prGetCgroupHeader <- function(x,
27 | cgroup_vec,
28 | n.cgroup_vec,
29 | cgroup_vec.just,
30 | row_no, top_row_style,
31 | rnames,
32 | rowlabel = NULL,
33 | cgroup_spacer_cells,
34 | style_list,
35 | prepped_cell_css,
36 | css_4_cgroup_vec) {
37 | header_str <- "\n\t "
38 | if (row_no == 1) {
39 | ts <- top_row_style
40 | } else {
41 | ts <- ""
42 | }
43 |
44 | if (!is.null(rowlabel)) {
45 | if (row_no == style_list$pos.rowlabel) {
46 | header_str %<>% sprintf(
47 | "%s\n\t\t%s ",
48 | .,
49 | prGetStyle(
50 | c(`font-weight` = 900),
51 | ts,
52 | attr(prepped_cell_css, "rnames")[1]
53 | ),
54 | rowlabel
55 | )
56 | } else {
57 | header_str %<>%
58 | sprintf(
59 | "%s\n\t\t ",
60 | .,
61 | prGetStyle(ts)
62 | )
63 | }
64 | } else if (!prSkipRownames(rnames)) {
65 | header_str %<>% sprintf(
66 | "%s\n\t\t ",
67 | .,
68 | prGetStyle(ts)
69 | )
70 | }
71 |
72 | for (i in 1:length(cgroup_vec)) {
73 | if (!is.na(n.cgroup_vec[i])) {
74 | start_column <- ifelse(i == 1,
75 | 1,
76 | sum(n.cgroup_vec[1:(i - 1)], na.rm = TRUE) + 1
77 | )
78 |
79 | # 10 3-1
80 | # 0 0 1
81 | colspan <- n.cgroup_vec[i] +
82 | ifelse(start_column > length(cgroup_spacer_cells) || n.cgroup_vec[i] == 1,
83 | 0,
84 | ifelse(start_column == 1,
85 | sum(cgroup_spacer_cells[1:(n.cgroup_vec[i] - 1)]),
86 | ifelse(sum(n.cgroup_vec[1:i], na.rm = TRUE) == ncol(x),
87 | sum(cgroup_spacer_cells[start_column:length(cgroup_spacer_cells)]),
88 | sum(cgroup_spacer_cells[start_column:((start_column - 1) + (n.cgroup_vec[i] - 1))])
89 | )
90 | ) * prGetEmptySpacerCellSize(style_list = style_list)
91 | )
92 |
93 |
94 | header_align <- prGetAlign(cgroup_vec.just,
95 | index = i,
96 | style_list = style_list)
97 | if (nchar(cgroup_vec[i]) == 0) { # Removed as this may now be on purpose || is.na(cgroup_vec[i]))
98 | header_values <- list(COLSPAN = colspan,
99 | STYLE = prGetStyle(c(`font-weight` = 900),
100 | ts,
101 | header_align,
102 | css_4_cgroup_vec[i]),
103 | CONTENT = "")
104 | } else {
105 | header_values <- list(COLSPAN = colspan,
106 | STYLE = prGetStyle(c(`font-weight` = 900,
107 | `border-bottom` = "1px solid grey"),
108 | ts,
109 | header_align,
110 | css_4_cgroup_vec[i]),
111 | CONTENT = cgroup_vec[i])
112 | }
113 |
114 | header_str %<>% paste(str_interp("${CONTENT} ",
115 | header_values),
116 | sep = "\n\t\t")
117 |
118 | # If not last then add a filler cell between the row categories
119 | # this is also the reason that we need the cgroup_spacer_cells
120 | if (i != sum(!is.na(cgroup_vec))) {
121 | bottom_border_style = str_interp("border-bottom: ${STYLE};",
122 | list(STYLE = style_list$spacer.css.cgroup.bottom.border))
123 | header_str %<>% prAddEmptySpacerCell(style_list = style_list,
124 | cell_style = prGetStyle(bottom_border_style,
125 | ts),
126 | align_style = header_align,
127 | cell_tag = "th")
128 | }
129 | }
130 | }
131 | header_str %<>%
132 | paste0("\n\t ")
133 |
134 | return(header_str)
135 | }
136 |
--------------------------------------------------------------------------------
/inst/htmlwidgets/lib/table_pagination/table_pagination.js:
--------------------------------------------------------------------------------
1 | /**
2 | * Refreshes the table and the navigation bar
3 | * @param table the table to paginate
4 | * @param nav_id the div where the pagination menu will appear
5 | * @param currPage the page of the table to show
6 | * @param rowsShown the number of rows to show per page
7 | */
8 | function refresh_table(table, nav_id, currPage, rowsShown) {
9 | "use strict";
10 | function append_link_to_page(pagenum, text, container) {
11 | var pagelink;
12 | pagelink = document.createElement("a");
13 | $(pagelink).attr('href','#').attr('data-page', pagenum).
14 | addClass('page_button').text(text);
15 | $(container).append(pagelink);
16 | return pagelink;
17 | }
18 |
19 | function showing_x_to_y_of_z_entries(startItem, endItem, rowsTotal) {
20 | var showing_entries_div = document.createElement('div');
21 | $(showing_entries_div).attr('id', 'showing_entries_div');
22 | if (+rowsTotal === 0) {
23 | $(showing_entries_div).append('No entries. ');
24 | } else {
25 | $(showing_entries_div).append('Showing ' +(+startItem+1) +
26 | ' to ' +endItem + ' of ' +rowsTotal + ' entries. ');
27 | }
28 | return showing_entries_div;
29 | }
30 |
31 | function first_previous_1_2_3_4_next_last(currPage, numPages, table, nav_id, rowsShown) {
32 | // First Previous 4 5 6 7 8 9 10 Next Last
33 | var page_numbers_div = document.createElement('div');
34 | if (numPages <= 1) {
35 | // Empty div if there are no pages to change
36 | return page_numbers_div;
37 | }
38 | $(page_numbers_div).attr('id', 'page_numbers_div');
39 |
40 | // Page: First and Previous
41 | var pagefirst = append_link_to_page(0, 'First', page_numbers_div);
42 | var pageprev = append_link_to_page(+currPage-1, 'Previous', page_numbers_div);
43 | if (+currPage === 0) {
44 | $(pagefirst).addClass('page_button_disabled');
45 | $(pageprev).addClass('page_button_disabled');
46 | }
47 |
48 | var spanpagenumber = document.createElement('span');
49 | $(page_numbers_div).append(spanpagenumber);
50 | var start_nearby_pages = Math.max(0, +currPage-3);
51 | var end_nearby_pages = Math.min(+numPages-1, +currPage+3);
52 | for (var i = start_nearby_pages; i <= end_nearby_pages; i++) {
53 | // Page: i
54 | var page_i = append_link_to_page(i, 1+i, spanpagenumber);
55 | if (+currPage === +i) {
56 | $(page_i).addClass('page_button_current');
57 | }
58 | }
59 | // Page: Next and Last
60 | var pagenext = append_link_to_page(+currPage+1, "Next", page_numbers_div);
61 | var pagelast = append_link_to_page(+numPages-1, "Last", page_numbers_div);
62 | if (+currPage === +numPages-1) {
63 | $(pagenext).addClass('page_button_disabled');
64 | $(pagelast).addClass('page_button_disabled');
65 | }
66 |
67 | $(page_numbers_div).find('a').bind('click', function() {
68 | var currPage = $(this).attr('data-page');
69 | refresh_table(table, nav_id, +currPage, +rowsShown);
70 | });
71 | return page_numbers_div;
72 | }
73 |
74 | var navobj = document.getElementById(nav_id);
75 | var rowsTotal = $(table).find('tbody').find('tr').length;
76 | var startItem = currPage * rowsShown;
77 | var endItem = Math.min(startItem + rowsShown, rowsTotal);
78 | var numPages;
79 | if (+rowsShown > 0) {
80 | numPages = Math.ceil(1.0*rowsTotal/rowsShown);
81 | } else {
82 | numPages = 0;
83 | }
84 |
85 | // Show the chosen rows:
86 | $(table).find('tbody').find('tr').css('opacity','0.0').hide().slice(startItem, endItem).
87 | css('display','table-row').animate({opacity:1}, 300);
88 |
89 | // Rewrite the navigation panel below the table on each page click
90 | $(navobj).empty();
91 | // Showing 31 to 40 entries out of 150 entries:
92 | $(navobj).append(showing_x_to_y_of_z_entries(startItem, endItem, rowsTotal));
93 | // First Previous 1 2 3 4 5 Next Last
94 | $(navobj).append(first_previous_1_2_3_4_next_last(currPage, numPages,
95 | table, nav_id, rowsShown));
96 | }
97 |
98 | /**
99 | * Adds pagination options to a table
100 | * @param table the table to be paginated
101 | * @param nav_id A string with the id of the div that will contain both the "Showing 11 to 20 of 100 entries" and the pagination buttons (First Previous 1 2 3 Next Last)
102 | * @param select_entries_div_id A string with the id of the div where "Show [10|25|100] entries" selection box will be placed
103 | * @param options Currently only one option accepted: options.number_of_entries = [10, 20, 30]. It controls the possible number of rows per page to show.
104 | */
105 | function table_pagination(table, nav_id, select_entries_div_id, options) {
106 | "use strict";
107 | // Show [10|25|100] entries
108 | var select_entries_div = document.getElementById(select_entries_div_id);
109 | $(select_entries_div).empty();
110 |
111 | // Get the possible entries per page:
112 | var select_entries_allowed = options.number_of_entries;
113 | if (select_entries_allowed.length === 0) {
114 | select_entries_allowed = [10, 25, 100];
115 | }
116 |
117 | // If select_entries_allowed is a scalar, do not offer a select:
118 | if (!$.isArray(select_entries_allowed)) {
119 | refresh_table(table, nav_id, 0, +select_entries_allowed);
120 | return;
121 | }
122 | // Otherwise show the select menu:
123 | var label_entries = document.createElement('label');
124 | var select_entries = document.createElement('select');
125 | var select_entries_id = select_entries_div_id.concat('_select');
126 | $(label_entries).attr('for', select_entries_id);
127 | $(label_entries).append('Show ');
128 | $(select_entries).attr('id', select_entries_id);
129 | for (var i=0;i