Skip to main content
flextable can embed graphics inside cells as chunk objects. Each graphic function returns a chunk that is passed to as_paragraph() and then to compose() or mk_par().
All graphic chunks require the officedown package in an R Markdown context when the output format is Word. PowerPoint cannot mix images and text in a paragraph — image chunks are silently removed from PowerPoint output.

Horizontal bar: minibar()

minibar(value, max, barcol, bg, width, height, unit) draws a simple filled progress bar scaled to a maximum value:
library(flextable)

ft <- flextable(head(iris, n = 10))
ft <- compose(ft,
  j = 1,
  value = as_paragraph(
    minibar(value = Sepal.Length, max = max(Sepal.Length))
  ),
  part = "body"
)
ft <- autofit(ft)
ft
ParameterDefaultDescription
valuerequiredNumeric vector of bar values.
maxmax(value)Value that maps to full width.
barcol"#CCCCCC"Bar fill color.
bg"transparent"Background color of the unfilled area.
width1Width of the output image in inches (or unit).
height0.2Height of the output image.
unit"in"Unit for width and height: "in", "cm", or "mm".
You can mix a minibar with text in the same cell:
ft <- flextable(airquality[sample.int(150, size = 10), ])
ft <- compose(ft,
  j = "Wind",
  value = as_paragraph(
    as_chunk(Wind, props = fp_text_default(color = "orange")),
    " ",
    minibar(
      value = Wind,
      max = max(airquality$Wind),
      barcol = "orange",
      bg = "black",
      height = .15
    )
  ),
  part = "body"
)
ft <- autofit(ft)
ft

Range plot: linerange()

linerange(value, min, max, rangecol, stickcol, bg, width, height, raster_width, unit) draws a line with end-stops and a vertical marker at the value’s position:
myft <- flextable(head(iris, n = 10))
myft <- compose(myft,
  j = 1,
  value = as_paragraph(
    linerange(value = Sepal.Length)
  ),
  part = "body"
)
autofit(myft)
ParameterDefaultDescription
valuerequiredNumeric vector of positions to mark.
minmin(value)Left end of the range axis.
maxmax(value)Right end of the range axis.
rangecol"#CCCCCC"Color of the range line and end-stops.
stickcol"#FF0000"Color of the position marker.
bg"transparent"Background.
width1Output image width.
height0.2Output image height.
raster_width30Number of pixels used when interpolating the position.
unit"in"Unit for width and height.

ggplot2 plots: gg_chunk()

gg_chunk(value, width, height, unit, res) renders a ggplot2 object stored in a list column as a PNG and embeds it:
library(data.table)
library(flextable)
if (require("ggplot2")) {
  my_cor_plot <- function(x) {
    cols <- colnames(x)[sapply(x, is.numeric)]
    x <- x[, .SD, .SDcols = cols]
    cormat <- as.data.table(cor(x))
    cormat$var1 <- colnames(cormat)
    cormat <- melt(cormat,
      id.vars = "var1", measure.vars = cormat$var1,
      variable.name = "var2", value.name = "correlation"
    )
    ggplot(data = cormat, aes(x = var1, y = var2, fill = correlation)) +
      geom_tile() +
      coord_equal() +
      scale_fill_gradient2(
        low = "blue", mid = "white", high = "red",
        limits = c(-1, 1), guide = "none"
      ) +
      theme_void()
  }
  z <- as.data.table(iris)
  z <- z[, list(gg = list(my_cor_plot(.SD))), by = "Species"]
  ft <- flextable(z)
  ft <- mk_par(ft,
    j = "gg",
    value = as_paragraph(
      gg_chunk(value = gg, width = 1, height = 1)
    )
  )
  ft
}
ParameterDefaultDescription
valuerequiredList column of ggplot2 objects.
width1Output image width.
height0.2Output image height.
unit"in"Unit for width and height.
res300PNG resolution in ppi.

Base R plots: plot_chunk()

plot_chunk(value, width, height, type, free_scale, unit, ...) renders a list column of numeric vectors as small base R plots:
library(data.table)
library(flextable)

z <- as.data.table(iris)
z <- z[, list(
  Sepal.Length = mean(Sepal.Length, na.rm = TRUE),
  z = list(.SD$Sepal.Length)
), by = "Species"]

ft <- flextable(z, col_keys = c("Species", "Sepal.Length", "box", "density"))
ft <- mk_par(ft, j = "box", value = as_paragraph(
  plot_chunk(
    value = z, type = "box",
    border = "red", col = "transparent"
  )
))
ft <- mk_par(ft, j = "density", value = as_paragraph(
  plot_chunk(value = z, type = "dens", col = "red")
))
ft <- set_table_properties(ft, layout = "autofit", width = .6)
ft <- set_header_labels(ft, box = "boxplot", density = "density")
theme_vanilla(ft)
type accepts "box", "line", "points", or "density". Additional ... arguments are forwarded to the underlying base R plot function.

Grid graphics: grid_chunk()

grid_chunk(value, width, height, unit, res) embeds grid graphical objects (grobs):
library(flextable)
ft <- flextable(head(cars))
if (require("grid")) {
  ft <- prepend_chunks(
    x = ft, i = 2, j = 2,
    grid_chunk(
      list(
        circleGrob(gp = gpar(
          fill = "#ec11c2",
          col = "transparent"
        ))
      ),
      width = .15, height = .15
    )
  )
}
ft

Embedding images: as_image()

as_image(src, width, height, unit, guess_size) reads an image file and embeds it as a chunk:
img.file <- file.path(
  R.home("doc"),
  "html", "logo.jpg"
)
if (require("magick")) {
  myft <- flextable(head(iris))
  myft <- compose(myft,
    i = 1:3, j = 1,
    value = as_paragraph(
      as_image(src = img.file),
      " ",
      as_chunk(Sepal.Length,
        props = fp_text_default(color = "red")
      )
    ),
    part = "body"
  )
  ft <- autofit(myft)
  ft
}
When guess_size = TRUE (the default) and magick is installed, flextable reads the image dimensions automatically so you don’t need to specify width and height.
For tables with many images, set guess_size = FALSE and supply explicit width and height values to avoid re-reading every image file during rendering.

Row height

Mini graphics expand the rendered PNG to the cell, but the row must be tall enough to display them. Use height() to set explicit row heights, or autofit() after composing to let flextable adjust automatically:
# Explicit row height for a 0.5-inch graphic
ft <- height(ft, height = 0.5)

# Or let autofit handle it
ft <- autofit(ft)

Output format considerations

  • Graphic chunks require the officedown package.
  • Images and text can coexist in the same paragraph.
  • Use width and height values that match the physical size you want in the printed document.