R Programming Quiz: Creating Common Plots
10 questions · exam conditions
0:00
Creating Common PlotsQuestion 1 of 10

A data frame d has a numeric column score and a factor column treatment with three levels. Some values of score are missing.

What type of plot is produced by plot(score ~ treatment, data = d) under standard base R method dispatch?

A scatterplot using the factor's integer codes as horizontal coordinates
A line plot connecting the group means in factor-level order
A boxplot of nonmissing scores separately for each treatment level
A histogram panel containing one score distribution per treatment level
← Back to quizzes

R Programming Quiz

R Programming Quiz: Creating Common Plots

Practice Creating Common Plots 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 Creating Common Plots, 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 d has a numeric column score and a factor column treatment with three levels. Some values of score are missing.

What type of plot is produced by plot(score ~ treatment, data = d) under standard base R method dispatch?

  1. A scatterplot using the factor's integer codes as horizontal coordinates
  2. A line plot connecting the group means in factor-level order
  3. A boxplot of nonmissing scores separately for each treatment level (correct answer)
  4. A histogram panel containing one score distribution per treatment level
Explanation: When you pass a formula of the form numeric ~ factor to plot() in base R, the interpreter doesn't blindly draw a scatterplot — it uses method dispatch to call the most appropriate plot method based on the data types involved. Specifically, R recognizes that the right-hand side is a factor and automatically invokes plot.formula, which in turn calls boxplot(). This means C is correct: you get one boxplot per factor level, and missing values in score are silently dropped from each group before the boxes are drawn. Choice A describes what might happen if R treated the factor as raw integers (its internal storage), but plot.formula is smarter than that — it checks the class of the grouping variable and routes accordingly. A plain plot(factor_var) would produce a bar chart of level frequencies, not this. Choice B describes behavior you might see with time-series objects or explicit type = "l" arguments; nothing about numeric ~ factor triggers line-drawing. Choice D describes hist() or faceted plotting systems like lattice or ggplot2 — base R's formula dispatch does not produce histogram panels. A useful pattern to remember: in base R, plot(y ~ x) reads the class of x to decide the plot type. Factor on the right → boxplot. Numeric on the right → scatterplot. This is a classic method-dispatch question, so whenever you see plot() with a formula, ask yourself "what type is the predictor?" — that single question will get you to the right answer every time.

Question 2

An analyst runs hist(c(0.2, 0.4, 1.2, 1.8), breaks = c(0, 1, 3), freq = FALSE, plot = FALSE). What are the histogram densities from left to right?

  1. c(0.50, 0.25), giving both bars the same total area (correct answer)
  2. c(0.50, 0.50), giving both bars the same displayed height
  3. c(2.00, 2.00), because each interval contains two observations
  4. c(0.25, 0.50), because the wider interval receives greater density
Explanation: When hist() uses freq = FALSE, it plots probability density, not counts. The key formula to remember is: density=proportion of observationsbin width\text{density} = \frac{\text{proportion of observations}}{\text{bin width}} This ensures that the area of each bar (density × width) equals the proportion of data in that bin, and all areas sum to 1. Here, the four values split evenly: two fall in (0, 1] and two fall in (1, 3], so each bin holds 2/4 = 0.50 of the data. Now apply the formula with different bin widths:
  • Left bin width = 1: density = 0.50 / 1 = 0.50
  • Right bin width = 2: density = 0.50 / 2 = 0.25
That's exactly answer A — and notice both bars have equal area (0.50 × 1 = 0.25 × 2 = 0.50), which is the whole point of density histograms. B is wrong because identical heights (0.50, 0.50) would give the wider bar double the area, misrepresenting the distribution. C is wrong because dividing raw counts (2, 2) by nothing ignores both total observations and bin width — it conflates frequency with density. D gets the direction of the adjustment backwards: wider bins receive lower density, not greater, precisely to compensate for their extra width. Study tip: Whenever you see freq = FALSE in an R histogram question, immediately think "area = proportion." Density goes down as bin width goes up — wider bins must have shorter bars to keep the areas honest.

Question 3

Consider b <- boxplot(c(1, 2, 3, 4, 100), range = 0, plot = FALSE). Which statement about b is correct?

  1. The whiskers reach the minimum and maximum, and b$out is empty (correct answer)
  2. The upper whisker stops near the upper quartile, and 100 is in b$out
  3. Both whiskers collapse to the median, and every other value is an outlier
  4. No statistics are computed because range = 0 disables the boxplot
Explanation: When you see boxplot() questions involving the range parameter, the key is understanding what range actually controls — it determines how far the whiskers extend, expressed as a multiple of the IQR. Most students associate range = 1.5 with the default outlier behavior, but the critical insight here is what happens when you set range = 0. Setting range = 0 tells R to extend the whiskers all the way to the data's minimum and maximum values, regardless of how extreme they are. So for the vector c(1, 2, 3, 4, 100), the lower whisker reaches 1 and the upper whisker reaches 100. Because the whiskers already capture every data point, nothing gets flagged as an outlier — meaning b$out is completely empty. This makes A the correct answer. B is wrong because it describes the default behavior (range = 1.5), where 100 would be an outlier since it falls far beyond the typical whisker cutoff. That's not what happens when range = 0. C describes a scenario where range is effectively infinite or both whiskers collapse, which has no basis in R's boxplot() logic — the whiskers don't collapse to the median based on any standard range value. D is a fabrication; range = 0 is a perfectly valid argument and R computes all statistics normally — it simply changes whisker length, not whether computation occurs. A handy rule of thumb: range = 0 means "no outliers ever" — the whiskers stretch to absorb all points. Always check the range argument before assuming default boxplot behavior.

Question 4

A data frame dat contains columns id, time, and score. Each participant has several observations, time is numeric, and the rows are not ordered by participant. The analyst wants one line per participant but does not want participant-specific colors.

Which code most directly creates the intended line plot?

  1. ggplot(dat, aes(time, score)) + geom_line(color = id)
  2. ggplot(dat, aes(time, score, group = id)) + geom_line() (correct answer)
  3. ggplot(dat, aes(time, score)) + geom_line(group = 1)
  4. ggplot(dat, aes(time, score, shape = id)) + geom_line()
Explanation: When working with longitudinal or repeated-measures data in ggplot2, the key concept to understand is grouping. By default, geom_line() connects all points in a single continuous line. To get one line per participant, you must tell ggplot2 how to split the data — and that's exactly what the group aesthetic does. Setting group = id inside aes() instructs ggplot2 to draw a separate line for each unique value of id, which is precisely what the analyst wants. Since color is not mapped, all lines share the same default color — satisfying the requirement of no participant-specific colors. This makes B the correct and most direct solution. Looking at the distractors: A writes color = id outside aes(), meaning it's treated as a literal fixed value rather than a variable mapping — R will throw an error or ignore it, and even if it worked as intended, it would add participant-specific colors, violating the stated requirement. C uses group = 1 inside geom_line(), which forces all data into a single group, producing one chaotic line connecting every observation across all participants rather than one line per participant. D maps shape to id, but shape has no effect on lines (it applies to points), so ggplot2 still lacks grouping information and won't draw separate participant lines correctly. As a study tip, remember: group controls line separation without changing visual styling. Whenever you need separate lines but no color or style differences, group inside aes() is your go-to tool.

Question 5

The data frame sales contains three rows: product A with units equal to 2, product A with units equal to 5, and product B with units equal to 4.

What is the result of ggplot(sales, aes(product, units)) + geom_col() using the default position?

  1. Two bars appear, with total heights 7 for A and 4 for B (correct answer)
  2. Two bars appear, with row counts 2 for A and 1 for B
  3. Three side-by-side bars appear, with heights 2, 5, and 4
  4. The plot fails because bar charts cannot contain repeated x categories
Explanation: When working with ggplot2 bar charts, the critical distinction is between geom_bar() and geom_col(). geom_bar() counts rows by default, while geom_col() uses actual values from a mapped y aesthetic — but the key detail here is how geom_col() handles multiple rows sharing the same x category. By default, geom_col() uses position = "stack". This means when multiple rows map to the same x value, their y values are stacked into a single bar. In your sales data, product A appears twice with units of 2 and 5. Those stack to a total height of 7. Product B appears once with units of 4, so its bar stays at 4. The result is two bars — making A the correct answer. Choice B describes behavior closer to geom_bar() without a y mapping, which counts the number of rows per category (2 rows for A, 1 for B) rather than summing values. Choice C describes position = "dodge", which places overlapping bars side by side instead of stacking them — that's not the default. Choice D is simply false; ggplot2 handles repeated x categories gracefully through its position system rather than throwing an error. A useful tip: memorize the three main position values — "stack" (default, bars stacked), "dodge" (bars side by side), and "fill" (bars stacked to 100%). Exam questions often test whether you know which behavior is the default, so when you see no explicit position argument, assume stacking.

Question 6

The matrix m is created by matrix(c(2, 5, 3, 4), nrow = 2, byrow = TRUE, dimnames = list(c("East", "West"), c("Q1", "Q2"))).

How does barplot(m, beside = TRUE) organize the bar heights?

  1. Two stacked bars appear with total heights of 7 for Q1 and 7 for Q2
  2. Two groups appear in row order: East contains bars of 2 and 5; West contains bars of 3 and 4
  3. Two groups appear in column order: Q1 contains bars of 2 (East) and 3 (West); Q2 contains bars of 5 (East) and 4 (West) (correct answer)
  4. Four groups appear, each containing one bar and one zero-height companion bar
Explanation: When working with barplot() on a matrix in R, the key question to ask is: how does R read the matrix, and what does beside = TRUE actually do? R fills matrices column by column by default, and barplot() treats each column as a group. With beside = TRUE, bars within each group are placed side by side rather than stacked. So for matrix m, the two columns — Q1 and Q2 — become the two groups. Within Q1, you get one bar per row: 2 for East and 3 for West. Within Q2, you get 5 for East and 4 for West. That's exactly what C describes, making it the correct answer. A is wrong because stacking happens when beside = FALSE (the default). Stacked bars would show total heights of 7 for Q1 and 9 for Q2 — and even the totals cited in A are incorrect. B is wrong because it treats rows as the grouping variable. barplot() groups by columns, not rows. East and West are the row names, so they label individual bars within a group, not the groups themselves. D is wrong because there's no concept of zero-height companion bars here. The matrix has two rows and two columns, producing exactly four bars total across two groups — nothing is padded or duplicated. A handy rule of thumb: in R's barplot(), columns = groups, rows = bars within each group. When you see beside = TRUE, picture columns becoming clusters on the x-axis.

Question 7

What value is returned by hist(c(0, 1, 1, 2), breaks = c(0, 1, 2), right = FALSE, include.lowest = TRUE, plot = FALSE)$counts?

  1. c(2, 2), because each boundary value is shared equally between the two adjacent bins
  2. c(1, 3), because right = FALSE makes bins left-closed and include.lowest = TRUE pulls the upper endpoint 2 into the last bin (correct answer)
  3. c(3, 1), because right = FALSE keeps values equal to 1 in the first bin rather than moving them to the second
  4. c(1, 2), because include.lowest applies only to the lower endpoint and the observation equal to 2 is therefore discarded
Explanation: When working with hist() in R, the key parameters to understand are right and include.lowest, which together control exactly which endpoints belong to which bin. By default, hist() creates right-closed intervals like [0,1) and [1,2]. Setting right = FALSE flips this to left-closed intervals: [0,1) and [1,2). Now here's the critical detail — with right = FALSE, the rightmost boundary of the last bin would normally exclude the value 2, leaving it unclassified. Setting include.lowest = TRUE overrides this by pulling the upper endpoint of the final bin inward, making the last interval [1,2] instead of [1,2). So your bins become [0,1) and [1,2]. Tallying your data c(0, 1, 1, 2): 0 falls in the first bin (count = 1), and 1, 1, 2 all fall in the second bin (count = 3), giving c(1, 3) — confirming B is correct. A is wrong because R doesn't split boundary values between bins; each observation belongs to exactly one interval based on the closed/open endpoint rules. C flips the logic: with right = FALSE, the value 1 is the left boundary of the second bin [1,2], so it belongs to the second bin, not the first. D misreads include.lowest — with right = FALSE, the parameter protects the upper endpoint of the last bin (not the lower), ensuring 2 is included rather than discarded. As a study tip, always trace through right and include.lowest together — they interact specifically at the extreme boundary of your break range, which is where exam questions love to probe your understanding.

Question 8

What typically happens when an analyst runs ggplot(d, aes(x, y)) + geom_point(aes(color = "navy"))?

  1. All points use the literal navy color, and no color legend is created
  2. The plot fails because quoted values cannot appear inside aes()
  3. Each point receives a different navy shade based on its row position
  4. All points share a palette-selected color, and a one-category legend appears (correct answer)
Explanation: When you pass a quoted string like "navy" inside aes(), ggplot2 does not interpret it as a literal color name. Instead, aes() maps variables or values to aesthetics by creating a new factor column behind the scenes. Because "navy" is a constant string, every row in your data gets mapped to the same single-level factor — essentially a category called "navy." ggplot2 then assigns that category a color from its default discrete color palette (typically a salmon/red), which is almost certainly not the navy blue you intended. It also automatically generates a legend showing that one category, labeled "navy." This makes D the correct answer. Choice A describes what you probably wanted to happen, but it's what occurs when you place color outside of aes() — for example, geom_point(color = "navy"). Outside aes(), the string is treated as a direct color specification with no legend. Choice B is wrong because quoted strings inside aes() are perfectly valid R syntax — ggplot2 won't throw an error. It silently does something you might not expect, which is actually what makes this a tricky bug to spot. Choice C is wrong because the string "navy" has no row-varying information. Every observation maps to the same single category, so there's no gradient or variation by row position. The key study tip: remember the inside-vs-outside-aes() rule. Inside aes() = data mapping (even constants become factor levels with legends). Outside aes() = fixed visual property. When you want a literal color, keep it outside aes().

Question 9

Base R executes plot(c(3, 1, 2), c(2, 5, 1), type = "l"). In what order are the points connected?

  1. They are connected from (1, 5) to (2, 1) to (3, 2)
  2. They are connected from (3, 2) to (1, 5) to (2, 1) (correct answer)
  3. They are connected from (1, 1) to (2, 2) to (3, 5)
  4. They are not connected because the x values are not increasing
Explanation: When using plot() with type = "l" in R, it's crucial to understand that R connects points in the order they appear in the vectors, not by sorting them numerically. Think of each vector as a sequence of coordinates: the first elements pair together, the second elements pair together, and so on. Here, c(3, 1, 2) supplies the x-values and c(2, 5, 1) supplies the y-values, forming three points in sequence: (3, 2), (1, 5), and (2, 1). With type = "l", R draws a line from the first point to the second, then from the second to the third — giving you (3, 2) → (1, 5) → (2, 1). That's exactly what B describes, making it the correct answer. A is wrong because it reorders the points by ascending x-value — sorting them as if R performs automatic ordering before plotting, which it does not. C makes the same sorting mistake but additionally pairs incorrect x and y values together, perhaps confusing the ranked positions of values with the values themselves. D reflects a misunderstanding borrowed from functions like lines() or curve-fitting contexts — R's plot() with type = "l" does not require sorted x-values; it simply connects whatever coordinates you give it in index order. A useful rule of thumb: in R's base plot(), index position is everything. The ith element of your x-vector always pairs with the ith element of your y-vector, and type = "l" connects them like a dot-to-dot puzzle from index 1 to the last.

Question 10

What bar sequence is produced by barplot(table(factor(c("open", "closed", "open"), levels = c("pending", "open", "closed"))))?

  1. Two bars appear in alphabetical order: closed = 1, then open = 2
  2. Two bars appear in encounter order: open = 2, then closed = 1
  3. Three bars appear alphabetically: closed = 1, open = 2, pending = 0
  4. Three bars appear in level order: pending = 0, open = 2, closed = 1 (correct answer)
Explanation: When you see a question combining factor(), table(), and barplot() in R, the key is tracing the data through each function in order — each one makes a specific decision that shapes the final output. Start with factor(c("open", "closed", "open"), levels = c("pending", "open", "closed")). By explicitly supplying levels, you're doing two things: defining the complete set of valid categories (including "pending", which never appears in the data) and fixing their order as pending → open → closed. The factor doesn't silently drop unused levels — it keeps them. Next, table() counts occurrences for every level, producing pending = 0, open = 2, closed = 1. Crucially, it respects the factor's level order, not alphabetical order. Finally, barplot() renders the bars in exactly the order table() presents them: pending, open, closed — with three bars total, including the zero-height bar for "pending." This makes D correct: three bars in level order — pending = 0, open = 2, closed = 1. A is wrong on two counts: it assumes alphabetical ordering and drops the "pending" level entirely. B also drops "pending" and assumes encounter order (the sequence values appear in the original vector). Both of these would be the behavior of a plain character vector, not a factor with explicit levels. C gets the count right and includes all three levels, but orders them alphabetically (closed, open, pending) — ignoring that factor levels override alphabetical sorting. The study tip: in R, explicit levels always win. They control order and which categories appear, even if some have zero observations.