Skip to content

Commit 66613f5

Browse files
authored
Merge pull request #41 from JulienBlasco/new-styling-method
New styling method
2 parents 3d9074c + d13ba17 commit 66613f5

14 files changed

+478
-32
lines changed

NAMESPACE

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,9 @@
22

33
export(add_table)
44
export(toxlsx)
5+
export(xls_theme)
6+
export(xls_theme_default)
7+
export(xls_theme_plain)
58
import(utils)
69
importFrom(cli,cli_alert_success)
710
importFrom(magrittr,"%>%")

NEWS.md

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,9 @@
11
# tablexlsx (WIP)
22

3-
* (fix) `toxlsx()` no longer fails when the `object` argument is the result of a computation (#18)
3+
* new method for styling tables: `toxlsx()` now accepts a `theme` argument, which has to be supplied as an object returned by `xls_theme()` functions. Some themes are provided by default: `xls_theme_default()` and `xls_theme_plain()`. The default theme has been slightly changed. (#40)
44
* provide meaningful error message if merge cols don't exist (#20)
55
* `path` can now be supplied as a file name with full path instead of a directory name (#29)
6+
* (fix) `toxlsx()` no longer fails when the `object` argument is the result of a computation (#18)
67

78
# tablexlsx 1.0.0
89

R/add_table.R

Lines changed: 15 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@
99
#' @param StartRow : export start line number in the sheet (by default 1)
1010
#' @param StartCol : export start column number in the sheet (by default 1)
1111
#' @param FormatList : list that indicates the format of each column of the data frame
12+
#' @param Theme : styling theme, a named list of `openxlsx` Styles
1213
#' @param HeightTableTitle : multiplier (if needed) for the height of the title line (by default 2)
1314
#' @param TableFootnote1 : string for TableFootnote1
1415
#' @param TableFootnote2 : string for TableFootnote2
@@ -28,7 +29,8 @@ add_table <- function(
2829
TableTitle,
2930
StartRow = 1,
3031
StartCol = 1,
31-
FormatList = list(),
32+
FormatList = setNames(rep(list(Theme[["character"]]), length(colnames(Table))), colnames(Table)),
33+
Theme = xls_theme_default(),
3234
HeightTableTitle = 2,
3335
TableFootnote1 = "",
3436
TableFootnote2 = "",
@@ -68,9 +70,7 @@ add_table <- function(
6870

6971

7072
# Adjusting the size of columns and rows
71-
openxlsx::setColWidths(WbTitle, sheet = mysheet, cols = StartCol + 1, widths = 45)
72-
openxlsx::setColWidths(WbTitle, sheet = mysheet, cols = StartCol + 2, widths = 30)
73-
openxlsx::setColWidths(WbTitle, sheet = mysheet, cols = c(StartCol + 3:38), widths = 20)
73+
openxlsx::setColWidths(WbTitle, sheet = mysheet, cols = StartCol + 1:(ncol(Table)-length(ByGroup)), widths = 20)
7474

7575
# Size of column headers
7676
openxlsx::setRowHeights(WbTitle, sheet = mysheet, rows = StartRow + 2, heights = 20 * HeightTableTitle)
@@ -92,7 +92,7 @@ add_table <- function(
9292
sheet = mysheet,
9393
cols = StartCol,
9494
rows = StartRow,
95-
style = style$title
95+
style = Theme$title
9696
)
9797

9898
if (isTRUE(asTable)) {
@@ -110,7 +110,7 @@ add_table <- function(
110110
startRow = StartRow + 2,
111111
startCol = StartCol + 1,
112112
rowNames = FALSE,
113-
headerStyle = style$col_header
113+
headerStyle = Theme$col_header
114114
)
115115
lastrowtable <- StartRow + 2 + nrow(Table)
116116
} else {
@@ -121,13 +121,16 @@ add_table <- function(
121121
startRow = StartRow + 2,
122122
startCol = StartCol + 1,
123123
rowNames = FALSE,
124-
headerStyle = style$col_header,
124+
headerStyle = Theme$col_header,
125125
group = ByGroup,
126126
groupname = GroupName,
127127
)
128128
lastrowtable <- StartRow + 2 + nrow(Table) + nrow(unique(Table[ByGroup]))
129129
}
130130

131+
# Remove grouping columns from the list of formats
132+
FormatList[colnames(Table) %in% ByGroup] <- NULL
133+
131134
# Format of the table's columns
132135
sapply(seq_len(length(FormatList)), function(i) {
133136
openxlsx::addStyle(
@@ -149,7 +152,7 @@ add_table <- function(
149152
WbTitle,
150153
sheet = mysheet,
151154
cols = StartCol, rows = lastrowtable + 2,
152-
style = style$footnote1
155+
style = Theme$footnote1
153156
)
154157

155158
openxlsx::writeData(
@@ -161,7 +164,7 @@ add_table <- function(
161164
WbTitle,
162165
sheet = mysheet,
163166
cols = StartCol, rows = lastrowtable + 3,
164-
style = style$footnote2
167+
style = Theme$footnote2
165168
)
166169

167170
openxlsx::writeData(
@@ -173,7 +176,7 @@ add_table <- function(
173176
WbTitle,
174177
sheet = mysheet,
175178
cols = StartCol, rows = lastrowtable + 4,
176-
style = style$footnote3
179+
style = Theme$footnote3
177180
)
178181

179182
# If mergecol is filled in
@@ -188,7 +191,7 @@ add_table <- function(
188191
# loop on each modality of mycol
189192
for (i in (1:distinct_mergecol)) {
190193

191-
mergeCells(wb = WbTitle,
194+
openxlsx::mergeCells(wb = WbTitle,
192195
sheet = mysheet,
193196
# here we add 1 because the table starts to be written from col 2 in workbook
194197
cols = which(names(Table) %in% mycol)+1,
@@ -206,7 +209,7 @@ add_table <- function(
206209
rows = convert_range_string(
207210
get_indices_from_vector(Table[[mycol]])
208211
) + StartRow + 2,
209-
style = style$mergedcell
212+
style = Theme$mergedcell
210213
)
211214

212215
}

R/asserts.R

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -110,3 +110,19 @@ assert_grouped <- function(x) {
110110
stop(substitute(x), " must not be grouped", call. = FALSE)
111111
}
112112
}
113+
114+
#' @name assert_xls_theme
115+
#'
116+
#' @param x Object
117+
#'
118+
#' @noRd
119+
assert_xls_theme <- function(x) {
120+
if (!all(vapply(x, FUN = inherits, FUN.VALUE = logical(1L), "Style"))) {
121+
stop(substitute(x), " must be a list of elements of class Style", call. = FALSE)
122+
}
123+
necessary_elements <- c("title", "col_header", "character", "footnote1", "footnote2", "footnote3", "mergedcell")
124+
missing_elements <- setdiff(necessary_elements, names(x))
125+
if (length(missing_elements) > 0) {
126+
stop(substitute(x), " must contain styles for elements ", paste(missing_elements, collapse=" "), call. = FALSE)
127+
}
128+
}

R/themes.R

Lines changed: 221 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,221 @@
1+
#' @name xls_theme
2+
#'
3+
#' @title Constructor function for xls themes
4+
#'
5+
#' @description
6+
#' This function creates an xls theme for styling exported tables.
7+
#' All its arguments must be `openxlsx` Style objects.
8+
#'
9+
#' @param title Style for the title
10+
#' @param col_header Style for the columns header
11+
#' @param character Default style for data cells
12+
#' @param footnote1 Style for footnote1
13+
#' @param footnote2 Style for footnote2
14+
#' @param footnote3 Style for footnote3
15+
#' @param mergedcell Style for merged cells
16+
#' @param ... Other (named) custom styles
17+
#'
18+
#' @return a named list of class xls_theme, whose elements are `openxlsx` Style objects.
19+
#' @export
20+
#'
21+
#' @seealso \code{\link[tablexlsx:xls_theme_plain]{xls_theme_plain()}},
22+
#' \code{\link[tablexlsx:xls_theme_default]{xls_theme_default()}}
23+
#'
24+
#' @examples
25+
#' my_theme <- xls_theme(
26+
#' title = openxlsx::createStyle(),
27+
#' col_header = openxlsx::createStyle(),
28+
#' character = openxlsx::createStyle(),
29+
#' footnote1 = openxlsx::createStyle(),
30+
#' footnote2 = openxlsx::createStyle(),
31+
#' footnote3 = openxlsx::createStyle(),
32+
#' mergedcell = openxlsx::createStyle()
33+
#' )
34+
#'
35+
#' \dontrun{
36+
#' toxlsx(object = iris, path = tempdir(), theme = my_theme)
37+
#' }
38+
xls_theme <- function(title,
39+
col_header,
40+
character,
41+
footnote1,
42+
footnote2,
43+
footnote3,
44+
mergedcell,
45+
...) {
46+
theme <- list(title = title,
47+
col_header = col_header,
48+
character = character,
49+
footnote1 = footnote1,
50+
footnote2 = footnote2,
51+
footnote3 = footnote3,
52+
mergedcell = mergedcell,
53+
...)
54+
class(theme) <- "xls_theme"
55+
assert_xls_theme(theme)
56+
theme
57+
}
58+
59+
#' @name xls_theme_plain
60+
#'
61+
#' @title Constructor function for a plain xls theme
62+
#'
63+
#' @description
64+
#' This function is a wrapper around [xls_theme()] that creates an xls theme for styling exported tables.
65+
#' It defines a simple theme whith no special formatting.
66+
#' All its arguments must be `openxlsx` Style objects.
67+
#'
68+
#' @param title Style for the title
69+
#' @param col_header Style for the columns header
70+
#' @param character Default style for data cells
71+
#' @param footnote1 Style for footnote1
72+
#' @param footnote2 Style for footnote2
73+
#' @param footnote3 Style for footnote3
74+
#' @param mergedcell Style for merged cells
75+
#' @param ... Other (named) custom styles
76+
#'
77+
#' @return a named list of class xls_theme, whose elements are `openxlsx` Style objects.
78+
#' @export
79+
#'
80+
#' @seealso \code{\link[tablexlsx:xls_theme]{xls_theme()}},
81+
#' \code{\link[tablexlsx:xls_theme_default]{xls_theme_default()}}
82+
#'
83+
#' @examples
84+
#' # plain theme
85+
#' xls_theme_plain()
86+
#'
87+
#' # plain theme with title in bold
88+
#' my_theme <- xls_theme_plain(title = openxlsx::createStyle(textDecoration = "bold"))
89+
#'
90+
#' \dontrun{
91+
#' toxlsx(object = iris, path = tempdir(), theme = my_theme)
92+
#' }
93+
xls_theme_plain = function(
94+
title = openxlsx::createStyle(),
95+
col_header = openxlsx::createStyle(),
96+
character = openxlsx::createStyle(),
97+
footnote1 = openxlsx::createStyle(),
98+
footnote2 = openxlsx::createStyle(),
99+
footnote3 = openxlsx::createStyle(),
100+
mergedcell = openxlsx::createStyle(),
101+
...
102+
) {
103+
xls_theme(
104+
title = title,
105+
col_header = col_header,
106+
character = character,
107+
footnote1 = footnote1,
108+
footnote2 = footnote2,
109+
footnote3 = footnote3,
110+
mergedcell = mergedcell,
111+
...
112+
)
113+
}
114+
115+
#' @name xls_theme_default
116+
#'
117+
#' @title Constructor function for the default xls theme
118+
#'
119+
#' @description
120+
#' This function is a wrapper around [xls_theme()] that creates an xls theme for styling exported tables.
121+
#' It defines a theme whith sensible default formatting values.
122+
#' It also defines custom styles for "number", "decimal" and "percent column types.
123+
#' All its arguments must be `openxlsx` Style objects.
124+
#'
125+
#' @param title Style for the title
126+
#' @param col_header Style for the columns header
127+
#' @param character Default style for data cells
128+
#' @param number Style for columns in number format
129+
#' @param decimal Style for columns in decimal format
130+
#' @param percent Style for columns in percent format
131+
#' @param footnote1 Style for footnote1
132+
#' @param footnote2 Style for footnote2
133+
#' @param footnote3 Style for footnote3
134+
#' @param mergedcell Style for merged cells
135+
#' @param ... Other (named) custom styles
136+
#'
137+
#' @return a named list of class xls_theme, whose elements are `openxlsx` Style objects.
138+
#' @export
139+
#'
140+
#' @seealso \code{\link[tablexlsx:xls_theme]{xls_theme()}},
141+
#' \code{\link[tablexlsx:xls_theme_plain]{xls_theme_plain()}}
142+
#'
143+
#' @examples
144+
#' # default theme
145+
#' xls_theme_default()
146+
#'
147+
#' # default theme with title in italic
148+
#' my_theme <- xls_theme_default(title = openxlsx::createStyle(textDecoration = "italic"))
149+
#'
150+
#' \dontrun{
151+
#' toxlsx(object = iris, path = tempdir(), theme = my_theme)
152+
#' }
153+
xls_theme_default = function(
154+
title = openxlsx::createStyle(fontSize = 16, textDecoration = "bold"),
155+
# For footnote1
156+
footnote1 = openxlsx::createStyle(fontSize = 12),
157+
# For footnote2
158+
footnote2 = openxlsx::createStyle(fontSize = 12),
159+
# For footnote3
160+
footnote3 = openxlsx::createStyle(fontSize = 12),
161+
# For column headers
162+
col_header = openxlsx::createStyle(
163+
fontSize = 12,
164+
textDecoration = "bold",
165+
border = c("top", "bottom", "left", "right"),
166+
borderStyle = "thin",
167+
wrapText = TRUE,
168+
halign = "center"
169+
),
170+
# For cells in character format
171+
character = openxlsx::createStyle(
172+
fontSize = 12,
173+
border = c("top", "bottom", "left", "right"),
174+
borderStyle = "thin"
175+
),
176+
# For cells in number format (with thousands separator)
177+
number = openxlsx::createStyle(
178+
fontSize = 12,
179+
numFmt = "### ### ### ##0",
180+
border = c("top", "bottom", "left", "right"),
181+
borderStyle = "thin"
182+
),
183+
# For cells in number format with decimals (and with thousands separator)
184+
decimal = openxlsx::createStyle(
185+
fontSize = 12,
186+
numFmt = "### ### ### ##0.0",
187+
border = c("top", "bottom", "left", "right"),
188+
borderStyle = "thin"
189+
),
190+
# For cells in percentage format (centered)
191+
percent = openxlsx::createStyle(
192+
fontSize = 12,
193+
numFmt = "#0.0",
194+
border = c("top", "bottom", "left", "right"),
195+
borderStyle = "thin",
196+
halign = "center"
197+
),
198+
mergedcell = openxlsx::createStyle(
199+
fontSize = 12,
200+
border = c("top", "bottom", "left", "right"),
201+
borderStyle = "thin",
202+
wrapText = TRUE,
203+
valign = "center",
204+
halign = "center"
205+
),
206+
...
207+
) {
208+
xls_theme_plain(
209+
title = title,
210+
col_header = col_header,
211+
character = character,
212+
number = number,
213+
decimal = decimal,
214+
percent = percent,
215+
footnote1 = footnote1,
216+
footnote2 = footnote2,
217+
footnote3 = footnote3,
218+
mergedcell = mergedcell,
219+
...
220+
)
221+
}

0 commit comments

Comments
 (0)