Using ggtrack

To start you just need a ggplot and some text you wish to encode into the QR. The QR is intended to contain enough information to uniquely identify the report, so a URL, file name or other unique identifier. The QR encode process automatically appends a time stamp. But try to keep the content of the QR code minimal. The for information it is the more pixels its requires and the larger it needs to be. The examples here need a QR code size of 1.8cm to be reliably scanned using a phone off the screen. QR code are encoded using the qrencoder package.


gg <- ggplot(mapping = aes(x = 1:10, y = rnorm(10))) +
  geom_bar(stat = 'identity') +

        qr_content = 'Report ID: 2c9075a5-4d7e-47a5-8616-55dd88af3dc5')

Add a Caption

Captions use the gridtext package. So you can use both HTML and markdown to style. Or if you prefer, create your own grob and pass that through instead.

g <- ggtrack(gg,
            qr_content = 'For all your image tracking needs:',
            logo = '',
            caption = 'Lots of extra info, or a fancy <span style="color:blue">"grob"</span>.')


Rearrange Banner Elements

The order and size of the banner elements can be easily rearranged via the order and positions variables. Each element is defined via a single letter code:

  • Caption is C
  • Logo is L
  • QR code is Q

And the element order is defined by the order of these codes. For example, the default order code is CLQ.

Depending on the size of the content in each element and its relative order, it becomes necessary to adjust the position or size of the elements. Position defines in order the proportional size of each element. You need to provide three numbers indicating the percent size of the element. These proportions are then converted into xmin and xmax values in the banner.

        order = 'LCQ', 
        positions = c(25, 55, 20),
        qr_content = 'For all your image tracking needs:',
        logo = '',
        caption = 'Lots of extra info, or a fancy <span style="color:blue">"grob"</span>.',
        logo_justification = 0)

When rearranging the order of banner elements it may be necessary to also change the justification of the logo and QR elements. By default these are justified to the right, so if your logo moves to the left it will appear out of place.

Justification is set via logo_justification and qr_justification. Justification here is positional. You need to imagine each element in its own rectangle with a bottom dimension of 0 to 1. If you want the logo or QR code on the right of the rectangle set justification to 1, or 0 for left. These are the main options, but you can use any number between 0 and 1 for more granular control.

Encode Additional Content Within Image

It is also possible to encode arbitrary text or an R object within knitr chunks of a report or within a downloaded file when using make_download. Using the stegasaur package knitr hook is the easiest way to include the code used to generate a plot (see stegasaur docs).

The stegasaur stenograph method is included here as a download option. Simply pass the text or R object you want encoded to the stenograph variable. Then to decode the content of the image use stegasaur::decode(). For this method to work the image must be saved in PNG format, this is the default for make_download.

dl_steg <- make_download(g, 
                         link_text = 'download file with stenograph encoded',
                         save_file = c('../man', 'figures', 'ggtrack_steg_chart'),
                         download_file = c('../reference', 'figures', 'ggtrack_steg_chart'),
                         type = 'link',
                         date = '',
                         render = FALSE,
                         stenograph = rnorm(10))

download file with stenograph encoded

Tracking Banner Style

The tracking banner is a simple ggplot object. The tracking elements are grob objects added via annotation_custom. As a ggplot object the banner can also be styled in the same way. Any ggplot theme options are passed directly to the tracking banner theme. This enables you to match the tracker to your page theme or ggplot theme. For all available theme options see


temperature <- get_historical_temp('aus', "year")

temperature_plot <- ggplot(temperature, aes(x = year, y = data)) +
  geom_path(color = 'blue') + geom_point(color = 'darkblue') +
  labs(title = 'Average Annual Temperature for Australia',
       y = 'degrees celcius') +
  stat_smooth(se = TRUE, colour = "darkred") +

for_QR <- paste0('Data accessed using R package: ',
                 ' / ',
for_Caption <- paste0('data accessed from the World Bank <br>',
                      'Climate Portal via the R package <br>',
                      '<span style="color:blue">rWBclimate</span>.')

        qr_content = for_QR,
        logo = '../man/figures/ggtrack-logo.svg',
        caption = for_Caption,
        plot.background = element_rect(fill = "#f0f0f0", size = 0))  

One Tracker Per Document

In some cases you may wish to create a single tracking banner and add it to multiple plots. ggtrack also has a more granular API that allows the user to iteratively build the banner. This banner can then be added to any existing plot.

track <- make_tracker() %>% 
  add_logo('../man/figures/ggtrack-logo.svg', 1) %>% 
  add_qr(for_QR, justification = 1) %>% 
  add_caption(for_Caption) %>%
  add_theme(plot.background = element_rect(fill = "#ff9955", size = 0))

temperature_plot %>%

Retrieving Metadata

The metadata from the QR code can be read using the scanner on your phone. If you need to programatically extract this data use the quadrangle package. Given the way the QR code are generated, you will need to ensure you specify flop = TRUE. This essentially flips the image to replicate what a scanner looking at a screen would capture.

With quadrangle you can pass in the entire file or just the QR code. The package will detect the location of the QR code before decoding.


qr <- qr_scan("../man/figures/ggtrack_chart_.png", flop = TRUE, plot = FALSE)

#> [1] "For all your image tracking needs: https/// ba52008d 20210710-085904"

And for a stegasaur encoded file, you can simply use stegasaur::decode.


#>  [1]  0.7116201 -1.8016491 -1.5395185  1.7487543  1.7490849  2.5620449
#>  [7]  1.1006261  0.5235852  0.8945168  0.3902852