--- title: "04. Styling" author: "Chris Bailiss" date: "`r Sys.Date()`" output: rmarkdown::html_vignette vignette: > %\VignetteIndexEntry{04. Styling} %\VignetteEngine{knitr::rmarkdown} %\VignetteEncoding{UTF-8} --- ## In This Vignette * Quick Styling * Styles and Themes * Styles and CSS * XL Styles * Included Themes * Simple Themes * Styling with the quick table functions * Styling Rows/Columns/Cells * Changing styling/formatting after table creation using `tbl$setStyling()` * Formatting cell borders for specific cells * Changing styling/formatting using `pt$mapStyling()` * Creating a New Theme * Summary of Styling Rules * Styling Output * Further Reading ## Quick Styling This 'Quick Start' describes one easy method of styling table cells. A fuller explanation is given in the other sections of this vignette. Cells in a table are styled using CSS. The quickest way to apply styles to individual cells in a table is using: `tbl$setStyling(rFrom, cFrom, rTo, cTo, rowNumbers, columnNumbers, cells, cellType, visible, baseStyleName, style, declarations)` To apply styles to a single cell, e.g. at row 1, column 2: `tbl$setStyling(1, 2, declarations=list("font-weight"="bold", "text-align"="center")` To apply styles to a range of cells, e.g. rows 2 to 3 and columns 1 to 5: `tbl$setStyling(2, 1, 3, 5, declarations=list("font-weight"="bold", "text-align"="center")` or equivalently: `tbl$setStyling(rowNumbers=2:3, columnNumbers=1:5, declarations=list("font-weight"="bold", "text-align"="center")` The above sets CSS style attributes on the individual cells. This is quick and easy, though very verbose. Named styles are more efficient for large tables (hundreds/thousands of cells) and are described in the following sections. ## Styles and Themes `basictabler` can render tables to a few different formats. The focus of this vignette is styling when rendering to HTML. When rendered to HTML, the appearance of `basictabler` tables can be changed using styles and themes: * A style defines the appearance of a cell in the table. + A cell here is a general term that covers row/column headings, values in the body of the table and totals. * A style has a name and a set of style settings. * Each table has a collection of styles. * For each cell in the table, a style name can be set. * A theme is a collection of styles that can easily be applied to a table. The `basictabler` package is supplied with some basic themes. Additional themes can be defined. In addition, for each cell in the table, a set of style overrides can be set. These are style declarations that apply to individual cells. ## Styles and CSS A style is a collection of name-value pairs. The name-value pairs used to specify styles are simply Cascading Style Sheet properties and values. A full introduction and reference for CSS can be found on the [w3schools](https://www.w3schools.com/css/default.asp) website. An example of defining a `basictabler` style is: ```{r, message=FALSE, warning=FALSE, eval=FALSE} tableStyles$addStyle(styleName="ColumnHeader", list( "font-family"="arial", "font-size"="0.75em", padding="2px", border="1px solid blue", "vertical-align"="middle", "text-align"="center", "font-weight"="bold", color="blue", "background-color"="#FFFFFF", "xl-wrap-text"="wrap" )) ``` When viewing tables in an IDE such as R Studio, then typically only one table is viewed at a time. If multiple tables are being output together (e.g. into a single HTML page) then specifying a `styleNamePrefix` in the `tbl$renderTable()` call is needed. The CSS declarations generated by the `basictabler` package for each table will then not overlap with each other. This can be seen in all of the examples in this vignette. ## XL Styles The `basictabler` package also supports outputting to Excel files. The Excel output can use CSS styling and/or Excel specific styling. The Excel specific styles are defined alongside the CSS styles and start with "xl-", e.g. see the example above. The Excel specific styles are ignored by the HTML output. For more details about the Excel export, see the [Excel Export](v07-excelexport.html) vignette. ## Included Themes The `basictabler` package includes three basic themes: ### Default Theme ```{r, message=FALSE, warning=FALSE} # data for the table saleIds <- c(5334, 5336, 5338) items <- c("Apple", "Orange", "Banana") quantities <- c(5, 8, 6) prices <- c(0.34452354, 0.4732543, 1.3443243) # construct the table library(basictabler) tbl <- BasicTable$new() tbl$addData(data.frame(saleIds, items, quantities, prices), firstColumnAsRowHeaders=TRUE, explicitColumnHeaders=c("Sale ID", "Item", "Quantity", "Price"), columnFormats=list(NULL, NULL, NULL, "%.2f")) # theme the table and render tbl$theme <- "default" # this theme is already the default, so this line isn't really needed tbl$renderTable(styleNamePrefix="t0") ``` ### Compact Theme ```{r, message=FALSE, warning=FALSE} # data for the table saleIds <- c(5334, 5336, 5338) items <- c("Apple", "Orange", "Banana") quantities <- c(5, 8, 6) prices <- c(0.34452354, 0.4732543, 1.3443243) # construct the table library(basictabler) tbl <- BasicTable$new() tbl$addData(data.frame(saleIds, items, quantities, prices), firstColumnAsRowHeaders=TRUE, explicitColumnHeaders=c("Sale ID", "Item", "Quantity", "Price"), columnFormats=list(NULL, NULL, NULL, "%.2f")) # theme the table and render tbl$theme <- "compact" tbl$renderTable(styleNamePrefix="t1") ``` ### Large Plain Theme ```{r, message=FALSE, warning=FALSE} # data for the table saleIds <- c(5334, 5336, 5338) items <- c("Apple", "Orange", "Banana") quantities <- c(5, 8, 6) prices <- c(0.34452354, 0.4732543, 1.3443243) # construct the table library(basictabler) tbl <- BasicTable$new() tbl$addData(data.frame(saleIds, items, quantities, prices), firstColumnAsRowHeaders=TRUE, explicitColumnHeaders=c("Sale ID", "Item", "Quantity", "Price"), columnFormats=list(NULL, NULL, NULL, "%.2f")) # theme the table and render tbl$theme <- "largeplain" tbl$renderTable(styleNamePrefix="t2") ``` ## Simple Themes Simple themes can be defined using a list. Several examples are shown below. ```{r, message=FALSE, warning=FALSE} # define the font and colours simpleBlueTheme <- list( fontName="Verdana, Arial", fontSize="0.75em", headerBackgroundColor = "rgb(68, 114, 196)", headerColor = "rgb(255, 255, 255)", cellBackgroundColor = "rgb(255, 255, 255)", cellColor = "rgb(0, 0, 0)", totalBackgroundColor = "rgb(186, 202, 233)", totalColor = "rgb(0, 0, 0)", borderColor = "rgb(48, 84, 150)" ) # data for the table saleIds <- c(5334, 5336, 5338) items <- c("Apple", "Orange", "Banana") quantities <- c(5, 8, 6) prices <- c(0.34452354, 0.4732543, 1.3443243) # construct the table library(basictabler) tbl <- BasicTable$new() tbl$addData(data.frame(saleIds, items, quantities, prices), firstColumnAsRowHeaders=TRUE, explicitColumnHeaders=c("Sale ID", "Item", "Quantity", "Price"), columnFormats=list(NULL, NULL, NULL, "%.2f")) # theme the table and render tbl$theme <- simpleBlueTheme tbl$renderTable(styleNamePrefix="t3") ``` ```{r, message=FALSE, warning=FALSE} # define the colours simpleGrayTheme <- list( fontName="Courier New, Courier", fontSize="0.75em", headerBackgroundColor = "rgb(128, 128, 128)", headerColor = "rgb(255, 255, 255)", cellBackgroundColor = "rgb(255, 255, 255)", cellColor = "rgb(0, 0, 0)", totalBackgroundColor = "rgb(192, 192, 192)", totalColor = "rgb(0, 0, 0)", borderColor = "rgb(64, 64, 64)" ) # data for the table saleIds <- c(5334, 5336, 5338) items <- c("Apple", "Orange", "Banana") quantities <- c(5, 8, 6) prices <- c(0.34452354, 0.4732543, 1.3443243) # construct the table library(basictabler) tbl <- BasicTable$new() tbl$addData(data.frame(saleIds, items, quantities, prices), firstColumnAsRowHeaders=TRUE, explicitColumnHeaders=c("Sale ID", "Item", "Quantity", "Price"), columnFormats=list(NULL, NULL, NULL, "%.2f")) # theme the table and render tbl$theme <- simpleGrayTheme tbl$renderTable(styleNamePrefix="t4") ``` ```{r, message=FALSE, warning=FALSE} # define the colours simpleGreenTheme <- list( fontName="Helvetica, arial", fontSize="0.75em", headerBackgroundColor = "rgb(112, 173, 71)", headerColor = "rgb(255, 255, 255)", cellBackgroundColor="rgb(255, 255, 255)", cellColor="rgb(0, 0, 0)", totalBackgroundColor = "rgb(182, 216, 158)", totalColor="rgb(0, 0, 0)", borderColor = "rgb(84, 130, 53)" ) # data for the table saleIds <- c(5334, 5336, 5338) items <- c("Apple", "Orange", "Banana") quantities <- c(5, 8, 6) prices <- c(0.34452354, 0.4732543, 1.3443243) # construct the table library(basictabler) tbl <- BasicTable$new() tbl$addData(data.frame(saleIds, items, quantities, prices), firstColumnAsRowHeaders=FALSE, explicitColumnHeaders=c("Sale ID", "Item", "Quantity", "Price"), columnFormats=list(NULL, NULL, NULL, "%.2f")) # theme the table and render tbl$theme <- simpleGreenTheme tbl$renderTable(styleNamePrefix="t6") ``` ## Styling with the quick table functions The following example defines a simple theme and supplies this to the quick table function to specify styling: ```{r, message=FALSE, warning=FALSE} # aggregate the sample data to make a small data frame library(basictabler) library(dplyr) tocsummary <- bhmsummary %>% group_by(TOC) %>% summarise(OnTimeArrivals=sum(OnTimeArrivals), OnTimeDepartures=sum(OnTimeDepartures), TotalTrains=sum(TrainCount)) %>% ungroup() %>% mutate(OnTimeArrivalPercent=OnTimeArrivals/TotalTrains*100, OnTimeDeparturePercent=OnTimeDepartures/TotalTrains*100) %>% arrange(TOC) # column formats columnFormats=list(NULL, list(big.mark=","), list(big.mark=","), list(big.mark=","), "%.1f", "%.1f") # simple theme simpleBlueTheme <- list( fontName="Verdana, Arial", fontSize="0.75em", headerBackgroundColor = "rgb(68, 114, 196)", headerColor = "rgb(255, 255, 255)", cellBackgroundColor = "rgb(255, 255, 255)", cellColor = "rgb(0, 0, 0)", totalBackgroundColor = "rgb(186, 202, 233)", totalColor = "rgb(0, 0, 0)", borderColor = "rgb(48, 84, 150)" ) # headings in red text, cells in light gray tbl <- qtbl(tocsummary, firstColumnAsRowHeaders=TRUE, explicitColumnHeaders=c("TOC", "On-Time Arrivals", "On-Time Departures", "Total Trains", "On-Time Arrival %", "On-Time Departure %"), columnFormats=columnFormats, theme=simpleBlueTheme) # render table tbl$renderTable(styleNamePrefix="t9") ``` The next example demonstrates specifying more granular style settings when using a quick table function: ```{r, message=FALSE, warning=FALSE} # aggregate the sample data to make a small data frame library(basictabler) library(dplyr) tocsummary <- bhmsummary %>% group_by(TOC) %>% summarise(OnTimeArrivals=sum(OnTimeArrivals), OnTimeDepartures=sum(OnTimeDepartures), TotalTrains=sum(TrainCount)) %>% ungroup() %>% mutate(OnTimeArrivalPercent=OnTimeArrivals/TotalTrains*100, OnTimeDeparturePercent=OnTimeDepartures/TotalTrains*100) %>% arrange(TOC) # column formats columnFormats=list(NULL, list(big.mark=","), list(big.mark=","), list(big.mark=","), "%.1f", "%.1f") # create the table tbl <- qtbl(tocsummary, firstColumnAsRowHeaders=FALSE, explicitColumnHeaders=c("TOC", "On-Time Arrivals", "On-Time Departures", "Total Trains", "On-Time Arrival %", "On-Time Departure %"), columnFormats=columnFormats, tableStyle=list("border-color"="maroon"), headingStyle=list("color"="cornsilk", "background-color"="maroon", "font-style"="italic", "border-color"="maroon"), cellStyle=list("color"="maroon", "background-color"="cornsilk", "border-color"="maroon")) # set column alignment of first column tbl$setStyling(2, 1, 5, 1, declarations=list("text-align"="left")) # render table tbl$renderTable(styleNamePrefix="t10") ``` The quick table functions specify the same styling/formatting for all headers and all cells. To specify different styling/formatting for specific headings and/or specific rows/columns, use the more verbose syntax for creating the table as shown in the examples below. ## Styling Rows/Columns/Cells ### Specifying cell appearance while creating a table from a data frame The following example defines a new style and uses this for one of the columns in the table, with the other columns using the normal cell style. ```{r, message=FALSE, warning=FALSE} # data for the table saleIds <- c(5334, 5336, 5338) items <- c("Apple", "Orange", "Banana") quantities <- c(5, 8, 6) prices <- c(0.34452354, 0.4732543, 1.3443243) df <- data.frame(saleIds, items, quantities, prices) colNames <- c("Sale ID", "Item", "Quantity", "Price") colFormats <- list(NULL, NULL, NULL, "%.2f") # construct the table library(basictabler) tbl <- BasicTable$new() # define a new style tbl$addStyle(styleName="AltCell", list( "font-family"="Arial", "font-size"="0.8em", "font-weight"="bold", padding="2px 2px 2px 8px", "border-bottom"="1px solid #9C0006", "text-align"="right", color="#9C0006", "background-color"="#FFC7CE" )) colStyleNames <- c("Cell", "Cell", "AltCell", "Cell") # populate the table tbl$addData(df, explicitColumnHeaders=colNames, columnFormats=colFormats, baseStyleNames=colStyleNames) tbl$renderTable(styleNamePrefix="t11") ``` ### Specifying cell appearance while creating a table column-by-column It is also possible to define a new style for an entire column when creating a table column-by-column. In the example below a new style is created and this is used as the base style for the third column. ```{r, message=FALSE, warning=FALSE} # data for the table saleIds <- c(5334, 5336, 5338) items <- c("Apple", "Orange", "Banana") quantities <- c(5, 8, 6) prices <- c(0.34452354, 0.4732543, 1.3443243) # construct the table library(basictabler) tbl <- BasicTable$new() # define a new style tbl$addStyle(styleName="AltColumn", list( "font-family"="Arial", "font-size"="0.8em", "font-weight"="bold", padding="2px 2px 2px 8px", "border-bottom"="1px solid #9C0006", "text-align"="right", color="#9C0006", "background-color"="#FFC7CE" )) tbl$cells$setCell(1, 1, cellType="root", rawValue="Sale ID") tbl$cells$setCell(1, 2, cellType="columnHeader", rawValue="Item") tbl$cells$setCell(1, 3, cellType="columnHeader", rawValue="Quantity") tbl$cells$setCell(1, 4, cellType="columnHeader", rawValue="Price") tbl$cells$setColumn(1, cellTypes="rowHeader", rawValues=saleIds) tbl$cells$setColumn(2, cellTypes="cell", rawValues=items) tbl$cells$setColumn(3, cellTypes="cell", rawValues=quantities, baseStyleName="AltColumn") tbl$cells$setColumn(4, cellTypes="cell", rawValues=prices, formats=list("%.2f")) tbl$renderTable(styleNamePrefix="t13") ``` ### Specifying cell appearance while creating a table row-by-row Similarly, it is possible to define a new style for an entire row when creating a table row-by-row. In the example below a new style is created and this is used as the base style for the...... ```{r, message=FALSE, warning=FALSE} # cell types for the cells in each row cellTypes <- c("rowHeader", "cell", "cell", "cell") # formats for the values in each row # (only the value in the fourth column needs formatting) formats <- list(NULL, NULL, NULL, "%.2f") # construct the table library(basictabler) tbl <- BasicTable$new() # define a new style tbl$addStyle(styleName="AltRow", list( "font-family"="Arial", "font-size"="0.8em", "font-weight"="bold", padding="2px 2px 2px 8px", "border-bottom"="1px solid #9C0006", "text-align"="right", color="#9C0006", "background-color"="#FFC7CE" )) tbl$cells$setCell(1, 1, cellType="root", rawValue="Sale ID") tbl$cells$setCell(1, 2, cellType="columnHeader", rawValue="Item") tbl$cells$setCell(1, 3, cellType="columnHeader", rawValue="Quantity") tbl$cells$setCell(1, 4, cellType="columnHeader", rawValue="Price") tbl$cells$setRow(2, cellTypes=cellTypes, formats=formats, rawValues=list(5334, "Apple", 5, 0.34452354)) tbl$cells$setRow(3, cellTypes=cellTypes, formats=formats, rawValues=list(5336, "Orange", 8, 0.4732543), baseStyleNames="AltRow") tbl$cells$setRow(4, cellTypes=cellTypes, formats=formats, rawValues=list(5338, "Banana", 6, 1.3443243)) tbl$renderTable(styleNamePrefix="t14") ``` When creating tables column-by-column and row-by-row, it is possible to specify a vector for baseStyleNames of the same length as rawValues, to be able to specify different styles for each cell in the column/row: ```{r, message=FALSE, warning=FALSE} # cell types for the cells in each row cellTypes <- c("rowHeader", "cell", "cell", "cell") # formats for the values in each row # (only the value in the fourth column needs formatting) formats <- list(NULL, NULL, NULL, "%.2f") # construct the table library(basictabler) tbl <- BasicTable$new() # define a new style tbl$addStyle(styleName="AltRowLeftAlign", list( "font-family"="Arial", "font-size"="0.8em", "font-weight"="bold", padding="2px 2px 2px 2px", "border-bottom"="1px solid #9C0006", "text-align"="left", color="#9C0006", "background-color"="#FFC7CE" )) tbl$addStyle(styleName="AltRowRightAlign", list( "font-family"="Arial", "font-size"="0.8em", "font-weight"="bold", padding="2px 2px 2px 8px", "border-bottom"="1px solid #9C0006", "text-align"="right", color="#9C0006", "background-color"="#FFC7CE" )) styleNames <- c("AltRowLeftAlign", "AltRowRightAlign", "AltRowRightAlign", "AltRowRightAlign") tbl$cells$setCell(1, 1, cellType="root", rawValue="Sale ID") tbl$cells$setCell(1, 2, cellType="columnHeader", rawValue="Item") tbl$cells$setCell(1, 3, cellType="columnHeader", rawValue="Quantity") tbl$cells$setCell(1, 4, cellType="columnHeader", rawValue="Price") tbl$cells$setRow(2, cellTypes=cellTypes, formats=formats, rawValues=list(5334, "Apple", 5, 0.34452354)) tbl$cells$setRow(3, cellTypes=cellTypes, formats=formats, rawValues=list(5336, "Orange", 8, 0.4732543), baseStyleNames=styleNames) tbl$cells$setRow(4, cellTypes=cellTypes, formats=formats, rawValues=list(5338, "Banana", 6, 1.3443243)) tbl$renderTable(styleNamePrefix="t15") ``` ### Specifying cell appearance while creating a table cell-by-cell The following example shows two different ways of specifying cell styling whilst creating a table cell-by-cell. The first method defines an entirely new cell style (i.e. that is not part of the standard theming). This cell style is then used when styling one of the cells. The second method specifies one additional style declaration that is applied on top of the standard theming. ```{r, message=FALSE, warning=FALSE} library(basictabler) tbl <- BasicTable$new() # specify a new cell style tbl$addStyle(styleName="AltCell", list( "font-family"="Arial", "font-size"="0.8em", "font-weight"="bold", padding="2px 2px 2px 8px", "border"="2px solid #9C0006", "text-align"="right", color="#9C0006", "background-color"="#FFC7CE" )) # build the table tbl$cells$setCell(1, 1, cellType="root", rawValue="Sale ID") tbl$cells$setCell(1, 2, cellType="columnHeader", rawValue="Item") tbl$cells$setCell(1, 3, cellType="columnHeader", rawValue="Quantity") tbl$cells$setCell(2, 1, cellType="rowHeader", rawValue=5334) tbl$cells$setCell(2, 2, cellType="cell", rawValue="Apple") tbl$cells$setCell(3, 1, cellType="rowHeader", rawValue=5336) tbl$cells$setCell(3, 2, cellType="cell", rawValue="Orange") # use the new style for the following cell (used instead of the theme styling) tbl$cells$setCell(2, 3, cellType="cell", rawValue=5, baseStyleName="AltCell") # specify an additional style declaration for the following cell (used on # top of the theme styling) tbl$cells$setCell(3, 3, cellType="cell", rawValue=8, styleDeclarations=list("background-color"="#FFFF00")) # render the table tbl$renderTable(styleNamePrefix="t12") ``` ## Changing styling/formatting after table creation using `tbl$setStyling()` The individual cells in the table can have their appearance changed by retrieving the cell then applying a style to the cell. The example below shows two different ways of applying cells to an individual cell. These styles apply in addition to the styles coming from the underlying theme, e.g. highlighting a cell: ```{r, message=FALSE, warning=FALSE} # define the colours orangeTheme <- list( fontName="Garamond, arial", fontSize="0.75em", headerBackgroundColor = "rgb(237, 125, 49)", headerColor = "rgb(255, 255, 255)", cellBackgroundColor = "rgb(255, 255, 255)", cellColor = "rgb(0, 0, 0)", totalBackgroundColor = "rgb(248, 198, 165)", totalColor = "rgb(0, 0, 0)", borderColor = "rgb(198, 89, 17)" ) # data for the table saleIds <- c(5334, 5336, 5338) items <- c("Apple", "Orange", "Banana") quantities <- c(5, 8, 6) prices <- c(0.34452354, 0.4732543, 1.3443243) # construct the table library(basictabler) tbl <- BasicTable$new() tbl$addData(data.frame(saleIds, items, quantities, prices), firstColumnAsRowHeaders=TRUE, explicitColumnHeaders=c("Sale ID", "Item", "Quantity", "Price"), columnFormats=list(NULL, NULL, NULL, "%.2f")) # theme the table and render tbl$theme <- orangeTheme # apply an additional highlight to one cell (3rd row, 2nd column) tbl$setStyling(3, 2, declarations=list("background-color"="#FFFF00")) # apply an additional highlight to one cell (3rd row, 3rd column) cellHighlight <- tbl$createInlineStyle(declarations=list("background-color"="#00FFFF")) cell <- tbl$cells$getCell(3, 3) cell$style <- cellHighlight # render the table tbl$renderTable(styleNamePrefix="t16") ``` In the example above, the default cell style from the theme is still applied. The highlight is applied in addition to the default styling. To stop the base styling being applied, create a new named style and set the baseStyleName property on the cell to the name of the new style. The `tbl$setStyling()` function is used in the example above. This function has the following arguments: * `rFrom` and `cFrom` are the coordinates of the cell where the styling is to be applied. If the styling is being applied to multiple cells, this is the top-left cell in the rectangular cell range where the styling is to be applied. * `rTo` and `cTo` are the coordinates of the bottom right cell when styling is being applied to a rectangular range of cells. If styling is only being applied to a single cell, these arguments are not needed. * `rowNumbers` and `columnNumbers` are integer vectors of row and/or column numbers specifying where the styling is to be applied. If both `rowNumbers` and `columnNumbers` are specified, then the cells at the intersection of the specified row numbers and column numbers are styled. * `cells` is a list of cells to apply styling to. Either `rFrom`/`cFrom` or `cells` is typically specified - not both. * `cellType` is one of the following values that specifies the cell type to be applied to the specified cells: root, rowHeader, columnHeader, cell, total. The cellType controls the default styling that is applied to the cell. * `visible` The cell visibility (`TRUE` or `FALSE`) to apply to the specified cells. * `baseStyleName` is the name of a style in the table theme to apply to the specified cells. Set this explicitly to NULL to revert to the default style specified in the table theme. * `style` is a `TableStyle` override object to apply to the specified cells. This is created by calling `tbl$createInlineStyle()` as shown in the example above. * `declarations` is a list of style override declarations to apply to the specified cells. * `applyBorderToAdjacentCells` is a logical value - specify TRUE to override the border in neighbouring cells, e.g. the left border of the current cell becomes the right border of the cell to the left. The `tbl$createInlineStyle()` function is also used in the example above. This function creates a new unnamed style (that is not part of the table theme) and takes two arguments: `baseStyleName` specifies the name of the style that the new style will be based on (i.e. will have it's style properties copied from) and `declarations` which specifies new/overriding style properties for the new style. The `lapply()` function can be used to set the style for multiple cells to a new inline style: ```{r, eval=FALSE} # apply inline style to multiple cells highlight <- tbl$createInlineStyle(declarations=list("background-color"="#FFCC66")) cells <- tbl$getCells(specifyCellsAsList=TRUE, rowNumbers=c(1, 3)) lst <- lapply(cells, function(cell) {cell$style <- highlight}) ``` For many more examples of styling parts of a table, see the [Finding and Formatting](v05-findingandformatting.html) vignette. ## Formatting cell borders for specific cells CSS rendering rules mean that the first encountered border setting is used. When table cells have no separation, this means the left/top borders of a cell are actually defined by the right/bottom borders of the previous cells (i.e. to the left and above). This means attempting to set the border of a specific cell often doesn't produce the desired effect, e.g. attempting to change the border of a specific cell to red: ```{r, message=FALSE, warning=FALSE} x <- data.frame(a=c(1,2,3),b=c(4,5,6),c=c(7,8,9)) tbl <- BasicTable$new() tbl$addData(x) tbl$setStyling(rowNumbers=3, columnNumbers=2, declarations=list("border"="1px solid red")) tbl$renderTable() ``` This can be resolved by specifying `applyBorderToAdjacentCells=TRUE`: ```{r, message=FALSE, warning=FALSE} x <- data.frame(a=c(1,2,3),b=c(4,5,6),c=c(7,8,9)) tbl <- BasicTable$new() tbl$addData(x) tbl$setStyling(rowNumbers=3, columnNumbers=2, declarations=list("border"="1px solid red"), applyBorderToAdjacentCells=TRUE) tbl$renderTable() ``` ## Changing styling/formatting using `pt$mapStyling()` Sometimes it is desirable to set the styling more dynamically, i.e. the styling of each cell should vary according to the value of the each cell, e.g. increasingly large numbers have an increasingly intense red cell background colour. This can be done with the `mapStyling()` method, which has the following arguments: * `styleProperty` - the name of the style property to set e.g. "background-color". * `cells` - a list specifying the `PivotCell` objects to be styled. * `valueType` - the type of style value to be set - one of the following values: `text`/`character`, `number`/`numeric`, or `color`/`colour` * `mapType` - the type of mapping to be performed - the following mapping types are supported: + `value` - a 1:1 mapping which maps each specified "from" value to the corresponding "to" value, e.g. 100 -> "green". + `logic` - each from value is logical criteria - see more details below. + `range` - values between each pair of "from" values are mapped to the corresponding "to" value, e.g. values in the range 80-100 -> "green". + `continuous` - rescales values between each pair of "from" values into the range of the corresponding pair of "to" values, e.g. if the "from" range is 80-100 and the corresponding "to" range is 0.8-1, then 90 -> 0.9. * `mappings` - the mappings to be applied, specified in one of the following three forms: + a list containing pairs of values, e.g. `list(0, "red", 0.4, "yellow", 0.8, "green")` + a list containing "from" and "to" vectors/lists, e.g. `list(from=c(0, 0.4, 0.8), to=c("red", "yellow", "green"))` + a custom mapping function that will be invoked once per cell, e.g. `function(v, cell) { if(isTRUE(v>0.8)) return("green") }`. + `styleLowerValues` - a logical value, default `FALSE`, that specifies whether values less than the lowest specified "from" value should be styled using the style specified for the lowest "from" value. * `styleHigherValues` - a logical value, default `TRUE`, that specifies whether values greater than the highest specified "from" value should be styled using the style specified for the highest "from" value. `mapType`="logical" is a generic way of specifying mapping rules, which can be of any of the following forms: * a specific value, e.g. 12. * a specific value equality condition, e.g. `"v==12"`, where v represents the cell value. * a value range expression using the following abbreviated form: "value1<=v% group_by(TOC) %>% summarise(OnTimeArrivals=sum(OnTimeArrivals), OnTimeDepartures=sum(OnTimeDepartures), TotalTrains=sum(TrainCount)) %>% ungroup() %>% mutate(OnTimeArrivalPercent=OnTimeArrivals/TotalTrains*100, OnTimeDeparturePercent=OnTimeDepartures/TotalTrains*100) %>% arrange(TOC) # formatting values (explained in the introduction vignette) columnFormats=list(NULL, list(big.mark=","), list(big.mark=","), list(big.mark=","), "%.1f", "%.1f") ``` ### Style mapping example with `mapType="logic"` The example pivot table below maps cell colours from cell values using conditional/logical expressions: ```{r, message=FALSE, warning=FALSE} tbl <- BasicTable$new() tbl$addData(tocsummary, firstColumnAsRowHeaders=TRUE, explicitColumnHeaders=c("TOC", "On-Time Arrivals", "On-Time Departures", "Total Trains", "On-Time Arrival %", "On-Time Departure %"), columnFormats=columnFormats) cells <- tbl$getCells(rowNumbers=2:5, columnNumbers=2:4, matchMode="combinations") tbl$mapStyling(cells=cells, styleProperty="background-color", valueType="color", mapType="logic", mappings=list("v==2348", "pink", "v<3000", "red", "3000<=v<15000", "yellow", "v>15000", "green")) tbl$mapStyling(cells=cells, styleProperty="background-color", valueType="text", mapType="logic", mappings=list("v==1404", "red")) tbl$renderTable() ``` ### Style mapping example with `mapType="range"` The example pivot table below maps cell colours from cell values using ranges, i.e. 0-1000 -> "red" and 1000-15000 -> "orange": ```{r, message=FALSE, warning=FALSE} tbl <- BasicTable$new() tbl$addData(tocsummary, firstColumnAsRowHeaders=TRUE, explicitColumnHeaders=c("TOC", "On-Time Arrivals", "On-Time Departures", "Total Trains", "On-Time Arrival %", "On-Time Departure %"), columnFormats=columnFormats) cells <- tbl$getCells(rowNumbers=2:5, columnNumbers=2:4, matchMode="combinations") tbl$mapStyling(cells=cells, styleProperty="background-color", valueType="color", mapType="range", mappings=list(0, "red", 3000, "orange", 5000, "yellow", 15000, "green")) tbl$renderTable() ``` ### Style mapping example with `mapType="continuous"` An example of styling using the "continuous" map type can be found in the [Finding and Formatting](v05-findingandformatting.html) vignette. ### Style mapping example with `mapType="function"` The example pivot table below maps cell colours using a custom function. The `cell` argument passed to the function is the current cell being styled, e.g. to format based on the column number: ```{r, message=FALSE, warning=FALSE} tbl <- BasicTable$new() tbl$addData(tocsummary, firstColumnAsRowHeaders=TRUE, explicitColumnHeaders=c("TOC", "On-Time Arrivals", "On-Time Departures", "Total Trains", "On-Time Arrival %", "On-Time Departure %"), columnFormats=columnFormats) cells <- tbl$getCells(rowNumbers=2:5, columnNumbers=2:4, matchMode="combinations") redclr <- function(x, cell) { clr <- 255-floor(140*cell$columnNumber/3) return(paste0("#", format(as.hexmode(255), width=2), format(as.hexmode(clr), width=2), format(as.hexmode(clr), width=2))) } tbl$mapStyling(cells=cells, styleProperty="background-color", mappings=redclr) tbl$renderTable() ``` ## Creating a New Theme Since a theme is a collection of styles, creating themes is relatively straightforward. The names of the styles are then assigned to the different types of cells within a table: * tableStyle - the name of the style applied to the table (i.e. the HTML `` element). * rootStyle - the name of the style applied to the empty cell at the top left of the table. * rowHeaderStyle - the name of the style applied to the row header cells. * colHeaderStyle - the name of the style applied to the column header cells. * cellStyle - the name of the style applied to the cells in the body of the table. * totalStyle - the name of the style applied to the total cells in the table. E.g. creating a custom theme that displays a mixture of bright colours (a rather ugly bubble-gum theme): ```{r, message=FALSE, warning=FALSE} library(basictabler) # define the theme and styles createCustomTheme <- function(parentTable=NULL, themeName="myCustomTheme") { tableStyles <- TableStyles$new(parentTable=parentTable, themeName=themeName) # borders in purple tableStyles$addStyle(styleName="Table", list( "display"="table", "border-collapse"="collapse", "border"="2px solid #B28DFF" )) # column headings in pink tableStyles$addStyle(styleName="ColumnHeader", list( "font-family"="\"Courier New\", Courier, monospace", "font-size"="0.75em", "font-weight"="bold", padding="2px", "border"="2px solid #B28DFF", "vertical-align"="middle", "text-align"="center", "font-weight"="bold", color="#DB49AC", "background-color"="#FFCCF9", "xl-wrap-text"="wrap" )) # row headings in blue tableStyles$addStyle(styleName="RowHeader", list( "font-family"="\"Courier New\", Courier, monospace", "font-size"="0.75em", "font-weight"="bold", padding="2px 8px 2px 2px", "border"="1px solid #B28DFF", "vertical-align"="middle", "text-align"="left", "font-weight"="bold", color="#438EC8", "background-color"="#ACE7FF", "xl-wrap-text"="wrap" )) # cells in yellow tableStyles$addStyle(styleName="Cell", list( "font-family"="\"Courier New\", Courier, monospace", "font-size"="0.75em", padding="2px 2px 2px 8px", "border"="1px solid #B28DFF", "text-align"="right", color="#FF800D", "background-color"="#FFFFD1" )) # totals in orange tableStyles$addStyle(styleName="Total", list( "font-family"="\"Courier New\", Courier, monospace", "font-size"="0.75em", "font-weight"="bold", padding="2px 2px 2px 8px", "border"="1px solid rgb(84, 130, 53)", "text-align"="right", color="#3BC6B6", "background-color"="#BFFCC6" )) tableStyles$tableStyle <- "Table" tableStyles$rootStyle <- "ColumnHeader" tableStyles$rowHeaderStyle <- "RowHeader" tableStyles$colHeaderStyle <- "ColumnHeader" tableStyles$cellStyle <- "Cell" tableStyles$totalStyle <- "Total" return(invisible(tableStyles)) } # data for the table saleIds <- c(5334, 5336, 5338) items <- c("Apple", "Orange", "Banana") quantities <- c(5, 8, 6) prices <- c(0.34452354, 0.4732543, 1.3443243) # construct the table library(basictabler) tbl <- BasicTable$new() tbl$addData(data.frame(saleIds, items, quantities, prices), firstColumnAsRowHeaders=TRUE, explicitColumnHeaders=c("Sale ID", "Item", "Quantity", "Price"), columnFormats=list(NULL, NULL, NULL, "%.2f")) # theme the table and render tbl$theme <- createCustomTheme(tbl) tbl$renderTable(styleNamePrefix="t8") ``` ## Summary of Styling Rules `basictabler` styles cells using the following rules: * Each cell in a table has an associated cell type (root / rowHeader / columnHeader / cell / total). This controls the default styling applied to a cell. + Specify cell type of a new cell: `tbl$cells$setCell(1, 2, cellType="columnHeader", rawValue="Item")` + Change cell type of an existing cell: ` tbl$cells$getCell(3, 2)$cellType <- "columnHeader"` * The styling theme applied to a table defines a set of styles and the default style for each cell type. + Create a new simple theme using a list and assigning this to the `tbl$theme` field. + Create a new custom theme by writing a function `createCustomTheme()`. + Assign a theme to the table `theme` property: `tbl$theme <- createCustomTheme(tbl)` * Each individual cell can also have a different style, specified by settings the `baseStyleName` for the cell. + Single cell example: `tbl$cells$getCell(3, 2)$baseStyleName <- "AltCellStyle"`. + Alternative single cell example: `tbl$setStyling(3, 2, baseStyleName="AltCellStyle")`. + Cell range example: `tbl$setStyling(3, 2, 3, 6, baseStyleName="AltCellStyle")`. * It is also possible to declare individual style overrides (e.g. a different text colour). These override specific style settings from the named styles. + Single cell example: `tbl$setStyling(3, 2, declarations=list("text-align"="left", "background-color"="yellow"))`. + Cell range example: `tbl$setStyling(3, 2, 3, 6, declarations=list("text-align"="left", "background-color"="yellow"))`. * It is possible to specify a new base style and overrides together. The declarations override the settings in the base style. + Single cell example: `tbl$setStyling(3, 2, baseStyleName="AltCellStyle", declarations=list("text-align"="left", "background-color"="yellow"))`. + Cell range example: `tbl$setStyling(3, 2, 3, 6, baseStyleName="AltCellStyle", declarations=list("text-align"="left", "background-color"="yellow"))`. * Instead of specifying the declarations as a list, an inline style can be declared. This is an unnamed style object that is used for one or multiple cells and is not part of the table theme. + See the "Changing cell appearance after cells have been created" section in this vignette for an example. + See the "Finding and Formatting" vignette for more examples. ## Styling Output When rendering to HTML, two styles settings are written by `basictabler` in the HTML for each table cell: **HTML class attribute** Example: < td class="StyleName" > * The `cell$baseStyleName` is used as the HTML class name. * If no `cell$baseStyleName` has been explicitly set for a cell, then the base style name (for the relevant cell type) specified in the table theme is used. * The class names can be prefixed if required - useful when using several tables on the same HTML page. * It is also possible to generate class names that refer to styles not defined in the table - useful when the styles are defined in an external CSS file. **HTML style attribute** Example: < td style="text-align:left;background-color:yellow;" > The cell style override declarations (= the declarations of the inline style) are used as the value of the HTML style attribute for each cell. ## Further Reading The full set of vignettes is: 1. [Introduction](v01-introduction.html) 2. [Working with Cells](v02-workingwithcells.html) 3. [Outputs](v03-outputs.html) 4. [Styling](v04-styling.html) 5. [Finding and Formatting](v05-findingandformatting.html) 6. [Shiny](v06-shiny.html) 7. [Excel Export](v07-excelexport.html)