0

I'm aware there are similar posts but I could not get those answers to work in my case.

e.g. Here and here.

Example:

diamonds %>% 
  ggplot(aes(scale(price) %>% as.vector)) +
  geom_density() +
  xlim(-3, 3) +
  facet_wrap(vars(cut))

Returns a plot: enter image description here

Since I used scale, those numbers are the zscores or standard deviations away from the mean of each break.

I would like to add as a row underneath the equivalent non scaled raw number that corresponds to each.

Tried:

diamonds %>% 
  ggplot(aes(scale(price) %>% as.vector)) +
  geom_density() +
  xlim(-3, 3) +
  facet_wrap(vars(cut)) +
  geom_text(aes(label = price))

Gives:

Error: geom_text requires the following missing aesthetics: y

My primary question is how can I add the raw values underneath -3:3 of each break? I don't want to change those breaks, I still want 6 breaks between -3:3.

Secondary question, how can I get -3 and 3 to actually show up in the chart? They have been trimmed.

[edit] I've been trying to make it work with geom_text but keep hitting errors:

diamonds %>% 
  ggplot(aes(x = scale(price) %>% as.vector)) +
  geom_density() +
  xlim(-3, 3) +
  facet_wrap(vars(cut)) +
  geom_text(label = price)

Error in layer(data = data, mapping = mapping, stat = stat, geom = GeomText, : object 'price' not found

I then tried changing my call to geom_text()

  geom_text(data = diamonds, aes(price), label = price)

This results in the same error message.

Doug Fir
  • 19,971
  • 47
  • 169
  • 299

2 Answers2

2

You can make a custom labeling function for your axis. This takes each label on the axis and performs a custom transform for you. In your case you could paste the z score, a line break, and the z-score times the standard deviation plus the mean. Because of the distribution of prices in the diamonds data set, this means that z scores below about -1 represent negative prices. This may not be a problem in your own data. For clarity I have drawn in a vertical line representing $0

labeller <- function(x) {
  paste0(x,"\n",  scales::dollar(sd(diamonds$price) * x + mean(diamonds$price)))
}

diamonds %>% 
  ggplot(aes(scale(price) %>% as.vector)) +
  geom_density() +
  geom_vline(aes(xintercept = -0.98580251364833), linetype = 2) +
  facet_wrap(vars(cut)) +
  scale_x_continuous(label = labeller, limits = c(-3, 3)) +
  xlab("price")

enter image description here

Allan Cameron
  • 147,086
  • 7
  • 49
  • 87
1

We can use the sec_axis functionality in scale_x_continuous. To use this functionality we need to manually scale your data. This will add a secondary axis at the top of the plot, not underneath. So it's not quite exactly what you're looking for.

library(tidyverse)
# manually scale the data
mean_price <- mean(diamonds$price)
sd_price <- sd(diamonds$price)
diamonds$price_scaled <- (diamonds$price - mean_price) / sd_price
# make the plot
ggplot(diamonds, aes(price_scaled))+
geom_density()+
facet_wrap(~cut)+
scale_x_continuous(sec.axis = sec_axis(~ mean_price + (sd_price * .)),
                   limits = c(-3, 4), breaks = -3:3)

You could cheat a bit by passing some dummy data to geom_text:

geom_text(data = tibble(label = round(((-3:3) * sd_price) + mean_price),
                            y = -0.25,
                            x = -3:3),
              aes(x, y, label = label))
bouncyball
  • 10,631
  • 19
  • 31
  • Thanks for the answer this is helpful. I'm going to hold out for a method that places the text under the existing x axis though, like in the first SO link above. Been trying and failing with geom_text – Doug Fir Aug 03 '20 at 21:19