Bar Chart & Histogram in R with Example

โšก Smart Summary

Bar Chart and Histogram in R are built with ggplot2, using geom_bar() for categorical counts and geom_histogram() for continuous distributions. This walkthrough customises colour, grouping, stacking, orientation, binning, and in-bar labels on the mtcars dataset.

  • ๐Ÿ“Š Core Distinction: A bar chart summarises a categorical variable, while a histogram bins a single continuous variable into intervals.
  • ๐Ÿงฑ Grammar of Graphics: Every plot combines a dataset, an aes() mapping, and a geometric object joined with the plus sign.
  • ๐ŸŽจ Colour Control: Place fill inside geom_bar() for one uniform colour, and inside aes() to colour bars by group.
  • ๐Ÿ“ Position Adjustments: position = “fill” converts counts to percentages and position_dodge() places grouped bars side by side.
  • ๐Ÿ”ข Plotting Values: Pass stat = “identity” when the y-axis already holds a computed statistic such as a group mean.
  • ๐Ÿ“ Histogram Binning: Set bins or binwidth in geom_histogram(), because the default of 30 bins rarely suits the data.

Bar Chart Histogram in R

What is a Bar Chart in R?

A bar chart is a great way to display categorical variables in the x-axis. This type of graph denotes two aspects in the y-axis.

  1. The first counts the number of occurrences in each group.
  2. The second shows a summary statistic (minimum, maximum, average and so on) of a variable on the y-axis.

You will use the mtcars dataset, which has the following variables:

  • cyl: Number of the cylinder in the car. Numeric variable
  • am: Type of transmission. 0 for automatic and 1 for manual. Numeric variable
  • mpg: Miles per gallon. Numeric variable

Because a histogram looks so similar, it is worth settling the difference before writing any code.

Bar Chart vs Histogram in R: Key Differences

The two charts look alike, and they are constantly confused. They answer different questions and use different geometric objects.

Criteria Bar Chart Histogram
X-axis variable Categorical or factor Continuous and numeric
What a bar represents One category One interval, or bin, of values
Gaps between bars Yes, categories are separate No, bins are adjacent
Bar order Can be rearranged freely Fixed by the numeric scale
Question answered How do groups compare? How is one variable distributed?
ggplot2 object geom_bar() geom_histogram()

The rule of thumb: if reordering the bars would still make sense, you have a bar chart. If reordering them would destroy the meaning, you have a histogram. For quartile-based summaries of the same continuous variable, use a box plot.

How to Create a Bar Chart in R

To create graph in R, you can use the library ggplot which creates ready-for-publication graphs. The basic syntax of this library is:

ggplot(data, mapping = aes()) +
geometric object 

arguments: 
data: dataset used to plot the graph 
mapping: Control the x and y-axis 
geometric object: The type of plot you want to show. The most common objects are:

- Point: `geom_point()`
- Bar: `geom_bar()`
- Line: `geom_line()`
- Histogram: `geom_histogram()` 

This tutorial focuses on the geometric object geom_bar(), which draws the bar chart, and on geom_histogram() for continuous data.

Bar chart: count

Your first graph shows the frequency of cylinder with geom_bar(). The code below is the most basic syntax.

library(ggplot2)
# Most basic bar chart
ggplot(mtcars, aes(x = factor(cyl))) +
    geom_bar()

Code Explanation

  • You pass the dataset mtcars to ggplot.
  • Inside the aes() argument, you set the x-axis to the factor variable cyl
  • The + sign means you want R to keep reading the code. It makes the code more readable by breaking it.
  • Use geom_bar() for the geometric object.

Output:

Bar chart: count

Note: make sure you convert the variables into a factor otherwise R treats the variables as numeric. See the example below.

Bar chart: count

Customize the graph

Four arguments can be passed to customize the graph:

- `stat`: Controls what is plotted on the y-axis. By default `count`, which tallies rows. To plot a value you already computed, pass `stat = "identity"`
- `alpha`: Control density of the color
- `fill`: Change the color of the bar
- `size`: Control the size the bar	

Change the color of the bars

You can change the color of the bars. Note that the colors of the bars are all similar.

# Change the color of the bars
ggplot(mtcars, aes(x = factor(cyl))) +
    geom_bar(fill = "coral") +
    theme_classic()

Code Explanation

  • The colors of the bars are controlled by the aes() mapping inside the geometric object (i.e. not in the ggplot()). You can change the color with the fill arguments. Here, you choose the coral color.

Output:

Change the Color of the Bars

You can use this code:

grDevices::colors()

to see all the colors available in R. There are around 650 colors.

Change the intensity

You can increase or decrease the intensity of the bars’ color

# Change intensity
ggplot(mtcars,
        aes(factor(cyl))) +
    geom_bar(fill = "coral",
        alpha = 0.5) +
    theme_classic()

Code Explanation

  • To increase/decrease the intensity of the bar, you can change the value of the alpha. A large alpha increases the intensity, and low alpha reduces the intensity. alpha ranges from 0 to 1. At 1 the colour matches the palette exactly; at 0 the bar is invisible. Here you choose alpha = 0.5.

Output:

Change the Intensity

Color by groups

You can change the colors of the bars, meaning one different color for each group. For instance, cyl variable has three levels, then you can plot the bar chart with three colors.

# Color by group
ggplot(mtcars, aes(factor(cyl),
        fill = factor(cyl))) +
    geom_bar()

Code Explanation

  • The argument fill inside the aes() changes the colour of the bar. You change the color by setting fill = x-axis variable. In your example, the x-axis variable is cyl; fill = factor(cyl)

Output:

Color by Groups

Add a group in the bars

You can further split the y-axis based on another factor level. For instance, you can count the number of automatic and manual transmission based on the cylinder type.

You will proceed as follow:

  • Step 1: Create the data frame with mtcars dataset
  • Step 2: Label the am variable with auto for automatic transmission and man for manual transmission. Convert am and cyl as a factor so that you don’t need to use factor() in the ggplot() function.
  • Step 3: Plot the bar chart to count the number of transmission by cylinder
library(dplyr)
# Step 1
data <- mtcars %>% 
#Step 2
mutate(am = factor(am, labels = c("auto", "man")),
    cyl = factor(cyl))

With the dataset ready, you can plot the graph:

# Step 3

ggplot(data, aes(x = cyl, fill = am)) +
    geom_bar() +
    theme_classic()

Code Explanation

  • The ggplot() call receives the dataset data and the aes() mapping.
  • In the aes() you include the variable x-axis and which variable is required to fill the bar (i.e. am)
  • geom_bar(): Create the bar chart

Output:

Add a Group in the Bars

The mapping will fill the bar with two colors, one for each level. It is effortless to change the group by choosing other factor variables in the dataset.

Bar chart in percentage

You can visualize the bar in percentage instead of the raw count.

# Bar chart in percentage

ggplot(data, aes(x = cyl, fill = am)) +
    geom_bar(position = "fill") +
    theme_classic()

Code Explanation

  • Use position = “fill” in the geom_bar() argument to create a graphic with percentage in the y-axis.

Output:

Bar Chart in Percentage

Side by side bars

It is easy to plot the bar chart with the group variable side by side.

# Bar chart side by side
ggplot(data, aes(x = cyl, fill = am)) +
    geom_bar(position = position_dodge()) +
    theme_classic()

Code Explanation

  • position=position_dodge(): Explicitly tells how to arrange the bars

Output:

Side by Side Bars

Bar Chart with a Summary Statistic

In the second part of the tutorial, the y-axis carries a computed value rather than a count. Note that this is still a bar chart: a true histogram is covered further down, and it uses a different geometric object.

Your objective is to create a graph with the average mile per gallon for each type of cylinder. To draw an informative graph, you will follow these steps:

  • Step 1: Create a new variable with the average mile per gallon by cylinder
  • Step 2: Create a basic histogram
  • Step 3: Change the orientation
  • Step 4: Change the color
  • Step 5: Change the size
  • Step 6: Add labels to the graph

Step 1) Create a new variable

You create a data frame named data_histogram which simply returns the average miles per gallon by the number of cylinders in the car. You call this new variable mean_mpg, and you round the mean with two decimals.

# Step 1

data_histogram <- mtcars %>%
mutate(cyl = factor(cyl)) %>%
group_by(cyl) %>%
summarize(mean_mpg = round(mean(mpg), 2))

Step 2) Create a basic histogram

You can plot the histogram. It is not yet polished enough to hand to a client, but it already shows the trend.

ggplot(data_histogram, aes(x = cyl, y = mean_mpg)) +
    geom_bar(stat = "identity")

Code Explanation

  • The aes() has now two variables. The cyl variable refers to the x-axis, and the mean_mpg is the y-axis.
  • You pass stat = “identity” so that geom_bar() uses the y-axis variable as it is instead of counting rows. The default for geom_bar() is stat = “count”.

Output:

Histogram

Step 3) Change the orientation

You change the orientation of the graph from vertical to horizontal.

ggplot(data_histogram, aes(x = cyl, y = mean_mpg)) +
    geom_bar(stat = "identity") +
    coord_flip()

Code Explanation

  • You can control the orientation of the graph with coord_flip().

Output:

Histogram

Step 4) Change the color

You can differentiate the colors of the bars according to the factor level of the x-axis variable.

ggplot(data_histogram, aes(x = cyl, y = mean_mpg, fill = cyl)) +
    geom_bar(stat = "identity") +
    coord_flip() +
    theme_classic()

Code Explanation

  • You can plot the graph by groups with the fill= cyl mapping. R takes care automatically of the colors based on the levels of cyl variable

Output:

Histogram

Step 5) Change the size

To make the graph looks prettier, you reduce the width of the bar.

graph <- ggplot(data_histogram, aes(x = cyl, y = mean_mpg, fill = cyl)) +
    geom_bar(stat = "identity",
        width = 0.5) +
    coord_flip() +
    theme_classic()

Code Explanation

  • The width argument inside geom_bar() controls the thickness of the bar. A larger value makes it wider.
  • The plot is stored in the object graph, because the next step reuses it unchanged. Storing intermediate plots keeps the code readable.

Output:

Histogram

Step 6) Add labels to the graph

The last step adds the value of mean_mpg as a label inside each bar.

graph +
    geom_text(aes(label = mean_mpg),
        hjust = 1.5,
        color = "white",
        size = 3) +
    theme_classic()

Code Explanation

  • The function geom_text() is useful to control the aesthetic of the text.
    • label=: Add a label inside the bars
    • mean_mpg: Use the variable mean_mpg for the label
  • hjust controls where the label sits along the bar. Values close to 1 place it near the end of the bar, and larger values push it back towards the axis. If the orientation of the graph is vertical, change hjust to vjust.
  • color=”white”: Change the color of the text. Here you use the white color.
  • size=3: Set the size of the text.

Output:

Histogram

How to Order and Label Bars in a Bar Chart in R

Two finishing touches separate a draft chart from a publishable one: sorting the bars by value and labelling the axes properly.

Reordering bars. ggplot2 arranges factor levels alphabetically by default, which is rarely the most informative order. Wrap the x variable in reorder() to sort by a second variable:

# Sort the bars from lowest to highest mean_mpg
ggplot(data_histogram, aes(x = reorder(cyl, mean_mpg), y = mean_mpg)) +
    geom_bar(stat = "identity", fill = "coral") +
    theme_classic()

Prefix the sorting variable with a minus sign, reorder(cyl, -mean_mpg), to reverse the direction.

Adding titles and axis labels. The labs() function sets every text element in one call:

ggplot(data_histogram, aes(x = cyl, y = mean_mpg, fill = cyl)) +
    geom_bar(stat = "identity") +
    labs(title = "Average fuel economy by cylinder count",
        subtitle = "mtcars dataset",
        x = "Number of cylinders",
        y = "Mean miles per gallon",
        fill = "Cylinders",
        caption = "Source: mtcars") +
    theme_classic()

Set fill = NULL inside labs() to drop the legend title entirely, and use theme(legend.position = “none”) to remove the legend when the x-axis already names the groups.

Choosing your own colours. Replace the default palette with an explicit one so the chart matches your house style:

scale_fill_manual(values = c("4" = "#0e9cd1", "6" = "coral", "8" = "grey40"))

How to Create a Histogram in R with geom_histogram()

A histogram shows how a single continuous variable is distributed. Instead of counting categories, ggplot2 slices the numeric range into bins and counts how many observations fall into each one.

library(ggplot2)
# Most basic histogram
ggplot(mtcars, aes(x = mpg)) +
    geom_histogram()

R prints a message recommending that you pick a better bin count, because the default of 30 bins is arbitrary. Two arguments control this:

  • bins: the number of intervals to split the range into.
  • binwidth: the width of each interval, expressed in the units of the variable. Use this one when the units are meaningful.
# Set the number of bins
ggplot(mtcars, aes(x = mpg)) +
    geom_histogram(bins = 10, fill = "coral", color = "white") +
    theme_classic()

# Or set the width of each bin instead
ggplot(mtcars, aes(x = mpg)) +
    geom_histogram(binwidth = 4, fill = "coral", color = "white") +
    theme_classic()

Binning is the single most important choice in a histogram. Too few bins hide real structure such as a second peak; too many turn the chart into noise. Try several values before settling on one.

Comparing groups. Map a factor to fill and set the position so the distributions stay readable:

ggplot(mtcars, aes(x = mpg, fill = factor(cyl))) +
    geom_histogram(bins = 10, position = "identity", alpha = 0.5) +
    theme_classic()

With position = “identity” and a reduced alpha the histograms overlap so you can compare shapes directly. Use position = “dodge” if you would rather see the bins side by side.

Density instead of counts. When the groups differ in size, plot density so the areas are comparable, and overlay a smoothed curve:

ggplot(mtcars, aes(x = mpg)) +
    geom_histogram(aes(y = after_stat(density)), bins = 10,
        fill = "coral", alpha = 0.6) +
    geom_density(color = "steelblue", linewidth = 1) +
    theme_classic()

Bar Chart and Histogram in R: Code Reference

A bar chart suits a categorical x-axis, where the y-axis is either a count or a summary statistic. The table below lists the ggplot2 call for each variant covered above:

Objective Code
Count
ggplot(df, aes(x = factor(x1))) + geom_bar()
Count with different color of fill
ggplot(df, aes(x = factor(x1), fill = factor(x1))) + geom_bar()
Count with groups, stacked
ggplot(df, aes(x = factor(x1), fill = factor(x2))) + geom_bar()
Count with groups, side by side
ggplot(df, aes(x = factor(x1), fill = factor(x2))) + geom_bar(position = position_dodge())
Count with groups, stacked in %
ggplot(df, aes(x = factor(x1), fill = factor(x2))) + geom_bar(position = "fill")
Values (summary statistic)
ggplot(df, aes(x = factor(x1), y = x2)) + geom_bar(stat = "identity")
Histogram of a continuous variable
ggplot(df, aes(x = x1)) + geom_histogram(bins = 30)

FAQs

Use a histogram when the x-axis variable is continuous and you want to see its distribution. Use a bar chart when the x-axis holds distinct categories and you want to compare them.

Inside aes() fill maps a variable to colour, so each group gets its own shade. Outside aes(), inside geom_bar(), fill is a fixed value applied to every bar.

There is no universal answer. Start with the square root of the observation count, then adjust. Too few bins hide structure such as a second peak, and too many produce a noisy, spiky chart.

Histograms are the standard first step in exploratory data analysis for AI projects, revealing skew, outliers, and class imbalance before any model is trained. Bar charts then summarise feature importance and category frequencies.

Yes. AI assistants can draft ggplot2 layers from a plain description of the chart and explain errors such as a missing stat argument. Always run the generated code on your own data to confirm the mapping is right.

Summarize this post with: