How do I plot charts with nested categories axes?
I think the facet approach is fine:
library(ggplot2)
library(gtable)
library(grid)
df <- data.frame(main.cat = c("A", "A", "B", "B", "B", "C"),
second.cat = c("a1", "a2", "b1", "b2", "b3", "c1"),
value = c(2, 3, 4, 2.5, 1.5, 2.3))
p = ggplot(data = df, aes(x = second.cat, y = value)) +
geom_point() + facet_grid(.~main.cat, space = "free_x", scales = "free_x") +
theme(strip.background = element_rect(fill = NA))
But if you want something closer to the excel look, one approach is to use gtable
functions to extract the strip and insert it below the tick mark labels, then insert some boundary lines between the major categories. Note that the code below is specific to your sample data.
p = p + theme(panel.spacing = unit(0, "lines"))
g = ggplotGrob(p)
gtable_show_layout(g) # to see the layout
# Add a row below the x-axis tick mark labels,
# the same height as the strip
g = gtable_add_rows(g, g$height[7], 9)
# Get the strip grob
stripGrob = gtable_filter(g, "strip")
# Insert the strip grob into the new row
g = gtable_add_grob(g, stripGrob, 10, 5, 10, 9)
# remove the old strip
g = g[-7, ]
# Insert line grobs as boundary lines between major categories
linesGrob = linesGrob(gp = gpar(col = "grey75"))
for(i in c(6,8)) g = gtable_add_grob(g, linesGrob, t=8, l=i, b=9, r=i)
# Insert new columns of zero width to take the line grobs for the first and last boundary lines
for(i in c(4, 10)) {
g = gtable_add_cols(g, unit(0, "lines"), i)
g = gtable_add_grob(g, linesGrob, t=8, l=i+1, b=9, r=i+1)
}
grid.newpage()
grid.draw(g)
Edit A crude attempt at generalising
library(ggplot2)
library(gtable)
library(grid)
df <- data.frame(main.cat = c("A", "A", "B", "B", "C", "D"),
second.cat = c("a1", "a2", "b1", "b2", "c1", "d1"),
value = c(2, 3, 4, 2.5, 1.5, 2.3))
p = ggplot(data = df, aes(x = second.cat, y = value)) +
geom_point() + facet_grid(.~main.cat, space = "free_x", scales = "free_x") +
theme(strip.background = element_rect(fill = NA))
p = p + theme(panel.spacing = unit(0, "lines"))
g = ggplotGrob(p)
gtable_show_layout(g) # to see the layout
# Get the indices for the panels (t=top, l=left, ...
panels <- c(subset(g$layout, grepl("panel", g$layout$name), se=t:r))
# Get the strip grob
stripGrob = gtable_filter(g, "strip")
# Its height is
height = stripGrob$height
# Add a row below the x-axis tick mark labels,
# the same height as the strip.
g = gtable_add_rows(g, height, unique(panels$b+1))
# Insert the strip grob into the new row
g = gtable_add_grob(g, stripGrob,
t = unique(panels$b+2),
l = min(panels$l),
r = max(panels$r))
# Insert line grobs as boundary lines between major categories
linesGrob = linesGrob(gp = gpar(col = "grey75"))
panelsR = panels$r[-length(panels$r)]
for(i in panelsR+1) g = gtable_add_grob(g, linesGrob,
t=unique(panels$b+1),
l=i,
b=unique(panels$b+2))
# Insert new columns of zero width to take the line grobs for the first and last boundary lines
panelBound = c(4, max(panels$r)+1)
for(i in panelBound) {
g = gtable_add_cols(g, unit(0, "lines"), i)
g = gtable_add_grob(g, linesGrob,
t=unique(panels$b+1),
l=i+1,
b=unique(panels$b+2))
}
# remove the old strip
g = g[-7, ]
# Draw it
grid.newpage()
grid.draw(g)
Line chart plotting nested categorical values for multiple groups (ggplot2)
Here is one option with ggh4x::guide_axis_nested()
. You can combine labels of super- and subcategories, which the guide will separate into different lines. Disclaimer: I'm the author of that function.
library(ggplot2)
hotels = data.frame(category = rep(c("room","room","service","service","overall rating"),each = 3),
subcategory = rep(c("comfort","cleanliness","professionalism","promptness","overall rating"),each = 3),
brand = rep(c("hotel 1","hotel 2","hotel 3"),times = 5),
score = c(6,10,4,7,9,2,6,9,5,9,7,3,6,8,3))
hotels$category = factor(hotels$category, levels = c("room","service","overall rating"))
hotels$subcategory = factor(hotels$subcategory, levels =c("comfort","cleanliness","professionalism","promptness","overall rating"))
# plot
library(dplyr)
library(ggplot2)
hotels %>%
ggplot(aes(x=paste0(subcategory, "&", category),
y=score, group=brand, color=brand)) +
geom_line() +
geom_point() +
guides(x = ggh4x::guide_axis_nested(delim = "&"))
Created on 2021-09-29 by the reprex package (v2.0.1)
Excel Graph - Category and Subcategory grouping
Here i my take on it. Unfortunately I can't post the screenshots as I don't have enough posts.
One solution is to use pivot charts put Amount in "Values", Category in "Row Lables", and SubCategory in "Column Labels".
I uploaded relevant images on a free image upload service.
This is our source data:
Amount Decription Category SubCategory
100 boat purchase boats 3 engine boat
200 boat purchase boats 2 engine boat
500 plane purchase planes 4 engine plane
900 car purchase cars 1 engine car
450 boat purchase boats 2 engine boat
110 plane purchase planes 4 engine plane
550 car purchase cars 1 engine car
230 car purchase cars 2 engine car
450 car purchase cars 5 engine car
This is the desired graph (Edit: This has ghost bars):
http://imageshack.us/photo/my-images/849/pivot.gif/
I just read the comment about no ghost graphs. This might be what you are looking for:
http://imageshack.us/photo/my-images/266/pivotnoghost.gif/
Just googled and found something very similar here:
peltiertech.com/WordPress/using-pivot-table-data-for-a-chart-with-a-dual-category-axis/
You need to add http:// ( I can't have more than two hyperlinks due to low number of posts)
Add Sub categories to y axis on highcharts
You have missing grouped-categories
plugin, but as you can see in this example: http://jsfiddle.net/BlackLabel/46j9xsow/ it doesn't play well with y-axis.
As a solution I recommend you to use inverted chart and grouped categories on x-axis.
chart: {
inverted: true
}
Live demo: http://jsfiddle.net/BlackLabel/sm2qbgkr/
API Reference: https://api.highcharts.com/highcharts/chart.inverted
Docs: https://www.npmjs.com/package/highcharts-grouped-categories
How to plot Multiple variables (i.e. Categories) in a Bar graph in ggplot2 in R
You can achieve something similar to the example from Excel using facets and some options.
Source_Data %>%
ggplot(aes(Product_Name, Cost)) +
geom_col(aes(fill = Product_desc), position = position_dodge(preserve = "single")) +
facet_wrap(~key, scales = "free_x", strip.position = "bottom") +
theme(strip.placement = "outside") +
theme_bw()
Result:
Plotting a bar chart with multiple groups
Styling always involves a bit of fiddling and trial (and sometimes error (;). But generally you could probably get quite close to your desired result like so:
library(ggplot2)
ggplot(example, aes(categorical_var, n)) +
geom_bar(position="dodge",stat="identity") +
# Add some more space between groups
scale_x_discrete(expand = expansion(add = .9)) +
# Make axis start at zero
scale_y_continuous(expand = expansion(mult = c(0, .05))) +
# Put facet label to bottom
facet_wrap(~treatment, strip.position = "bottom") +
theme_minimal() +
# Styling via various theme options
theme(panel.spacing.x = unit(0, "pt"),
strip.placement = "outside",
strip.background.x = element_blank(),
axis.line.x = element_line(size = .1),
panel.grid.major.y = element_line(linetype = "dotted"),
panel.grid.major.x = element_blank(),
panel.grid.minor = element_blank())
Related Topics
Read Column Names as Date Format
Add a Constant Value to All Rows in a Dataframe
Cannot Install Library(Xlsx) in R and Look for an Alternative
"Non-Finite Function Value" When Using Integrate() in R
R:Function to Generate a Mixture Distribution
Ggplot Scale_X_Continuous with Symbol: Make Bold
Create a Variable That Identifies the Original Data.Frame After Rbind Command in R
Convert Numeric Vector to Binary (0/1) Based on Limit
How to Set Ggplot X-Label Equal to Variable Name During Lapply
How to Substitute Symbols in a Language Object
Error Using T.Test() in R - Not Enough 'Y' Observations
Sum Columns Row-Wise with Similar Names
Find Closest Points (Lat/Lon) from One Data Set to a Second Data Set
Separate a Column into Multiple Columns Using Tidyr::Separate with Sep=""
How to Subset Column Variables in Df1 Based on the Important Variables I Got in Df2