Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Welcome To Ask or Share your Answers For Others

Categories

0 votes
879 views
in Technique[技术] by (71.8m points)

r - Combine geom_tile() and facet_grid/facet_wrap and remove space between tiles (ggplot2)

I have a data set with x, y, and z (resp) values along with two columns for facetting in order to create a grid of tile plots.

The output of dput() is at the end of the post.

library(ggplot2)

My actual data set has six unique interactions between variables, however I've limited it to four for simplicity. I can create a tile plot with each unique combination, but not the whole set. The output of dput() is at the end of the post. I thought it might have to do with ggplot needing a common y axis scale, but that's not the issue.

library(ggplot2)
p <- ggplot(data_sub, aes(x = x, y = y)) + geom_tile(aes(fill = resp))
p <- p + facet_wrap(var2 ~ var1, scales = "free", ncol = 2)

The output:

tile plot with white space

Plotted on their own, there is no such white space:

x1x2 <- data_sub[data_sub$var1 == "x1" & data_sub$var2 == "x3", ]
ggplot(x1x2, aes(x = x, y = y)) + geom_tile(aes(fill = resp))

filled in single tile plot

I believe the issue is defining some sort of dynamic height and width aesthetic in the geom_tile() call, but I'm not sure how to do this. It seems that a single tile plot will use something like diff((unique(x)) to come up with the appropriate height, but I'm not sure how to do that for each facet level -- is the only way to create such columns in my data frame?


The data:

dput(data_sub)
structure(list(x = c(-3, -2.33333333333333, -1.66666666666667, 
-1, -0.333333333333333, 0.333333333333333, 1, 1.66666666666667, 
2.33333333333333, 3, -3, -2.33333333333333, -1.66666666666667, 
-1, -0.333333333333333, 0.333333333333333, 1, 1.66666666666667, 
2.33333333333333, 3, -3, -2.33333333333333, -1.66666666666667, 
-1, -0.333333333333333, 0.333333333333333, 1, 1.66666666666667, 
2.33333333333333, 3, -3, -2.33333333333333, -1.66666666666667, 
-1, -0.333333333333333, 0.333333333333333, 1, 1.66666666666667, 
2.33333333333333, 3, -3, -2.33333333333333, -1.66666666666667, 
-1, -0.333333333333333, 0.333333333333333, 1, 1.66666666666667, 
2.33333333333333, 3, -3, -2.33333333333333, -1.66666666666667, 
-1, -0.333333333333333, 0.333333333333333, 1, 1.66666666666667, 
2.33333333333333, 3, -3, -2.33333333333333, -1.66666666666667, 
-1, -0.333333333333333, 0.333333333333333, 1, 1.66666666666667, 
2.33333333333333, 3, -3, -2.33333333333333, -1.66666666666667, 
-1, -0.333333333333333, 0.333333333333333, 1, 1.66666666666667, 
2.33333333333333, 3, -3, -2.33333333333333, -1.66666666666667, 
-1, -0.333333333333333, 0.333333333333333, 1, 1.66666666666667, 
2.33333333333333, 3, -3, -2.33333333333333, -1.66666666666667, 
-1, -0.333333333333333, 0.333333333333333, 1, 1.66666666666667, 
2.33333333333333, 3, -3, -2.33333333333333, -1.66666666666667, 
-1, -0.333333333333333, 0.333333333333333, 1, 1.66666666666667, 
2.33333333333333, 3, -3, -2.33333333333333, -1.66666666666667, 
-1, -0.333333333333333, 0.333333333333333, 1, 1.66666666666667, 
2.33333333333333, 3, -3, -2.33333333333333, -1.66666666666667, 
-1, -0.333333333333333, 0.333333333333333, 1, 1.66666666666667, 
2.33333333333333, 3, -3, -2.33333333333333, -1.66666666666667, 
-1, -0.333333333333333, 0.333333333333333, 1, 1.66666666666667, 
2.33333333333333, 3, -3, -2.33333333333333, -1.66666666666667, 
-1, -0.333333333333333, 0.333333333333333, 1, 1.66666666666667, 
2.33333333333333, 3, -3, -2.33333333333333, -1.66666666666667, 
-1, -0.333333333333333, 0.333333333333333, 1, 1.66666666666667, 
2.33333333333333, 3, -3, -2.33333333333333, -1.66666666666667, 
-1, -0.333333333333333, 0.333333333333333, 1, 1.66666666666667, 
2.33333333333333, 3, -3, -2.33333333333333, -1.66666666666667, 
-1, -0.333333333333333, 0.333333333333333, 1, 1.66666666666667, 
2.33333333333333, 3, -3, -2.33333333333333, -1.66666666666667, 
-1, -0.333333333333333, 0.333333333333333, 1, 1.66666666666667, 
2.33333333333333, 3, -3, -2.33333333333333, -1.66666666666667, 
-1, -0.333333333333333, 0.333333333333333, 1, 1.66666666666667, 
2.33333333333333, 3, 0, 0.111111111111111, 0.222222222222222, 
0.333333333333333, 0.444444444444444, 0.555555555555556, 0.666666666666667, 
0.777777777777778, 0.888888888888889, 1, 0, 0.111111111111111, 
0.222222222222222, 0.333333333333333, 0.444444444444444, 0.555555555555556, 
0.666666666666667, 0.777777777777778, 0.888888888888889, 1, 0, 
0.111111111111111, 0.222222222222222, 0.333333333333333, 0.444444444444444, 
0.555555555555556, 0.666666666666667, 0.777777777777778, 0.888888888888889, 
1, 0, 0.111111111111111, 0.222222222222222, 0.333333333333333, 
0.444444444444444, 0.555555555555556, 0.666666666666667, 0.777777777777778, 
0.888888888888889, 1, 0, 0.111111111111111, 0.222222222222222, 
0.333333333333333, 0.444444444444444, 0.555555555555556, 0.666666666666667, 
0.777777777777778, 0.888888888888889, 1, 0, 0.111111111111111, 
0.222222222222222, 0.333333333333333, 0.444444444444444, 0.555555555555556, 
0.666666666666667, 0.777777777777778, 0.888888888888889, 1, 0, 
0.111111111111111, 0.222222222222222, 0.333333333333333, 0.444444444444444, 
0.555555555555556, 0.666666666666667, 0.777777777777778, 0.888888888888889, 
1, 0, 0.111111111111111, 0.222222222222222, 0.333333333333333, 
0.444444444444444, 0.555555555555556, 0.666666666666667, 0.777777777777778, 
0.888888888888889, 1, 0, 0.111111111111111, 0.222222222222222, 
0.333333333333333, 0.444444444444444, 0.555555555555556, 0.666666666666667, 
0.777777777777778, 0.888888888888889, 1, 0, 0.111111111111111, 
0.222222222222222, 0.333333333333333, 0.444444444444444, 0.555555555555556, 
0.666666666666667, 0.777777777777778, 0.888888888888889, 1, 0, 
0.111111111111111, 0.222222222222222, 0.333333333333333, 0.444444444444444, 
0.555555555555556, 0.666666666666667, 0.777777777777778, 0.888888888888889, 
1, 0, 0.111111111111111, 0.222222222222222, 0.333333333333333, 
0.444444444444444, 0.555555555555556, 0.666666666666667, 0.777777777777778, 
0.888888888888889, 1, 0, 0.111111111111111, 0.222222222222222, 
0.333333333333333, 0.444444444444444, 0.555555555555556, 0.666666666666667, 
0.777777777777778, 0.888888888888889, 1, 0, 0.111111111111111, 
0.222222222222222, 0.333333333333333, 0.444444444444444, 0.555555555555556, 
0.666666666666667, 0.777777777777778, 0.888888888888889, 1, 0, 
0.111111111111111, 0.222222222222222, 0.333333333333333, 0.444444444444444, 
0.555555555555556, 0.666666666666667, 0.777777777777778, 0.888888888888889, 
1, 0, 0.111111111111111, 0.222222222222222, 0.333333333333333, 
0.444444444444444, 0.555555555555556, 0.666666666666667, 0.777777777777778, 
0.888888888888889, 1, 0, 0.111111111111111, 0.222222222222222, 
0.333333333333333, 0.444444444444444, 0.555555555555556, 0.666666666666667, 
0.777777777777778, 0.888888888888889, 1, 0, 0.111111111111111, 
0.222222222222222, 0.333333333333333, 0.444444444444444, 0.555555555555556, 
0.666666666666667, 0.777777777777778, 0.888888888888889, 1, 0, 
0.111111111111111, 0.222222222222222, 0.333333333333333, 0.444444444444444, 
0.555555555555556, 0.666666666666667, 0.777777777777778, 0.888888888888889, 
1, 0, 0.111111111111111, 0.222222222222222, 0.333333333333333, 
0.444444444444444, 0.555555555555556, 0.666666666666667, 0.777777777777778, 
0.888888888888889, 1), y = c(5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 6.66666666666667, 
6.66666666666667, 6.66666666666667, 6.66666666666667, 6.66666666666667, 
6.66666666666667, 6.66666666666667, 6.66666666666667, 6.66666666666667, 
6.66666666666667, 8.33333333333333, 8.33333333333333, 8.33333333333333, 
8.33333333333333, 8.33333333333333, 8.33333333333333, 8.33333333333333, 
8.33333333333333, 8.33333333333333, 8.33333333333333, 10, 10, 
10, 10, 10, 10, 10, 10, 10, 10, 11.6666666666667, 11.6666666666667, 
11.6666666666667, 11.6666666666667, 11.6666666666667, 11.6666666666667, 
11.6666666666667, 11.6666666666667, 11.6666666666667, 11.6666666666667, 
13.3333333333333, 13.3333333333333, 13.3333333333333, 13.3333333333333, 
13.3333333333333, 13.3333333333333, 13.3333333333333, 13.3333333333333, 
13.3333333333333, 13.3333333333333, 15, 15, 15, 15, 15, 15, 15, 
15, 15, 15, 16.6666666666667, 16.6666666666667, 16.6666666666667, 
16.6666666666667, 16.6666666666667, 16.6666666666667, 16.6666666666667, 
16.6666666666667, 16.6666666666667, 16.6666666666667, 18.3333333333333, 
18.3333333333333, 18.3333333333333, 18.3333333333333, 18.3333333333333, 
18.3333333333333, 18.3333333333333, 18.3333333333333, 18.3333333333333, 
18.3333333333333, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 0, 
0, 0, 0, 0, 0, 0, 0, 0, 0, 0.777777777777778, 0.777777777777778, 
0.777777777777778, 0.777777777777778, 0.777777777777778, 0.777777777777778, 
0.777777777777778, 0.777777777777778, 0.777777777777778, 0.777777777777778, 
1.55555555555556, 1.55555555555556, 1.55555555555556, 1.55555555555556, 
1.55555555555556, 1.55555555555556, 1.55555555555556, 1.55555555555556, 
1.55555555555556, 1.55555555555556, 2.33333333333333, 2.33333333333333, 
2.33333333333333, 2.33333333333333, 2.33333333333333, 2.33333333333333, 
2.33333333333333, 2.33333333333333, 2.33333333333333, 2.33333333333333, 
3.11111111111111, 3.11111111111111, 3.11111111111111, 3.11111111111111, 
3.11111111111111, 3.11111111111111, 3.11111111111111, 3.11111111111111, 
3.11111111111111, 3.11111111111111, 3.88888888888889, 3.88888888888889, 
3.88888888888889, 3.88888888888889, 3.88888888888889, 3.88888888888889, 
3.88888888888889, 3.88888888888889, 3.88888888888889, 3.88888888888889, 
4.66666666666667, 4.66666666666667, 4.66666666666667, 4.66666666666667, 
4.66666666666667, 4.66666666666667, 4.66666666666667, 4.66666666666667, 
4.66666666666667, 4.66666666666667, 5.44444444444444, 5.44444444444444, 
5.44444444444444, 5.44444444444444, 5.44444444444444, 5.44444444444444, 
5.44444444444444, 5.44444444444444, 5.44444444444444, 5.44444444444444, 
6.22222222222222, 6.22222222222222, 6.22222222222222, 6.22222222222222, 
6.22222222222222, 6.22222222222222, 6.22222222222222, 6.22222222222222, 
6.22222222222222, 6.22222222222222, 7, 7, 7, 7, 7, 7, 7, 7, 7, 
7, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 6.66666666666667, 6.66666666666667, 
6.66666666666667, 6.66666666666667, 6.66666666666667, 6.66666666666667, 
6.66666666666667, 6.66666666666667, 6.66666666666667, 6.66666666666667, 
8.33333333333333, 8.33333333333333, 8.33333333333333, 8.33333333333333, 
8.33333333333333, 8.33333333333333, 8.33333333333333, 8.33333333333333, 
8.33333333333333, 8.33333333333333, 10, 10, 10, 10, 10, 10, 10, 
10, 10, 10, 11.6666666666667, 11.6666666666667, 11.6666666666667, 
11.6666666666667, 11.6666666666667, 11.6666666666667, 11.6666666666667, 
11.6666666666667, 11.6666666666667, 11.6666666666667, 13.3333333333333, 
13.3333333333333, 13.3333333333333, 13.3333333333333, 13.3333333333333, 
13.3333333333333, 13.3333333333333, 13.3333333333333, 13.3333333333333, 
13.3333333333333, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 16.6666666666667, 
16.6666666666667, 16.6666666666667, 16.6666666666667, 16.6666666666667, 
16.6666666666667, 16.6666666666667, 16.6666666666667, 16.6666666666667, 
16.6666666666667, 18.3333333333333, 18.3333333333333, 18.3333333333333, 
18.3333333333333, 18.3333333333333, 18.3333333333333, 18.3333333333333, 
18.3333333333333, 18.3333333333333, 18.3333333333333, 20, 20, 
20, 20, 20, 20, 20, 20, 20, 20, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 
0.777777777777778, 0.777777777777778, 0.777777777777778, 0.777777777777778, 
0.777777777777778, 0.777777777777778, 0.777777777777778, 0.777777777777778, 
0.777777777777778, 0.777777777777778, 1.55555555555556, 1.55555555555556

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome To Ask or Share your Answers For Others

1 Reply

0 votes
by (71.8m points)

I ran into two issues:

1) My true data set is generated via fit <- lm(x ~ y), followed by creating a new input data set via expand.grid, and then creating my plot data with predict(fit, newdata). Oddly, if I don't round the x and y points, I can't generate a plot (full code for creating my plot data is below).

2) When plotting one geom_tile plot, the height/width of the tiles are set to fill the space. When creating a facetted set of tile plots, it seems that the height and width arguments for geom_tile() default to something else. I'd say they default to the smallest range, but no plot actually fills the full facet window width or height... so it's not that.

Apologies for the example above not being reproducible. I didn't expect that dput() wouldn't create an identical data set and it was much simpler to just paste the output of that than have someone run all the code below.


Full code for generating the data set:

set.seed(42)
x1 <- rnorm(20)
x2 <- runif(20)
x3 <- rpois(20,10)
x4 <- rexp(20)
y <- 10 + 2*x1 + 3*x2^2 + 4*x3 +5*x4 + rnorm(20, sd=0.1)

dat <- data.frame(x1, x2, x3, x4, y)

# vector of variable names for easy data.frame column naming later
var_names <- c("x1", "x2", "x3", "x4")

# possible combinations of four variables
combis <- combn(1:4, 2)
combis <- rbind(combis, combis[, 6:1])

# steps to generate for the contour using `rep(min, max, length.out = n)`
n <- 100

#fit the model
fit <- lm(y~x1+I(x2^2)+x3+x4, data=dat)

# range values for when variable is featured on an axis
mins_maxs <- data.frame(x1 = c(-3, 3),
                        x2 = c(0, 1),
                        x3 = c(5, 20),
                        x4 = c(0, 7))

# values to hold for plots in which variables are not on an axis
holds <- c(0, 0.5, 10, 5)

sim_data <- list()
sim_data <- lapply(seq_len(ncol(combis)), function (i) {
  sim_data[[i]] <- expand.grid(seq(mins_maxs[1, combis[1, i]], 
                                   mins_maxs[2, combis[1, i]], length.out = n),
                               seq(mins_maxs[1, combis[2, i]], 
                                   mins_maxs[2, combis[2, i]], length.out = n),
                               holds[combis[3, i]],
                               holds[combis[4, i]])
} )

# we create a new data frame for the data set we want to plot
# for each contour of interest, we want the first two columns, as the second two
# were only created for the sake of feeding into our fit lm 
# we'll also create a vector for facetting using paste()
plot_data <- list()
plot_data <- lapply(1:ncol(combis), function(i) {
  plot_data[[i]] <- sim_data[[i]][, 1:2]
  plot_data[[i]]$var1 <- rep(var_names[combis[1, i]],
                             nrow(plot_data[[i]]))
  plot_data[[i]]$var2 <- rep(var_names[combis[2, i]],
                                   nrow(plot_data[[i]]))
  return(plot_data[[i]])
} )

# now we rename the columns of plot_data
plot_data <- lapply(1:length(plot_data), function(i) {
  names(plot_data[[i]]) <- c("x", "y", "var1", "var2")
  return(plot_data[[i]])
} )

# similarly, we need to re-name the sim_data columns so we can rbind them
# and predict new values using our fit lm
sim_data <- lapply(1:length(sim_data), function(i) {
  names(sim_data[[i]]) <- var_names[combis[, i]]
  return(sim_data[[i]])
} )


# collapse the separate lists into one data.frame
plot_data <- do.call(rbind, plot_data)
sim_data <- do.call(rbind, sim_data)

# create a vector of predictions using sim_data
plot_data$resp <- predict(fit, sim_data)

At this point, if one attempts to plot using plot_data, we get this:

library(ggplot2)
p <- ggplot(plot_data, aes(x = x, y = y, z = resp))
p <- p + geom_tile(aes(fill = resp))
p <- p + facet_wrap(var2 ~ var1, scales = "free", ncol = 3) + theme_bw()

data as-is

If we round the data, we get something else:

plot_data_round <- plot_data
plot_data_round[, c("x", "y")] <- round(plot_data_round[, c("x", "y")], 5)

# same plot call as above
p <- ggplot(plot_data_round, aes(x = x, y = y, z = resp))
p <- p + geom_tile(aes(fill = resp))
p <- p + facet_wrap(var2 ~ var1, scales = "free", ncol = 3) + theme_bw()

data with rounding

If we take the un-rounded data and add vectors to store height and width, we're back to a blank facetted plot like the un-rounded data alone.

plot_data_hw <- plot_data
hw <- ddply(plot_data, .(var1, var2), summarize,
            height = (max(y) - min(y))/n, width = (max(x) - min(x))/n)
plot_data_hw <- merge(plot_data_hw, hw, by = c("var1", "var2"), all.x = T)
# verify using same plot call and plot_data_hw

If we combine rounding and height and width values per facet interaction, we get the desired result (adding height/width arguments to geom_tile()):

plot_data_hw_round <- merge(plot_data_round, hw, by = c("var1", "var2"), all.x = T)
p <- ggplot(plot_data_hw_round, aes(x = x, y = y, z = resp))
p <- p + geom_tile(aes(fill = resp, height = height, width = width))
p <- p + facet_wrap(var2 ~ var1, scales = "free", ncol = 3) + theme_bw()

facetted tile map as desired

So, there it is. I'm going to file a bug report about the rounding issue, as that seems quite peculiar to me. Perhaps there's still something going on other than that, but if it is a but due to floating point precision or whatnot, Hadley may still be interested.


与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
OGeek|极客中国-欢迎来到极客的世界,一个免费开放的程序员编程交流平台!开放,进步,分享!让技术改变生活,让极客改变未来! Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Click Here to Ask a Question

...