--- title: "Formatting cells" output: rmarkdown::html_vignette vignette: > %\VignetteIndexEntry{Formatting cells} %\VignetteEngine{knitr::rmarkdown} %\VignetteEncoding{UTF-8} --- ```{r setup, include = FALSE} knitr::opts_chunk$set(collapse = TRUE, comment = "#>") library(writexl) ``` One kind of object describes appearance everywhere in writexl: an `xl_format`. The same object styles a cell, a whole column, a chart series or a conditional rule, so there is one vocabulary to learn rather than five. ## Building a format Six group constructors, each covering one family of Excel properties. Every argument defaults to unset, so you name only what you want to change: ```{r} xl_font(bold = TRUE, color = "navy", size = 12) xl_fill(background = "#FFF2CC") xl_border(all = "thin", color = "gray") xl_align(horizontal = "center", vertical = "top", wrap = TRUE) xl_num_format("#,##0.00") xl_protection(locked = FALSE) ``` Colours accept R colour names, hex strings or integers, via `xl_color()`. Each constructor already returns a complete format, so one can be used alone. Combine them with `+`, which merges **property by property** --- later values win, but nothing you did not touch is lost: ```{r} money <- xl_num_format("$#,##0.00") + xl_font(color = "darkgreen") money + xl_font(bold = TRUE) # still green, now bold ``` ## Applying it to cells `xl_cell_general()` attaches a format to values. One format covers the column; a list gives a format per cell: ```{r} df <- data.frame(item = c("Widget", "Gadget", "Gizmo")) df$price <- xl_cell_general(value = c(1234.5, 67.25, 890), format = money) df$flag <- xl_cell_general( value = c(10, -5, 3), format = list(xl_fill(background = "lightgreen"), xl_fill(background = "salmon"), xl_fill(background = "lightgreen"))) path <- write_xlsx(df, tempfile(fileext = ".xlsx")) ``` A cell with a format and no value is a formatted blank --- useful for ruling a sheet out to a fixed size: ```{r} xl_cell_general(value = NA, format = xl_fill(background = "#EEEEEE")) ``` Dates and times take the workbook's date format automatically when their own format sets no number format. ## Applying it to columns and rows More often you want a whole column. `xl_col_spec()` and `xl_row_spec()` *are* `xl_format` objects that additionally carry a target and some geometry, so they combine with `+` like any other format: ```{r} sheet <- xl_sheet( data.frame(date = as.Date("2024-01-01") + 0:2, revenue = c(1000.5, 2000.25, 1500.75)), cols = list(xl_col_spec("date", width = 12), xl_col_spec("revenue", width = 14, format = money)), rows = xl_row_spec(1, height = 20)) path <- write_xlsx(list(Sales = sheet), tempfile(fileext = ".xlsx")) ``` Columns are named or indexed; rows are counted from 1 as *data* rows, ignoring the header. ## Where a format comes from Formats cascade. What Excel finally applies to a cell is the workbook's `default_format`, merged with the column or row format, merged with the cell's own. Identical results are written once, so styling thousands of cells stays compact. See [Worksheets and workbooks](c-worksheets-workbooks.html) for the workbook end of that. ## Conditional formatting A conditional format is a rule plus a format, applied to a range and evaluated by Excel rather than by you: ```{r} scores <- data.frame(name = c("a", "b", "c", "d"), score = c(35, 78, 55, 92)) sheet <- xl_sheet(scores, conditional = list( xl_cond_cell(list(cols = "score"), "cell", ">=", 80, format = xl_fill(background = "lightgreen")), xl_cond_cell(list(cols = "score"), "cell", "<", 50, format = xl_fill(background = "salmon")))) path <- write_xlsx(list(Scores = sheet), tempfile(fileext = ".xlsx")) ``` Rules are tried in order, and `stop_if_true` stops at the first match. The format on a rule is a **differential** format: it says what to change, not what the cell looks like. A rule setting only a fill leaves the font alone, which is why these are stored apart from ordinary cell styles. `type` picks what is being tested --- a cell's value, whether it is in the top or bottom *n*, above or below average, a duplicate, blank, an error, text containing something, a date in a relative window, or a formula of your own. ### Scales, bars and icons Three constructors cover Excel's graphical rules, none of which needs a format: ```{r} xl_cond_scale(list(cols = "score"), colors = c("salmon", "lightgreen")) xl_cond_bar(list(cols = "score"), color = "steelblue") xl_cond_icons(list(cols = "score"), style = "3_traffic_lights") ``` A two-colour scale takes two colours, a three-colour scale three. Data bars draw behind the value in the cell. Icon sets take one of Excel's built-in `style`s, optionally reversed or shown without their values. Every one of these takes its range the same way as anything else in writexl: `list(cols = )` against the data frame, or A1 text. ## What is elsewhere * The same format objects style **charts**, translated to what a chart can draw: [Charts and images](d-charts-images.html). * **Number formats** are ordinary Excel format strings --- anything the Custom box in Excel accepts. * `xl_protection()` only takes effect once the sheet itself is protected: see [Worksheets and workbooks](c-worksheets-workbooks.html).