Use Barplot in Polar Coordinate with ggplot2 to Visualize Cars Engine Power

In this work, we’ll create an ordered bar plot to visualize the relative length of sleeping time (normalized into z-score) of mammalian animals. Major techniques covered in this work include:


Packages and data cleanup

The dataset used for visualization is built in base R.

library(ggplot2)library(dplyr)
head(msleep, n = 4)

Output:

# A tibble: 4 × 11
name genus vore order conservation sleep_total sleep_rem sleep_cycle awake
<chr> <chr> <chr> <chr> <chr> <dbl> <dbl> <dbl> <dbl>
1 Cheetah Acin… carni Carn… lc 12.1 NA NA 11.9
2 Owl mo… Aotus omni Prim… <NA> 17 1.8 NA 7
3 Mounta… Aplo… herbi Rode… nt 14.4 2.4 NA 9.6
4 Greate… Blar… omni Sori… lc 14.9 2.3 0.133 9.1
# ℹ 2 more variables: brainwt <dbl>, bodywt <dbl>

Normalize the sleep time into z-scores.

msleep.2 <- msleep %>%   mutate(sleep.z = scale(sleep_total))

Rearrange the rows based on sleeping time, and convert the name variable to a factor to “memorize” the current name order. This will correspondingly generate an ordered bar plot arranged by the name variable. Check this complete guide to learn more techniques about reordering of graphic elements in ggplot2.

msleep.2 <- msleep.2 %>%   arrange(sleep_total) %>%   mutate(name = factor(name, levels = name))

Visualization

Create a flipped bar plot. After coordinate flip, the aesthetic mapping rule is unchanged: the horizontal axis (normalized sleep time) remains the aesthetic y axis, and the vertical axis (animal names) remains the aesthetic x axis.

p1 <- msleep.2 %>%   ggplot(aes(x = name, y = sleep.z, fill = log10(bodywt))) +  geom_col() +  coord_flip() +  geom_hline(yintercept = 0)p1

Relabel the animal names near the base of the bars with geom_text. A key in this edit is to right-justify texts in the upper half of the plot, and left-justify texts in the lower half, using y-aesthetic as the justification anchoring point. In this example, the bottom 45 labels are left-justified to y = .05, and the top 38 labels are right-justified to y = -0.05. In both vectors of y aesthetic and hjust, the values are sequentially applied to the animal names in a bottom-up direction. The resulted layout greatly improves readability, and the efficiency of plot space utilization.

p2 <- p1 +   geom_text(    aes(label = name,         # the anchoring position        y = c(rep(.05, 45), rep( -.05, 38))),    # left or right justification    hjust = c(rep(0, 45), rep(1, 38)),     size = 2) p2

Adjust the color scale and the associated color bar.

p3 <- p2 +   # use viridis palette G  scale_fill_viridis_c(    option = "G", direction = -1,     breaks = seq(-2, 3, 1),         # adjust the appearance of the color bar    guide = guide_colorbar(      barheight = unit(200, "pt"),      barwidth = unit(10, "pt"),      title.theme = element_text(angle = 90, hjust = .5),      title.position = "left",      title = "log10( body weight )"))p3

A final touch-up. In the theme syntax, horizontal axis (at the bottom or top of the plot) is always considered as x-axis, and vertical axis (left or right) as the y-axis, regardless of coordinate flip.

p4 <- p3 +   # revise y axis title  labs(y = "Sleeping time (z-score) of Animals") +    # theme  theme(    # remove elements on the left-side axis    axis.text.y = element_blank(),    axis.ticks.y = element_blank(),    axis.title.y = element_blank(),    axis.line.y.left = element_blank(),        # modify elements on the top-side axis     axis.text.x = element_text(size = 12, face = "bold"),    axis.title.x = element_text(size = 15, face = "bold"),    axis.line.x = element_line(), # for the top axis        # increase margin around the plot    # l: left; r, right; t, top; b, bottom    plot.margin = margin(l = 30, r = 30, t = 20, b = 20),        legend.position =  c(.9, .5),        # background    panel.grid = element_blank(),    panel.background = element_rect(fill = "lightyellow"),    plot.background = element_rect(fill = "lightyellow"),    legend.background = element_rect(fill = "lightyellow")) +    # move y axis (default on the left before flip) to the opposite (i.e., right) side of the plot  # after flip, the y-axis is positioned at the top of the plot  scale_y_continuous(position = "right") +    # increase the margin between the top-axis and the bar plots  scale_x_discrete(expand = expansion(add = 2))
p4

Save the plot.

ggsave(filename = "bars sleep time.pdf",       path = "graphics",        width = 6, height = 8)
library(ggplot2)library(dplyr)
msleep.2 <- msleep %>% # normalize the sleeping time to z-score mutate(sleep.z = scale(sleep_total)) %>% # reorder the bar (animals) by sleeping time arrange(sleep_total) %>% mutate(name = factor(name, levels = name))

# Create a flipped bar plot.p1 <- msleep.2 %>% ggplot(aes(x = name, y = sleep.z, fill = log10(bodywt))) + geom_col() + coord_flip() + geom_hline(yintercept = 0)p1

# Relabel the animal names near the base of the bars.p2 <- p1 + geom_text( aes(label = name, # the anchoring position y = c(rep(.05, 45), rep( -.05, 38))), # justification direction hjust = c(rep(0, 45), rep(1, 38)), size = 2) p2

# Adjust the color scale and the associated legend color bar. p3 <- p2 + # use viridis palette G scale_fill_viridis_c( option = "G", direction = -1, breaks = seq(-2, 3, 1), # adjust the appearance of the color bar guide = guide_colorbar( barheight = unit(200, "pt"), barwidth = unit(10, "pt"), title.theme = element_text(angle = 90, hjust = .5), title.position = "left", title = "log10( body weight )"))p3

# Theme customizationp4 <- p3 + # revise y axis title labs(y = "Sleeping time (z-score) of Animals") + # theme theme( # remove elements on the left-side axis axis.text.y = element_blank(), axis.ticks.y = element_blank(), axis.title.y = element_blank(), axis.line.y.left = element_blank(), # modify elements on the top-side axis axis.text.x = element_text(size = 12, face = "bold"), axis.title.x = element_text(size = 15, face = "bold"), axis.line.x = element_line(), # for the top axis # increase margin around the plot # l: left; r, right; t, top; b, bottom plot.margin = margin(l = 30, r = 30, t = 20, b = 20), legend.position = c(.9, .5), # background panel.grid = element_blank(), panel.background = element_rect(fill = "lightyellow"), plot.background = element_rect(fill = "lightyellow"), legend.background = element_rect(fill = "lightyellow")) + # move y axis (default on the left before flip) to the opposite (i.e., right) side of the plot # after flip, the y-axis is positioned at the top of the plot scale_y_continuous(position = "right") + # increase the margin between the top-axis and the bar plots scale_x_discrete(expand = expansion(add = 2))
p4

# Save the plot.ggsave(filename = "bars sleep time.pdf", path = "graphics", # using a relative path, save to the "graphics" folder width = 6, height = 8)




Continue Exploring — 🚀 one level up!


In the reordered bar plot above, relabeling the animal names (the x-axis labels) at the base of the bars greatly improves plot readability and space utilization efficiency. The following faceted donut plots in a U.S. map layout is another excellent example of text position refinement: relocating the U.S. state names (faceted subplot titles) to the inside of donuts not only renders a more concise outlook, but also frees more space to further enlarge the donut circles.



Proper reordering of graphic elements is one of the most used and powerful techniques in data visualization, as illustrated above in the bar plot of animals’ sleeping time. Besides, check the following amazing stacked area / alluvial plot, where ribbons of different countries are carefully reordered and clustered, such that gradient colors can be leveraged to differentiate countries and continents.