user1420372
user1420372

Reputation: 2187

Scale density plots in ggplot2 to have same x-axis range

I want to overlay two density plots; one of data prior to transformation and one after. I don't care about the x and y values, only the shape of the curve.

I want to superimpose the 2 charts for a given Predictor on top of each other, even though the x-axis is different. I find it hard to look across the two facets. In reality, as well, there will be a lot more plots, so combining the non-transformed and transformed data into the one would be the best solution.

library(tidyverse)
require(caret)
data(BloodBrain)
bbbTrans <- preProcess(select(bbbDescr, adistd, adistm, dpsa3, inthb), method = "YeoJohnson")
bbbTransData <- predict(bbbTrans, select(bbbDescr, adistd, adistm, dpsa3, inthb)) 
dat <- bbbTransData %>%
  gather(Predictor, Value) %>%
  mutate(Transformation = "Yeo-Johnson") %>%
  bind_rows(data.frame(gather(select(bbbDescr, adistd, adistm, dpsa3, inthb), Predictor, Value), Transformation = "NA", stringsAsFactors = FALSE))  



# For the predictor adistd, I would like the x-axis range to be 0:12.5 for the
# "Yeo-Johnson" transformation and 0:250 for no transformation.  In this plot, it
# is hard to see the shape of the transformed variables due to the different x-value range.
dat %>% ggplot(aes(x = Value, color = Transformation)) +  
  geom_density(aes(y = ..scaled..), position = "dodge") + 
  facet_wrap(~Predictor, scales = "free")


# i.e., I want to superimpose the 2 charts for a given Predictor on top of each other, even though the x-axis is different
# I find it hard to look across the two facets.  In reality, as well, there will be a lot more plots, so combining the non-transformed and transformed data into the one plot using colour would be the best solution.
  filter(dat, Transformation != 'NA') %>% ggplot(aes(x = Value, y = ..scaled..)) +  
  geom_density() + 
  facet_wrap(~Predictor, scales = "free")

  filter(dat, Transformation == 'NA') %>% ggplot(aes(x = Value, y = ..scaled..)) +  
  geom_density() + 
  facet_wrap(~Predictor, scales = "free")

Edit: The algorithm I think I need is (and prefer to do using tidyverse):

  1. Group by predictor/transformation
  2. Get density for each
  3. Transform x of density to (x-xmin)/(xmax-xmin) so that between 0 to 1
  4. Plot transformed density$x, density$y

Upvotes: 1

Views: 1131

Answers (1)

pogibas
pogibas

Reputation: 28329

Solution that scales (base::scale) and calculates density (stats::density). density function outputs same number of equally spaced points so we can arrange them from 0 to 1 (as OP wants).

# How many points we want 
nPoints <- 1e3

# Final result
res <- list()

# Using simple loop to scale and calculate density
combinations <- expand.grid(unique(dat$Predictor), unique(dat$Transformation))
for(i in 1:nrow(combinations)) {
    # Subset data
    foo <- subset(dat, Predictor == combinations$Var1[i] & Transformation == combinations$Var2[i])
    # Perform density on scaled signal
    densRes <- density(x = scale(foo$Value), n = nPoints)
    # Position signal from 1 to wanted number of points
    res[[i]] <- data.frame(x = 1:nPoints, y = densRes$y, 
                           pred = combinations$Var1[i], trans = combinations$Var2[i])
}
res <- do.call(rbind, res)
ggplot(res, aes(x / nPoints, y, color = trans, linetype = trans)) +
    geom_line(alpha = 0.5, size = 1) +
    facet_wrap(~ pred, scales = "free")

enter image description here

Upvotes: 1

Related Questions