How to Plot Charts with Nested Categories Axes

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)

Sample Image

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 = "&"))

Sample Image

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:

Sample Image

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())

Sample Image



Related Topics



Leave a reply



Submit