R Programming Quiz: Faceting
10 questions · exam conditions
0:00
FacetingQuestion 1 of 10

A data frame contains observations from three sites. At each site, both Control and Treatment observations are present, and each site–treatment subset has enough observations to fit a linear model.

What does the following code fit?

ggplot(df, aes(x, y, color = treatment)) + geom_smooth(method = "lm", se = FALSE) + facet_wrap(vars(site))

One model using all observations, with its single line copied into every site panel.
Three models, one per site, because faceting overrides the color-based grouping.
Two models, one per treatment, with each fitted line copied across sites.
Six models, one for each site–treatment combination represented in a panel.
← Back to quizzes

R Programming Quiz

R Programming Quiz: Faceting

Practice Faceting in R Programming with focused quiz questions that help you check what you know, review explanations, and build confidence with test-style prompts.

What this quiz covers

This quiz focuses on Faceting, giving you a quick way to practice the rules, question types, and explanations that matter most for R Programming.

How to use this quiz

Try each quiz question before looking at the correct answer. Use the explanations to review missed ideas, then come back to similar questions until the pattern feels familiar.

All questions

Question 1

A data frame contains observations from three sites. At each site, both Control and Treatment observations are present, and each site–treatment subset has enough observations to fit a linear model.

What does the following code fit?

ggplot(df, aes(x, y, color = treatment)) + geom_smooth(method = "lm", se = FALSE) + facet_wrap(vars(site))

  1. One model using all observations, with its single line copied into every site panel.
  2. Three models, one per site, because faceting overrides the color-based grouping.
  3. Two models, one per treatment, with each fitted line copied across sites.
  4. Six models, one for each site–treatment combination represented in a panel. (correct answer)
Explanation: When ggplot2 fits smoothing lines, it fits one model per unique aesthetic-group combination within each panel. The key is recognizing that two grouping mechanisms are active simultaneously here: color = treatment splits observations into groups, and facet_wrap(vars(site)) splits them into panels. These two mechanisms compound — they don't override each other. Within each of the three site panels, geom_smooth sees two distinct color groups (Control and Treatment) and fits a separate linear model to each. Three sites × two treatments = six models total, making D the correct answer. A is wrong because geom_smooth does not fit one global model and copy it everywhere. Each panel receives its own data subset, so no line is ever simply "copied" — every line is fit from the observations actually present in that panel. B is wrong because faceting does not override the color grouping. Faceting partitions the data into panels, but within each panel, the color aesthetic still creates sub-groups. Both grouping layers remain active. C is wrong for the same structural reason as B, just from the opposite direction. The color aesthetic does not override faceting either. You don't get just two models shared across sites — the faceting ensures each site's data is handled independently, so treatment-level models are re-fit within every panel. A useful mental rule: in ggplot2, every distinct combination of panel and aesthetic group gets its own geom_smooth fit. When you see facet_* combined with a grouping aesthetic like color or group, always multiply the panel count by the group count to find the number of models being fit.

Question 2

A factor named group has eight displayed levels ordered A through H. No levels are missing from the data.

Using the default horizontal filling direction, where is the H panel placed by facet_wrap(vars(group), ncol = 3)?

  1. It is placed in the second row and third column of a three-row layout.
  2. It is placed in the third row and first column of a three-row layout.
  3. It is placed in the third row and second column of a three-row layout. (correct answer)
  4. It is placed in the first row and second column because ncol = 3 causes panels to fill vertically before wrapping.
Explanation: When working with facet_wrap(), picture your panels filling a grid left-to-right, then top-to-bottom — exactly like reading English text. With eight panels (A–H) and ncol = 3, you get a grid that is 3 columns wide. Dividing 8 by 3 gives you three rows: the first two rows hold three panels each (A–C, then D–F), and the third row holds the remaining two panels (G and H). That means G lands in row 3, column 1, and H lands in row 3, column 2 — making C the correct answer. Choice A is wrong because it places H in row 2, column 3. That position actually belongs to F, the sixth panel. Choice B places H in row 3, column 1, but that slot belongs to G, the seventh panel — H comes immediately after G, one column to the right. Choice D describes a vertical filling order, where panels fill downward through a column before moving to the next. That behavior belongs to facet_grid() or facet_wrap() with dir = "v" specified explicitly; the default direction in facet_wrap() is always horizontal (dir = "h"). A reliable strategy here is to sketch the grid on paper: write out your panel labels in order, filling row by row with the given ncol. Count to your target panel and read off its row and column. This simple sketch eliminates all ambiguity and takes only seconds — a worthwhile habit whenever a facet layout question appears.

Question 3

A wrapped plot has three facets. Values in two facets range roughly from 0 to 10, while one observation in the third facet has a value of 100.

If the plot uses facet_wrap(vars(group)) without a scales argument, which outcome should be expected?

  1. All panels share a y scale that includes 100, so values in the first two panels may look compressed. (correct answer)
  2. Only the third panel includes 100, while the first two automatically receive narrower y scales.
  3. The observation at 100 is omitted because it falls outside the ranges of most panels.
  4. The third panel expands to 100, and its expanded y scale is copied only to adjacent panels.
Explanation: When working with facet_wrap() in ggplot2, the key concept to understand is how y-axis scales are handled across panels. By default — meaning when no scales argument is specified — all panels share a fixed, identical scale on both axes. This shared scale is determined by the global range of the data across all facets combined. Because one observation reaches 100, the shared y-axis must extend to accommodate that value across every panel. This means the two panels where values only reach 10 will display their data compressed near the bottom of a scale that stretches to 100. That's exactly what option A describes, making it the correct answer. Option B is wrong because it describes the behavior of scales = "free_y", which allows each panel to set its own independent y range. Without that argument, panels don't get individual scales. Option C is a fundamental misconception — ggplot2 never silently drops observations simply because they stand out from others; the scale expands to include all data points. Option D incorrectly suggests a "spreading" behavior where adjacent panels inherit a modified scale, which is not how ggplot2 works — scales are either fully shared (default) or fully independent ("free"), not partially propagated. A useful study tip: memorize the four scales options for faceting — "fixed" (default), "free", "free_x", and "free_y". On exam questions, if you see no scales argument, immediately think "everything is fixed and globally shared." That single assumption will let you reason through most faceting questions correctly.

Question 4

A plot is faceted with facet_grid(rows = vars(region), labeller = label_both). One value of region is East.

How does label_both affect the strip for that facet?

  1. It displays only East, because strip labels always omit variable names.
  2. It displays only region, because the labeller replaces values with variable names.
  3. It displays region (East), wrapping the value in parentheses after the variable name.
  4. It displays region: East, including both the variable name and its value. (correct answer)
Explanation: When working with facet_grid() in ggplot2, the labeller argument controls how strip labels are rendered — specifically, what text appears in the colored band identifying each facet panel. The default labeller shows only the variable's value, but label_both is designed to display more context. label_both formats strip labels by combining the variable name and its value with a colon-and-space separator, producing output like region: East. This is especially useful when you have multiple faceting variables and want the reader to immediately understand what each strip represents without consulting a legend or title. D is correct because that colon-space format — "variable: value" — is exactly what label_both produces by definition in ggplot2. A is wrong because it describes the default labeller behavior (label_value), not label_both. Using label_value, you'd see East alone — but the question explicitly specifies label_both. B reverses the logic entirely: label_both never replaces the value with the variable name; it always shows both, and omitting the value would defeat the purpose of the labeller. C is tempting if you're guessing based on the phrase "label both," but the parentheses format region (East) is not the actual output — ggplot2 uses a colon, not parentheses. There's no standard ggplot2 labeller that uses that parenthetical format. As a study tip, remember the three core labellers as a set: label_value (value only), label_both (name: value), and label_context (name: value, but only when needed for disambiguation). Knowing their output formats precisely will help you eliminate wrong answers quickly on format-specific questions like this one.

Question 5

A data frame contains observations for four existing regionquarter combinations: East–Q1, East–Q2, West–Q2, and West–Q3. Both regions and all three quarters occur somewhere in the data.

Compare these two plots:

p1 + facet_grid(rows = vars(region), cols = vars(quarter))

p1 + facet_wrap(vars(region, quarter))

With the default facet settings, how many panels does each plot contain?

  1. The grid contains four panels, and the wrapped layout contains six panels.
  2. The grid contains six panels, and the wrapped layout contains four panels. (correct answer)
  3. Both layouts contain four panels because only observed pairs are displayed.
  4. Both layouts contain six panels because all region–quarter pairs are displayed.
Explanation: When working with ggplot2's faceting functions, the most important distinction to internalize is that facet_grid() and facet_wrap() handle missing combinations very differently. facet_grid() builds a full Cartesian grid from your row and column variables. With 2 regions (East, West) and 3 quarters (Q1, Q2, Q3), it produces 2 × 3 = 6 panels — one slot for every region–quarter combination, even if some cells contain no data. Those empty cells still appear as blank panels. facet_wrap(), by contrast, only creates panels for observed combinations in your data. Since the data contains exactly four region–quarter pairs (East–Q1, East–Q2, West–Q2, West–Q3), facet_wrap() produces 4 panels — no empty slots, no wasted space. This makes B the correct answer: the grid contains six panels, and the wrapped layout contains four. Choice A has the counts swapped — it mistakenly assigns the smaller number to the grid and the larger to the wrap, which is backwards. Choice C incorrectly assumes both functions suppress empty combinations; only facet_wrap() does this by default. Choice D incorrectly assumes both functions display all possible combinations; that behavior belongs to facet_grid(), not facet_wrap(). A reliable memory hook: think of facet_grid() as a spreadsheet — it always draws the full table, blank cells included. Think of facet_wrap() as a photo album — it only makes a page if there's something to show. On any faceting question, ask yourself first: which function fills in blanks, and which one skips them?

Question 6

A plot uses regions as facet rows and products as facet columns. Some regions have much larger response values than others.

The plot adds facet_grid(rows = vars(region), cols = vars(product), scales = "free_y"). Which description of the resulting y scales is correct?

  1. Every panel receives an independent y scale, regardless of its row or column.
  2. Panels in the same product column share a y scale, while columns may differ.
  3. Panels in the same region row share a y scale, while rows may differ. (correct answer)
  4. All panels retain one global y scale because grid facets cannot free scales.
Explanation: When working with facet_grid() in ggplot2, the scales argument controls how y (and x) axes are shared across panels — but the key insight is that "free_y" doesn't mean every panel gets its own scale. Instead, it frees scales along rows, meaning panels in the same row still share a y scale, but different rows can have different y ranges. This is the logic behind answer C being correct. Because region maps to rows (rows = vars(region)), all panels within a given region row share a common y scale. However, since some regions have much larger response values, different rows are permitted to use different y ranges. This is exactly what scales = "free_y" delivers — row-level freedom, not panel-level freedom. Answer A describes scales = "free", which grants every individual panel a fully independent scale on both axes. That's a different setting entirely. Answer B has the logic backwards: it describes behavior along columns, which would correspond to freeing the x scale (scales = "free_x") when products are mapped to columns — not the y scale. Answer D is simply false; facet_grid() absolutely supports scale freedom through the scales argument, and "fixed" (not the absence of an option) is what forces a single global scale. A handy memory trick: in facet_grid, "free_y" frees scales across rows (the y-direction of the grid), so row membership still ties panels together — only the row-to-row comparison becomes flexible. When you see scales = in a facet question, always ask which dimension is being freed and which variable defines that dimension.

Question 7

The main data frame has observations from four sites. An annotation data frame contains one column, limit, and has no site column.

Consider this plot:

ggplot(readings, aes(day, value)) + geom_point() + geom_hline(data = limits, aes(yintercept = limit)) + facet_wrap(vars(site))

Assuming limits has one row, what happens to the horizontal reference line?

  1. The same horizontal line is drawn in each of the four site panels. (correct answer)
  2. The line is drawn only in the panel for the first site level.
  3. The line appears once behind the combined data rather than inside panels.
  4. The plot fails because the annotation data lacks the site variable.
Explanation: When ggplot2 applies faceting, it handles layer-level data differently depending on whether that data contains the faceting variable. The key insight: if a data frame passed to a geom lacks the faceting variable (site here), ggplot2 treats that data as a global annotation and replicates it across every panel automatically. That's exactly what happens here. limits has one row and no site column. When geom_hline receives this data, ggplot2 cannot map any row to a specific panel, so instead of dropping or failing, it draws the line in all four site panels — which is actually the intended, useful behavior for adding a shared reference line to a faceted plot. So A is correct. B is wrong because ggplot2 doesn't default to the "first level" when the faceting variable is absent — it replicates to all panels, not just one. C is wrong because faceting doesn't produce a single combined backdrop layer; all geoms render inside their respective panels (or all panels if unkeyed). There's no "behind the panels" space where a line would appear. D is the most tempting distractor — you might assume ggplot2 would throw an error for the missing variable — but ggplot2 is explicitly designed to handle this gracefully: a missing faceting key means "show everywhere," not "fail." A useful rule of thumb: if a data frame lacks the faceting variable, its geom appears in every panel. You can exploit this deliberately when you want a consistent reference line, mean, or annotation across all facets without duplicating rows.

Question 8

The variable tier is a factor with levels Bronze, Silver, and Gold. A filtering operation removes every Gold observation but does not drop the factor's unused Gold level.

What is the result of adding facet_wrap(vars(tier), drop = FALSE) after the filtering operation?

  1. Two panels appear because facets always discard levels with no remaining observations.
  2. Three panels appear, including an empty panel corresponding to the Gold level. (correct answer)
  3. One panel appears because drop = FALSE combines all factor levels together.
  4. Faceting fails because an unused factor level cannot define an empty panel.
Explanation: When working with facet_wrap() in ggplot2, the key distinction to understand is how the function handles factor levels that have no data after filtering. By default, facet_wrap() uses drop = TRUE, which silently removes any panels corresponding to empty factor levels. Setting drop = FALSE overrides this behavior, explicitly telling ggplot2 to retain and display a panel for every level in the factor — even levels with zero remaining observations. In this scenario, filtering removes all Gold rows but leaves the Gold level intact in the factor structure. When you pass drop = FALSE to facet_wrap(vars(tier)), ggplot2 honors all three factor levels — Bronze, Silver, and Gold — and creates three panels. The Gold panel simply renders empty, with no plotted data inside it. This is answer B, and it's the correct outcome. Answer A describes the default drop = TRUE behavior, not what happens when you explicitly set drop = FALSE. The whole point of the argument is to prevent the automatic discarding of empty levels. Answer C reflects a fundamental misunderstanding — drop = FALSE does not merge or collapse factor levels; it preserves them as separate panels. Answer D is also wrong because ggplot2 handles unused levels gracefully; an empty panel is a valid, intentional output, not an error condition. A useful rule of thumb: think of drop = FALSE as a "show your work" instruction to ggplot2 — it forces the plot to acknowledge every level in the factor, even those with nothing to display. This pattern appears not just in faceting but also in grouped summaries and bar charts.

Question 9

A numeric variable named score takes exactly four distinct values—1, 2, 3, and 4—with many observations at each value.

What layout results from facet_wrap(vars(score), ncol = 2)?

  1. Two panels are created because the numeric values are automatically divided into two bins.
  2. Four panels are created, arranged in two columns and two rows. (correct answer)
  3. One panel is created because continuous variables cannot directly define facets.
  4. Many panels are created, with one panel for every individual observation.
Explanation: When working with facet_wrap() in ggplot2, the key insight is that faceting splits your plot into panels based on the unique values of the faceting variable — not based on whether that variable is numeric or categorical. What matters is how many distinct values exist. Here, score has exactly four distinct values (1, 2, 3, 4), so facet_wrap(vars(score), ncol = 2) creates four panels, one per unique value, arranged with 2 columns. Since there are 4 panels and 2 columns, ggplot2 automatically fills in 2 rows — giving you a clean 2×2 grid. That makes B the correct answer. Choice A is wrong because facet_wrap() does not bin numeric values. Binning is something you'd do manually (e.g., with cut()) or via facet_grid() combined with a binning step — it doesn't happen automatically. Choice C reflects a common misconception: continuous variables can define facets as long as there are a manageable number of distinct values. ggplot2 simply treats each unique value as its own panel label. Choice D would only be true if every single observation had a unique value for score — since this variable has only four distinct values, you get four panels, not one per row. A useful rule of thumb: facet_wrap() always creates exactly as many panels as there are unique values in the faceting variable. When you see ncol = or nrow =, those just control the layout grid, not the panel count. Keep that distinction in mind for any faceting question.

Question 10

An analyst wants one panel for each site. Within every site panel, Control and Treatment observations should be distinguished by color. All panels should retain the default common axis scales.

Which code most directly creates the requested display?

  1. ggplot(df, aes(x, y, color = site)) + geom_point() + facet_wrap(vars(treatment))
  2. ggplot(df, aes(x, y)) + geom_point() + facet_wrap(vars(site, treatment))
  3. ggplot(df, aes(x, y, color = treatment)) + geom_point() + facet_wrap(vars(site)) (correct answer)
  4. ggplot(df, aes(x, y)) + geom_point() + facet_grid(treatment ~ site)
Explanation: When building a ggplot2 visualization, it helps to map each requirement directly to a specific layer or argument before looking at the code. Here, you need three things: panels by site, color by treatment, and default shared axis scales. facet_wrap(vars(site)) creates one panel per site, and mapping color = treatment inside aes() distinguishes Control from Treatment observations within each panel using color. That's exactly what C does — it satisfies both requirements cleanly and directly. Since facet_wrap uses free scales only when you explicitly set scales = "free", the default behavior already gives you common axes, so no extra argument is needed. A has the mapping backwards: color = site colors by site instead of treatment, and facet_wrap(vars(treatment)) creates panels by treatment instead of site — the exact opposite of what's requested. B passes both site and treatment into facet_wrap, which creates a separate panel for every unique site-treatment combination. This over-facets the plot and eliminates the within-panel color distinction entirely, since aes() has no color mapping. D uses facet_grid(treatment ~ site), which creates a grid with treatment as rows and site as columns — again over-faceting and separating what should be colored within a single panel. It also lacks a color aesthetic. A useful habit: read the requirements as a checklist — what gets faceted, what gets colored, what stays shared — and verify each aes() mapping and facet_* argument against that list before choosing your answer.