├── .github
├── .gitignore
├── workflows
│ ├── R-CMD-check.yaml
│ ├── test-coverage.yaml
│ └── pkgdown.yaml
├── CODE_OF_CONDUCT.md
└── CONTRIBUTING.md
├── LICENSE
├── data
└── qr_mod.rda
├── tests
├── testthat
│ ├── Rplots.pdf
│ ├── test-git_info.R
│ ├── files
│ │ ├── ggtrack-logo.jpg
│ │ ├── ggtrack-logo.png
│ │ └── ggtrack-logo.svg
│ ├── test-caption.R
│ ├── test-position.R
│ ├── test-logo.R
│ ├── test-theme.R
│ ├── test-qr.R
│ ├── test-banner.R
│ ├── test-download.R
│ └── test-grid.R
└── testthat.R
├── man
├── figures
│ ├── README-hide-1.png
│ ├── README-logo-1.png
│ ├── ggtrack-logo.jpg
│ ├── ggtrack-logo.png
│ ├── ggtrack_chart_.png
│ ├── README-caption-1.png
│ ├── README-example-1.png
│ ├── README-pressure-1.png
│ ├── ggtrack-logo_sten.png
│ ├── README-interactive-1.png
│ ├── ggtrack_steg_chart_.png
│ ├── ggtrack-favicon.svg
│ ├── qr.svg
│ └── ggtrack-logo.svg
├── print.tracker.Rd
├── plot.tracker.Rd
├── qr_mod.Rd
├── qr_size.Rd
├── get_git_info.Rd
├── pipe.Rd
├── make_qr.Rd
├── add_theme.Rd
├── add_banner.Rd
├── get_positions.Rd
├── obj_tracker.Rd
├── make_tracker.Rd
├── caption.Rd
├── logo.Rd
├── make_download.Rd
├── qr.Rd
└── ggtrack.Rd
├── pkgdown
└── favicon
│ ├── favicon.ico
│ ├── favicon-16x16.png
│ ├── favicon-32x32.png
│ ├── apple-touch-icon.png
│ ├── apple-touch-icon-120x120.png
│ ├── apple-touch-icon-152x152.png
│ ├── apple-touch-icon-180x180.png
│ ├── apple-touch-icon-60x60.png
│ └── apple-touch-icon-76x76.png
├── .gitignore
├── .Rbuildignore
├── codecov.yml
├── R
├── utils-pipe.R
├── theme.R
├── calibration.R
├── banner.R
├── git_info.R
├── position.R
├── caption.R
├── logo.R
├── qr.R
├── download.R
└── grid.R
├── project.Rproj
├── _pkgdown.yml
├── NAMESPACE
├── LICENSE.md
├── NEWS.md
├── DESCRIPTION
├── inst
└── working
│ └── plotly.R
├── vignettes
├── qr_calibrate.Rmd
└── ggtrack.Rmd
├── README.Rmd
└── README.md
/.github/.gitignore:
--------------------------------------------------------------------------------
1 | *.html
2 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | YEAR: 2021
2 | COPYRIGHT HOLDER: ggtrack authors
3 |
--------------------------------------------------------------------------------
/data/qr_mod.rda:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/mrjoh3/ggtrack/HEAD/data/qr_mod.rda
--------------------------------------------------------------------------------
/tests/testthat/Rplots.pdf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/mrjoh3/ggtrack/HEAD/tests/testthat/Rplots.pdf
--------------------------------------------------------------------------------
/man/figures/README-hide-1.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/mrjoh3/ggtrack/HEAD/man/figures/README-hide-1.png
--------------------------------------------------------------------------------
/man/figures/README-logo-1.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/mrjoh3/ggtrack/HEAD/man/figures/README-logo-1.png
--------------------------------------------------------------------------------
/man/figures/ggtrack-logo.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/mrjoh3/ggtrack/HEAD/man/figures/ggtrack-logo.jpg
--------------------------------------------------------------------------------
/man/figures/ggtrack-logo.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/mrjoh3/ggtrack/HEAD/man/figures/ggtrack-logo.png
--------------------------------------------------------------------------------
/pkgdown/favicon/favicon.ico:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/mrjoh3/ggtrack/HEAD/pkgdown/favicon/favicon.ico
--------------------------------------------------------------------------------
/tests/testthat/test-git_info.R:
--------------------------------------------------------------------------------
1 | test_that("multiplication works", {
2 | expect_equal(2 * 2, 4)
3 | })
4 |
--------------------------------------------------------------------------------
/man/figures/ggtrack_chart_.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/mrjoh3/ggtrack/HEAD/man/figures/ggtrack_chart_.png
--------------------------------------------------------------------------------
/tests/testthat.R:
--------------------------------------------------------------------------------
1 | library(testthat)
2 | library(ggplot2)
3 | library(ggtrack)
4 |
5 | test_check("ggtrack")
6 |
--------------------------------------------------------------------------------
/man/figures/README-caption-1.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/mrjoh3/ggtrack/HEAD/man/figures/README-caption-1.png
--------------------------------------------------------------------------------
/man/figures/README-example-1.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/mrjoh3/ggtrack/HEAD/man/figures/README-example-1.png
--------------------------------------------------------------------------------
/man/figures/README-pressure-1.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/mrjoh3/ggtrack/HEAD/man/figures/README-pressure-1.png
--------------------------------------------------------------------------------
/man/figures/ggtrack-logo_sten.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/mrjoh3/ggtrack/HEAD/man/figures/ggtrack-logo_sten.png
--------------------------------------------------------------------------------
/pkgdown/favicon/favicon-16x16.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/mrjoh3/ggtrack/HEAD/pkgdown/favicon/favicon-16x16.png
--------------------------------------------------------------------------------
/pkgdown/favicon/favicon-32x32.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/mrjoh3/ggtrack/HEAD/pkgdown/favicon/favicon-32x32.png
--------------------------------------------------------------------------------
/man/figures/README-interactive-1.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/mrjoh3/ggtrack/HEAD/man/figures/README-interactive-1.png
--------------------------------------------------------------------------------
/man/figures/ggtrack_steg_chart_.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/mrjoh3/ggtrack/HEAD/man/figures/ggtrack_steg_chart_.png
--------------------------------------------------------------------------------
/pkgdown/favicon/apple-touch-icon.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/mrjoh3/ggtrack/HEAD/pkgdown/favicon/apple-touch-icon.png
--------------------------------------------------------------------------------
/tests/testthat/files/ggtrack-logo.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/mrjoh3/ggtrack/HEAD/tests/testthat/files/ggtrack-logo.jpg
--------------------------------------------------------------------------------
/tests/testthat/files/ggtrack-logo.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/mrjoh3/ggtrack/HEAD/tests/testthat/files/ggtrack-logo.png
--------------------------------------------------------------------------------
/pkgdown/favicon/apple-touch-icon-120x120.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/mrjoh3/ggtrack/HEAD/pkgdown/favicon/apple-touch-icon-120x120.png
--------------------------------------------------------------------------------
/pkgdown/favicon/apple-touch-icon-152x152.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/mrjoh3/ggtrack/HEAD/pkgdown/favicon/apple-touch-icon-152x152.png
--------------------------------------------------------------------------------
/pkgdown/favicon/apple-touch-icon-180x180.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/mrjoh3/ggtrack/HEAD/pkgdown/favicon/apple-touch-icon-180x180.png
--------------------------------------------------------------------------------
/pkgdown/favicon/apple-touch-icon-60x60.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/mrjoh3/ggtrack/HEAD/pkgdown/favicon/apple-touch-icon-60x60.png
--------------------------------------------------------------------------------
/pkgdown/favicon/apple-touch-icon-76x76.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/mrjoh3/ggtrack/HEAD/pkgdown/favicon/apple-touch-icon-76x76.png
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | .Rproj.user
2 | .Rhistory
3 | .Rdata
4 | .httr-oauth
5 | .DS_Store
6 | ggtrack.Rcheck/
7 | ggtrack*.tar.gz
8 | ggtrack*.tgz
9 | docs
10 |
--------------------------------------------------------------------------------
/.Rbuildignore:
--------------------------------------------------------------------------------
1 | ^project\.Rproj$
2 | ^\.Rproj\.user$
3 | ^README\.Rmd$
4 | ^ggtrack\.Rcheck$
5 | ^ggtrack.*\.tar\.gz$
6 | ^ggtrack.*\.tgz$
7 | ^LICENSE\.md$
8 | ^_pkgdown\.yml$
9 | ^docs$
10 | ^pkgdown$
11 | ^\.github$
12 | ^codecov\.yml$
13 |
--------------------------------------------------------------------------------
/codecov.yml:
--------------------------------------------------------------------------------
1 | comment: false
2 |
3 | coverage:
4 | status:
5 | project:
6 | default:
7 | target: auto
8 | threshold: 1%
9 | informational: true
10 | patch:
11 | default:
12 | target: auto
13 | threshold: 1%
14 | informational: true
15 |
--------------------------------------------------------------------------------
/R/utils-pipe.R:
--------------------------------------------------------------------------------
1 | #' Pipe operator
2 | #'
3 | #' See \code{magrittr::\link[magrittr:pipe]{\%>\%}} for details.
4 | #'
5 | #' @name %>%
6 | #' @rdname pipe
7 | #' @keywords internal
8 | #' @export
9 | #' @importFrom magrittr %>%
10 | #' @usage lhs \%>\% rhs
11 | #' @param lhs A value or the magrittr placeholder.
12 | #' @param rhs A function call using the magrittr semantics.
13 | #' @return The result of calling `rhs(lhs)`.
14 | NULL
15 |
--------------------------------------------------------------------------------
/man/print.tracker.Rd:
--------------------------------------------------------------------------------
1 | % Generated by roxygen2: do not edit by hand
2 | % Please edit documentation in R/grid.R
3 | \name{print.tracker}
4 | \alias{print.tracker}
5 | \title{Print Tracker}
6 | \usage{
7 | \method{print}{tracker}(x, ...)
8 | }
9 | \arguments{
10 | \item{x}{ggtrack tracker object}
11 |
12 | \item{...}{print options}
13 | }
14 | \description{
15 | Print Tracker
16 | }
17 | \examples{
18 | \dontrun{
19 | print(make_tracker())
20 | }
21 | }
22 |
--------------------------------------------------------------------------------
/man/plot.tracker.Rd:
--------------------------------------------------------------------------------
1 | % Generated by roxygen2: do not edit by hand
2 | % Please edit documentation in R/grid.R
3 | \name{plot.tracker}
4 | \alias{plot.tracker}
5 | \title{Plot Tracker Object}
6 | \usage{
7 | \method{plot}{tracker}(x, ...)
8 | }
9 | \arguments{
10 | \item{x}{ggtrack tracker object}
11 |
12 | \item{...}{plot options}
13 | }
14 | \description{
15 | Plot Tracker Object
16 | }
17 | \examples{
18 | \dontrun{
19 | plot(make_tracker())
20 | }
21 | }
22 |
--------------------------------------------------------------------------------
/man/qr_mod.Rd:
--------------------------------------------------------------------------------
1 | % Generated by roxygen2: do not edit by hand
2 | % Please edit documentation in R/calibration.R
3 | \docType{data}
4 | \name{qr_mod}
5 | \alias{qr_mod}
6 | \title{Estimate QR Size.}
7 | \format{
8 | A linear model
9 | }
10 | \usage{
11 | qr_mod
12 | }
13 | \description{
14 | A model predicting the required QR size based
15 | on the number of bytes to be encoded. The model is generated in the
16 | package vignette qr_calibrate
17 | }
18 | \keyword{datasets}
19 |
--------------------------------------------------------------------------------
/man/qr_size.Rd:
--------------------------------------------------------------------------------
1 | % Generated by roxygen2: do not edit by hand
2 | % Please edit documentation in R/calibration.R
3 | \name{qr_size}
4 | \alias{qr_size}
5 | \title{Get QR Size}
6 | \usage{
7 | qr_size(txt)
8 | }
9 | \arguments{
10 | \item{txt}{character to be encoded into the QR}
11 | }
12 | \value{
13 | numeric size of QR in cm.
14 | }
15 | \description{
16 | Given a character string, calculate the minimum size
17 | of a QR that will reliably scan off a computer monitor
18 | }
19 |
--------------------------------------------------------------------------------
/man/get_git_info.Rd:
--------------------------------------------------------------------------------
1 | % Generated by roxygen2: do not edit by hand
2 | % Please edit documentation in R/git_info.R
3 | \name{get_git_info}
4 | \alias{get_git_info}
5 | \title{Get Local Git Information}
6 | \usage{
7 | get_git_info()
8 | }
9 | \value{
10 | character
11 | }
12 | \description{
13 | Uses \link[base]{system} to determine if a git repository exists
14 | and if so returns the upstream remote URL and current commit SHA
15 | }
16 | \examples{
17 | \dontrun{
18 |
19 | get_git_info()
20 |
21 | }
22 | }
23 |
--------------------------------------------------------------------------------
/project.Rproj:
--------------------------------------------------------------------------------
1 | Version: 1.0
2 |
3 | RestoreWorkspace: No
4 | SaveWorkspace: No
5 | AlwaysSaveHistory: Default
6 |
7 | EnableCodeIndexing: Yes
8 | UseSpacesForTab: Yes
9 | NumSpacesForTab: 2
10 | Encoding: UTF-8
11 |
12 | RnwWeave: knitr
13 | LaTeX: pdfLaTeX
14 |
15 | AutoAppendNewline: Yes
16 | StripTrailingWhitespace: Yes
17 | LineEndingConversion: Posix
18 |
19 | BuildType: Package
20 | PackageUseDevtools: Yes
21 | PackageInstallArgs: --no-multiarch --with-keep.source
22 | PackageRoxygenize: rd,collate,namespace
23 |
--------------------------------------------------------------------------------
/man/pipe.Rd:
--------------------------------------------------------------------------------
1 | % Generated by roxygen2: do not edit by hand
2 | % Please edit documentation in R/utils-pipe.R
3 | \name{\%>\%}
4 | \alias{\%>\%}
5 | \title{Pipe operator}
6 | \usage{
7 | lhs \%>\% rhs
8 | }
9 | \arguments{
10 | \item{lhs}{A value or the magrittr placeholder.}
11 |
12 | \item{rhs}{A function call using the magrittr semantics.}
13 | }
14 | \value{
15 | The result of calling \code{rhs(lhs)}.
16 | }
17 | \description{
18 | See \code{magrittr::\link[magrittr:pipe]{\%>\%}} for details.
19 | }
20 | \keyword{internal}
21 |
--------------------------------------------------------------------------------
/man/make_qr.Rd:
--------------------------------------------------------------------------------
1 | % Generated by roxygen2: do not edit by hand
2 | % Please edit documentation in R/qr.R
3 | \name{make_qr}
4 | \alias{make_qr}
5 | \title{Make QR}
6 | \usage{
7 | make_qr(qr_content, color = "black", color_bg = "white")
8 | }
9 | \arguments{
10 | \item{qr_content}{\code{character} content passed to \link[qrencoder]{qrencode}. A time stamp is automatically added plus the current
11 | git commit where available.}
12 |
13 | \item{color}{character color of QR code}
14 |
15 | \item{color_bg}{character background color of QR code}
16 | }
17 | \value{
18 | matrix
19 | }
20 | \description{
21 | Make QR
22 | }
23 |
--------------------------------------------------------------------------------
/man/add_theme.Rd:
--------------------------------------------------------------------------------
1 | % Generated by roxygen2: do not edit by hand
2 | % Please edit documentation in R/theme.R
3 | \name{add_theme}
4 | \alias{add_theme}
5 | \title{Modify Tracking Banner Theme}
6 | \usage{
7 | add_theme(tracker, ...)
8 | }
9 | \arguments{
10 | \item{tracker}{ggtrack tracker object}
11 |
12 | \item{...}{options passed to \link[ggplot2]{theme} in order to style the tracker banner}
13 | }
14 | \value{
15 | tracker
16 | }
17 | \description{
18 | Modify Tracking Banner Theme
19 | }
20 | \examples{
21 | \dontrun{
22 | make_tracker() \%>\% add_theme(plot.background = ggplot2::element_rect(fill = "red", size = 0))
23 | }
24 | }
25 |
--------------------------------------------------------------------------------
/tests/testthat/test-caption.R:
--------------------------------------------------------------------------------
1 |
2 | pos <- get_positions("CLQ", c(10, 50, 40))
3 |
4 | test_that("we can add a Caption to a plot", {
5 |
6 | # this should only ever occur in ggtrack function
7 | cap <- ggplot(mapping = aes(x = 0:1, y = 1)) %>%
8 | add_caption('add to qr', position = pos)
9 |
10 | expect_type(cap, 'list')
11 | expect_s3_class(cap, 'gg')
12 | expect_s3_class(cap, 'ggplot')
13 |
14 | })
15 |
16 | test_that("we can add a Caption to a tracker", {
17 | cap <- make_tracker(add_git = FALSE) %>%
18 | add_caption('add to qr')
19 |
20 | expect_type(cap, 'list')
21 | expect_s3_class(cap, 'tracker')
22 |
23 | })
24 |
--------------------------------------------------------------------------------
/man/add_banner.Rd:
--------------------------------------------------------------------------------
1 | % Generated by roxygen2: do not edit by hand
2 | % Please edit documentation in R/banner.R
3 | \name{add_banner}
4 | \alias{add_banner}
5 | \title{Add Tracking Banner to Plot}
6 | \usage{
7 | add_banner(gg, tracker, height_plot = 7)
8 | }
9 | \arguments{
10 | \item{gg}{ggplot object to track}
11 |
12 | \item{tracker}{ggtrack tracker object}
13 |
14 | \item{height_plot}{numeric tracker height in cm.}
15 | }
16 | \value{
17 | tracker
18 | }
19 | \description{
20 | Add Tracking Banner to Plot
21 | }
22 | \examples{
23 |
24 | \dontrun{
25 |
26 | track <- make_tracker()
27 |
28 | ggplot() \%>\%
29 | add_banner(track)
30 |
31 | }
32 | }
33 |
--------------------------------------------------------------------------------
/tests/testthat/test-position.R:
--------------------------------------------------------------------------------
1 |
2 | test_that("position inputs are correct", {
3 | expect_error(get_positions("ABC", 100))
4 | expect_error(get_positions("ABC", c(10, 50, 40)))
5 | expect_error(get_positions("CLQ", 100))
6 | expect_error(get_positions("CLQ", 50))
7 | })
8 |
9 | test_that("position data.frame is accurate", {
10 | pos <- get_positions("CLQ", c(10, 50, 40))
11 | expect_equal(nrow(pos), 3)
12 | expect_equal(sum(pos$position), 100)
13 | expect_true(all(pos$order %in% c('C','L','Q')))
14 | })
15 |
16 | test_that('position input can be lower or mixed case',{
17 | expect_s3_class(get_positions("qLC", c(10, 50, 40)), 'data.frame')
18 | })
19 |
20 |
21 |
22 |
--------------------------------------------------------------------------------
/tests/testthat/test-logo.R:
--------------------------------------------------------------------------------
1 |
2 | pos <- get_positions("CLQ", c(10, 50, 40))
3 |
4 | test_that("we can add a Logo to a plot", {
5 |
6 | # this should only ever occur in ggtrack function
7 | logo <- ggplot(mapping = aes(x = 0:1, y = 1)) %>%
8 | add_logo('files/ggtrack-logo.png', position = pos, height_tracker = 2, justification = 1)
9 |
10 | expect_type(logo, 'list')
11 | expect_s3_class(logo, 'gg')
12 | expect_s3_class(logo, 'ggplot')
13 |
14 | })
15 |
16 | test_that("we can add a Logo to a tracker", {
17 | logo <- make_tracker(add_git = FALSE) %>%
18 | add_logo('files/ggtrack-logo.png', justification = 1)
19 |
20 | expect_type(logo, 'list')
21 | expect_s3_class(logo, 'tracker')
22 |
23 | })
24 |
--------------------------------------------------------------------------------
/R/theme.R:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 | #' @title Modify Tracking Banner Theme
7 | #'
8 | #' @param tracker ggtrack tracker object
9 | #' @param ... options passed to \link[ggplot2]{theme} in order to style the tracker banner
10 | #'
11 | #' @return tracker
12 | #' @export
13 | #'
14 | #' @examples
15 | #' \dontrun{
16 | #' make_tracker() %>% add_theme(plot.background = ggplot2::element_rect(fill = "red", size = 0))
17 | #' }
18 | add_theme <- function(tracker, ...) {
19 |
20 | height_tracker <- tracker$height
21 | position <- tracker$pos
22 | banner <- tracker$track
23 | git <- tracker$git
24 | ts <- tracker$ts
25 |
26 | tracker$track <- banner + theme(...)
27 |
28 | mtrack <- obj_tracker(tracker, 'theme')
29 |
30 | return(mtrack)
31 |
32 | }
33 |
34 |
--------------------------------------------------------------------------------
/tests/testthat/test-theme.R:
--------------------------------------------------------------------------------
1 |
2 | gg <- ggplot(mapping = aes(x = 1:10, y = rnorm(10))) +
3 | geom_bar(stat = 'identity')
4 |
5 | test_that('tracker theme can be modified', {
6 | thm <- ggtrack(gg,
7 | qr_content = 'some text',
8 | logo = 'files/ggtrack-logo.svg',
9 | caption = 'some text',
10 | plot.background = element_rect(fill = "#f0f0f0", size = 0),
11 | add_git = FALSE)
12 |
13 | expect_s3_class(thm, "gtable")
14 | expect_s3_class(thm, "gTree")
15 | expect_s3_class(thm, "grob")
16 | expect_s3_class(thm, "gDesc")
17 |
18 | expect_length(thm$heights, 2)
19 | expect_equal(as.numeric(thm$heights[1]), 7)
20 | expect_equal(as.numeric(thm$heights[2]), 3.3)
21 |
22 | })
23 |
--------------------------------------------------------------------------------
/R/calibration.R:
--------------------------------------------------------------------------------
1 |
2 | #' @title Estimate QR Size.
3 | #'
4 | #' @description A model predicting the required QR size based
5 | #' on the number of bytes to be encoded. The model is generated in the
6 | #' package vignette qr_calibrate
7 | #'
8 | #' @format A linear model
9 | #'
10 | "qr_mod"
11 |
12 |
13 | #' @title Get QR Size
14 | #'
15 | #' @description Given a character string, calculate the minimum size
16 | #' of a QR that will reliably scan off a computer monitor
17 | #'
18 | #' @param txt character to be encoded into the QR
19 | #'
20 | #' @return numeric size of QR in cm.
21 | #' @export
22 | #'
23 | #' @examples
24 | qr_size <- function(txt) {
25 |
26 | bts <- nchar(txt, 'bytes')
27 | pred <- predict(qr_mod, data.frame(bytes = bts))
28 | pred <- round(as.numeric(pred), 1)
29 |
30 | return(max(1.8, pred))
31 | }
32 |
--------------------------------------------------------------------------------
/R/banner.R:
--------------------------------------------------------------------------------
1 |
2 |
3 | #' @title Add Tracking Banner to Plot
4 | #'
5 | #' @param gg ggplot object to track
6 | #' @param tracker ggtrack tracker object
7 | #' @param height_plot numeric tracker height in cm.
8 | #'
9 | #' @return tracker
10 | #' @export
11 | #'
12 | #' @examples
13 | #'
14 | #' \dontrun{
15 | #'
16 | #' track <- make_tracker()
17 | #'
18 | #' ggplot() %>%
19 | #' add_banner(track)
20 | #'
21 | #' }
22 | add_banner <- function(gg, tracker, height_plot = 7) {
23 |
24 | if (missing(gg)) {
25 | gg <- ggplot() + theme_void()
26 | height_plot <- 0
27 | }
28 |
29 | height_tracker <- tracker$height
30 |
31 | tracker$track <- tracker$track +
32 | theme(plot.margin=unit(c(.5, 0, .3, 0),"cm"))
33 |
34 | gridExtra::grid.arrange(gg, tracker$track, heights = unit(c(height_plot, height_tracker + 1.5 ), "cm"))
35 |
36 | }
37 |
38 |
39 |
--------------------------------------------------------------------------------
/man/get_positions.Rd:
--------------------------------------------------------------------------------
1 | % Generated by roxygen2: do not edit by hand
2 | % Please edit documentation in R/position.R
3 | \name{get_positions}
4 | \alias{get_positions}
5 | \title{Define Tracker Container Positions}
6 | \usage{
7 | get_positions(order, positions)
8 | }
9 | \arguments{
10 | \item{order}{\code{character} of \code{length} 3 defining placement
11 | order for "caption" (C), "logo" (L) and "QR" (Q) code. Must be one of:
12 | \itemize{
13 | \item{CLQ}
14 | \item{LCQ}
15 | \item{QLC}
16 | \item{CQL}
17 | }}
18 |
19 | \item{positions}{\code{numeric} \code{vector} of \code{length} 3,
20 | defining the horizontal proportion of each container. The 3 numbers
21 | must add to 100.}
22 | }
23 | \value{
24 | data.frame
25 | }
26 | \description{
27 | Define Tracker Container Positions
28 | }
29 | \examples{
30 |
31 | get_positions(order = 'CLQ', positions = c(55, 25, 20))
32 |
33 | }
34 |
--------------------------------------------------------------------------------
/man/obj_tracker.Rd:
--------------------------------------------------------------------------------
1 | % Generated by roxygen2: do not edit by hand
2 | % Please edit documentation in R/grid.R
3 | \name{obj_tracker}
4 | \alias{obj_tracker}
5 | \title{Create Tracker Object}
6 | \usage{
7 | obj_tracker(
8 | tracker,
9 | contains,
10 | pos = NULL,
11 | height_tracker = NULL,
12 | git = NULL,
13 | timestamp = NULL
14 | )
15 | }
16 | \arguments{
17 | \item{tracker}{ggtrack tracker object}
18 |
19 | \item{contains}{character vector tracks what elements have been added to tracker}
20 |
21 | \item{pos}{\code{numeric} \code{vector} of \code{length} 3,
22 | defining the horizontal proportion of each container. The 3 numbers
23 | must add to 100.}
24 |
25 | \item{height_tracker}{numeric tracker height in cm.}
26 |
27 | \item{git}{character git information derived by \link[ggtrack]{get_git_info}}
28 | }
29 | \value{
30 | tracker
31 | }
32 | \description{
33 | Create Tracker Object
34 | }
35 |
--------------------------------------------------------------------------------
/tests/testthat/test-qr.R:
--------------------------------------------------------------------------------
1 |
2 | pos <- get_positions("CLQ", c(10, 50, 40))
3 |
4 | test_that("we can create a QR matrix", {
5 | qr <- ggtrack:::make_qr('minimal test of QR')
6 |
7 | expect_type(qr, 'character')
8 | expect_equal(unique(qr[1,]), c('black','white'))
9 | expect_equal(dim(qr), c(25,25))
10 |
11 | })
12 |
13 |
14 | test_that("we can add a QR to a plot", {
15 |
16 | # this should only ever occur in ggtrack function
17 | qr <- ggplot(mapping = aes(x = 0:1, y = 1)) %>%
18 | add_qr('add to qr', justification = 1, height_tracker = 2, position = pos)
19 |
20 | expect_type(qr, 'list')
21 | expect_s3_class(qr, 'gg')
22 | expect_s3_class(qr, 'ggplot')
23 |
24 | })
25 |
26 |
27 |
28 |
29 | test_that("we can add a QR to a tracker", {
30 | qr <- make_tracker(add_git = FALSE) %>%
31 | add_qr('add to qr', justification = 1)
32 |
33 | expect_type(qr, 'list')
34 | expect_s3_class(qr, 'tracker')
35 |
36 | })
37 |
--------------------------------------------------------------------------------
/_pkgdown.yml:
--------------------------------------------------------------------------------
1 | url: https://mrjoh3.github.io/ggtrack
2 |
3 | home:
4 | title: ggtrack, add a tracking banner to your plots.
5 | description: The `ggtrack` package will embed enough metadata in a plot image to later identify the source and the exact time it was produced.
6 |
7 | navbar:
8 | type: default
9 | structure:
10 | left: [home, intro, articles, reference, news]
11 | right: [github]
12 |
13 | repo:
14 | url:
15 | home: https://github.com/mrjoh3/ggtrack/
16 | source: https://github.com/mrjoh3/ggtrack/blob/master/
17 | issue: https://github.com/mrjoh3/ggtrack/issues/
18 | user: https://github.com/mrjoh3/
19 |
20 | development:
21 | mode: auto
22 |
23 | template:
24 | params:
25 | bootswatch: flatly
26 | opengraph:
27 | image:
28 | src: man/figures/ggtrack-logo.png
29 | alt: "Use ggrack to add metadata to your ggplot"
30 | twitter:
31 | creator: "@mrjoh3"
32 | card: summary
33 |
--------------------------------------------------------------------------------
/.github/workflows/R-CMD-check.yaml:
--------------------------------------------------------------------------------
1 | # For help debugging build failures open an issue on the RStudio community with the 'github-actions' tag.
2 | # https://community.rstudio.com/new-topic?category=Package%20development&tags=github-actions
3 | on:
4 | push:
5 | branches:
6 | - main
7 | - master
8 | pull_request:
9 | branches:
10 | - main
11 | - master
12 |
13 | name: R-CMD-check
14 |
15 | jobs:
16 | R-CMD-check:
17 | runs-on: macOS-latest
18 | env:
19 | GITHUB_PAT: ${{ secrets.GITHUB_TOKEN }}
20 | steps:
21 | - uses: actions/checkout@v2
22 | - uses: r-lib/actions/setup-r@v1
23 | - name: Install dependencies
24 | run: |
25 | install.packages(c("remotes", "rcmdcheck"))
26 | remotes::install_deps(dependencies = TRUE)
27 | shell: Rscript {0}
28 | - name: Check
29 | run: |
30 | options(crayon.enabled = TRUE)
31 | rcmdcheck::rcmdcheck(args = "--no-manual", error_on = "error")
32 | shell: Rscript {0}
33 |
--------------------------------------------------------------------------------
/NAMESPACE:
--------------------------------------------------------------------------------
1 | # Generated by roxygen2: do not edit by hand
2 |
3 | S3method(add_caption,gg)
4 | S3method(add_caption,tracker)
5 | S3method(add_logo,gg)
6 | S3method(add_logo,tracker)
7 | S3method(add_qr,gg)
8 | S3method(add_qr,tracker)
9 | S3method(plot,tracker)
10 | S3method(print,tracker)
11 | export("%>%")
12 | export(add_banner)
13 | export(add_caption)
14 | export(add_logo)
15 | export(add_qr)
16 | export(add_theme)
17 | export(caption)
18 | export(get_git_info)
19 | export(get_positions)
20 | export(ggtrack)
21 | export(make_download)
22 | export(make_tracker)
23 | export(qr_size)
24 | import(RCurl)
25 | import(ggplot2)
26 | import(grid)
27 | import(gridExtra)
28 | import(jpeg)
29 | import(png)
30 | import(qrencoder)
31 | import(rsvg)
32 | importFrom(ggplot2,annotation_custom)
33 | importFrom(glue,glue)
34 | importFrom(grid,rasterGrob)
35 | importFrom(gridtext,richtext_grob)
36 | importFrom(htmltools,a)
37 | importFrom(htmltools,css)
38 | importFrom(magick,image_read_svg)
39 | importFrom(magrittr,"%>%")
40 | importFrom(stegasaur,lsb_encode)
41 | importFrom(tools,file_ext)
42 |
--------------------------------------------------------------------------------
/man/make_tracker.Rd:
--------------------------------------------------------------------------------
1 | % Generated by roxygen2: do not edit by hand
2 | % Please edit documentation in R/grid.R
3 | \name{make_tracker}
4 | \alias{make_tracker}
5 | \title{Define Tracker Base}
6 | \usage{
7 | make_tracker(
8 | order = "CLQ",
9 | positions = c(55, 25, 20),
10 | height_tracker = 1.8,
11 | add_git = TRUE,
12 | add_ts = TRUE
13 | )
14 | }
15 | \arguments{
16 | \item{order}{\code{character} of \code{length} 3 defining placement
17 | order for "caption" (C), "logo" (L) and "QR" (Q) code. Must be one of:
18 | \itemize{
19 | \item{CLQ}
20 | \item{LCQ}
21 | \item{QLC}
22 | \item{CQL}
23 | }}
24 |
25 | \item{positions}{\code{numeric} \code{vector} of \code{length} 3,
26 | defining the horizontal proportion of each container. The 3 numbers
27 | must add to 100.}
28 |
29 | \item{height_tracker}{numeric tracker height in cm.}
30 |
31 | \item{add_git}{logical include git info in encoding}
32 |
33 | \item{add_ts}{logical include timestamp info in encoding}
34 | }
35 | \value{
36 | tracker
37 | }
38 | \description{
39 | Define Tracker Base
40 | }
41 | \examples{
42 | \dontrun{
43 | make_tracker()
44 | }
45 | }
46 |
--------------------------------------------------------------------------------
/LICENSE.md:
--------------------------------------------------------------------------------
1 | # MIT License
2 |
3 | Copyright (c) 2021 ggtrack authors
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy
6 | of this software and associated documentation files (the "Software"), to deal
7 | in the Software without restriction, including without limitation the rights
8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | copies of the Software, and to permit persons to whom the Software is
10 | furnished to do so, subject to the following conditions:
11 |
12 | The above copyright notice and this permission notice shall be included in all
13 | copies or substantial portions of the Software.
14 |
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 | SOFTWARE.
22 |
--------------------------------------------------------------------------------
/tests/testthat/test-banner.R:
--------------------------------------------------------------------------------
1 |
2 | track <- make_tracker(add_git = FALSE) %>%
3 | add_logo('files/ggtrack-logo.svg', 1) %>%
4 | add_qr('for_QR', justification = 1) %>%
5 | add_caption('for_Caption') %>%
6 | add_theme(plot.background = element_rect(fill = "#ff9955", size = 0))
7 |
8 | gg <- ggplot(mapping = aes(x = 1:10, y = rnorm(10))) +
9 | geom_bar(stat = 'identity') +
10 | theme_minimal()
11 |
12 |
13 | test_that("we can add a tracking banner", {
14 | tbn <- gg %>%
15 | add_banner(track)
16 |
17 | expect_s3_class(tbn, "gtable")
18 | expect_s3_class(tbn, "gTree")
19 | expect_s3_class(tbn, "grob")
20 | expect_s3_class(tbn, "gDesc")
21 |
22 | expect_length(tbn$heights, 2)
23 | expect_equal(as.numeric(tbn$heights[1]), 7)
24 | expect_equal(as.numeric(tbn$heights[2]), 3.3)
25 | })
26 |
27 |
28 | test_that("we can add a tracking banner without a plot", {
29 | tbn <- add_banner(tracker = track)
30 |
31 | expect_s3_class(tbn, "gtable")
32 | expect_s3_class(tbn, "gTree")
33 | expect_s3_class(tbn, "grob")
34 | expect_s3_class(tbn, "gDesc")
35 |
36 | expect_length(tbn$heights, 2)
37 | expect_equal(as.numeric(tbn$heights[1]), 0)
38 | expect_equal(as.numeric(tbn$heights[2]), 3.3)
39 | })
40 |
--------------------------------------------------------------------------------
/R/git_info.R:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | #' @title Get Local Git Information
5 | #' @description Uses \link[base]{system} to determine if a git repository exists
6 | #' and if so returns the upstream remote URL and current commit SHA
7 | #'
8 | #' @return character
9 | #' @export
10 | #'
11 | #' @examples
12 | #' \dontrun{
13 | #'
14 | #' get_git_info()
15 | #'
16 | #' }
17 | get_git_info <- function() {
18 |
19 | g <- Sys.which('git')
20 |
21 | if (as.character(g) != '') {
22 | # we might have git but not be in a git repo
23 | in_git_repo <- invisible(system("git rev-parse --git-dir",
24 | ignore.stderr = TRUE,
25 | ignore.stdout = TRUE))
26 |
27 | if (in_git_repo == 0) {
28 |
29 | git_sha <- strtrim(system("git rev-parse HEAD", intern=TRUE), 8)
30 | git_url <- system("git config --get remote.origin.url", intern=TRUE)
31 | git_url <- gsub(':', '/', git_url) # change remote to web URL
32 | git_url <- gsub('git@', 'http://', git_url)
33 | git_url <- gsub('\\.git', '', git_url)
34 |
35 | git <- paste0(git_url, ' ', git_sha)
36 |
37 | } else {
38 | git <- ""
39 | }
40 | }
41 |
42 | return(git)
43 |
44 | }
45 |
--------------------------------------------------------------------------------
/R/position.R:
--------------------------------------------------------------------------------
1 |
2 |
3 | #' @title Define Tracker Container Positions
4 | #'
5 | #' @param order \code{character} of \code{length} 3 defining placement
6 | #' order for "caption" (C), "logo" (L) and "QR" (Q) code. Must be one of:
7 | #' \itemize{
8 | #' \item{CLQ}
9 | #' \item{LCQ}
10 | #' \item{QLC}
11 | #' \item{CQL}
12 | #' }
13 | #' @param positions \code{numeric} \code{vector} of \code{length} 3,
14 | #' defining the horizontal proportion of each container. The 3 numbers
15 | #' must add to 100.
16 | #'
17 | #' @return data.frame
18 | #' @export
19 | #'
20 | #' @examples
21 | #'
22 | #' get_positions(order = 'CLQ', positions = c(55, 25, 20))
23 | #'
24 | get_positions <- function(order, positions) {
25 |
26 | order <- toupper(order)
27 | stopifnot(order %in% c('CLQ','LCQ','QLC','CQL'))
28 | stopifnot(sum(positions) == 100)
29 | stopifnot(length(positions) == 3)
30 |
31 | pos <- data.frame(order = unlist(strsplit(order, split = "")),
32 | position = positions,
33 | xmin = 0,
34 | xmax = 1,
35 | stringsAsFactors = FALSE)
36 |
37 | pos[1, 'xmax'] <- pos[2, 'xmin'] <- (positions[1] / 100)
38 | pos[2, 'xmax'] <- pos[3, 'xmin'] <- ((positions[1] + positions[2]) / 100)
39 |
40 | return(pos)
41 |
42 | }
43 |
--------------------------------------------------------------------------------
/NEWS.md:
--------------------------------------------------------------------------------
1 | # ggtrack 0.1.3
2 |
3 | * QR now resizes automatically based on bytes to encode. This ensures QR code readability
4 |
5 | # ggtrack 0.1.2
6 |
7 | * `add_banner` now works without a `ggplot` input. This is useful where you just want to create the banner. Like this the banner could be placed above or below an interactive chart or map, or any other content.
8 |
9 | # ggtrack 0.1.1
10 |
11 | * move git and timestamp options higher up in API and make them optional
12 | * using `stegasaur` package add encoded text or R object to saved PNG (https://github.com/richfitz/stegasaur)
13 |
14 | # ggtrack 0.1.0
15 |
16 | * complete minimum tests
17 | * complete minimum documentation
18 | * add `codecov` badge
19 | * update lifecycle badge to stable
20 | * R-CMD check passing
21 |
22 | # ggtrack 0.0.3
23 |
24 | * add additional API for incremental banner build
25 | * ability to add banner to multiple plots
26 | * generic print and plot functions for `tracker` object
27 |
28 | # ggtrack 0.0.2
29 |
30 | * add logo caption and QR code to tracking banner
31 | * rearrange order of banner elements
32 | * style banner area
33 | * add JPEG, PNG or SVG logos from URL or local file
34 | * add button or link to download plot with tracking banner
35 | * documentation in `pkgdown` site
36 | * fancy SGV hex logo
37 |
38 | # ggtrack 0.0.1
39 |
40 | * Currently a work in progress
41 |
--------------------------------------------------------------------------------
/DESCRIPTION:
--------------------------------------------------------------------------------
1 | Package: ggtrack
2 | Title: Build tracking banners using QR codes for addition to plots and reports
3 | Version: 0.1.3
4 | Authors@R:
5 | person(given = "Matt",
6 | family = "Johnson",
7 | role = c("aut", "cre"),
8 | email = "mrjoh3@gmail.com")
9 | Description: Sometimes in a workplace it is hard to know exactly where or when a
10 | specific chart has been produced. This is especially true when someone has copied
11 | a chart out of a report to use somewhere else. The `ggtrack` package aims to
12 | solve this problem by embedding enough metadata in the charts image to identify
13 | the source and the exact time it was produced.
14 | License: MIT + file LICENSE
15 | Encoding: UTF-8
16 | LazyData: true
17 | Date: 2021-07-04
18 | Roxygen: list(markdown = TRUE)
19 | RoxygenNote: 7.1.1
20 | BugReports: https://github.com/mrjoh3/ggtrack/issues
21 | Suggests:
22 | covr,
23 | testthat (>= 3.0.0)
24 | Config/testthat/edition: 3
25 | Remotes:
26 | hrbrmstr/qrencoder,
27 | richfitz/stegasaur
28 | Imports:
29 | grid,
30 | ggplot2,
31 | RCurl,
32 | gridExtra,
33 | jpeg,
34 | png,
35 | rsvg,
36 | magick,
37 | gridtext,
38 | qrencoder,
39 | magrittr,
40 | glue,
41 | htmltools,
42 | stegasaur
43 | URL: https://mrjoh3.github.io/ggtrack
44 | Depends:
45 | R (>= 2.10)
46 |
--------------------------------------------------------------------------------
/inst/working/plotly.R:
--------------------------------------------------------------------------------
1 |
2 |
3 | p1 = plotly_empty(x = 1, y = 1) %>%
4 | layout(
5 | images = list(list(
6 | source = raster2uri(q, interpolate = FALSE),
7 | xref = "paper",
8 | yref = "paper",
9 | x = .5, y = .5,
10 | sizex = 1, sizey = 1,
11 | xanchor = "left", yanchor = "bottom"
12 | ))
13 | ) %>% layout(margin=list(l=10, r=10, b=0, t=0),
14 | xaxis=list(showticklabels=FALSE, ticks=""),
15 | yaxis=list(showticklabels=FALSE, ticks=""))
16 |
17 |
18 |
19 | p2 <- plotly_empty(x = 1, y = 1) %>%
20 | layout(
21 | images = list(list(
22 | source = raster2uri(logo_imported),
23 | xref = "paper",
24 | yref = "paper",
25 | x = .5, y = .5,
26 | sizex = 1, sizey = 1,
27 | xanchor = "left", yanchor = "bottom"
28 | ))
29 | ) %>% layout(margin=list(l=10, r=10, b=0, t=0),
30 | xaxis=list(showticklabels=FALSE, ticks=""),
31 | yaxis=list(showticklabels=FALSE, ticks=""))
32 |
33 | p3 <- plotly_empty(x = 1, y = 1) %>%
34 | add_text(text = 'some text here', x = .5, y = .5) %>%
35 | layout(margin=list(l=10, r=10, b=0, t=0),
36 | xaxis=list(showticklabels=FALSE, ticks=""),
37 | yaxis=list(showticklabels=FALSE, ticks=""))
38 |
39 |
40 | bn <- subplot(p3, p2, p1, nrows = 1, widths = c(.6, .2, .2))
41 |
42 | subplot(ggplotly(tracker), bn, nrows = 2, heights = c(.7,.3))
43 |
44 |
45 |
46 |
--------------------------------------------------------------------------------
/man/caption.Rd:
--------------------------------------------------------------------------------
1 | % Generated by roxygen2: do not edit by hand
2 | % Please edit documentation in R/caption.R
3 | \name{caption}
4 | \alias{caption}
5 | \alias{add_caption}
6 | \alias{add_caption.gg}
7 | \alias{add_caption.tracker}
8 | \title{Add Caption to Tracker}
9 | \usage{
10 | caption(tracker, caption, position, ...)
11 |
12 | add_caption(tracker, ...)
13 |
14 | \method{add_caption}{gg}(tracker, caption, position, ...)
15 |
16 | \method{add_caption}{tracker}(tracker, caption, ...)
17 | }
18 | \arguments{
19 | \item{tracker}{ggtrack tracker object}
20 |
21 | \item{caption}{\code{character} or \code{grob} to add to footer. Text can be
22 | \code{html} or \code{md} and is passed directly to \link[gridtext]{richtext_grob}}
23 |
24 | \item{position}{data.frame generated by get \link[ggtrack]{get_positions}}
25 |
26 | \item{...}{additional options passed through to \link[gridtext]{richtext_grob}}
27 | }
28 | \value{
29 | tracker
30 | }
31 | \description{
32 | Add Caption to Tracker
33 | }
34 | \examples{
35 | \dontrun{
36 | make_tracker() \%>\% add_caption('your caption')
37 | }
38 | }
39 | \seealso{
40 | Other gg:
41 | \code{\link{logo}()},
42 | \code{\link{qr}()}
43 |
44 | Other tracker:
45 | \code{\link{logo}()},
46 | \code{\link{qr}()}
47 |
48 | Other gg:
49 | \code{\link{logo}()},
50 | \code{\link{qr}()}
51 |
52 | Other tracker:
53 | \code{\link{logo}()},
54 | \code{\link{qr}()}
55 | }
56 | \concept{add_caption}
57 | \concept{gg}
58 | \concept{tracker}
59 |
--------------------------------------------------------------------------------
/.github/CODE_OF_CONDUCT.md:
--------------------------------------------------------------------------------
1 | # Contributor Code of Conduct
2 |
3 | As contributors and maintainers of this project, we pledge to respect all people who
4 | contribute through reporting issues, posting feature requests, updating documentation,
5 | submitting pull requests or patches, and other activities.
6 |
7 | We are committed to making participation in this project a harassment-free experience for
8 | everyone, regardless of level of experience, gender, gender identity and expression,
9 | sexual orientation, disability, personal appearance, body size, race, ethnicity, age, or religion.
10 |
11 | Examples of unacceptable behavior by participants include the use of sexual language or
12 | imagery, derogatory comments or personal attacks, trolling, public or private harassment,
13 | insults, or other unprofessional conduct.
14 |
15 | Project maintainers have the right and responsibility to remove, edit, or reject comments,
16 | commits, code, wiki edits, issues, and other contributions that are not aligned to this
17 | Code of Conduct. Project maintainers who do not follow the Code of Conduct may be removed
18 | from the project team.
19 |
20 | Instances of abusive, harassing, or otherwise unacceptable behavior may be reported by
21 | opening an issue or contacting one or more of the project maintainers.
22 |
23 | This Code of Conduct is adapted from the Contributor Covenant
24 | (http://contributor-covenant.org), version 1.0.0, available at
25 | http://contributor-covenant.org/version/1/0/0/
26 |
--------------------------------------------------------------------------------
/vignettes/qr_calibrate.Rmd:
--------------------------------------------------------------------------------
1 | ---
2 | title: "QR Size Calibration"
3 | output: rmarkdown::html_vignette
4 | vignette: >
5 | %\VignetteIndexEntry{QR Size Calibration}
6 | %\VignetteEngine{knitr::rmarkdown}
7 | %\VignetteEncoding{UTF-8}
8 | ---
9 |
10 | ```{r setup, include = FALSE}
11 | knitr::opts_chunk$set(
12 | collapse = TRUE,
13 | comment = "#>"
14 | )
15 |
16 | library(dplyr)
17 | library(ggplot2)
18 | library(ggtrack)
19 | ```
20 |
21 |
22 |
23 |
24 |
25 | ```{r}
26 | df <- tribble(~ bytes, ~ cm,
27 | 47 , 1.8,
28 | 109 , 2.0,
29 | 218 , 2.6,
30 | 327 , 3.1,
31 | 436 , 3.3,
32 | 545 , 3.5,
33 | 654 , 4.0)
34 | ```
35 |
36 |
37 | ```{r, fig.width=8, fig.height=5, out.width="100%", fig.align='center', fig.retina=2}
38 | gg <- ggplot(df, aes(x = bytes, y = cm)) +
39 | geom_point() +
40 | geom_smooth(method = 'lm') +
41 | labs(x = 'bytes encoded into QR',
42 | y = 'height of QR in cm',
43 | title = 'QR size calibration') +
44 | theme_minimal()
45 |
46 | ggtrack(gg,
47 | caption = 'calibration based on QR code scanned
from computer monitor',
48 | qr_content = 'https://mrjoh3.github.io/ggtrack/articles/qr_calibrate.html',
49 | logo = '../man/figures/ggtrack-logo.svg')
50 | ```
51 |
52 |
53 |
54 | ```{r}
55 |
56 | qr_mod <- lm(cm ~ bytes, data = df)
57 |
58 | summary(qr_mod)
59 | ```
60 |
61 |
62 | ```{r, eval=FALSE}
63 | usethis::use_data(qr_mod, internal = FALSE, overwrite = TRUE)
64 | ```
65 |
66 |
--------------------------------------------------------------------------------
/man/logo.Rd:
--------------------------------------------------------------------------------
1 | % Generated by roxygen2: do not edit by hand
2 | % Please edit documentation in R/logo.R
3 | \name{logo}
4 | \alias{logo}
5 | \alias{add_logo}
6 | \alias{add_logo.gg}
7 | \alias{add_logo.tracker}
8 | \title{Add Logo to Tracker}
9 | \usage{
10 | logo(tracker, logo, height_tracker, position, justification, ...)
11 |
12 | add_logo(tracker, ...)
13 |
14 | \method{add_logo}{gg}(tracker, logo, height_tracker, position, justification, ...)
15 |
16 | \method{add_logo}{tracker}(tracker, logo, justification, ...)
17 | }
18 | \arguments{
19 | \item{tracker}{ggtrack tracker object}
20 |
21 | \item{logo}{character file path or image url. Image extension can be any of:
22 | \itemize{
23 | \item{jpeg}
24 | \item{jpg}
25 | \item{png}
26 | \item{svg}
27 | }}
28 |
29 | \item{height_tracker}{numeric tracker height in cm.}
30 |
31 | \item{position}{data.frame generated by get \link[ggtrack]{get_positions}}
32 |
33 | \item{justification}{numeric between 0 and 1 passed to \link[grid]{rasterGrob}.}
34 |
35 | \item{...}{additional options passed to \link[grid]{rasterGrob}}
36 | }
37 | \value{
38 | tracker
39 | }
40 | \description{
41 | Add Logo to Tracker
42 | }
43 | \examples{
44 | \dontrun{
45 | make_tracker() \%>\% add_logo('https://www.r-project.org/logo/Rlogo.png', justification = 1)
46 | }
47 | }
48 | \seealso{
49 | Other gg:
50 | \code{\link{caption}()},
51 | \code{\link{qr}()}
52 |
53 | Other tracker:
54 | \code{\link{caption}()},
55 | \code{\link{qr}()}
56 |
57 | Other gg:
58 | \code{\link{caption}()},
59 | \code{\link{qr}()}
60 |
61 | Other tracker:
62 | \code{\link{caption}()},
63 | \code{\link{qr}()}
64 | }
65 | \concept{add_logo}
66 | \concept{gg}
67 | \concept{tracker}
68 |
--------------------------------------------------------------------------------
/man/make_download.Rd:
--------------------------------------------------------------------------------
1 | % Generated by roxygen2: do not edit by hand
2 | % Please edit documentation in R/download.R
3 | \name{make_download}
4 | \alias{make_download}
5 | \title{Tracker Download Link}
6 | \usage{
7 | make_download(
8 | tracker,
9 | save_file,
10 | download_file,
11 | ext = "png",
12 | link_text = "download",
13 | type = c("link", "button"),
14 | height = 13,
15 | height_units = c("cm", "mm", "in"),
16 | button_style = htmltools::css(background.color = "DodgerBlue", border = "none", color
17 | = "white", padding = "12px 30px", cursor = "pointer", font.size = "16px", width =
18 | "150px"),
19 | date = format(Sys.time(), "\%Y\%m\%d-\%H\%M\%S"),
20 | render = TRUE,
21 | stenograph = FALSE
22 | )
23 | }
24 | \arguments{
25 | \item{tracker}{tracker object to be saved}
26 |
27 | \item{save_file}{character vector, where length > 1, path is generated using \link[base]{file.path}}
28 |
29 | \item{download_file}{character vector, where length > 1, path is generated using \link[base]{file.path}}
30 |
31 | \item{ext}{character device type passed to \link[ggplot2]{ggsave}}
32 |
33 | \item{link_text}{character text to appear on the page}
34 |
35 | \item{type}{character must be one of "link" or "button".}
36 |
37 | \item{height}{integer height value passed to \link[ggplot2]{ggsave}}
38 |
39 | \item{height_units}{character units value passed to \link[ggplot2]{ggsave}}
40 |
41 | \item{button_style}{css object generated by \link[htmltools]{css} or a css character}
42 |
43 | \item{render}{Boolean, render in-place or save for later}
44 |
45 | \item{stenograph}{use \link[stegasaur]{lsb_encode} to enbed content within the png output.}
46 |
47 | \item{stenograph_text}{character text or R object to encode using \link[stegasaur]{lsb_encode}, must be less than 2^16 bytes}
48 | }
49 | \value{
50 | html of the link object
51 | }
52 | \description{
53 | Save tracker object to file and render link or button for user download
54 | }
55 |
--------------------------------------------------------------------------------
/.github/workflows/test-coverage.yaml:
--------------------------------------------------------------------------------
1 | on:
2 | push:
3 | branches:
4 | - main
5 | - master
6 | pull_request:
7 | branches:
8 | - main
9 | - master
10 |
11 | name: test-coverage
12 |
13 | jobs:
14 | test-coverage:
15 | runs-on: ubuntu-latest
16 | env:
17 | GITHUB_PAT: ${{ secrets.GITHUB_TOKEN }}
18 | steps:
19 | - uses: actions/checkout@v2
20 |
21 | - uses: r-lib/actions/setup-r@v1
22 |
23 | - uses: r-lib/actions/setup-pandoc@v1
24 |
25 | - name: Install curl
26 | run: sudo apt-get install libcurl4-openssl-dev curl
27 |
28 | - name: Install pkgdown dep
29 | run: sudo apt-get install libharfbuzz-dev libfribidi-dev
30 |
31 | - name: Install libmagick png and jpeg
32 | run: sudo apt-get install libmagick++-dev libpng-dev libjpeg-dev
33 |
34 | - name: Install gdal
35 | run: sudo apt-get install gdal-bin proj-bin libgdal-dev libproj-dev
36 |
37 | - name: Query dependencies
38 | run: |
39 | install.packages('remotes')
40 | saveRDS(remotes::dev_package_deps(dependencies = TRUE), ".github/depends.Rds", version = 2)
41 | writeLines(sprintf("R-%i.%i", getRversion()$major, getRversion()$minor), ".github/R-version")
42 | shell: Rscript {0}
43 |
44 | - name: Restore R package cache
45 | uses: actions/cache@v2
46 | with:
47 | path: ${{ env.R_LIBS_USER }}
48 | key: ${{ runner.os }}-${{ hashFiles('.github/R-version') }}-1-${{ hashFiles('.github/depends.Rds') }}
49 | restore-keys: ${{ runner.os }}-${{ hashFiles('.github/R-version') }}-1-
50 |
51 | - name: Install dependencies
52 | run: |
53 | install.packages(c("remotes"))
54 | remotes::install_deps(dependencies = TRUE)
55 | remotes::install_cran("covr")
56 | shell: Rscript {0}
57 |
58 | - name: Test coverage
59 | run: covr::codecov(token = "${{ secrets.CODECOV_TOKEN }}")
60 | shell: Rscript {0}
61 |
--------------------------------------------------------------------------------
/man/qr.Rd:
--------------------------------------------------------------------------------
1 | % Generated by roxygen2: do not edit by hand
2 | % Please edit documentation in R/qr.R
3 | \name{qr}
4 | \alias{qr}
5 | \alias{add_qr}
6 | \alias{add_qr.gg}
7 | \alias{add_qr.tracker}
8 | \title{Add QR Code to Tracker}
9 | \usage{
10 | qr(
11 | tracker,
12 | qr_content,
13 | color = "black",
14 | color_bg = "white",
15 | height_tracker,
16 | position,
17 | justification,
18 | ...
19 | )
20 |
21 | add_qr(tracker, ...)
22 |
23 | \method{add_qr}{gg}(
24 | tracker,
25 | qr_content,
26 | color = "black",
27 | color_bg = "white",
28 | height_tracker,
29 | position,
30 | justification,
31 | ...
32 | )
33 |
34 | \method{add_qr}{tracker}(
35 | tracker,
36 | qr_content,
37 | color = "black",
38 | color_bg = "white",
39 | justification,
40 | ...
41 | )
42 | }
43 | \arguments{
44 | \item{tracker}{ggtrack tracker object}
45 |
46 | \item{qr_content}{\code{character} content passed to \link[qrencoder]{qrencode}. A time stamp is automatically added plus the current
47 | git commit where available.}
48 |
49 | \item{color}{character color of QR code}
50 |
51 | \item{color_bg}{character background color of QR code}
52 |
53 | \item{height_tracker}{numeric tracker height in cm.}
54 |
55 | \item{position}{data.frame generated by get \link[ggtrack]{get_positions}}
56 |
57 | \item{justification}{numeric between 0 and 1 passed to \link[grid]{rasterGrob}.}
58 |
59 | \item{...}{additional options passed to \link[grid]{rasterGrob}}
60 | }
61 | \value{
62 | tracker
63 | }
64 | \description{
65 | Add QR Code to Tracker
66 | }
67 | \examples{
68 | \dontrun{
69 | make_tracker() \%>\% add_qr('Report ID: 2c9075a5-4d7e-47a5-8616-55dd88af3dc5', justification = 1)
70 | }
71 | }
72 | \seealso{
73 | Other gg:
74 | \code{\link{caption}()},
75 | \code{\link{logo}()}
76 |
77 | Other tracker:
78 | \code{\link{caption}()},
79 | \code{\link{logo}()}
80 |
81 | Other gg:
82 | \code{\link{caption}()},
83 | \code{\link{logo}()}
84 |
85 | Other tracker:
86 | \code{\link{caption}()},
87 | \code{\link{logo}()}
88 | }
89 | \concept{add_qr}
90 | \concept{gg}
91 | \concept{tracker}
92 |
--------------------------------------------------------------------------------
/R/caption.R:
--------------------------------------------------------------------------------
1 |
2 |
3 | #' @title Add Caption to Tracker
4 | #'
5 | #' @param tracker ggtrack tracker object
6 | #' @param caption \code{character} or \code{grob} to add to footer. Text can be
7 | #' \code{html} or \code{md} and is passed directly to \link[gridtext]{richtext_grob}
8 | #' @param position data.frame generated by get \link[ggtrack]{get_positions}
9 | #' @param ... additional options passed through to \link[gridtext]{richtext_grob}
10 | #'
11 | #' @importFrom gridtext richtext_grob
12 | #' @importFrom ggplot2 annotation_custom
13 | #'
14 | #' @return tracker
15 | #' @export
16 | #'
17 | #' @examples
18 | #' \dontrun{
19 | #' make_tracker() %>% add_caption('your caption')
20 | #' }
21 | caption <- function(tracker, caption, position, ...) {
22 |
23 | if (is.character(caption)) {
24 | tg <- richtext_grob(caption, x = 0, hjust = 0, name = 'caption', ...)
25 | } else if ('grob' %in% class(caption)) {
26 | tg <- caption
27 | } else {
28 | stop('A caption needs to be either text or a "grob"')
29 | }
30 |
31 | # define position
32 | p <- as.list(position[position$order == 'C', ])
33 |
34 | tracker +
35 | annotation_custom(tg, xmin = p$xmin, xmax = p$xmax)
36 |
37 | }
38 |
39 |
40 |
41 | #' @rdname caption
42 | #' @family add_caption
43 | #' @family gg
44 | #' @family tracker
45 | #' @export
46 | add_caption <- function (tracker, ...) {
47 | UseMethod("add_caption", tracker)
48 | }
49 |
50 | #' @rdname caption
51 | #' @family add_caption
52 | #' @family gg
53 | #' @export
54 | add_caption.gg <- function(tracker, caption, position, ...) {
55 |
56 | caption(tracker, caption, position, ...)
57 |
58 | }
59 |
60 | #' @rdname caption
61 | #' @family add_caption
62 | #' @family tracker
63 | #' @export
64 | add_caption.tracker <- function(tracker, caption, ...) {
65 |
66 | height_tracker <- tracker$height
67 | position <- tracker$pos
68 | banner <- tracker$track
69 | git <- tracker$git
70 | ts <- tracker$ts
71 |
72 | tracker$track <- caption(banner, caption, position, ...)
73 |
74 | mtrack <- obj_tracker(tracker, 'caption')
75 |
76 | return(mtrack)
77 |
78 | }
79 |
80 |
--------------------------------------------------------------------------------
/.github/workflows/pkgdown.yaml:
--------------------------------------------------------------------------------
1 | on:
2 | push:
3 | branches:
4 | - main
5 | - master
6 |
7 | name: pkgdown
8 |
9 | jobs:
10 | pkgdown:
11 | runs-on: ubuntu-latest
12 | env:
13 | GITHUB_PAT: ${{ secrets.GITHUB_TOKEN }}
14 | steps:
15 | - uses: actions/checkout@v2
16 |
17 | - uses: r-lib/actions/setup-r@v1
18 |
19 | - uses: r-lib/actions/setup-pandoc@v1
20 |
21 | - name: Install curl
22 | run: sudo apt-get install libcurl4-openssl-dev curl
23 |
24 | - name: Install pkgdown dep
25 | run: sudo apt-get install libharfbuzz-dev libfribidi-dev
26 |
27 | - name: Install libmagick
28 | run: sudo apt-get install libmagick++-dev
29 |
30 | - name: Install gdal
31 | run: sudo apt-get install gdal-bin proj-bin libgdal-dev libproj-dev
32 |
33 | - name: Query dependencies
34 | run: |
35 | install.packages('remotes')
36 | saveRDS(remotes::dev_package_deps(dependencies = TRUE), ".github/depends.Rds", version = 2)
37 | writeLines(sprintf("R-%i.%i", getRversion()$major, getRversion()$minor), ".github/R-version")
38 | shell: Rscript {0}
39 |
40 | - name: Restore R package cache
41 | uses: actions/cache@v2
42 | with:
43 | path: ${{ env.R_LIBS_USER }}
44 | key: ${{ runner.os }}-${{ hashFiles('.github/R-version') }}-1-${{ hashFiles('.github/depends.Rds') }}
45 | restore-keys: ${{ runner.os }}-${{ hashFiles('.github/R-version') }}-1-
46 |
47 | - name: Install dependencies
48 | run: |
49 | remotes::install_deps(dependencies = TRUE)
50 | install.packages("pkgdown")
51 | install.packages("ggthemes")
52 | remotes::install_github("ropensci/rWBclimate")
53 | remotes::install_github("brianwdavis/quadrangle")
54 | shell: Rscript {0}
55 |
56 | - name: Install package
57 | run: R CMD INSTALL .
58 |
59 | - name: Deploy package
60 | run: |
61 | git config --local user.email "actions@github.com"
62 | git config --local user.name "GitHub Actions"
63 | Rscript -e 'pkgdown::deploy_to_branch(new_process = FALSE)'
64 |
--------------------------------------------------------------------------------
/tests/testthat/test-download.R:
--------------------------------------------------------------------------------
1 |
2 | gg <- ggplot(mapping = aes(x = 1:10, y = rnorm(10))) +
3 | geom_bar(stat = 'identity')
4 |
5 | test_that("Download generates a file and link with basic API", {
6 |
7 | api_basic <- ggtrack(gg,
8 | qr_content = 'text content here')
9 |
10 | dl_basic <- make_download(api_basic,
11 | save_file = c('files', 'basic_ggtrack'),
12 | download_file = c('files', 'basic_ggtrack'),
13 | type = 'button',
14 | date = 'delete',
15 | render = FALSE)
16 |
17 | expect_true(file.exists('files/basic_ggtrack_delete.png'))
18 | expect_type(dl_basic, 'character')
19 |
20 | # does the link contain the correct URL and type
21 | expect_equal(as.character(strcapture('href="(.*?)"', dl_basic, proto = 'c')),
22 | "files/basic_ggtrack_delete.png")
23 | expect_equal(as.character(strcapture('button type="(.*?)"', dl_basic, proto = 'c')),
24 | 'submit')
25 |
26 | expect_true(file.remove("files/basic_ggtrack_delete.png"))
27 | })
28 |
29 |
30 | test_that("Download generates a file and link with advanced API", {
31 |
32 | adv <- make_tracker() %>%
33 | add_logo('files/ggtrack-logo.svg', 1) %>%
34 | add_qr('some text', justification = 1) %>%
35 | add_caption('some text') %>%
36 | add_theme(plot.background = element_rect(fill = "#ff9955", size = 0))
37 |
38 | api_adv <- gg %>%
39 | add_banner(adv)
40 |
41 | dl_adv <- make_download(api_adv,
42 | save_file = c('files', 'adv_ggtrack'),
43 | download_file = c('files', 'adv_ggtrack'),
44 | type = 'link',
45 | date = 'delete',
46 | render = FALSE)
47 |
48 | expect_true(file.exists('files/adv_ggtrack_delete.png'))
49 | expect_s3_class(dl_adv, 'shiny.tag')
50 |
51 | # does the link contain the correct URL and type
52 | expect_equal(as.character(strcapture('href="(.*?)"', as.character(dl_adv), proto = 'c')),
53 | "files/adv_ggtrack_delete.png")
54 | expect_true(is.na(strcapture('button type="(.*?)"', as.character(dl_adv), proto = 'c')))
55 |
56 | expect_true(file.remove("files/adv_ggtrack_delete.png"))
57 | })
58 |
59 |
60 |
--------------------------------------------------------------------------------
/man/ggtrack.Rd:
--------------------------------------------------------------------------------
1 | % Generated by roxygen2: do not edit by hand
2 | % Please edit documentation in R/grid.R
3 | \name{ggtrack}
4 | \alias{ggtrack}
5 | \title{Add Tracking Footer}
6 | \usage{
7 | ggtrack(
8 | gg,
9 | qr_content = NULL,
10 | color = "black",
11 | color_bg = "white",
12 | caption = NULL,
13 | logo = NULL,
14 | order = "CLQ",
15 | positions = c(55, 25, 20),
16 | logo_justification = 1,
17 | qr_justification = 1,
18 | height_plot = 7,
19 | height_tracker = 1.8,
20 | add_git = TRUE,
21 | add_ts = TRUE,
22 | interactive = FALSE,
23 | plotly_heights = c(0.8, 0.2),
24 | ...
25 | )
26 | }
27 | \arguments{
28 | \item{gg}{ggplot object to track}
29 |
30 | \item{qr_content}{\code{character} content passed to \link[qrencoder]{qrencode}. A time stamp is automatically added plus the current
31 | git commit where available.}
32 |
33 | \item{color}{character color of the QR code}
34 |
35 | \item{color_bg}{character background color of QR code}
36 |
37 | \item{caption}{\code{character} or \code{grob} to add to footer. Text can be
38 | \code{html} or \code{md} and is passed directly to \link[gridtext]{richtext_grob}}
39 |
40 | \item{logo}{file to add to footer as a logo}
41 |
42 | \item{order}{\code{character} of \code{length} 3 defining placement
43 | order for "caption" (C), "logo" (L) and "QR" (Q) code. Must be one of:
44 | \itemize{
45 | \item{CLQ}
46 | \item{LCQ}
47 | \item{QLC}
48 | \item{CQL}
49 | }}
50 |
51 | \item{positions}{\code{numeric} \code{vector} of \code{length} 3,
52 | defining the horizontal proportion of each container. The 3 numbers
53 | must add to 100.}
54 |
55 | \item{logo_justification}{numeric between 0 and 1 passed to \link[grid]{rasterGrob}. See note below.}
56 |
57 | \item{qr_justification}{numeric between 0 and 1 passed to \link[grid]{rasterGrob}. See note below.}
58 |
59 | \item{height_plot}{numeric plot height in cm.}
60 |
61 | \item{height_tracker}{numeric tracker height in cm.}
62 |
63 | \item{add_git}{logical include git info in encoding}
64 |
65 | \item{add_ts}{logical include timestamp info in encoding}
66 |
67 | \item{interactive}{logical use plotly for interactivity}
68 |
69 | \item{plotly_heights}{numeric vector of length 2 to fix relative height of plot and tracking banner}
70 |
71 | \item{...}{options passed to \link[ggplot2]{theme} in order to style the tracker banner.}
72 | }
73 | \value{
74 | grid
75 | }
76 | \description{
77 | Add Tracking Footer
78 | }
79 | \note{
80 | For Justification you need to imagine each element in its own rectangle with a bottom
81 | dimension of 0 to 1. If you want the logo or QR code on the right of the rectangle set justification
82 | to 1, or 0 for left.
83 | }
84 |
--------------------------------------------------------------------------------
/R/logo.R:
--------------------------------------------------------------------------------
1 |
2 |
3 | #' @title Add Logo to Tracker
4 | #'
5 | #' @param tracker ggtrack tracker object
6 | #' @param logo character file path or image url. Image extension can be any of:
7 | #' \itemize{
8 | #' \item{jpeg}
9 | #' \item{jpg}
10 | #' \item{png}
11 | #' \item{svg}
12 | #' }
13 | #' @param height_tracker numeric tracker height in cm.
14 | #' @param position data.frame generated by get \link[ggtrack]{get_positions}
15 | #' @param justification numeric between 0 and 1 passed to \link[grid]{rasterGrob}.
16 | #' @param ... additional options passed to \link[grid]{rasterGrob}
17 | #'
18 | #' @importFrom tools file_ext
19 | #' @import RCurl
20 | #' @import png
21 | #' @import jpeg
22 | #' @import rsvg
23 | #' @importFrom magick image_read_svg
24 | #'
25 | #' @return tracker
26 | #'
27 | #' @examples
28 | #' \dontrun{
29 | #' make_tracker() %>% add_logo('https://www.r-project.org/logo/Rlogo.png', justification = 1)
30 | #' }
31 | logo <- function(tracker, logo, height_tracker, position, justification, ...) {
32 |
33 | # check if url or file
34 | typ <- ifelse(grepl('http', logo), 'url', 'file')
35 |
36 | # check type of logo
37 | ext <- tolower(file_ext(logo))
38 |
39 | if (typ == 'url') {
40 | logo <- RCurl::getURLContent(logo)
41 | }
42 |
43 | if (ext == 'png') {
44 | logo_imported <- png::readPNG(logo)
45 | } else if (ext %in% c('jpg', 'jpeg')) {
46 | logo_imported <- jpeg::readJPEG(logo)
47 | } else if (ext == 'svg') {
48 | logo_imported <- magick::image_read_svg(logo, height = 300)
49 | } else {
50 | stop(paste0('Unable to Add filetype: ', ext))
51 | }
52 |
53 | lg <- grid::rasterGrob(logo_imported, x = justification, just = justification, height = unit(height_tracker, 'cm'), name = 'logo', ...)
54 |
55 | # define position
56 | p <- as.list(position[position$order == 'L', ])
57 |
58 | tracker +
59 | annotation_custom(lg, xmin = p$xmin, xmax = p$xmax)
60 |
61 | }
62 |
63 | #' @rdname logo
64 | #' @family add_logo
65 | #' @family gg
66 | #' @family tracker
67 | #' @export
68 | add_logo <- function (tracker, ...) {
69 | UseMethod("add_logo", tracker)
70 | }
71 |
72 | #' @rdname logo
73 | #' @family add_logo
74 | #' @family gg
75 | #' @export
76 | add_logo.gg <- function(tracker, logo, height_tracker, position, justification, ...) {
77 |
78 | logo(tracker, logo, height_tracker, position, justification, ...)
79 |
80 | }
81 |
82 | #' @rdname logo
83 | #' @family add_logo
84 | #' @family tracker
85 | #' @export
86 | add_logo.tracker <- function(tracker, logo, justification, ...) {
87 |
88 | height_tracker <- tracker$height
89 | position <- tracker$pos
90 | banner <- tracker$track
91 | git <- tracker$git
92 | ts <- tracker$ts
93 |
94 | tracker$track <- logo(banner, logo, height_tracker, position, justification, ...)
95 |
96 | mtrack <- obj_tracker(tracker, 'logo')
97 |
98 | return(mtrack)
99 |
100 | }
101 |
--------------------------------------------------------------------------------
/R/qr.R:
--------------------------------------------------------------------------------
1 |
2 |
3 | #' @title Add QR Code to Tracker
4 | #'
5 | #' @param tracker ggtrack tracker object
6 | #' @param qr_content \code{character} content passed to \link[qrencoder]{qrencode}. A time stamp is automatically added plus the current
7 | #' git commit where available.
8 | #' @param color character color of QR code
9 | #' @param color_bg character background color of QR code
10 | #' @param height_tracker numeric tracker height in cm.
11 | #' @param position data.frame generated by get \link[ggtrack]{get_positions}
12 | #' @param justification numeric between 0 and 1 passed to \link[grid]{rasterGrob}.
13 | #' @param ... additional options passed to \link[grid]{rasterGrob}
14 | #'
15 | #' @import qrencoder
16 | #' @importFrom grid rasterGrob
17 | #'
18 | #' @return tracker
19 | #'
20 | #' @examples
21 | #' \dontrun{
22 | #' make_tracker() %>% add_qr('Report ID: 2c9075a5-4d7e-47a5-8616-55dd88af3dc5', justification = 1)
23 | #' }
24 | qr <- function(tracker, qr_content, color = 'black', color_bg = 'white', height_tracker, position, justification, ...) {
25 |
26 | # setup QR code
27 | qr_matrix <- make_qr(qr_content, color, color_bg)
28 |
29 | qr <- grid::rasterGrob(qr_matrix, interpolate = FALSE, x = justification, just = justification, height = unit(height_tracker, 'cm'), name = 'qrcode', ...)
30 |
31 | # define position
32 | p <- as.list(position[position$order == 'Q', ])
33 |
34 | tracker +
35 | annotation_custom(qr, xmin = p$xmin, xmax = p$xmax)
36 |
37 | }
38 |
39 |
40 | #' @rdname qr
41 | #' @family add_qr
42 | #' @family gg
43 | #' @family tracker
44 | #' @export
45 | add_qr <- function (tracker, ...) {
46 | UseMethod("add_qr", tracker)
47 | }
48 |
49 |
50 | #' @rdname qr
51 | #' @family add_qr
52 | #' @family gg
53 | #' @export
54 | add_qr.gg <- function(tracker, qr_content, color = 'black', color_bg = 'white', height_tracker, position, justification, ...) {
55 | qr(tracker, qr_content, color, color_bg, height_tracker, position, justification, ...)
56 | }
57 |
58 |
59 | #' @rdname qr
60 | #'
61 | #' @importFrom glue glue
62 | #' @family add_qr
63 | #' @family tracker
64 | #' @export
65 | add_qr.tracker <- function(tracker, qr_content, color = 'black', color_bg = 'white', justification, ...) {
66 |
67 | height_tracker <- tracker$height
68 | position <- tracker$pos
69 | banner <- tracker$track
70 | git <- tracker$git
71 | ts <- tracker$ts
72 |
73 | qr_content <- paste(qr_content, git, ts, sep = ' ')
74 |
75 | qr_cm <- qr_size(qr_content)
76 |
77 | if (height_tracker < qr_cm) {
78 | height_tracker <- tracker$height <- qr_cm
79 | message(glue('to encode this much text into QR making QR height {qr_cm}cm'))
80 | }
81 |
82 | tracker$track <- qr(banner, qr_content, color, color_bg, height_tracker, position, justification, ...)
83 |
84 | mtrack <- obj_tracker(tracker, 'qr')
85 |
86 | return(mtrack)
87 |
88 | }
89 |
90 |
91 | #' @title Make QR
92 | #'
93 | #' @param qr_content \code{character} content passed to \link[qrencoder]{qrencode}. A time stamp is automatically added plus the current
94 | #' git commit where available.
95 | #' @param color character color of QR code
96 | #' @param color_bg character background color of QR code
97 | #'
98 | #' @return matrix
99 | #'
100 | make_qr <- function(qr_content, color = 'black', color_bg = 'white') {
101 |
102 | qr_matrix <- qrencoder::qrencode(qr_content)
103 |
104 | qr_matrix[qr_matrix == 1] <- color
105 | qr_matrix[qr_matrix == 0] <- color_bg
106 |
107 | return(qr_matrix)
108 | }
109 |
110 |
111 |
112 |
113 |
114 |
115 |
116 |
117 |
118 |
119 |
120 |
121 |
122 |
123 |
124 |
125 |
--------------------------------------------------------------------------------
/R/download.R:
--------------------------------------------------------------------------------
1 |
2 |
3 | #' @title Tracker Download Link
4 | #'
5 | #' @description Save tracker object to file and render link or button for user download
6 | #'
7 | #' @param tracker tracker object to be saved
8 | #' @param save_file character vector, where length > 1, path is generated using \link[base]{file.path}
9 | #' @param download_file character vector, where length > 1, path is generated using \link[base]{file.path}
10 | #' @param ext character device type passed to \link[ggplot2]{ggsave}
11 | #' @param link_text character text to appear on the page
12 | #' @param type character must be one of "link" or "button".
13 | #' @param height integer height value passed to \link[ggplot2]{ggsave}
14 | #' @param height_units character units value passed to \link[ggplot2]{ggsave}
15 | #' @param button_style css object generated by \link[htmltools]{css} or a css character
16 | #' @param date character date add to filename. Default is \code{format(Sys.time(), "%Y%m%d-%H%M%S")}
17 | #' @param render Boolean, render in-place or save for later
18 | #' @param stenograph use \link[stegasaur]{lsb_encode} to enbed content within the png output.
19 | #' @param stenograph_text character text or R object to encode using \link[stegasaur]{lsb_encode}, must be less than 2^16 bytes
20 | #'
21 | #' @importFrom htmltools a css
22 | #' @importFrom glue glue
23 | #' @importFrom stegasaur lsb_encode
24 | #'
25 | #' @return html of the link object
26 | #' @export
27 | #'
28 | make_download <- function(tracker,
29 | save_file,
30 | download_file,
31 | ext = 'png',
32 | link_text = 'download',
33 | type = c('link','button'),
34 | height = 13,
35 | height_units = c("cm","mm", "in"),
36 | button_style = htmltools::css(background.color = 'DodgerBlue',
37 | border = 'none',
38 | color = 'white',
39 | padding = '12px 30px',
40 | cursor = 'pointer',
41 | font.size = '16px',
42 | width = '150px'),
43 | date = format(Sys.time(), '%Y%m%d-%H%M%S'),
44 | render = TRUE,
45 | stenograph = FALSE) {
46 |
47 | if (missing(save_file)) {
48 | save_file <- paste0('chart_', date, '.', ext)
49 | } else {
50 | save_file <- paste0(paste(save_file, collapse = .Platform$file.sep),
51 | '_', date,
52 | '.', ext)
53 | }
54 |
55 | if (missing(download_file)) {
56 | download_file <- save_file
57 | } else {
58 | download_file <- paste0(paste(download_file, collapse = .Platform$file.sep),
59 | '_', date,
60 | '.', ext)
61 | }
62 |
63 | type <- match.arg(type, choices = type)
64 | height_units <- match.arg(height_units, choices = height_units)
65 |
66 | # save to file
67 | ggsave(save_file, tracker, device = ext, height = height, units = height_units)
68 |
69 | if (!isFALSE(stenograph)) {
70 | img <- png::readPNG(save_file)
71 | png::writePNG(lsb_encode(stenograph, img), save_file) # need method to pass content lsb_encode
72 | }
73 |
74 | if (type == 'link') {
75 | link <- htmltools::a(href = download_file,
76 | download = basename(download_file),
77 | link_text)
78 | } else if (type == 'button'){
79 | link <- glue::glue('',
80 | '',
84 | '')
85 | }
86 |
87 | if (render){
88 | cat(as.character(link))
89 | }
90 |
91 | return(link)
92 |
93 | }
94 |
95 |
--------------------------------------------------------------------------------
/man/figures/ggtrack-favicon.svg:
--------------------------------------------------------------------------------
1 |
2 |
81 |
--------------------------------------------------------------------------------
/README.Rmd:
--------------------------------------------------------------------------------
1 | ---
2 | output:
3 | md_document:
4 | variant: markdown_github
5 | ---
6 |
7 |
8 |
9 | ```{r, include = FALSE}
10 | knitr::opts_chunk$set(
11 | collapse = TRUE,
12 | comment = "#>",
13 | fig.path = "man/figures/README-",
14 | out.width = "100%"
15 | )
16 | ```
17 |
18 | # ggtrack
19 |
20 |
21 | [](https://lifecycle.r-lib.org/articles/stages.html#stable)
22 | [](https://github.com/mrjoh3/ggtrack/actions)
23 | [](https://codecov.io/gh/mrjoh3/ggtrack?branch=master)
24 |
25 |
26 |
103 |
104 | ## Related and Enabling Packages
105 |
106 | The `ggrack` package makes use of many [R
107 | packages](https://github.com/mrjoh3/ggtrack/blob/master/DESCRIPTION#L20).
108 | But I want to include a special thank-you to some packages without which
109 | the `ggtrack` package would not be possible.
110 |
111 | - The [qrencoder](https://github.com/hrbrmstr/qrencoder) package
112 | generate to QR codes that form the basis for much of `ggtrack`.
113 | `qrencoder` is both fast and easy to use, and provides a variety of
114 | outputs that make it easy to incorporate QR codes into a project.
115 | - Without [ggplot2](https://github.com/tidyverse/ggplot2/) there would
116 | be little point to a package like `ggtrack`. The entire banner
117 | object is a `ggplot` with `theme_void` and `annotation_custom` used
118 | to place the three tracking elements.
119 | - The `rasterGrob` elements from the
120 | [grid](https://github.com/cran/grid) package make it possible to add
121 | both the QR code and arbitrary images such as logos.
122 | - `grid.arrange` from
123 | [gridExtra](https://cran.r-project.org/package=gridExtra) makes it
124 | possible to stack the `ggplot` object on top of the tracking banner.
125 | - The [stegasaur](https://github.com/richfitz/stegasaur) is used the
126 | encode arbitrary text or R objects into the plot `PNG`. This is very
127 | cool and [stegasaur](https://github.com/richfitz/stegasaur) is a
128 | great package that makes it really easy to encode and decode images.
129 |
--------------------------------------------------------------------------------
/tests/testthat/test-grid.R:
--------------------------------------------------------------------------------
1 |
2 | gg <- ggplot(mapping = aes(x = 1:10, y = rnorm(10))) +
3 | geom_bar(stat = 'identity')
4 |
5 | test_that("We can add a QR code", {
6 | qr_test <- ggtrack(gg,
7 | qr_content = 'text content here',
8 | add_git = FALSE)
9 | expect_s3_class(qr_test, "gtable")
10 | expect_s3_class(qr_test, "gTree")
11 | expect_s3_class(qr_test, "grob")
12 | expect_s3_class(qr_test, "gDesc")
13 |
14 | expect_length(qr_test$heights, 2)
15 | expect_equal(as.numeric(qr_test$heights[1]), 7)
16 | expect_equal(as.numeric(qr_test$heights[2]), 3.3)
17 | })
18 |
19 |
20 | test_that("We can add a Logo from URL", {
21 | qr_logo <- ggtrack(gg,
22 | logo = 'https://www.r-project.org/logo/Rlogo.png',
23 | add_git = FALSE)
24 | expect_s3_class(qr_logo, "gtable")
25 | expect_s3_class(qr_logo, "gTree")
26 | expect_s3_class(qr_logo, "grob")
27 | expect_s3_class(qr_logo, "gDesc")
28 |
29 | expect_length(qr_logo$heights, 2)
30 | expect_equal(as.numeric(qr_logo$heights[1]), 7)
31 | expect_equal(as.numeric(qr_logo$heights[2]), 3.3)
32 | })
33 |
34 |
35 | test_that("We can add a PNG Logo from file", {
36 | qr_logo <- ggtrack(gg,
37 | logo = 'files/ggtrack-logo.png',
38 | add_git = FALSE)
39 | expect_s3_class(qr_logo, "gtable")
40 | expect_s3_class(qr_logo, "gTree")
41 | expect_s3_class(qr_logo, "grob")
42 | expect_s3_class(qr_logo, "gDesc")
43 |
44 | expect_length(qr_logo$heights, 2)
45 | expect_equal(as.numeric(qr_logo$heights[1]), 7)
46 | expect_equal(as.numeric(qr_logo$heights[2]), 3.3)
47 | })
48 |
49 |
50 |
51 | test_that("We can add a JPEG Logo from file", {
52 | qr_logo <- ggtrack(gg,
53 | logo = 'files/ggtrack-logo.jpg',
54 | add_git = FALSE)
55 | expect_s3_class(qr_logo, "gtable")
56 | expect_s3_class(qr_logo, "gTree")
57 | expect_s3_class(qr_logo, "grob")
58 | expect_s3_class(qr_logo, "gDesc")
59 |
60 | expect_length(qr_logo$heights, 2)
61 | expect_equal(as.numeric(qr_logo$heights[1]), 7)
62 | expect_equal(as.numeric(qr_logo$heights[2]), 3.3)
63 | })
64 |
65 |
66 |
67 |
68 | test_that("We can add a SVG Logo from file", {
69 | qr_logo <- ggtrack(gg,
70 | logo = 'files/ggtrack-logo.svg',
71 | add_git = FALSE)
72 | expect_s3_class(qr_logo, "gtable")
73 | expect_s3_class(qr_logo, "gTree")
74 | expect_s3_class(qr_logo, "grob")
75 | expect_s3_class(qr_logo, "gDesc")
76 |
77 | expect_length(qr_logo$heights, 2)
78 | expect_equal(as.numeric(qr_logo$heights[1]), 7)
79 | expect_equal(as.numeric(qr_logo$heights[2]), 3.3)
80 | })
81 |
82 |
83 |
84 | test_that("We can add a Logo and a QR", {
85 | qr_logo <- ggtrack(gg,
86 | qr_content = 'text content here',
87 | logo = 'files/ggtrack-logo.svg',
88 | add_git = FALSE)
89 | expect_s3_class(qr_logo, "gtable")
90 | expect_s3_class(qr_logo, "gTree")
91 | expect_s3_class(qr_logo, "grob")
92 | expect_s3_class(qr_logo, "gDesc")
93 |
94 | expect_length(qr_logo$heights, 2)
95 | expect_equal(as.numeric(qr_logo$heights[1]), 7)
96 | expect_equal(as.numeric(qr_logo$heights[2]), 3.3)
97 | })
98 |
99 |
100 | test_that("We can add a Caption", {
101 | qr_logo <- ggtrack(gg,
102 | caption = 'text to display',
103 | add_git = FALSE)
104 | expect_s3_class(qr_logo, "gtable")
105 | expect_s3_class(qr_logo, "gTree")
106 | expect_s3_class(qr_logo, "grob")
107 | expect_s3_class(qr_logo, "gDesc")
108 |
109 | expect_length(qr_logo$heights, 2)
110 | expect_equal(as.numeric(qr_logo$heights[1]), 7)
111 | expect_equal(as.numeric(qr_logo$heights[2]), 3.3)
112 | })
113 |
114 |
115 | test_that("We can add a Caption and a QR", {
116 | qr_logo <- ggtrack(gg,
117 | qr_content = 'text content here',
118 | caption = 'text to display',
119 | add_git = FALSE)
120 | expect_s3_class(qr_logo, "gtable")
121 | expect_s3_class(qr_logo, "gTree")
122 | expect_s3_class(qr_logo, "grob")
123 | expect_s3_class(qr_logo, "gDesc")
124 |
125 | expect_length(qr_logo$heights, 2)
126 | expect_equal(as.numeric(qr_logo$heights[1]), 7)
127 | expect_equal(as.numeric(qr_logo$heights[2]), 3.3)
128 | })
129 |
130 |
131 |
132 | test_that("We can add a Caption, logo and a QR", {
133 |
134 | qr_logo <- ggtrack(gg,
135 | qr_content = 'text content here',
136 | logo = 'files/ggtrack-logo.svg',
137 | caption = 'text to display',
138 | add_git = FALSE)
139 | expect_s3_class(qr_logo, "gtable")
140 | expect_s3_class(qr_logo, "gTree")
141 | expect_s3_class(qr_logo, "grob")
142 | expect_s3_class(qr_logo, "gDesc")
143 |
144 | expect_length(qr_logo$heights, 2)
145 | expect_equal(as.numeric(qr_logo$heights[1]), 7)
146 | expect_equal(as.numeric(qr_logo$heights[2]), 3.3)
147 | })
148 |
149 |
150 | test_that('element order can be rearranged', {
151 | pos <- ggtrack(gg,
152 | order = 'LCQ',
153 | positions = c(25, 55, 20),
154 | qr_content = 'For all your image tracking needs: https://github.com/mrjoh3/ggtrack',
155 | logo = 'https://www.r-project.org/logo/Rlogo.png',
156 | caption = 'Lots of extra info, or a fancy "grob".',
157 | logo_justification = 0,
158 | add_git = FALSE)
159 |
160 | expect_s3_class(pos, "gtable")
161 | expect_s3_class(pos, "gTree")
162 | expect_s3_class(pos, "grob")
163 | expect_s3_class(pos, "gDesc")
164 |
165 | expect_length(pos$heights, 2)
166 | expect_equal(as.numeric(pos$heights[1]), 7)
167 | expect_equal(as.numeric(pos$heights[2]), 3.5)
168 |
169 | })
170 |
171 |
172 | test_that('element size can be modified', {
173 | pos <- ggtrack(gg,
174 | order = 'LCQ',
175 | positions = c(60, 10, 30),
176 | qr_content = 'For all your image tracking needs: https://github.com/mrjoh3/ggtrack',
177 | logo = 'https://www.r-project.org/logo/Rlogo.png',
178 | caption = 'Lots of extra info, or a fancy "grob".',
179 | logo_justification = 0,
180 | add_git = FALSE)
181 |
182 | expect_s3_class(pos, "gtable")
183 | expect_s3_class(pos, "gTree")
184 | expect_s3_class(pos, "grob")
185 | expect_s3_class(pos, "gDesc")
186 |
187 | expect_length(pos$heights, 2)
188 | expect_equal(as.numeric(pos$heights[1]), 7)
189 | expect_equal(as.numeric(pos$heights[2]), 3.5)
190 |
191 | })
192 |
193 |
194 |
195 |
--------------------------------------------------------------------------------
/R/grid.R:
--------------------------------------------------------------------------------
1 |
2 |
3 | #' @title Add Tracking Footer
4 | #'
5 | #' @param gg ggplot object to track
6 | #' @param qr_content \code{character} content passed to \link[qrencoder]{qrencode}. A time stamp is automatically added plus the current
7 | #' git commit where available.
8 | #' @param color character color of the QR code
9 | #' @param color_bg character background color of QR code
10 | #' @param caption \code{character} or \code{grob} to add to footer. Text can be
11 | #' \code{html} or \code{md} and is passed directly to \link[gridtext]{richtext_grob}
12 | #' @param logo file to add to footer as a logo
13 | #' @param order \code{character} of \code{length} 3 defining placement
14 | #' order for "caption" (C), "logo" (L) and "QR" (Q) code. Must be one of:
15 | #' \itemize{
16 | #' \item{CLQ}
17 | #' \item{LCQ}
18 | #' \item{QLC}
19 | #' \item{CQL}
20 | #' }
21 | #' @param positions \code{numeric} \code{vector} of \code{length} 3,
22 | #' defining the horizontal proportion of each container. The 3 numbers
23 | #' must add to 100.
24 | #' @param logo_justification numeric between 0 and 1 passed to \link[grid]{rasterGrob}. See note below.
25 | #' @param qr_justification numeric between 0 and 1 passed to \link[grid]{rasterGrob}. See note below.
26 | #' @param height_plot numeric plot height in cm.
27 | #' @param height_tracker numeric tracker height in cm.
28 | #' @param add_git logical include git info in encoding
29 | #' @param add_ts logical include timestamp info in encoding
30 | #' @param interactive logical use plotly for interactivity
31 | #' @param plotly_heights numeric vector of length 2 to fix relative height of plot and tracking banner
32 | #' @param ... options passed to \link[ggplot2]{theme} in order to style the tracker banner.
33 | #'
34 | #' @note For Justification you need to imagine each element in its own rectangle with a bottom
35 | #' dimension of 0 to 1. If you want the logo or QR code on the right of the rectangle set justification
36 | #' to 1, or 0 for left.
37 | #'
38 | #' @import ggplot2
39 | #' @import grid
40 | #' @import gridExtra
41 | #'
42 | #' @return grid
43 | #' @export
44 | #'
45 | ggtrack <- function(gg,
46 | qr_content = NULL,
47 | color = 'black',
48 | color_bg = 'white',
49 | caption = NULL,
50 | logo = NULL,
51 | order = 'CLQ',
52 | positions = c(55, 25, 20),
53 | logo_justification = 1,
54 | qr_justification = 1,
55 | height_plot = 7,
56 | height_tracker = 1.8,
57 | add_git = TRUE,
58 | add_ts = TRUE,
59 | interactive = FALSE,
60 | plotly_heights = c(.8,.2),
61 | ...) {
62 |
63 |
64 | # define size and order of 3 containers
65 | pos <- get_positions(order, positions)
66 |
67 | # build tracker as plot, this is the tracker object
68 | tracker <- ggplot(mapping = aes(x = 0:1, y = 1)) +
69 | theme_void() +
70 | theme(...)
71 |
72 | # setup qr
73 | if (!is.null(qr_content)) {
74 |
75 | # build QR content
76 | if (add_git) {
77 | git <- get_git_info()
78 | qr_content <- paste(qr_content, git, sep = ' ')
79 | }
80 |
81 | if (add_ts) {
82 | qr_content <- paste(qr_content, format(Sys.time(), '%Y%m%d-%H%M%S'), sep = ' ')
83 | }
84 |
85 | qr_cm <- qr_size(qr_content)
86 |
87 | if (height_tracker < qr_cm) {
88 | height_tracker <- qr_cm
89 | message(glue('to encode this much text into QR making QR height {qr_cm}cm'))
90 | }
91 |
92 | tracker <- add_qr(tracker, qr_content, color, color_bg, height_tracker, pos, qr_justification)
93 | }
94 |
95 | # setup logo
96 | if (!is.null(logo)) {
97 | tracker <- add_logo(tracker, logo, height_tracker, pos, logo_justification)
98 | }
99 |
100 | # setup caption
101 | if (!is.null(caption)) {
102 | tracker <- add_caption(tracker, caption, pos)
103 | }
104 |
105 | # style tracker
106 | tracker <- tracker +
107 | theme(plot.margin=unit(c(.5, 0, .3, 0),"cm"))
108 |
109 | if (interactive) {
110 | #plotly::subplot(gg, tracker, nrows = 2, heights = plotly_heights)
111 | warning('interactive option currently unavailable')
112 | } else {
113 | gridExtra::grid.arrange(gg, tracker, heights = unit(c(height_plot, height_tracker + 1.5 ), "cm"))
114 | }
115 |
116 |
117 | }
118 |
119 |
120 |
121 |
122 |
123 |
124 | #' @title Define Tracker Base
125 | #'
126 | #' @param order \code{character} of \code{length} 3 defining placement
127 | #' order for "caption" (C), "logo" (L) and "QR" (Q) code. Must be one of:
128 | #' \itemize{
129 | #' \item{CLQ}
130 | #' \item{LCQ}
131 | #' \item{QLC}
132 | #' \item{CQL}
133 | #' }
134 | #' @param positions \code{numeric} \code{vector} of \code{length} 3,
135 | #' defining the horizontal proportion of each container. The 3 numbers
136 | #' must add to 100.
137 | #' @param height_tracker numeric tracker height in cm.
138 | #' @param add_git logical include git info in encoding
139 | #' @param add_ts logical include timestamp info in encoding
140 | #'
141 | #' @return tracker
142 | #' @export
143 | #'
144 | #' @examples
145 | #' \dontrun{
146 | #' make_tracker()
147 | #' }
148 | make_tracker <- function(order = 'CLQ',
149 | positions = c(55, 25, 20),
150 | height_tracker = 1.8,
151 | add_git = TRUE,
152 | add_ts = TRUE) {
153 |
154 | # define size and order of 3 containers
155 | pos <- get_positions(order, positions)
156 |
157 | # build QR content
158 | if (add_git) {
159 | git <- get_git_info()
160 | } else {
161 | git <- ''
162 | }
163 |
164 | if (add_ts) {
165 | ts <- format(Sys.time(), '%Y%m%d-%H%M%S')
166 | } else {
167 | ts <- ''
168 | }
169 |
170 | # build tracker as plot, this is the tracker object
171 | tracker <- ggplot(mapping = aes(x = 0:1, y = 1)) +
172 | theme_void()
173 |
174 | mtrack <- obj_tracker(tracker, 'background', pos, height_tracker, git, ts)
175 |
176 | return(mtrack)
177 |
178 | }
179 |
180 |
181 | #' @title Create Tracker Object
182 | #'
183 | #' @param tracker ggtrack tracker object
184 | #' @param contains character vector tracks what elements have been added to tracker
185 | #' @param pos \code{numeric} \code{vector} of \code{length} 3,
186 | #' defining the horizontal proportion of each container. The 3 numbers
187 | #' must add to 100.
188 | #' @param height_tracker numeric tracker height in cm.
189 | #' @param git character git information derived by \link[ggtrack]{get_git_info}
190 | #' @param timestamp character timestamp information obtained from \code{format(Sys.time(), '%Y%m%d-%H%M%S')}
191 | #'
192 | #'
193 | #'
194 | #' @return tracker
195 | #'
196 | obj_tracker <- function(tracker, contains, pos = NULL, height_tracker = NULL, git = NULL, timestamp = NULL) {
197 |
198 | if (is.null(tracker$contains)) {
199 | tracker <- list(track = tracker,
200 | pos = pos,
201 | height = height_tracker,
202 | contains = contains,
203 | git = git,
204 | ts = timestamp)
205 | class(tracker) <- 'tracker'
206 | } else {
207 | tracker$contains <- c(tracker$contains, contains)
208 | }
209 |
210 | return(tracker)
211 |
212 | }
213 |
214 |
215 |
216 |
217 |
218 | #' @title Print Tracker
219 | #'
220 | #' @param x ggtrack tracker object
221 | #' @param ... print options
222 | #'
223 | #' @export
224 | #' @examples
225 | #' \dontrun{
226 | #' print(make_tracker())
227 | #' }
228 | print.tracker <- function(x, ...) {
229 |
230 | cat("ggtrack tracking banner\n")
231 | cat("=======================\n\n")
232 | cat(glue("banner height: {x$height} cm \n"))
233 | cat("\n\nincluded elements:\n - ")
234 | cat(x$contains, sep = '\n - ')
235 | cat('\nelement positions:\n\n')
236 | x$pos
237 |
238 | }
239 |
240 | #' @title Plot Tracker Object
241 | #'
242 | #' @param x ggtrack tracker object
243 | #' @param ... plot options
244 | #'
245 | #' @export
246 | #' @examples
247 | #' \dontrun{
248 | #' plot(make_tracker())
249 | #' }
250 | plot.tracker <- function(x, ...) {
251 |
252 | x$track +
253 | labs(title = 'ggtrack tracker banner',
254 | subtitle = "add to a ggplot using add_banner(plot, tracker)")
255 | }
256 |
--------------------------------------------------------------------------------
/vignettes/ggtrack.Rmd:
--------------------------------------------------------------------------------
1 | ---
2 | title: "ggtrack"
3 | output: rmarkdown::html_vignette
4 | vignette: >
5 | %\VignetteIndexEntry{ggtrack}
6 | %\VignetteEngine{knitr::rmarkdown}
7 | %\VignetteEncoding{UTF-8}
8 | ---
9 |
10 | ```{r setup, include = FALSE}
11 | knitr::opts_chunk$set(
12 | collapse = TRUE,
13 | comment = "#>",
14 | warning = FALSE,
15 | message = FALSE
16 | )
17 | ```
18 |
19 |
20 |
21 | ## Using ggtrack
22 |
23 | 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](https://github.com/hrbrmstr/qrencoder) package.
24 |
25 | ```{r example, fig.width=6, fig.height=5, out.width="80%", fig.align='center', fig.retina=2}
26 | library(ggtrack)
27 | library(ggplot2)
28 | library(grid)
29 |
30 | gg <- ggplot(mapping = aes(x = 1:10, y = rnorm(10))) +
31 | geom_bar(stat = 'identity') +
32 | theme_minimal()
33 |
34 | ggtrack(gg,
35 | qr_content = 'Report ID: 2c9075a5-4d7e-47a5-8616-55dd88af3dc5')
36 |
37 | ```
38 |
39 | ### Add a Logo
40 |
41 | A logo can be added either from a local or remote source. For now only `png` and `jpeg/jpg` are supported.
42 |
43 | ```{r logo, fig.width=6, fig.height=5, out.width="80%", fig.align='center', fig.retina=2}
44 | ggtrack(gg,
45 | qr_content = 'text content here',
46 | logo = 'https://www.r-project.org/logo/Rlogo.png')
47 |
48 | ```
49 |
50 |
51 |
52 |
53 | ### Add a Caption
54 |
55 | Captions use the [gridtext](https://github.com/wilkelab/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.
56 |
57 | ```{r caption, fig.width=6, fig.height=5, out.width="80%", fig.align='center', fig.retina=2}
58 | g <- ggtrack(gg,
59 | qr_content = 'For all your image tracking needs: https://github.com/mrjoh3/ggtrack',
60 | logo = 'https://www.r-project.org/logo/Rlogo.png',
61 | caption = 'Lots of extra info, or a fancy "grob".')
62 |
63 | grid.draw(g)
64 | ```
65 |
66 |
67 | ### Rearrange Banner Elements
68 |
69 | 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:
70 |
71 | * Caption is C
72 | * Logo is L
73 | * QR code is Q
74 |
75 | And the element order is defined by the order of these codes. For example, the default order code is `CLQ`.
76 |
77 | 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.
78 |
79 | ```{r order, fig.width=6, fig.height=5, out.width="80%", fig.align='center', fig.retina=2}
80 |
81 | ggtrack(gg,
82 | order = 'LCQ',
83 | positions = c(25, 55, 20),
84 | qr_content = 'For all your image tracking needs: https://github.com/mrjoh3/ggtrack',
85 | logo = 'https://www.r-project.org/logo/Rlogo.png',
86 | caption = 'Lots of extra info, or a fancy "grob".',
87 | logo_justification = 0)
88 |
89 | ```
90 |
91 | 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.
92 |
93 | 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.
94 |
95 |
96 |
97 |
98 | ### Add a download link
99 |
100 | The tracking chart can also be saved and made available for download. You can do this manually with `gplotly::ggsave()` and a simple markdown link as below.
101 |
102 | ```r
103 | ggsave(g, filename = 'ggrack_simple_download.png')
104 | ```
105 |
106 | ```md
107 | [download png](ggrack_simple_download.png)
108 | ```
109 |
110 | However, `ggtracker` also has a helper function to facilitate. Using `make_download` you can create either a download link or button. Unlike the markdown link which simply opens the file in the browser; `make_download` creates a proper download link. Note, in the example below it is necessary to specify both location to save the file and the download location. This is only necessary in this example due to the way `pkgdown` handles file locations. In most instances you only needs specify the save location. The button can also be styled by `CSS`.
111 |
112 | ```{r save link, results='asis'}
113 | dl <- make_download(g,
114 | save_file = c('../man', 'figures', 'ggtrack_chart'),
115 | download_file = c('../reference', 'figures', 'ggtrack_chart'),
116 | type = 'button',
117 | date = '',
118 | render = FALSE)
119 | ```
120 |
121 | `r dl`
122 |
123 | Something to consider at this point, with a down load button it is possible to display a plot without the additional metadata. Then pass the tracker object to the download link or button for users. This is a simple way to maintain the aesthetics of your report but still include vital metadata.
124 |
125 |
126 | ### Encode Additional Content Within Image
127 |
128 | 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](https://github.com/richfitz/stegasaur) package `knitr` hook is the easiest way to include the code used to generate a plot (see [stegasaur docs](https://richfitz.github.io/stegasaur/reference/hook_figasaur.html)).
129 |
130 | The [stegasaur](https://github.com/richfitz/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`.
131 |
132 | ```{r steg link, results='asis'}
133 | dl_steg <- make_download(g,
134 | link_text = 'download file with stenograph encoded',
135 | save_file = c('../man', 'figures', 'ggtrack_steg_chart'),
136 | download_file = c('../reference', 'figures', 'ggtrack_steg_chart'),
137 | type = 'link',
138 | date = '',
139 | render = FALSE,
140 | stenograph = rnorm(10))
141 |
142 | ```
143 |
144 | `r dl_steg`
145 |
146 |
147 |
148 | ## Tracking Banner Style
149 |
150 | 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 https://ggplot2.tidyverse.org/reference/theme.html.
151 |
152 | ```{r style, fig.width=8, fig.height=5, out.width="100%", fig.align='center', fig.retina=2}
153 |
154 | library(rWBclimate)
155 | library(ggthemes)
156 |
157 | temperature <- get_historical_temp('aus', "year")
158 |
159 | temperature_plot <- ggplot(temperature, aes(x = year, y = data)) +
160 | geom_path(color = 'blue') + geom_point(color = 'darkblue') +
161 | labs(title = 'Average Annual Temperature for Australia',
162 | y = 'degrees celcius') +
163 | stat_smooth(se = TRUE, colour = "darkred") +
164 | theme_fivethirtyeight()
165 |
166 | for_QR <- paste0('Data accessed using R package: ',
167 | 'https://github.com/ropensci/rWBclimate / ',
168 | 'https://docs.ropensci.org/rWBclimate/')
169 | for_Caption <- paste0('data accessed from the World Bank