Start with a Basic Barplot
A basic barplot converts a numeric vector into rectangular bars whose heights are proportional to the supplied values.
R Graphics Ā· Barplot
Practical patterns from a basic base-R chart to grouped, stacked, interactive, ordered, proportional, and uncertainty-aware barplots.
Barplots compare quantities across discrete categories. The best variation depends on whether you need simple comparison, readable category names, subgroup composition, side-by-side comparison, or interactive exploration.
A basic barplot converts a numeric vector into rectangular bars whose heights are proportional to the supplied values.

The base R barplot() function needs only a numeric vector. It returns the midpoint of each bar invisibly, which can also be reused when adding annotations.
values <- c(0.40, 0.75, 0.20, 0.60, 0.50)
barplot(values, main = "Basic barplot", ylab = "Value")Color can distinguish bars, reinforce categories, or establish a consistent visual identity across related figures.

Use the col argument for the fill and border for the outline. A single restrained color is often clearer when all bars belong to one series.
values <- c(0.40, 0.75, 0.20, 0.60, 0.50)
barplot(values, col = "#2563eb", border = NA,
main = "Barplot with color", ylab = "Value")A horizontal barplot places categories on the vertical axis and measures values from left to right.

Horizontal bars are particularly effective when category names are long or when the ranking of categories is the main message.
values <- c(0.40, 0.75, 0.20, 0.60, 0.50)
barplot(values, horiz = TRUE, col = "#2563eb",
border = NA, xlab = "Value")Category labels identify what each bar represents and turn an otherwise anonymous sequence into an interpretable comparison.

The names.arg vector must have the same length and order as the values. Axis titles should state the measure and unit where relevant.
values <- c(0.40, 0.75, 0.20, 0.60, 0.50)
groups <- LETTERS[1:5]
barplot(values, names.arg = groups, col = "#2563eb",
border = NA, ylab = "Value")A stacked barplot divides every bar into segments, showing both the overall total and the contribution of each subgroup.

Pass a matrix to barplot(). Each matrix row becomes a colored segment. A legend is essential because color carries the subgroup meaning.
data <- rbind(
"Group 1" = c(0.2, 0.3, 0.7, 0.1, 0.3),
"Group 2" = c(0.4, 0.1, 0.1, 0.2, 0.3)
)
barplot(data, col = c("#2563eb", "#172554"), border = NA)
legend("topright", legend = rownames(data),
fill = c("#2563eb", "#172554"), bty = "n")A grouped barplot places subgroup bars side by side, making direct comparisons within and across categories easier.

Set beside = TRUE when passing a matrix. Grouped bars emphasize subgroup differences, whereas stacked bars emphasize composition and totals.
data <- rbind(
"Group 1" = c(0.2, 0.3, 0.7, 0.1, 0.3),
"Group 2" = c(0.4, 0.1, 0.1, 0.2, 0.3)
)
barplot(data, col = c("#2563eb", "#172554"),
beside = TRUE, border = NA)
legend("topright", legend = rownames(data),
fill = c("#2563eb", "#172554"), bty = "n")ggplot2 creates barplots through layered components, separating the data, visual mappings, geometry, labels, and theme.

Use geom_col() when bar heights already exist in the data. The related geom_bar() function calculates category counts by default.
install.packages("ggplot2") # Run once
library(ggplot2)
data_ggp <- data.frame(
group = LETTERS[1:5],
value = c(0.40, 0.75, 0.20, 0.60, 0.50)
)
ggplot(data_ggp, aes(x = group, y = value)) +
geom_col(fill = "#2563eb") +
labs(title = "Barplot with ggplot2", x = "Group", y = "Value") +
theme_minimal()A plotly barplot is interactive: viewers can inspect values with tooltips, zoom, pan, and use the chart toolbar.

plot_ly() creates an HTML widget rather than a static base-R image. The preview illustrates the initial chart; running the code enables interaction.
install.packages("plotly") # Run once
library(plotly)
group <- LETTERS[1:5]
values <- c(0.40, 0.75, 0.20, 0.60, 0.50)
plot_ly(x = group, y = values, type = "bar",
marker = list(color = "#636efa")) %>%
layout(title = "Interactive barplot",
xaxis = list(title = "Group"),
yaxis = list(title = "Value"))An ordered barplot arranges categories by magnitude so rankings and large differences are immediately visible.

Sort the named values before plotting. Decreasing order is useful for rankings, while increasing order can support progressive comparisons.
values <- c(A = 0.40, B = 0.75, C = 0.20, D = 0.60, E = 0.50)
ordered_values <- sort(values, decreasing = TRUE)
barplot(ordered_values, col = "#2563eb", border = NA,
main = "Bars ordered by value", ylab = "Value")Direct value labels make exact quantities available without requiring readers to estimate them from the axis.

Save the bar midpoints returned by barplot(), then pass those x positions to text(). Expand the y-axis limit to leave room above the bars.
values <- c(A = 0.40, B = 0.75, C = 0.20, D = 0.60, E = 0.50)
midpoints <- barplot(values, col = "#2563eb", border = NA,
ylim = c(0, 0.9))
text(midpoints, values + 0.04, labels = values,
font = 2, col = "#172554")A 100% stacked barplot converts every bar to the same total and compares the proportional composition of subgroups.

Divide each matrix column by its total before plotting. This emphasizes relative shares but intentionally removes differences in absolute totals.
data <- rbind(
"Group 1" = c(0.2, 0.3, 0.7, 0.1, 0.3),
"Group 2" = c(0.4, 0.1, 0.1, 0.2, 0.3)
)
proportions <- sweep(data, 2, colSums(data), "/")
barplot(proportions, col = c("#2563eb", "#172554"),
border = NA, ylab = "Share")
legend("topright", legend = rownames(proportions),
fill = c("#2563eb", "#172554"), bty = "n")Error bars add uncertainty informationāsuch as standard errors or confidence intervalsāto summary values shown by bars.

Draw the bars first, retain their midpoints, and add capped arrows from the lower to upper limits. Always state what the intervals represent.
means <- c(A = 5.2, B = 6.8, C = 4.4, D = 7.1, E = 5.9)
errors <- c(0.5, 0.7, 0.4, 0.6, 0.5)
midpoints <- barplot(means, col = "#2563eb", border = NA,
ylim = c(0, 8.3), ylab = "Mean")
arrows(midpoints, means - errors, midpoints, means + errors,
angle = 90, code = 3, length = 0.06, lwd = 2)