R PROGRAMMING • R-SPECIFIC TOPICS (DATA WORKFLOWS)

Creating Common Plots — Create common plots (scatter, line, bar, histogram, boxplot)

Master the essential R visualization toolkit to reveal structure, relationships, and distributions hidden within data.

Historical Context & Motivation

The art and science of statistical graphics stretches back centuries, but the computational revolution of the late twentieth century fundamentally transformed how practitioners create visualizations. Before programmable tools existed, researchers drew plots by hand or relied on expensive mainframe batch-processing systems—a workflow that made iterative exploration prohibitively slow. The emergence of R as a free, open-source statistical computing environment democratized access to publication-quality plotting, enabling researchers and engineers alike to move from raw data to insightful graphics in seconds. Understanding the lineage of these plotting paradigms helps contextualize why R's current visualization ecosystem looks the way it does and why certain plot types have become canonical representations of data.

1786
Playfair's Statistical Charts
William Playfair published The Commercial and Political Atlas, introducing the line chart and bar chart to represent economic data—establishing the visual grammar still used today.
1976
S Language at Bell Labs
John Chambers and colleagues at Bell Labs created the S language, which pioneered interactive statistical computing and introduced functions like plot() and hist() that directly influenced R's base graphics system.
1993
Birth of R
Ross Ihaka and Robert Gentleman at the University of Auckland began developing R as an open-source implementation of S, bringing powerful visualization capabilities to anyone with a computer and an internet connection.
2005
ggplot2 and the Grammar of Graphics
Hadley Wickham released ggplot2, implementing Leland Wilkinson's Grammar of Graphics framework. This package gave R a declarative, layered approach to building visualizations that rapidly became the dominant plotting paradigm.
2020s
Modern R Visualization Ecosystem
R's plotting ecosystem now spans base graphics, ggplot2, plotly for interactivity, and packages like patchwork for composition—offering CS practitioners a rich toolkit for exploratory data analysis, algorithm benchmarking, and communicating computational results.

The central question this lesson addresses is straightforward yet fundamental: given a dataset, how do you choose and implement the right plot type in R to effectively reveal patterns, distributions, and relationships? Whether you are profiling algorithm runtime complexity, exploring a machine-learning feature space, or summarizing simulation results, the five plot types covered here—scatter, line, bar, histogram, and boxplot—form the foundational visual vocabulary you will use daily.

Core Principles of Statistical Plotting in R

Before diving into individual plot types, it is essential to internalize the foundational principles that govern effective data visualization in R. These principles apply regardless of whether you use base R graphics or ggplot2. They determine not only which function to call but how to structure your data, map variables to visual channels, and select the appropriate geometric representation for your analytical question. A solid grasp of these ideas will let you reason about new plot types you encounter in the future, not just the five covered here.

1

Data ↔ Aesthetic Mapping

Every plot maps data variables to aesthetic channels—x-position, y-position, color, size, and shape. In ggplot2 this mapping is explicit via aes(); in base R it is implicit in function arguments.
2

Geometry Selection

The geometric object (point, line, bar, etc.) encodes information. Choosing the wrong geom obscures the story: bars for continuous distributions or scatters for categorical counts both mislead.
3

Tidy Data Prerequisite

Effective plotting requires tidy data: each variable occupies a column, each observation a row. Most plotting errors trace back to improperly shaped data rather than incorrect function calls.
4

Layered Composition

Complex visualizations are built by layering geometric elements, statistical transformations, and annotations. In ggplot2, the + operator chains layers; in base R, functions like points() and lines() add to an existing canvas.
5

Scale & Coordinate Control

Axes, legends, and coordinate systems determine how raw data values are translated into pixel positions. Logarithmic scales, flipped coordinates, and custom breaks all affect interpretation—and R exposes fine-grained control over each.
KEY TAKEAWAY
Think of plotting in R like assembling a circuit on a breadboard. Your data is the power source, the aesthetic mapping is the wiring diagram, and the geometry is the component you plug in—an LED, a resistor, a capacitor—each revealing different characteristics of the signal. Swap the component, and the same data tells a different story.

Visual Overview — Five Plot Types at a Glance

The following diagram provides a visual reference for all five canonical plot types covered in this lesson. Each plot is shown with a schematic representation of its geometric elements and annotated with the type of data relationship it is best suited to reveal. Refer to this diagram throughout the lesson as a quick orientation tool.

Each card shows the geometric structure of a plot type alongside the data relationship it is designed to reveal. Scatter plots use points, line plots connect ordered observations, bar charts compare categorical values, histograms bin continuous data into frequency counts, and boxplots summarize distributional properties.

Notice that the first two plot types (scatter and line) both place continuous variables on both axes, but they differ in a critical assumption: scatter plots make no assumption about ordering, whereas line plots assert that the x-axis represents a meaningful sequence (often time). The bar chart and histogram look superficially similar—both use rectangles—but the histogram's bars are contiguous because they represent adjacent intervals of a continuous variable, while bar chart bars are separated because their categories are discrete. The boxplot occupies a unique role as a statistical summary visualization, encoding five-number summary statistics (minimum, Q1, median, Q3, maximum) plus outliers into a compact glyph.

How R Produces Plots — Base Graphics vs. ggplot2

R provides two major plotting subsystems, and understanding their architectural differences helps you choose wisely for each task. Base R graphics follows an imperative, pen-on-paper model: you open a graphics device, draw one element at a time, and the final image is the accumulated result of sequential function calls. ggplot2 follows a declarative, grammar of graphics model: you specify what you want (data, mappings, geometries, scales), and the library figures out how to render it. In a CS analogy, base R is like writing assembly instructions for a GPU, while ggplot2 is like writing a scene description for a ray tracer.

Base R Syntax Patterns

Base R functions and their most important parameters for each of the five common plot types.
Plot TypeBase R FunctionKey Arguments
Scatterplot(x, y)pch, col, cex, xlab, ylab, main
Lineplot(x, y, type="l")lty, lwd, col
Barbarplot(height)names.arg, col, beside, horiz
Histogramhist(x)breaks, freq, col, border
Boxplotboxplot(x ~ group)notch, outline, col, horizontal

ggplot2 Syntax Patterns

ggplot2 geometry layers and typical aesthetic mappings for each plot type.
Plot Typeggplot2 Geom LayerTypical Aesthetics
Scattergeom_point()aes(x, y, color, size, shape)
Linegeom_line()aes(x, y, color, linetype, group)
Bargeom_bar() / geom_col()aes(x, y, fill)
Histogramgeom_histogram()aes(x), bins, binwidth, fill
Boxplotgeom_boxplot()aes(x, y, fill), outlier.shape
💡 geom_bar() vs. geom_col()
A common source of confusion: geom_bar() computes counts from raw data (uses stat = "count" internally), while geom_col() expects pre-summarized data with explicit y-values (uses stat = "identity"). If you already have a summary table, use geom_col().

The general ggplot2 template for any of these five plot types follows the same structure: ggplot(data, aes(...)) + geom_*(). Additional layers for themes (theme_minimal()), labels (labs()), and scale overrides (scale_x_continuous()) can be appended freely. This composability is ggplot2's principal advantage over base graphics for complex, multi-layered visualizations.

Detailed Breakdown — Anatomy and Options for Each Plot Type

Each of the five plot types has unique parameters and conventions that control its appearance and statistical behavior. This section provides a deeper dive into the anatomy of each plot and the key decisions you must make when constructing them. The diagram below illustrates the internal structure of a boxplot—the most statistically rich of the five types—as a reference for the summary statistics it encodes.

The boxplot encodes the five-number summary: minimum, Q1, median, Q3, and maximum (within 1.5 × IQR). Points beyond the whiskers are marked as outliers. The interquartile range (IQR) equals Q3 − Q1 and represents the middle 50% of the data.

Key Decisions by Plot Type

  • Scatter: Choose point character (pch or shape) and transparency (alpha) to manage overplotting. Consider adding a trend line with geom_smooth() or abline().
  • Line: Ensure data is sorted by the x-variable before plotting. Use group aesthetic to handle multiple series; without it, ggplot2 may connect points incorrectly.
  • Bar: Decide between geom_bar() (counts raw data) and geom_col() (uses pre-computed values). For grouped bars, set position = "dodge"; for stacked bars, use the default position = "stack".
  • Histogram: The bins or binwidth parameter profoundly affects interpretation. Too few bins over-smooth the distribution; too many create noise. Sturges' rule (breaks = "Sturges") and Freedman-Diaconis (breaks = "FD") are common heuristics.
  • Boxplot: Use the formula interface y ~ group in both base R and ggplot2. Set notch = TRUE for a visual test of median differences between groups.
STURGES' RULE FOR HISTOGRAM BINS
k = ⌈log₂(n)⌉ + 1
Where k is the number of bins, n is the number of observations, and ⌈·⌉ denotes the ceiling function. This is R's default when you call hist(x) without specifying breaks.
FREEDMAN-DIACONIS BIN WIDTH
h = 2 × IQR(x) × n^(−1/3)
Where h is the bin width, IQR(x) is the interquartile range of the data, and n is the sample size. This rule is more robust to skewed distributions than Sturges' rule.

Worked Example — Visualizing Algorithm Benchmarks

Suppose you have benchmarked three sorting algorithms (bubble sort, merge sort, and quicksort) across various input sizes and stored the results in a data frame called benchmarks with columns algorithm, n (input size), and time_ms (runtime in milliseconds). We will create all five plot types using ggplot2 to extract different insights from this data.

Creating Five Plots from Benchmark Data
1
Step 1 — Set Up Data and Load LibraryFirst, load ggplot2 and create the sample data frame. In practice, you would read this from a CSV or generate it programmatically. We use library(ggplot2) and then construct the data frame with set.seed(42) for reproducibility.
library(ggplot2) set.seed(42) n_vals <- rep(c(100, 500, 1000, 5000, 10000), each = 30) algo <- rep(rep(c("Bubble", "Merge", "Quick"), each = 10), 5) time_ms <- ifelse(algo == "Bubble", 0.001 * n_vals^2 + rnorm(150, 0, 50), ifelse(algo == "Merge", 0.05 * n_vals * log2(n_vals) + rnorm(150, 0, 20), 0.04 * n_vals * log2(n_vals) + rnorm(150, 0, 15))) benchmarks <- data.frame(algorithm = algo, n = n_vals, time_ms = abs(time_ms))
2
Step 2 — Scatter Plot: Runtime vs. Input SizeA scatter plot reveals the relationship between input size and runtime, colored by algorithm. Each point represents a single trial. The alpha parameter adds transparency to reveal overlapping points.
ggplot(benchmarks, aes(x = n, y = time_ms, color = algorithm)) + geom_point(alpha = 0.6, size = 2) + labs(title = "Sorting Algorithm Runtime", x = "Input Size (n)", y = "Time (ms)") + theme_minimal()
3
Step 3 — Line Plot: Mean Runtime TrendsAggregate the data to compute mean runtime per algorithm and input size, then connect the means with lines. This shows the growth rate trend more clearly than raw scatter points. We use stat_summary() as a convenient shortcut.
ggplot(benchmarks, aes(x = n, y = time_ms, color = algorithm)) + stat_summary(fun = mean, geom = "line", linewidth = 1.2) + stat_summary(fun = mean, geom = "point", size = 3) + labs(title = "Mean Runtime by Input Size", x = "Input Size (n)", y = "Mean Time (ms)") + theme_minimal()
4
Step 4 — Bar Chart: Total Time by AlgorithmUse geom_col() with pre-summarized totals to compare aggregate runtime. We first compute the totals with aggregate() or dplyr::summarise().
totals <- aggregate(time_ms ~ algorithm, data = benchmarks, FUN = sum) ggplot(totals, aes(x = algorithm, y = time_ms, fill = algorithm)) + geom_col(width = 0.6) + labs(title = "Total Runtime per Algorithm", x = "Algorithm", y = "Total Time (ms)") + theme_minimal() + theme(legend.position = "none")
5
Step 5 — Histogram: Distribution of Quicksort TimesFilter to quicksort only and examine the distribution of runtimes across all input sizes. We set bins = 20 to balance detail and smoothness.
qs <- benchmarks[benchmarks$algorithm == "Quick", ] ggplot(qs, aes(x = time_ms)) + geom_histogram(bins = 20, fill = "#34d399", color = "white") + labs(title = "Distribution of Quicksort Runtimes", x = "Time (ms)", y = "Count") + theme_minimal()
6
Step 6 — Boxplot: Comparing Distributions by AlgorithmA boxplot compares the distributional characteristics (median, spread, outliers) of runtime across algorithms for a fixed input size. We filter to n == 5000 and use geom_boxplot().
sub <- benchmarks[benchmarks$n == 5000, ] ggplot(sub, aes(x = algorithm, y = time_ms, fill = algorithm)) + geom_boxplot(outlier.shape = 21, outlier.size = 2) + labs(title = "Runtime Distribution at n = 5000", x = "Algorithm", y = "Time (ms)") + theme_minimal() + theme(legend.position = "none")

Strengths & Limitations of Each Plot Type

No single plot type is universally optimal. Each has strengths that make it the ideal choice for certain data configurations and limitations that can mislead if the plot is used inappropriately. The table below summarizes these trade-offs to guide your selection process.

Comparative strengths and limitations of the five common plot types.
Plot TypeStrengthsLimitations
ScatterReveals correlations, clusters, and nonlinear relationships. Works well with color and size mappings for multivariate exploration.Overplotting with large n; poor for categorical data; no built-in statistical summary.
LineClearly shows trends and temporal patterns; easy to compare multiple series with color/linetype.Implies ordering/continuity; misleading for unordered data; sensitive to missing values creating gaps.
BarIntuitive for comparing magnitudes across categories; easily extended with stacking and faceting.Can be misleading with truncated y-axes; not suitable for continuous distributions; cluttered with many categories.
HistogramShows distributional shape (skewness, modality); essential for assessing normality assumptions.Bin width choice significantly affects interpretation; difficult to compare multiple distributions directly.
BoxplotCompact multi-group comparison; highlights median, spread, and outliers; scales well to many groups.Hides distributional shape (bimodality invisible); less intuitive for non-statistical audiences.
🎯 CHOOSING THE RIGHT PLOT
Think of plot selection like choosing a data structure in software engineering. Just as you wouldn't use a linked list when you need O(1) random access, you shouldn't use a bar chart to display continuous distributions. The type of your variables (categorical vs. continuous) and the analytical question (relationship? distribution? comparison?) should be the two inputs to your plot-selection function.

Connection to Advanced Visualization Techniques

The five basic plot types covered in this lesson are the building blocks from which more sophisticated visualizations are constructed. Each has advanced descendants that address specific limitations or extend functionality. Understanding this progression will help you know when to reach for a more powerful tool and how it relates to the foundational plot you already understand.

How each basic plot type maps to its advanced descendant in the ggplot2 ecosystem.
Basic PlotAdvanced ExtensionWhat It Adds
ScatterHexbin plot / 2D density plotHandles millions of points by aggregating into hexagonal bins with geom_hex() or geom_density_2d().
LineRibbon / area chartShows confidence intervals or ranges with geom_ribbon(); stacked areas for proportional time series.
BarLollipop chart / Cleveland dot plotReduces ink-to-data ratio; cleaner when many categories exist. Uses geom_segment() + geom_point().
HistogramDensity plot / ridgeline plotSmoothed continuous estimate with geom_density(); ridgeline plots (ggridges) compare many distributions.
BoxplotViolin plot / beeswarm plotShows full distributional shape with geom_violin(); beeswarm (ggbeeswarm) shows individual data points.

Beyond individual plot upgrades, the broader visualization frontier in R includes interactive graphics (via plotly::ggplotly() or shiny), faceted small multiples (via facet_wrap() and facet_grid()), and animation (via gganimate). Each of these builds on the same grammar-of-graphics foundation, so the conceptual investment you make in learning the five basic geoms pays compounding dividends as you explore the R visualization ecosystem.

🔄 From Static to Interactive
Any ggplot2 object can be converted to an interactive plot with a single function call: plotly::ggplotly(p). This adds hover tooltips, zoom, and pan—extremely useful for exploring algorithm benchmarks or large datasets during development.

Practice Problems

PROBLEM 1CONCEPTUAL
You have a dataset of HTTP response times (continuous, measured in milliseconds) collected from a web server over one week. You want to understand the overall shape of the distribution. Which of the five plot types is most appropriate, and why would a boxplot alone be insufficient for this task?
PROBLEM 2BASIC CALCULATION
Write the ggplot2 code to create a scatter plot from a data frame df with columns cpu_usage (x-axis) and memory_mb (y-axis), colored by a factor column process_type. Add appropriate axis labels and a minimal theme.
PROBLEM 3INTERMEDIATE
You need to compare the distribution of request latencies across five microservices. The data frame latency_df has columns service (factor) and latency_ms (numeric). Write the code for a boxplot that uses notches and adds the raw data points on top with jitter to show the underlying distribution.
PROBLEM 4APPLIED
You are profiling a machine learning training loop and have a data frame training_log with columns epoch (integer), loss (numeric), and split (factor: 'train' or 'validation'). Create a line plot that shows loss curves for both splits, add a horizontal dashed reference line at loss = 0.1 representing the target loss, and use a log-scale y-axis. Explain each layer.
PROBLEM 5CRITICAL THINKING
A colleague presents a bar chart comparing median runtimes of four algorithms. The y-axis starts at 95ms (not zero), and the visual difference between the tallest and shortest bars is dramatic. Critique this visualization from both a perceptual and statistical standpoint. Propose two alternative visualizations and explain what additional information each would provide.

Lesson Summary

This lesson covered the five foundational plot types in R: scatter plots for revealing relationships between two continuous variables, line plots for displaying trends over ordered sequences, bar charts for comparing magnitudes across categorical groups, histograms for examining the distributional shape of continuous data, and boxplots for compact multi-group distributional comparisons including median, spread, and outlier detection. We explored both base R syntax (imperative, pen-on-paper model) and ggplot2 syntax (declarative, grammar-of-graphics model) for constructing each type.

The key to effective visualization is matching the variable type and analytical question to the appropriate geometric representation. Remember that aesthetic mappings connect data columns to visual channels, geometry selection determines what is drawn, and parameters like bin width, alpha transparency, and axis scales profoundly affect interpretation. These five plot types serve as the foundation for the entire R visualization ecosystem, from interactive dashboards to publication-quality figures.

Varsity Tutors • R Programming • Creating Common Plots — Create common plots (scatter, line, bar, histogram, boxplot)