Issue When Passing Variable With Dollar Sign Notation ($) to Aes() in Combination With Facet_Grid() or Facet_Wrap()

Issue when passing variable with dollar sign notation ($) to aes() in combination with facet_grid() or facet_wrap()

tl;dr

Never use [ or $ inside aes().


Consider this illustrative example where the facetting variable f is purposely in a non-obvious order with respect to x

d <- data.frame(x=1:10, f=rev(letters[gl(2,5)]))

Now contrast what happens with these two plots,

p1 <- ggplot(d) +
facet_grid(.~f, labeller = label_both) +
geom_text(aes(x, y=0, label=x, colour=f)) +
ggtitle("good mapping")

p2 <- ggplot(d) +
facet_grid(.~f, labeller = label_both) +
geom_text(aes(d$x, y=0, label=x, colour=f)) +
ggtitle("$ corruption")

Sample Image

We can get a better idea of what's happening by looking at the data.frame created internally by ggplot2 for each panel,

 ggplot_build(p1)[["data"]][[1]][,c("x","PANEL")]

x PANEL
1 6 1
2 7 1
3 8 1
4 9 1
5 10 1
6 1 2
7 2 2
8 3 2
9 4 2
10 5 2

ggplot_build(p2)[["data"]][[1]][,c("x", "PANEL")]

x PANEL
1 1 1
2 2 1
3 3 1
4 4 1
5 5 1
6 6 2
7 7 2
8 8 2
9 9 2
10 10 2

The second plot has the wrong mapping, because when ggplot creates a data.frame for each panel, it picks x values in the "wrong" order.

This occurs because the use of $ breaks the link between the various variables to be mapped (ggplot must assume it's an independent variable, which for all it knows could come from an arbitrary, disconnected source). Since the data.frame in this example is not ordered according to the factor f, the subset data.frames used internally for each panel assume the wrong order.

facet_wrap plotting incorrect x axis co-ordinates

ggplot has a data argument for a reason. When you re-specify the data frame inside aes(), it overrides the subsetting and ordering done for the faceting. Just don't re-specify the name of the data frame (no mydata$column) and everything works fine:

ggplot(ZoutliersM,
aes(x = leftPos,
y = as.numeric(Def.x),
xend = leftPos,
yend = 0)) +
geom_point(fill = "magenta", size = 2, colour = "red") +
facet_wrap(~chr)

Sample Image

Now we can see that in the "22" facet, the point is a little under 10M, as expected.

Two other notes:

  • specifying a "fill" for geom_point won't do anything unless you also use a shape that has separate fill and colors, such as shape = 21

  • In your dput data, Def.x is already numeric, so you don't need to convert it. If it was a factor previously, make sure you convert with as.numeric(as.character(Def.x)), otherwise you'll simply be taking the levels rather than the value to numeric.

Wrong colour when using facet_wrap()

Don't use $ notation in ggplot aesthetics. Use raw variable names instead:

qplot(a,b,data=df,geom='point',color=factor(c)) + 
facet_wrap(~d) +
scale_colour_manual(values=c("blue","orange"))

facet_grid weird rearrangement of values

Do it like here (in aes fill should be the column NAME not the VECTOR):

plot <- ggplot(mockdata, aes(variable, Measurement, fill = plotval)) + 
geom_tile(colour = "dark red") +
facet_grid(category~type, scales='free', space='free') +
scale_fill_gradient2(limits=c(-20, 20),high = "firebrick3", low = "dodgerblue4") +
theme_minimal() +
theme(axis.text.x=element_text(size=28, angle=90),
axis.text.y=element_text(size=28, face = "italic"),
strip.text.x=element_blank(),
strip.text.y=element_text(size=20, angle=0)) +
labs(title="", x="", y="", fill="")

ggplot facet_grid data.table order bug

Just remove all dat.rel$ inside the plot configuration makes the facet_grids work like desired, indipendently from the row order.

Problem with ggplot when reassigning variables for data

ggplot2 saves the data.frame passed to the data parameter in the ggplot object. For anything referenced in aes that is not in this data.frame it has to rely on scoping to find it when the plot is build (each time it is printed).

So, just make sure that resp is passed to the data parameter, too.

resp <- iris$Sepal.Length
p <- ggplot(cbind(iris, resp), aes(x = Petal.Length, y = resp))+
geom_point()
p

resp <- iris$Sepal.Width
p
#same plot

PS: Your example with the function works, because the plot environment of q1 and q2 are environments created during the function call whereas the plot environment of p is the global environment. Compare p$plot_env and q1$plot_env and check out ls(q1$plot_env).

Issue when passing variable with dollar sign notation ($) to aes() in combination with facet_grid() or facet_wrap()

tl;dr

Never use [ or $ inside aes().


Consider this illustrative example where the facetting variable f is purposely in a non-obvious order with respect to x

d <- data.frame(x=1:10, f=rev(letters[gl(2,5)]))

Now contrast what happens with these two plots,

p1 <- ggplot(d) +
facet_grid(.~f, labeller = label_both) +
geom_text(aes(x, y=0, label=x, colour=f)) +
ggtitle("good mapping")

p2 <- ggplot(d) +
facet_grid(.~f, labeller = label_both) +
geom_text(aes(d$x, y=0, label=x, colour=f)) +
ggtitle("$ corruption")

Sample Image

We can get a better idea of what's happening by looking at the data.frame created internally by ggplot2 for each panel,

 ggplot_build(p1)[["data"]][[1]][,c("x","PANEL")]

x PANEL
1 6 1
2 7 1
3 8 1
4 9 1
5 10 1
6 1 2
7 2 2
8 3 2
9 4 2
10 5 2

ggplot_build(p2)[["data"]][[1]][,c("x", "PANEL")]

x PANEL
1 1 1
2 2 1
3 3 1
4 4 1
5 5 1
6 6 2
7 7 2
8 8 2
9 9 2
10 10 2

The second plot has the wrong mapping, because when ggplot creates a data.frame for each panel, it picks x values in the "wrong" order.

This occurs because the use of $ breaks the link between the various variables to be mapped (ggplot must assume it's an independent variable, which for all it knows could come from an arbitrary, disconnected source). Since the data.frame in this example is not ordered according to the factor f, the subset data.frames used internally for each panel assume the wrong order.

error: ggplot2 facet is plotting incorrect values

The key is to adjust the data before calling ggplot() and not to keep calling "df$" inside ggplot. Otherwise certain errors are more likely to happen (e.g. factor orders can get mixed). To fix that in this case, you can try this:

require(ggplot2)

df$exp_fit <- exp(df$fit)
df$exp_lower <- exp(df$lower)
df$exp_upper <- exp(df$upper)
df$Type <- as.factor(df$Type)
df$ZQVT <- as.factor(df$ZQVT)

ggplot(df, aes(x=ZMemScore, y=exp_fit,
color=Type)) +
geom_ribbon(aes(ymin=exp_lower, ymax=exp_upper,
color=NA, fill=Type),
linetype=1, alpha=0.3) +
geom_line(aes(linetype=Type), size=1.2) +
xlab("ZMemScore") + ylab("Predicted RT (ms)") +
labs(color="Type", subtitle="ZQVT") +
facet_grid(. ~ ZQVT) +
scale_linetype_discrete(name='Type', labels=c('Nonword','Real Word')) +
theme_classic() +
scale_color_manual(values=c("black","firebrick2")) +
theme(plot.subtitle = element_text(hjust=0.5)) +
theme(text = element_text(size=14))+
guides(fill=FALSE, color=FALSE)

Output:

Sample Image

Sample data:

require(data.table)
df <- fread("ZMemScore ZQVT Type fit se lower upper
-1 -2 LDTNW 7.029661 0.04961080 6.932423 7.126900
0 -2 LDTNW 7.130045 0.03618878 7.059115 7.200976
1 -2 LDTNW 7.230430 0.05005473 7.132321 7.328538
2 -2 LDTNW 7.330814 0.07777387 7.178375 7.483253
-1 -1 LDTNW 6.953625 0.03015198 6.894526 7.012723
0 -1 LDTNW 7.021205 0.02288979 6.976340 7.066069
1 -1 LDTNW 7.088784 0.03319670 7.023718 7.153851
2 -1 LDTNW 7.156364 0.05141379 7.055592 7.257137
-1 0 LDTNW 6.877588 0.02308945 6.832332 6.922844
0 0 LDTNW 6.912364 0.01719115 6.878669 6.946059
1 0 LDTNW 6.947139 0.02335335 6.901366 6.992912
2 0 LDTNW 6.981915 0.03581413 6.911718 7.052111
-1 1 LDTNW 6.801552 0.03651265 6.729986 6.873117
0 1 LDTNW 6.803523 0.02498816 6.754545 6.852500
1 1 LDTNW 6.805494 0.02890588 6.748837 6.862150
2 1 LDTNW 6.807465 0.04434635 6.720545 6.894385
-1 2 LDTNW 6.725515 0.05752647 6.612762 6.838269
0 2 LDTNW 6.694682 0.03886592 6.618504 6.770860
1 2 LDTNW 6.663848 0.04441321 6.576797 6.750899
2 2 LDTNW 6.633015 0.06852165 6.498711 6.767319
-1 -2 LDTRW 6.903851 0.04518178 6.815294 6.992409
0 -2 LDTRW 6.972785 0.03334094 6.907436 7.038134
1 -2 LDTRW 7.041719 0.04585878 6.951835 7.131603
2 -2 LDTRW 7.110653 0.07082106 6.971842 7.249464
-1 -1 LDTRW 6.806363 0.02755119 6.752362 6.860364
0 -1 LDTRW 6.855938 0.02116456 6.814455 6.897421
1 -1 LDTRW 6.905514 0.03046645 6.845799 6.965229
2 -1 LDTRW 6.955089 0.04690274 6.863158 7.047020
-1 0 LDTRW 6.708874 0.02124658 6.667230 6.750518
0 0 LDTRW 6.739091 0.01594271 6.707843 6.770339
1 0 LDTRW 6.769308 0.02146327 6.727240 6.811377
2 0 LDTRW 6.799525 0.03272497 6.735384 6.863667
-1 1 LDTRW 6.611386 0.03344309 6.545836 6.676935
0 1 LDTRW 6.622244 0.02302851 6.577108 6.667381
1 1 LDTRW 6.633103 0.02646563 6.581230 6.684976
2 1 LDTRW 6.643962 0.04035829 6.564858 6.723065
-1 2 LDTRW 6.513897 0.05253701 6.410923 6.616871
0 2 LDTRW 6.505397 0.03572626 6.435373 6.575422
1 2 LDTRW 6.496898 0.04058913 6.417342 6.576453
2 2 LDTRW 6.488398 0.06223723 6.366411 6.610384")

ggplot2 faceting - plots not reordered when labels reordered

The factor levels reordering that you used seems to work with that small example at least:

library(ggplot2)
dtf <- data.frame(day = c("Mon", "Tue", "Wed", "Thu",
"Fri", "Sat", "Sun"),
value = 1:7)
ggplot(dtf, aes(x = value, y = value)) +
geom_point() + facet_wrap(~day)

day plot

dtf$day1 <- factor(dtf$day, levels = c("Mon", "Tue", "Wed", "Thu",
"Fri", "Sat", "Sun"))
ggplot(dtf, aes(x = value, y = value)) +
geom_point() + facet_wrap(~day1)

day1 plot

Let's have a look at the structure of the data frame:

str(dtf)
# 'data.frame': 7 obs. of 3 variables:
# $ day : Factor w/ 7 levels "Fri","Mon","Sat",..: 2 6 7 5 1 3 4
# $ value: int 1 2 3 4 5 6 7
# $ day1 : Factor w/ 7 levels "Mon","Tue","Wed",..: 1 2 3 4 5 6 7

Values are the same but the order of factor levels has been changed.



Related Topics



Leave a reply



Submit