Quarto with R

Abstrave quarto theme

This document showcases the use of R.
Author

Roy Francis

Published

18-Dec-2024

1 Code execution

Code can be defined inline where `r Sys.Date()` renders 2024-12-18.

Code can be defined inside code blocks.

```{r}
Sys.Date()
```

which shows the source code and output.

Sys.Date()
[1] "2024-12-18"

Here is another example of executed R code with input and output.

data(iris)
head(iris[,1:2])

2 Chunk attributes

Properties and behaviour of code chunks can be controlled using chunk attributes. This is specified as comment sign of the language and pipe followed by key: value. So for example, in R: #| eval: false.

In this example, the R source code and results are hidden but the code is evaluated.

```{r}
#| eval: true
#| echo: false
#| results: hide
Sys.Date()
```

Source code blocks can be folded.

```{r}
#| code-fold: true
Sys.Date()
```
Code
Sys.Date()
[1] "2024-12-18"

There is not proper implementation to fold code output. Here is a hacky solution that uses a custom lua filter.

```{r}
#| attr.output: '.details summary="Output"'
Sys.Date()
```
Sys.Date()
Output
[1] "2024-12-18"

A code chunk can be given a code filename using the chunk attribute filename.

```{r}
#| filename: R code
Sys.Date()
```
R code
Sys.Date()

Enable line numbers using code-line-numbers: true.

```{r}
#| code-line-numbers: true
Sys.Date()
sessionInfo()
```
Sys.Date()
sessionInfo()

An example showing bash code generated from R.

```{r}
#| attr-output: "filename='bash'"
#| class-output: bash
#| echo: false
d <- "custom"
cat(paste("mkdir", d))
```
bash
mkdir custom

Code chunk attributes are documented here.

3 Tables

3.1 Manual

For simple cases, tables can be manually created in markdown.

|speed|dist|
|-----|----|
|4    |   2|
|4    |  10|
|7    |   4|
speed dist
4 2
4 10
7 4

3.2 kable

Simple table using kable from R package knitr.

library(knitr)
kable(head(iris))
Sepal.Length Sepal.Width Petal.Length Petal.Width Species
5.1 3.5 1.4 0.2 setosa
4.9 3.0 1.4 0.2 setosa
4.7 3.2 1.3 0.2 setosa
4.6 3.1 1.5 0.2 setosa
5.0 3.6 1.4 0.2 setosa
5.4 3.9 1.7 0.4 setosa

3.2.1 Layout

```{r}
#| column: body-outset
#| label: tbl-dual-table
#| tbl-cap: "Example"
#| tbl-subcap: 
#|   - "Cars"
#|   - "Pressure"
#| layout-ncol: 2

kable(head(cars))
kable(head(pressure))
```
Table 1: Example
(a) Cars
speed dist
4 2
4 10
7 4
7 22
8 16
9 10
(b) Pressure
temperature pressure
0 0.0002
20 0.0012
40 0.0060
60 0.0300
80 0.0900
100 0.2700

3.2.2 Cross referencing

Images and tables can be automatically numbered by using label attribute. Image label must start with fig- and tables with tbl-. Tables and images can also be cross-referenced when using the label attribute. For example, the table above can be referenced like @tbl-dual-table which renders as Table 1.

3.2.3 Margin table

```{r}
#| fig-caption: This table is in the margin.
#| column: margin

head(cars)
```

3.3 paged

Interactive table from R package rmarkdown.

library(rmarkdown)
rmarkdown::paged_table(head(iris))

3.4 gt

Tables using the gt package. A structured approach to creating tables using grammar of tables with extensive customization options.

library(gt)

iris %>%
    group_by(Species) %>%
    slice(1:4) %>%
    gt() %>%
    cols_label(
      Sepal.Length = "Sepal Length", Sepal.Width = "Sepal Width",
      Petal.Length = "Petal Length", Petal.Width = "Petal Width"
    ) %>%
    tab_source_note(
        source_note = md("Source: Iris data. Anderson, 1936; Fisher, 1936)")
    )
Sepal Length Sepal Width Petal Length Petal Width
setosa
5.1 3.5 1.4 0.2
4.9 3.0 1.4 0.2
4.7 3.2 1.3 0.2
4.6 3.1 1.5 0.2
versicolor
7.0 3.2 4.7 1.4
6.4 3.2 4.5 1.5
6.9 3.1 4.9 1.5
5.5 2.3 4.0 1.3
virginica
6.3 3.3 6.0 2.5
5.8 2.7 5.1 1.9
7.1 3.0 5.9 2.1
6.3 2.9 5.6 1.8
Source: Iris data. Anderson, 1936; Fisher, 1936)

3.5 htmlTable

Markdown tables can be enhanced using the R package htmlTable.

library(htmlTable)

iris1 <- iris[c(1:4,51:53,105:108),]
htmlTable(iris1, rgroup=unique(iris1$Species), n.rgroup=rle(as.character(iris1$Species))$lengths)
Sepal.Length Sepal.Width Petal.Length Petal.Width Species
setosa
  1 5.1 3.5 1.4 0.2 setosa
  2 4.9 3 1.4 0.2 setosa
  3 4.7 3.2 1.3 0.2 setosa
  4 4.6 3.1 1.5 0.2 setosa
versicolor
  51 7 3.2 4.7 1.4 versicolor
  52 6.4 3.2 4.5 1.5 versicolor
  53 6.9 3.1 4.9 1.5 versicolor
virginica
  105 6.5 3 5.8 2.2 virginica
  106 7.6 3 6.6 2.1 virginica
  107 4.9 2.5 4.5 1.7 virginica
  108 7.3 2.9 6.3 1.8 virginica

3.6 kableExtra

More advanced table using kableExtra and formattable.

library(kableExtra)

iris[c(1:4,51:53,105:108),] %>%
  mutate(Sepal.Length=color_bar("lightsteelblue")(Sepal.Length)) %>%
  mutate(Sepal.Width=color_tile("white","orange")(Sepal.Width)) %>%
  mutate(Species=cell_spec(Species,"html",color="white",bold=T,
    background=c("#8dd3c7","#fb8072","#bebada")[factor(.$Species)])) %>%
  kable("html",escape=F) %>%
  kable_styling(bootstrap_options=c("striped","hover","responsive"),
                full_width=F,position="left") %>%
  column_spec(5,width="3cm")
Table using kableextra.
Sepal.Length Sepal.Width Petal.Length Petal.Width Species
1 5.1 3.5 1.4 0.2 setosa
2 4.9 3.0 1.4 0.2 setosa
3 4.7 3.2 1.3 0.2 setosa
4 4.6 3.1 1.5 0.2 setosa
51 7.0 3.2 4.7 1.4 versicolor
52 6.4 3.2 4.5 1.5 versicolor
53 6.9 3.1 4.9 1.5 versicolor
105 6.5 3.0 5.8 2.2 virginica
106 7.6 3.0 6.6 2.1 virginica
107 4.9 2.5 4.5 1.7 virginica
108 7.3 2.9 6.3 1.8 virginica

3.7 DT

Interactive table using R package DT.

library(DT)

iris %>%
  slice(1:15) %>%
  datatable(options=list(pageLength=7))

3.8 reactable

Advanced interactive tables with reactable.

library(reactable)

reactable(iris[sample(1:150,10),],
  columns = list(
    Sepal.Length = colDef(name = "Sepal Length"),
    Sepal.Width = colDef(name = "Sepal Width"),
    Petal.Width = colDef(name = "Petal Width"),
    Petal.Width = colDef(name = "Petal Width")
  ),
  striped = TRUE,
  highlight = TRUE,
  filterable = TRUE
)

reactable creation can be simplified as well as enhanced by using reactablefmtr.

4 Static images using R

Quarto chunks can be used to control image display size using the argument out.width.

This image below is displayed at a size of 300 pixels.

```{r}
#| out-width: 300px
knitr::include_graphics("assets/image.webp")
```

This image below is displayed at a size of 75 pixels and a caption added.

```{r}
#| out-width: 75px
#| fig-cap: This is a caption
knitr::include_graphics("assets/image.webp")
```

This is a caption

This is a caption

For more information on figures, see here. For plots generated through R, see section further below.

5 Static plots

5.1 Base plot

  • Plots using base R are widely used and may be good enough for most situations.
  • But they lack a consistent coding framework.
{
  plot(x=iris$Sepal.Length,y=iris$Sepal.Width,
      col=c("coral","steelblue","forestgreen")[iris$Species],
      xlab="Sepal Length",ylab="Sepal Width",pch=19)

  legend(x=7,y=4.47,legend=c("setosa","versicolor","virginica"),
        col=c("coral","steelblue","forestgreen"),pch=19)
}
Figure 1: Static plot using base plot.

5.1.1 Multiple plots

```{r}
#| column: screen-inset-shaded
#| layout-nrow: 1
#| fig-cap:
#|   - "Scatterplot of speed vs distance"
#|   - "Pairwise scatterplot of all variables"
#|   - "Scatterplot of temperature vs pressure"

plot(cars)
plot(iris)
plot(pressure)
```

Scatterplot of speed vs distance

Scatterplot of speed vs distance

Pairwise scatterplot of all variables

Pairwise scatterplot of all variables

Scatterplot of temperature vs pressure

Scatterplot of temperature vs pressure

5.1.2 Margin plot

```{{r}}
#| column: margin

plot(cars)
```
plot(cars)

5.2 ggplot2

R package ggplot2 is one of the most versatile and complete plotting solutions.

library(ggplot2)

iris %>%
  ggplot(aes(x=Sepal.Length,y=Sepal.Width,col=Species))+
  geom_point(size=2)+
  labs(x="Sepal Length",y="Sepal Width")+
  theme_report()

Static plot using ggplot2.

Static plot using ggplot2.

6 Interactive plots

6.1 highcharter

R package highcharter is a wrapper around javascript library highcharts.

library(highcharter)

h <- iris %>%
  hchart(.,"scatter",hcaes(x="Sepal.Length",y="Sepal.Width",group="Species")) %>%
  hc_xAxis(title=list(text="Sepal Length"),crosshair=TRUE) %>%
  hc_yAxis(title=list(text="Sepal Width"),crosshair=TRUE) %>%
  hc_chart(zoomType="xy",inverted=FALSE) %>%
  hc_legend(verticalAlign="top",align="right") %>%
  hc_size(height=400)

htmltools::tagList(list(h))

Interactive scatterplot using highcharter.

6.2 plotly

R package plotly provides R binding around javascript plotting library plotly.

library(plotly)

p <- iris %>%
  plot_ly(x=~Sepal.Length,y=~Sepal.Width,color=~Species,width=500,height=400) %>%
  add_markers()
p

Interactive scatterplot using plotly.

6.3 ggplotly

plotly also has a function called ggplotly which converts a static ggplot2 object into an interactive plot.

library(plotly)

p <- iris %>%
  ggplot(aes(x=Sepal.Length,y=Sepal.Width,col=Species))+
  geom_point()+
  labs(x="Sepal Length",y="Sepal Width")+
  theme_bw(base_size=12)

ggplotly(p,width=500,height=400)

Interactive scatterplot using ggplotly.

6.4 ggiraph

ggiraph is also an R package that can be used to convert a static ggplot2 object into an interactive plot.

library(ggiraph)

p <- ggplot(iris,aes(x=Sepal.Length,y=Petal.Length,colour=Species))+
      geom_point_interactive(aes(tooltip=paste0("<b>Petal Length:</b> ",Petal.Length,"\n<b>Sepal Length: </b>",Sepal.Length,"\n<b>Species: </b>",Species)),size=2)+
  theme_bw()

tooltip_css <- "background-color:#e7eef3;font-family:Roboto;padding:10px;border-style:solid;border-width:2px;border-color:#125687;border-radius:5px;"

girafe(code=print(p),
  options=list(
    opts_hover(css="cursor:pointer;stroke:black;fill-opacity:0.3"),
    opts_zoom(max=5),
    opts_tooltip(css=tooltip_css,opacity=0.9)
  )
)

Interactive scatterplot using ggiraph.

6.5 dygraphs

R package dygraphs provides R bindings for javascript library dygraphs for time series data.

library(dygraphs)

lungDeaths <- cbind(ldeaths, mdeaths, fdeaths)
dygraph(lungDeaths,main="Deaths from Lung Disease (UK)") %>%
  dyOptions(colors=c("#66C2A5","#FC8D62","#8DA0CB"))

Interactive time series plot using dygraph.

6.6 Network graph

R package networkD3 allows the use of interactive network graphs from the D3.js javascript library.

library(networkD3)

data(MisLinks,MisNodes)
forceNetwork(Links=MisLinks,Nodes=MisNodes,Source="source",
             Target="target",Value="value",NodeID="name",
             Group="group",opacity=0.4)

Interactive network plot.

6.7 leaflet

R package leaflet provides R bindings for javascript mapping library; leafletjs.

library(leaflet)

leaflet(height=500,width=700) %>%
  addTiles(urlTemplate='http://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png') %>%
  #addProviderTiles(providers$Esri.NatGeoWorldMap) %>%
  addMarkers(lat=57.639327,lng=18.288534,popup="RaukR") %>%
  setView(lat=57.639327,lng=18.288534,zoom=15)

Interactive map using leaflet.

6.8 crosstalk

R package crosstalk allows crosstalk enabled plotting libraries to be linked. Through the shared ‘key’ variable, data points can be manipulated simultaneously on two independent plots.

library(crosstalk)

shared_quakes <- SharedData$new(quakes[sample(nrow(quakes), 100),])
lf <- leaflet(shared_quakes,height=300) %>%
        addTiles(urlTemplate='http://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png') %>%
        addMarkers()
py <- plot_ly(shared_quakes,x=~depth,y=~mag,size=~stations,height=300) %>%
        add_markers()

htmltools::div(lf,py)

Linking independent plots using crosstalk.

7 ObservableJS

Quarto supports ObservableJS for interactive visualisations in the browser.

Pass data from R to OJS

irism <- iris
colnames(irism) <- gsub("[.]","_",tolower(colnames(irism)))
ojs_define(ojsd = irism)
ojsdata = transpose(ojsd)

Display as a table

viewof filtered_table = Inputs.table(ojsdata)

Define inputs

viewof x = Inputs.select(Object.keys(ojsdata[0]), {value: "sepal_length", multiple: false, label: "X axis"})
viewof y = Inputs.select(Object.keys(ojsdata[0]), {value: "sepal_width", multiple: false, label: "Y axis"})

Display plot

Plot.plot({
  marks: [
    Plot.dot(ojsdata, {
      x: x,
      y: y,
      fill: "species",
      title: (d) =>
        `${d.species} \n Petal length: ${d.petal_length} \n Sepal length: ${d.sepal_length}`
    })
  ],
  grid: true
})

ObservableJS in quarto documentation.

8 Icons

Icons can be placed programatically through R using the R package fontawesome.

`r fontawesome::fa('lightbulb')`

Optional arguments are height and fill.

`r fontawesome::fa('lightbulb',height='30px',fill='steelblue')`

For full list of icons check out FontAwesome.