1

I'm trying to make a bar chart with a 3rd variable (which in this case is "frequency") where the 3rd variable changes the width of the bars (higher frequency = larger width). Obviously I have to figure out the sizing, but that is just aesthetics and I can figure that out later. When I use this code I keep getting the error "position_dodge requires non-overlapping x intervals" and the plot then stacks the bars instead of grouping them. Also (maybe this could help) wondering if there is a way to increase the distance between labels on the x-axis (meaning increase the distance between "Iso", "Transition", "P&R Handler", etc.) All help appreciated.

library(tidyverse)
library(ggrepel)
percentile_playtype = c(70.10, 41.20, 83.90, 0, 0, 97.30, 40, 0, 49.30, 20.10, 88.90, 91.80,
                        94.60, 0, 83.60, 86.90, 42, 41.10, 46.90, 0, 81.50, 84.00)
frequency = c(8.5,16.5,53.3,0,0,6,7.2,0,2.1,0.6,5.4,1.9,12.4,0,28,8.1,16,1.9,13.6,0,10.6,6.1)
v1 = sqrt(sqrt(sqrt(frequency)))/10
lowsize <- element_text(size=8)
playtype = c("Iso","Transition","P&R Handler","P&R Roll","Post Up","Spot Up",
             "Handoff","Cut","Off Screen","Putbacks","Misc")
Player = rep(c("Trae Young","John Collins"), each=11)
PlayData <- data.frame(percentile_playtype,frequency,playtype,Player)
a1 <- ggplot(PlayData, aes(fill=Player, y=percentile_playtype, x=playtype)) + 
  geom_bar(position="dodge", stat="identity",width=v1)
a1
2
  • 1
    Hi Luke. What you are trying to do is use width for an aesthetic mapping. This isn't available in ggplot, and you can't do it by just passing a vector of widths to width =. It's possible to get the effect you are looking for, but it would be involved and difficult. My guess is that even if you could do it easily, the end result would look kinda lame. There are other, better ways to represent these numbers in a nice plot. Commented Jul 31, 2020 at 18:43
  • Do you have any suggestions? I tried using labels instead and using geom_label_repel to help make the labels look nicer, but the plot just wouldn't work (labels would be incorrectly placed everywhere). One idea I did have was add labels with varying size for emphasis and that would certainly be enough for me, but I need to make sure the labels signify what bar they belong to. Commented Jul 31, 2020 at 19:05

2 Answers 2

1

If you really want frequency to be mapped to bar width, you need to do it the hard way, and calculate those widths, plotting geom_rect rather than geom_bar. From a visual impact point of view it is better to scale the area of the bars rather than their absolute width:

PlayData$playtype_n <- as.numeric(as.factor(PlayData$playtype))
PlayData$frequency_n <- PlayData$frequency/max(PlayData$frequency) * 0.5 / 
                        (PlayData$percentile_playtype / 100) *
                        (2 * as.numeric(as.factor(PlayData$Player)) - 3) +
                        as.numeric(as.factor(PlayData$playtype))


ggplot(PlayData, aes(fill = Player)) + 
  geom_rect(aes(xmin = playtype_n, xmax = frequency_n, ymin = 0,
                ymax = percentile_playtype)) +
  scale_x_continuous(breaks = sort(unique(PlayData$playtype_n)),
                     labels = levels(as.factor(PlayData$playtype))) +
  scale_fill_manual(values = c("deepskyblue4", "orange")) +
  labs(x = "Play type (area scaled to frequency)", y = "Percentile playtype") +
  theme_bw()

enter image description here

Personally, I don't think this looks great, and I'm not convinced it's worth the trouble. Another, easier to understand approach might be to use facets

ggplot(PlayData, aes(fill=frequency, y=percentile_playtype, x=playtype)) + 
  geom_col(position = "dodge", width=0.75) +
  geom_text(aes(label = frequency), vjust = 1.5, color = "white") +
  facet_wrap(Player~., ncol = 1) +
  scale_fill_viridis_c() +
  theme_classic() +
  theme(panel.grid.major.y = element_line(color = "gray90"),
        strip.background = element_blank(),
        strip.text.x = element_text(size = 16),
        axis.line.x.bottom = element_line())

enter image description here

Or perhaps a labelled scatter plot using ggrepel:

ggplot(PlayData, aes(percentile_playtype, frequency, color = Player)) +
  geom_point() +
  geom_text_repel(aes(label = playtype), size = 5) +
  scale_color_manual(values = c("deepskyblue4", "orange")) +
  theme_bw()

enter image description here

Sign up to request clarification or add additional context in comments.

3 Comments

The first one was what I was looking for, but the 2nd graph definitely serves better. I was also looking into having colors represent frequency, but I couldn't figure it out. Thank you so much for this.
Do you know how I can change the fill colors in the 2nd graph? I like the colors, but I feel like the colors don't properly demonstrate high vs low frequency (because of the disparity). I would prefer something a little more monochrome.
@LukeFox maybe try + scale_fill_gradient(low = "blue", high = "red") (with whatever colors you prefer)
1

Are you trying to mimic something like a mosaic plot?

percentile_playtype = c(70.10, 41.20, 83.90, 0, 0, 97.30, 40, 0, 49.30, 20.10, 88.90, 91.80,
                        94.60, 0, 83.60, 86.90, 42, 41.10, 46.90, 0, 81.50, 84.00)
frequency = c(8.5,16.5,53.3,0,0,6,7.2,0,2.1,0.6,5.4,1.9,12.4,0,28,8.1,16,1.9,13.6,0,10.6,6.1)
v1 = sqrt(sqrt(sqrt(frequency)))/10
playtype = c("Iso","Transition","P&R Handler","P&R Roll","Post Up","Spot Up",
             "Handoff","Cut","Off Screen","Putbacks","Misc")
Player = rep(c("Trae Young","John Collins"), each=11)
PlayData <- data.frame(percentile_playtype,frequency,playtype,Player)

CGPfunctions::PlotXTabs2(PlayData, 
                         x = playtype, 
                         y = Player, 
                         counts = percentile_playtype, 
                         plottype = "mosaic", 
                         x.axis.orientation = "slant",
                         sample.size.label = FALSE,
                         label.text.size = 2)

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.