library(ggtargets)
library(targets)library(ggtargets)
library(targets)ggtargets plots a targets pipeline as a ggplot2 object, in dagviz’s “metro” style: one row per target, thick colored lines for dependencies, rounded bends where a lane changes column, and a white “bridge” wherever two lines cross.
tar_script() writes a _targets.R file. This one reads some numbers, cleans them, fits a model, and reports on it - fit_model() is a named function, not inlined, so the next section can edit just its body:
tar_script({
fit_model <- function(data) stats::lm(y ~ x, data = data)
list(
tar_target(raw_data, data.frame(x = 1:20, y = 1:20 * 2 + stats::rnorm(20))),
tar_target(clean_data, raw_data[stats::complete.cases(raw_data), ]),
tar_target(model, fit_model(clean_data)),
tar_target(
summary,
data.frame(
term = names(stats::coef(model)),
estimate = unname(stats::coef(model))
)
),
tar_target(
report,
paste(utils::capture.output(print(summary)), collapse = "\n")
)
)
})tar_ggplot() is the one-call entry point: it reads the pipeline in the current directory and returns a plot.
tar_ggplot()Reading the plot: each row is one target, in the pipeline’s dependency order (a target’s row always comes after everything it depends on). Each target gets its own color and lane; a lane runs straight down when nothing else needs the column, and curves left or right - a rounded bend, not a sharp corner - when it has to make room. The dashed gray line from each node to its label is just a leader line, not a dependency.
Before tar_make() runs, every target is outdated (targets doesn’t distinguish “not yet built” from “needs a rebuild” - both are outdated). Color by status to see this directly:
tar_ggplot(node_color = "status", palette = targets_status_colors())tar_make(reporter = "silent")tar_ggplot(node_color = "status", palette = targets_status_colors())Every target is uptodate now. Change fit_model()’s body (not raw_data’s or clean_data’s definitions) and only model and what depends on it go back to outdated - raw_data and clean_data don’t depend on fit_model(), so they stay uptodate. Without rerunning anything, tar_ggplot() shows you exactly what tar_make() would rebuild:
tar_script({
fit_model <- function(data) stats::lm(y ~ x, data = data, weights = NULL)
list(
tar_target(raw_data, data.frame(x = 1:20, y = 1:20 * 2 + stats::rnorm(20))),
tar_target(clean_data, raw_data[stats::complete.cases(raw_data), ]),
tar_target(model, fit_model(clean_data)),
tar_target(
summary,
data.frame(
term = names(stats::coef(model)),
estimate = unname(stats::coef(model))
)
),
tar_target(
report,
paste(utils::capture.output(print(summary)), collapse = "\n")
)
)
})tar_ggplot(node_color = "status", palette = targets_status_colors())tar_ggplot()’s ... arguments pass straight to targets::tar_network(), so it filters exactly like tar_visnetwork(): names/allow/exclude take tidyselect helpers. allow keeps exactly the named targets; names keeps them and everything upstream they depend on (useful for “show me how target X gets built”, not just “show me X”):
tar_ggplot(allow = tidyselect::any_of(c("model", "summary")))tar_ggplot(names = tidyselect::any_of(c("model", "summary")))tar_ggplot(exclude = tidyselect::starts_with("report"))targets_only = FALSE (unlike tar_ggplot()’s own default of TRUE) also shows imported functions and objects, the way tar_visnetwork(targets_only = FALSE) does - useful for seeing exactly what a target depends on, at the cost of a busier plot. Nodes are drawn by their type, as in tar_visnetwork(): a regular target is a circle, a dynamic-branching one a square, an imported function an up triangle and an imported object a down triangle, with a legend when more than one shape is drawn.
tar_ggplot(targets_only = FALSE)Every visual detail is a style_metro() argument - bigger nodes, wider arcs, thicker edges:
tar_ggplot(
style = style_metro(
node_radius = 9,
arc_radius = 20,
edge_stroke_width = 3,
scale = 14
)
)A plot has a fixed physical size: one data unit is one pixel at 96 dpi. Nodes, lines and text therefore look the same in every pipeline, and a bigger pipeline just gives a bigger plot. dag_size() returns that size in inches, legend included. ggsave_dag() saves at that size, which is dagviz’s own scale (one data unit is one pixel; set style_metro(minimal_width = 500) for its canvas width too):
p <- tar_ggplot()
dag_size(p)
#> width height
#> 1.354167 1.041667
ggsave_dag(tempfile(fileext = ".png"), p)A large pipeline can be too big for the RStudio Plots pane, which clips it. zoom scales nodes, lines and text together. fixed_size = FALSE instead stretches the plot to fill the device, like an ordinary ggplot. Nodes, lines and text keep their size, and only the spacing between the nodes stretches.
tar_ggplot(zoom = 0.5)tar_ggplot()’s script/store arguments locate a pipeline’s files, but targets::tar_network() (which it wraps) still runs _targets.R from the current working directory - and most real pipelines use relative paths, like tar_source("R"), that only resolve correctly from the project’s own root. The reliable way to plot a pipeline living elsewhere is withr::with_dir():
# knitr resets the working directory to this vignette's own project folder
# before every chunk, so switch elsewhere just within this one chunk to
# demonstrate the pattern.
setwd(dirname(proj_dir))
getwd() # not the pipeline's own folder
#> [1] "/tmp/RtmpskZ5Uy"
withr::with_dir(proj_dir, tar_ggplot())A pipeline of many targets is easier to read as a few stages. targets has no tag or category field for a target, but it has one free-form text field, description, so the stage goes there. tar_option_set(description = ) sets it for every target defined after it, so each block of targets is a stage, and a last call puts the default back:
tar_script({
tar_option_set(description = "ingest")
ingest <- list(
tar_target(raw_data, 1:10),
tar_target(clean_data, raw_data * 2),
tar_target(features, clean_data + 1)
)
tar_option_set(description = "model")
model <- list(
tar_target(fit_mean, mean(features)),
tar_target(fit_median, median(features))
)
tar_option_set(description = "report")
report <- list(tar_target(report_text, c(fit_mean, fit_median)))
tar_option_set(description = character(0))
c(ingest, model, report)
})collapse_by = "description" merges the targets that share a stage into one node, with their number in the label. node_size = "n" and edge_width = "n" show that number as the size of a node and the width of an edge:
tar_ggplot(collapse_by = "description", node_size = "n", edge_width = "n")The “Collapsing a pipeline” article on the package website covers this in more detail: per-target descriptions, tarchetypes::tar_map(), coloring the collapsed graph by build status, and what happens when stages depend on each other both ways.