Skip to main content

ggplot2 Histogram in R: Complete Tutorial with Examples

Learn to create and customize ggplot2 histograms in R, from basic plots to colored, faceted, and density-overlaid visualizations.
Updated Jun 2, 2026  · 7 min read

Histograms reveal the shape of a dataset's distribution at a glance. In this tutorial, I'll walk you through creating and customizing histograms using ggplot2, R's most widely used plotting library and a core part of the tidyverse ecosystem. ggplot2 follows a grammar of graphics that lets you build complex visualizations by layering plot elements. For a base R approach, see our histogram tutorial with base R.

TL;DR

  • Use geom_histogram() inside a ggplot() call to draw a histogram

  • Control bin count with bins or bin size with binwidth inside geom_histogram()

  • Customize bar colors with the color (outline) and fill (interior) arguments

  • Overlay a density curve using geom_density() after setting y = after_stat(density)

  • Split by category using fill = variable in aes() or facet_grid() for separate panels

Learn R Essentials

Master the basics of data analysis in R, including vectors, lists, and data frames, and practice R with real data sets.
Start Learning R for Free

What Is a Histogram?

Histograms are visualizations that show frequency distributions across continuous (numeric) variables. They allow us to see the count of observations in data within ranges that the continuous variable spans.

Getting Started with ggplot2

To follow this tutorial, you need R installed and the following packages: ggplot2, readr, and dplyr. The code in the next section installs them if you haven't already.

Installing packages

We will first need to import the ggplot2 library using the library function. This will bring in all of the different built-in functions available in the ggplot2 library. If you have not already installed ggplot2, you will need to install it by running the install.packages() command. We will do the same for the readr library, which will allow us to read in a CSV file, and dplyr, which allows us to work more easily with the data we read in. 

install.packages("ggplot2")
install.packages("readr")
install.packages("dplyr")
library(ggplot2)
library(readr)
library(dplyr)

Loading the dataset

For this tutorial, we will be using this housing dataset, which includes details about different house listings, including the size of the house, the number of rooms, the price, and location information. 

We can read the data using the read_csv() function. We can read it directly from the URL or download the CSV file into a directory and read it from our local storage. The first attribute of read_csv() is the location of the data, and the col_select attribute allows us to choose the columns we are interested in. 

home_data <- read_csv(
    "https://raw.githubusercontent.com/rashida048/Datasets/master/home_data.csv",
    col_select = c(price, condition)
)

We can then look at the first few rows of data using the head() function:

head(home_data)

First rows of the housing dataset showing price and condition columns

How to Make a Histogram With ggplot2

Now we can create the histogram. Regardless of the type of graph we are creating in ggplot2, we always start with the ggplot() function, which creates a canvas to add plot elements to. It takes two parameters.

  • The first argument is a data frame. Here we want to use home_data.

  • The second argument is a mapping from columns in the data frame to plot aesthetics. This mapping must call the aes() function. Here, we map the price column to the x-axis.

So far, our code is

ggplot(data = home_data, aes(x = price))

This won't draw anything useful by itself. To make this a histogram, we add a histogram geometry using geom_histogram().

ggplot(data = home_data, aes(x = price)) +
  geom_histogram()

Basic ggplot2 histogram of housing prices

Add descriptive statistics to a histogram using geom_vline()

We can add descriptive statistics to our plot using the geom_vline() function. This adds a vertical line geometry to the plot.

First, we calculate a descriptive statistic, in this case, the mean price, using dplyr's summarize().

price_stats <- home_data |>
summarize(mean_price = mean(price))
price_stats
# A tibble: 1 × 1
  mean_price
      <dbl>
1    540088.

The function takes the xintercept parameter, and optional color and linewidth attributes to customize the color and size of the lines, respectively. We will add a mean line using the plus sign as we did in the previous section.

ggplot(home_data, aes(x = price)) +
    geom_histogram() +
    geom_vline(aes(xintercept = mean_price), price_stats, color = "red", linewidth = 2)

Notice that in geom_ functions, the mapping and data arguments are swapped compared to ggplot().

ggplot2 histogram with a red vertical mean price line added by geom_vline()

Plotting Probability Densities Instead of Counts

To add a probability density line to the histogram, we first change the y-axis to be scaled to density. In the aes() function, we set y to after_stat(density)

We can then add a density layer to our graph using the geom_density() function. Here we set the color attribute to green and the linewidth attribute to 2.

ggplot(home_data, aes(x = price, y = after_stat(density))) +
    geom_histogram() +
    geom_vline(aes(xintercept = mean_price), price_stats, color = "red", linewidth = 2) +
    geom_density(color = "green", linewidth = 2)

image4.png

Notice that the numbers on the y-axis have changed.

Notice how each layer follows the same pattern: a + sign, a function call, and optional arguments. You can add geom_ functions, statistics, and themes without relearning the syntax for each combination.

Update binning using bins

We can update the binning of our ggplot2 histogram using the bin attribute. We set bin attributes equal to the number of bins we want to display on our graph. This will help us see more or less granular data in our histogram. 

ggplot(data = home_data, aes(x = price)) +
  geom_histogram(bins = 100)

image12.png

We can also set the bin width manually using the binwidth attribute of geom_histogram().

ggplot(data = home_data, aes(x = price)) +
  geom_histogram(binwidth = 50000)

image5.png

Finally, you can align the boundaries using the center or boundary attributes. If you want the boundaries of bins to fall on specific multiples, you can use these attributes (only one can be used at a time). To ensure bins end up on integer values, set the attribute equal to 1.   

ggplot(data = home_data, aes(x = price)) +
  geom_histogram(boundary = 1)

ggplot2 histogram with bin boundaries aligned using the boundary argument

Customize the color of the histogram

In this section, we will change the colors of the histogram. We can customize the color of the outlines of each bar using the color attribute, and we can change the fill of the bars using the fill attribute of geom_histogram(). We will fill the bars with blue and change the outline color to white. 

ggplot(data = home_data, aes(x = price)) +
  geom_histogram(color = "white", fill = "blue")

ggplot2 histogram with white bar outlines and blue fill

Customize the color of the ggplot2 histogram based on groups

You can customize the colors of the histogram bars. 

Changing the fill aesthetic (inside aes() the function) will change the interior colors of the bars based on the value of a variable in the dataset. That variable should be categorical (a factor) rather than integers, so we can convert it using the factor() function. For this example, we will look at the condition variable, a value ranging from 1 (bad condition) to 5 (great condition). 

home_data <- home_data |>
    mutate(condition = factor(condition))

ggplot(data = home_data, aes(x = price, fill = condition)) +
    geom_histogram()

ggplot2 histogram with bars colored by housing condition category

Add labels and titles using labs()

Next, we add titles and labels to our graph using the labs() function. We set the x, y, and title attributes to our desired labels. 

ggplot(data = home_data, aes(x = price)) +
  geom_histogram() +
  labs(x ='Price (USD)', y='Number of Listings', title = 'Housing Price Distributions')

ggplot2 histogram with custom x-axis, y-axis, and title labels

Setting x-axis limits using xlim()

We can set the x-axis limits of our plot using the xlim()  function to zoom in on the data we are interested in. For example, it is sometimes helpful to focus on the central part of the distribution rather than over the long tail we currently see when we view the whole plot. 

Changing the y-axis limits is also possible (using ylim()), but this is less useful for histograms since the automatically calculated values are almost always ideal.

We will zoom in on prices between $0 and $2M.

ggplot(home_data, aes(x = price)) +
    geom_histogram(bins = 100) +
    xlim(0, 2000000)

ggplot2 histogram zoomed to prices between $0 and $2M using xlim()

Change legend position

If we want to move the legend on our graph, for instance, when we visualize the condition in different colors, we can use the theme() function and the legend.position attribute. The values that legend.position takes are “bottom”, “top”, “left”, or “right”. You can also pass the coordinates you would like the legend to be in using c(x, y).

ggplot(home_data, aes(x = price, fill = condition)) +
    geom_histogram() +
    theme(legend.position = "bottom")

Using facets in ggplot2

Finally, we can visualize data in different groups in separate graphs using facets. This will split the visualization into several subplots for each category. This can be done using the facet_grid() function. We will visualize the distributions of prices by different condition values below. 

ggplot(home_data, aes(x = price)) +
  geom_histogram() +  facet_grid(vars(condition))

Faceting is covered in more detail in the Facets for ggplot in R tutorial.

image2.png

Final Thoughts

To create a histogram in ggplot2, build the base with ggplot(), pass your data frame and aes() mapping, then add geom_histogram(). From there, layer on customization: labs() for axis titles, xlim() to zoom the x-axis, and theme() to reposition the legend or adjust visual styling.

ggplot2 is covered in depth in the Data Visualization in R skill track, beginning with Introduction to Data Visualization with ggplot2. You can learn to combine ggplot2 with other tidyverse tools in the Tidyverse Fundamentals with R skill track.

For more ggplot2 plot types beyond histograms, see our Graphics with ggplot2 tutorial, and download a copy of the ggplot2 cheat sheet for a handy reference.


Author
Kevin Babitz
LinkedIn

Data Science writer | Senior Technical Marketing Analyst at Wayfair | MSE in Data Science at University of Pennsylvania

Topics

Learn R with DataCamp!

Track

Data Analyst in R

36 hr
From exploratory data analysis with dplyr to data visualization with ggplot2—gain the career-building R skills you need to succeed as a data analyst!
See DetailsRight Arrow
Start Course
See MoreRight Arrow
Related
ggplot2 cheat sheet.png

cheat-sheet

ggplot2 Cheat Sheet

ggplot2 is considered to be one of the most robust data visualization packages in any programming language. Use this cheat sheet to guide your ggplot2 learning journey.
Richie Cotton's photo

Richie Cotton

Tutorial

R Histogram Tutorial: Create and Customize Plots with Base R

Learn to create and customize histograms in base R using the hist() function. Covers colors, labels, bins, density curves, and descriptive statistics.

Kevin Babitz

Tutorial

Graphics with ggplot2 Tutorial

Data visualization is an essential skill for data scientists. It combines statistics and design in meaningful and appropriate ways.
DataCamp Team's photo

DataCamp Team

Tutorial

Facets for ggplot2 in R

In this tutorial, you'll learn how to make the most of ggplots facetting functions.
DataCamp Team's photo

DataCamp Team

Tutorial

Visualizing Climate Change Data with ggplot2: A Step-by-Step Tutorial

Learn how to use ggplot2 in R to create compelling visualizations of climate change data. This step-by-step tutorial teaches you to find, analyze, and visualize historical weather data.

Bruno Ponne

Tutorial

Box Plot in R Tutorial

Learn about box plots in R, including what they are, when you should use them, how to implement them, and how they differ from histograms.
DataCamp Team's photo

DataCamp Team

See MoreSee More