three_states <- sample(state.name, 3)
data.frame(
states = factor(rep(three_states, 3), levels = three_states),
vals = c(10, 20, 30, 6, 14, 40, 30, 20, 10),
col = rep(c("blue", "black", "red"), 3),
fct = c(rep("Thing 1", 3), rep("Thing 2", 3), rep("Thing 3", 3))
) -> xdf
xdf
## states vals col fct
## 1 Nebraska 10 blue Thing 1
## 2 Ohio 20 black Thing 1
## 3 Wyoming 30 red Thing 1
## 4 Nebraska 6 blue Thing 2
## 5 Ohio 14 black Thing 2
## 6 Wyoming 40 red Thing 2
## 7 Nebraska 30 blue Thing 3
## 8 Ohio 20 black Thing 3
## 9 Wyoming 10 red Thing 3
We’ll use this as a base for some of the examples to enable focusing on tweaking the contents of geom_waffle()
:
This likely should be the default. Waffles work best when they are square (makes it easier to compare parts to whole which is the purpose of the chart). You could do this normalization prior to passing data into geom_waffle()
or let it do it for you with the make_proportional
parameter.
Need to be careful as this can shift perception to the background grid vs the data encoding you’re trying to present.
You can use this to match any background you’re going to use or to just provide a different aesthetic feel. Note that the same problem can occur here as in the “bigger lines” case and attention can be inadvertedly shifted to the grid lines vs the colored proportions.
We can also “fill in the lines” but that pretty much makes it not a waffle chart:
You can also map the colour
aesthetic to a column which can help make a “highlight” effect, but that’s going to also contribute to perception skew:
waf +
geom_waffle(
aes(colour = states),
n_rows = 10, size = 0.45, make_proportional = TRUE
) +
scale_colour_manual(
values = c(alpha("black", 1/3), "black", alpha("black", 1/3))
)
You can possibly correct for perception skew by shrinking the width and the height of each cell to make some room for the strokes:
waf +
geom_waffle(
aes(colour = states),
n_rows = 10, size = 0.3, make_proportional = TRUE,
height = 0.9, width = 0.9
) +
scale_colour_manual(
values = c("white", "black", "white")
)
You might be better off just changing the alpha value’s though:
To mix things up you can also round out the corners by specifying a grid::unit()
value to the radius
parameter. This isn’t generally recommended as the goal is to enable quick mental perception for parts to whole and the rounded corners can delay and/or skew said interpretation.
Here that is with and without proportional waffles:
waf +
geom_waffle(
n_rows = 10, size = 0.5, colour = "white",
make_proportional = TRUE,
radius = unit(4, "pt")
)
Also, think twice when changing the stroke color as it continues to contribute to perception skew. Consider shrinking the cells to add more space between them if you choose to do this:
waf +
geom_waffle(
n_rows = 10, size = 1, colour = "black",
make_proportional = TRUE,
radius = unit(4, "pt"),
height = 0.8, width = 0.8
)
You can also use this for the same highlight effect as above:
You can make a bar-like chart with the waffles by using facet wrapping and hacking on strip spacing:
Since you now know we can use faceting, we can go all sorts of crazy. We’ll do another setup for this waffle buffet:
If you have parts-of-a-whole groups you want to compare across observations you can facet on another variable
buf +
geom_waffle(
color = "white", size = 0.33
) +
facet_wrap(~fct) +
theme(strip.text.x = element_text(hjust = 0.5))
Again, waffles generally work better when they are square and each one sums to 100 and this is even more true in a buffet grid of waffles:
buf +
geom_waffle(
color = "white", size = 0.33,
make_proportional = TRUE, n_rows = 10
) +
facet_wrap(~fct) +
theme(legend.position = "bottom") +
theme(strip.text.x = element_text(hjust = 0.5))
They can be rounded tiles as well:
buf +
geom_waffle(
color = "white", size = 0.33,
make_proportional = TRUE, n_rows = 10,
radius = unit(2, "pt")
) +
facet_wrap(~fct) +
theme(legend.position = "bottom") +
theme(strip.text.x = element_text(hjust = 0.5))
And, you can do the highlight hack:
buf +
geom_waffle(
color = "white", size = 0.33,
make_proportional = TRUE, n_rows = 10,
radius = unit(2, "pt")
) +
facet_wrap(~fct) +
scale_fill_manual(
values = c("#f8766d", alpha("#00ba38", 1/3), alpha("#619cff", 1/3))
) +
theme(legend.position = "bottom") +
theme(strip.text.x = element_text(hjust = 0.5))
If you aren’t going to use proportional waffle buffet charts consider altering the aesthetics to make them waffle bars instead:
storms %>%
filter(year >= 2010) %>%
count(year, status) -> storms_df
ggplot(storms_df, aes(fill = status, values = n)) +
geom_waffle(color = "white", size = .25, n_rows = 10, flip = TRUE) +
facet_wrap(~year, nrow = 1, strip.position = "bottom") +
scale_x_discrete() +
scale_y_continuous(labels = function(x) x * 10, # make this multiplyer the same as n_rows
expand = c(0,0)) +
ggthemes::scale_fill_tableau(name=NULL) +
coord_equal() +
labs(
title = "Faceted Waffle Bar Chart",
subtitle = "{dplyr} storms data",
x = "Year",
y = "Count"
) +
theme_minimal(base_family = "Roboto Condensed") +
theme(panel.grid = element_blank(), axis.ticks.y = element_line()) +
guides(fill = guide_legend(reverse = TRUE))