This question already has answers here:
Conditionally change panel background with facet_grid?
(2 answers)
Closed 10 months ago.
I would like to change the background color of specific facets in a ggplot arranged as a facet_grid.
test <- tibble(rows = c("C", "D","C", "D"),
cols = c("A", "B", "B", "A"),
x = c(1, 1, 1, 1),
y = c(1, 1, 1, 1))
ggplot(test) +
geom_point(aes(x = x, y = y)) +
facet_grid(vars(rows), vars(cols)) +
theme_minimal() +
theme(
panel.grid.major.y = element_blank(),
panel.grid.minor.y = element_blank(),
panel.background = element_rect(fill = NA, color = "grey60")
)
For example, if it were possible to make specifically facet AC have a red panel background color while the others are grey.
I've seen some ways of drilling down into the grob object to do something like this with the strip background (https://github.com/tidyverse/ggplot2/issues/2096) but I can't work out how to get this kind of thing to work for different parts of the plot.
Any help would be great!
Perhaps you prefer a solution like this, no grob manipulation necessary:
ggplot(test) +
geom_rect(
aes(xmin = -Inf, xmax = Inf, ymin = -Inf, ymax = Inf),
data.frame(rows = 'C', cols = 'A'),
fill = 'red', alpha = 0.5
) +
geom_point(aes(x = x, y = y)) +
facet_grid(vars(rows), vars(cols)) +
theme_minimal() +
theme(
panel.grid.major.y = element_blank(),
panel.grid.minor.y = element_blank(),
panel.background = element_rect(fill = NA, color = "grey60")
)
A downside is that the color is drawn on top of the grid lines. Some transparency as used above is usually a good solution. Alternatively, you can use theme(panel.ontop = TRUE) to draw the grid lines on top, but then they will also be plotted on top of the data.
This is a follow-up on https://stackoverflow.com/questions/32275113
The problem is to tweak the legend elements to increase the space between legend keys without simultaneously extending the legend keys themselves. The solution is likely to be in tweaking the correct legend theme option.
Desired result: more vertical space between the legend key text labels, but without stretching the legend key lines.
d <- data.frame(x = mtcars$mpg, y = 0.10)
vlines <- rbind(aggregate(d[1], d[2], mean),
aggregate(d[1], d[2], median))
vlines$stat <- rep(c("mean", "median"), each = nrow(vlines)/2)
library("ggplot2")
ggplot(data = d, aes(x = x, y = ..density..)) +
geom_histogram(fill = "lightblue", color = "black") +
geom_vline(data = vlines, mapping = aes(xintercept = x, colour = stat),
show.legend = TRUE) +
theme(legend.direction = "vertical",
legend.position = "right",
# legend.key = element_rect(size = 2),
legend.key.size = unit(3, "cm"),
# legend.key.width = unit(2, "cm"),
# legend.key.height = unit(1, "cm")
)
Increasing legend.key.size, as suggested in answers to the linked question (see above), has the undesired side effect of increasing the vertical lines as well.
Edit Based on PoGibas's clever workaround, here's a screenshot of the desired result, included here to make sure the purpose is clear:
Following PoGibas, I used: shape = 73, legend.key.height = unit(2, "cm") and size = 6 inside the color guide.
One solution is to replace lines with points (requires additional geom layer):
Create plot with invisible points (size = 0 and rectangle shape shape = 15).
p <- ggplot(d, aes(x, ..density..)) +
geom_histogram(fill = "lightblue", color = "black") +
geom_vline(data = vlines, mapping = aes(xintercept = x, colour = stat)) +
geom_point(data = vlines, aes(0, 0, colour = stat), size = 0, shape = 15)
Add legend theme to:
Mask background color in legend (legend.key = element_rect(fill = "white"))
Create large legend (legend.key.height = unit(3, "cm"))
Remove lines (linetype = 0) and make large points (size = 5)
Code:
p +
theme(legend.direction = "vertical",
legend.position = "right",
legend.key = element_rect(fill = "white"),
legend.key.height = unit(3, "cm")) +
guides(color = guide_legend(override.aes = list(linetype = 0, size = 5)))
PS.:
This is not a perfect solution as there's a gap between legend label and boxes.
If you want lines instead of rectangles use shape = 73
This question already has answers here:
ggplot2 - jitter and position dodge together
(2 answers)
Closed 6 years ago.
I have a data which can be divaded via two seperators. One is year and second is a field characteristics.
box<-as.data.frame(1:36)
box$year <- c(1996,1996,1996,1996,1996,1996,1996,1996,1996,
1997,1997,1997,1997,1997,1997,1997,1997,1997,
1996,1996,1996,1996,1996,1996,1996,1996,1996,
1997,1997,1997,1997,1997,1997,1997,1997,1997)
box$year <- as.character(box$year)
box$case <- c(6.40,6.75,6.11,6.33,5.50,5.40,5.83,4.57,5.80,
6.00,6.11,6.40,7.00,NA,5.44,6.00, NA,6.00,
6.00,6.20,6.40,6.64,6.33,6.60,7.14,6.89,7.10,
6.73,6.27,6.64,6.41,6.42,6.17,6.05,5.89,5.82)
box$code <- c("L","L","L","L","L","L","L","L","L","L","L","L",
"L","L","L","L","L","L","M","M","M","M","M","M",
"M","M","M","M","M","M","M","M","M","M","M","M")
colour <- factor(box$code, labels = c("#F8766D", "#00BFC4"))
In boxplots, I want to display points over them, to see how data is distributed. That is easily done with one single boxplot for every year:
ggplot(box, aes(x = year, y = case, fill = "#F8766D")) +
geom_boxplot(alpha = 0.80) +
geom_point(colour = colour, size = 5) +
theme(text = element_text(size = 18),
axis.title.x = element_blank(),
axis.title.y = element_blank(),
panel.grid.minor.x = element_blank(),
panel.grid.major.x = element_blank(),
legend.position = "none")
But it become more complicated as I add fill parameter in them:
ggplot(box, aes(x = year, y = case, fill = code)) +
geom_boxplot(alpha = 0.80) +
geom_point(colour = colour, size = 5) +
theme(text = element_text(size = 18),
axis.title.x = element_blank(),
axis.title.y = element_blank(),
panel.grid.minor.x = element_blank(),
panel.grid.major.x = element_blank(),
legend.position = "none")
And now the question: How to move these points to boxplot axes, where they belong? As blue points to blue boxplot and red to red one.
Like Henrik said, use position_jitterdodge() and shape = 21. You can clean up your code a bit too:
No need to define box, then fill it piece by piece
You can let ggplot hash out the colors if you wish and skip constructing the colors factor. If you want to change the defaults, look into scale_fill_manual and scale_color_manual.
box <- data.frame(year = c(1996,1996,1996,1996,1996,1996,1996,1996,1996,
1997,1997,1997,1997,1997,1997,1997,1997,1997,
1996,1996,1996,1996,1996,1996,1996,1996,1996,
1997,1997,1997,1997,1997,1997,1997,1997,1997),
case = c(6.40,6.75,6.11,6.33,5.50,5.40,5.83,4.57,5.80,
6.00,6.11,6.40,7.00,NA,5.44,6.00, NA,6.00,
6.00,6.20,6.40,6.64,6.33,6.60,7.14,6.89,7.10,
6.73,6.27,6.64,6.41,6.42,6.17,6.05,5.89,5.82),
code = c("L","L","L","L","L","L","L","L","L","L","L","L",
"L","L","L","L","L","L","M","M","M","M","M","M",
"M","M","M","M","M","M","M","M","M","M","M","M"))
ggplot(box, aes(x = factor(year), y = case, fill = code)) +
geom_boxplot(alpha = 0.80) +
geom_point(aes(fill = code), size = 5, shape = 21, position = position_jitterdodge()) +
theme(text = element_text(size = 18),
axis.title.x = element_blank(),
axis.title.y = element_blank(),
panel.grid.minor.x = element_blank(),
panel.grid.major.x = element_blank(),
legend.position = "none")
I see you've already accepted #JakeKaupp's nice answer, but I thought I would throw in a different option, using geom_dotplot. The data you are visualizing is rather small, so why not forego the boxplot?
ggplot(box, aes(x = factor(year), y = case, fill = code))+
geom_dotplot(binaxis = 'y', stackdir = 'center',
position = position_dodge())
I have been trying to shift my legend title across to be centered over the legend contents using the guide function. I've been trying to use the following code:
guides(colour=guide_legend(title.hjust = 20))
I thought of trying to make a reproducable example, but I think the reason it's not working has something to do with the above line not matching the rest of my code specifically. So here is the rest of the code I'm using in my plot:
NH4.cum <- ggplot(data=NH4_by_Date, aes(x=date, y=avg.NH4, group = CO2, colour=CO2)) +
geom_line(aes(linetype=CO2), size=1) + #line options
geom_point(size=3) + #point symbol sizes
#scale_shape_manual(values = c(1, 16)) + #manually choose symbols
theme_bw()+
theme(axis.text.x=element_text(colour="white"), #change x axis labels to white.
axis.title=element_text(size=12),
axis.title.x = element_text(color="white"), #Change x axis label colour to white
panel.border = element_blank(), #remove box boarder
axis.line.x = element_line(color="black", size = 0.5), #add x axis line
axis.line.y = element_line(color="black", size = 0.5), #add y axis line
legend.key = element_blank(), #remove grey box from around legend
legend.position = c(0.9, 0.6))+ #change legend position
geom_vline(xintercept=c(1.4,7.5), linetype="dotted", color="black")+ #put in dotted lines for season boundaries
scale_color_manual(values = c("#FF6600", "green4", "#0099FF"),
name=expression(CO[2]~concentration~(ppm))) + #manually define line colour
scale_linetype_manual(guide="none", values=c("solid", "solid", "solid")) + #manually define line types
scale_shape_manual(values = c(16, 16, 16)) + #manually choose symbols
guides(colour=guide_legend(title.hjust = 20))+
scale_y_continuous(expand = c(0, 0), limits = c(0,2200), breaks=seq(0,2200,200))+ #change x axis to intercept y axis at 0
xlab("Date")+
ylab(expression(Membrane~available~NH[4]^{" +"}~-N~(~mu~g~resin^{-1}~14~day^{-1})))+
theme(panel.grid.major = element_blank(), panel.grid.minor = element_blank())+
geom_errorbar(aes(ymin = avg.NH4 - se.NH4, #set y error bars
ymax = avg.NH4 + se.NH4),
width=0.1)
I have tried doing the following instead with no luck:
guides(fill=guide_legend(title.hjust=20)
I have also adjusted the hjust value from values between -2 to 20 just to see if that made a difference but it didn't.
I'll try to attach a picture of the graph so far so you can see what I'm talking about.
I've looked through all the questions I can on stack overflow and to the best of my knowledge this is not a duplicate as it's specific to a coding error of my own somewhere.
Thank-you in advance!!
The obvious approach e.g.
theme(legend.title = element_text(hjust = .5))
didn't work for me. I wonder if it is related to this open issue in ggplot2. In any case, one manual approach would be to remove the legend title, and position a new one manually:
ggplot(mtcars, aes(x = wt, y = mpg, colour = factor(cyl))) +
geom_point() +
stat_smooth(se = FALSE) +
theme_bw() +
theme(legend.position = c(.85, .6),
legend.title = element_blank(),
legend.background = element_rect(fill = alpha("white", 0)),
panel.grid.major = element_blank(),
panel.grid.minor = element_blank()) +
annotate("text", x = 5, y = 27, size = 3,
label = "CO[2]~concentration~(ppm)", parse = TRUE)
Output:
I'm plotting a species prediction map in ggplot using a spatial pixels data frame. I have the plot pretty much how I want it, the only problem is that my raster scale goes from white to red and so it's hard to see where it begins in the legend see the plot. I want to draw a box to outline to the legend key- just the bar going from white to red not the rest of it. I've being searching for over an hour but I can't find any way to do this, only ways to give the legend a background or draw a box around the legend text and bar, which I don't want to do. Does anyone know if this is possible to do in ggplot or do I need to change my colour gradient?
Thanks!
My plotting code:
ggplot() +
geom_raster(data=habs_pop_clip1, aes(x = easting.x, y = northing.x, fill = pred)) +
scale_fill_gradient("Probability of occurrence", low="white", high="red",limits = c(0,1)) +
coord_fixed(ratio=1, xlim=c(545000, 654000), ylim=c(278000,347000))+
geom_polygon(data=Norfolk1, aes(x=long, y=lat, Group=group), color="grey",fill=NA)+
theme(text = element_text(family = "serif")) +
geom_segment(aes(x = 550000, y = 278500, xend = 560000, yend = 278500), lineend = "round") +
annotate("text", x = 555000, xend = 555000, y = 282000, yend = 282000, label = "10 km", family = "serif", size = 4) +
ggtitle(colnames(bat_occ[i+7])) +
theme(plot.margin=unit(c(0.5, 0.5, 0.5, 0.5), "cm")) +
theme_bw() +
theme(axis.line = element_line(colour = "black"),
panel.grid.major = element_blank(),
panel.grid.minor = element_blank(),
panel.border = element_blank(),
panel.background = element_blank(),
axis.line=element_blank(),
axis.ticks=element_blank(),
axis.title.x=element_blank(),
axis.title.y=element_blank(),
axis.text =element_blank())
I don't know if there's a built-in parameter. If not, you could add a rectangle manually,
df <- reshape2::melt(outer(1:4, 1:4), varnames = c("X1", "X2"))
p <- ggplot(df, aes(X1, X2)) + geom_tile(aes(fill = value))+ scale_fill_continuous(guide = "colorbar")
g <- ggplotGrob(p)
g$grobs[[8]][[1]][[1]] <- gtable::gtable_add_grob(g$grobs[[8]][[1]][[1]],
rectGrob(gp=gpar(fill=NA, lwd=5)), 4, 2)
grid.newpage()
grid.draw(g)